Guest User

Untitled

a guest
Jul 15th, 2026
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.47 KB | None | 0 0
  1. #!/usr/bin/env -S mg run
  2.  
  3. import "mg/face"
  4. import "mg/math"
  5. import "mg/prim"
  6. import "mg/topology"
  7. import "mg/trans"
  8. import "mg/types"
  9. import "mg/util"
  10.  
  11. threshold := 0.00001
  12.  
  13. func deskFan(smoothness=1.0) {
  14. # Base
  15. baseCols := types.Int(16.0*smoothness)
  16. baseMaxRows := types.Int(32.0*smoothness)
  17. baseRadius := 0.5
  18. baseRadiusThreshold := baseRadius / (smoothness*15.0)
  19. baseTopRadius := 0.075
  20. baseHeight := 0.7
  21.  
  22. base := trans.Scale([baseRadius, baseRadius], prim.Ngon(baseCols))
  23.  
  24. prevRadius := baseRadius
  25. prevRing := base
  26. baseRad := func() {
  27. return func(i=0) {
  28. i++
  29. curve := (types.Float(baseMaxRows+1)/(types.Float(i)/smoothness+1.0)-1.0)/types.Float(baseMaxRows+1)
  30. return curve*(baseRadius-baseTopRadius)+baseTopRadius
  31. }
  32. }()
  33. for i := range baseMaxRows {
  34. nextRadius := baseRad(i)
  35. if i < baseMaxRows-1 && nextRadius ~baseRadiusThreshold:>= prevRadius {
  36. continue
  37. }
  38. z := baseHeight*types.Float(i+1)/types.Float(baseMaxRows)
  39. nextRing := trans.Translate([0, 0, z],
  40. trans.Scale([nextRadius, nextRadius],
  41. prim.Ngon(baseCols)))
  42. topology.Quads(prevRing, nextRing, true)
  43. prevRing = nextRing
  44. prevRadius = nextRadius
  45. }
  46.  
  47. face.Face(util.Reverse(base).(base)...)
  48.  
  49. out := face.Connected(base...)
  50.  
  51. # Back
  52. backRadius := 0.25
  53. backFacets := types.Int(6.0*smoothness)
  54. backDomeScale := 0.5
  55. backSideLength := 0.40
  56. backBaseOverlap := 0.03
  57.  
  58. back := trans.Scale([backRadius, backRadius, backRadius],
  59. trans.Scale([1.0, 1.0, backDomeScale],
  60. prim.Sphere(backFacets*2, backFacets*4)))
  61.  
  62. backBottom := [for _, v := range back; if v.z ~threshold:<= 0.0 {v}]
  63. backEquator := [for _, v := range backBottom; if v.z ~threshold:>= 0.0 {v}]
  64. backExtend := trans.Translate([0.0, 0.0, backSideLength],
  65. util.DeepCopy(backEquator).(backEquator))
  66.  
  67. topology.Quads(backEquator, backExtend, true)
  68. face.Face(backExtend...)
  69.  
  70. back &= backExtend
  71.  
  72. out &= backBottom & backExtend
  73.  
  74. trans.Translate([0.0, 0.0, baseHeight-backBaseOverlap],
  75. trans.Rotate([0.0, 90.0, 0.0],
  76. trans.Translate([-backRadius, 0.0, -backSideLength/2.0],
  77. back)))
  78.  
  79. backRef := [backSideLength/2.0, 0.0, baseHeight-backBaseOverlap+backRadius]
  80. backTop := baseHeight+backRadius*2.0-backBaseOverlap
  81.  
  82. # Cage
  83. cageScale := 0.4
  84. cageRadius := 0.75
  85. cageOverlap := 0.035
  86. cageRibCount := 18
  87. cageFacets := types.Int(20.0*smoothness)
  88. cageRibFacets := types.Int(2.0*smoothness)
  89. cageRibWidth := 0.03
  90.  
  91. cageCenter := [backRef[0]+cageRadius*cageScale-cageOverlap, 0.0, backRef[2]]
  92.  
  93. cage := [{0, 0, 0}][:0]
  94. cageRibCrossSection := trans.Scale([types.Float(cageRibWidth)/2.0, types.Float(cageRibWidth)/2.0], prim.Ngon(cageRibFacets*2))
  95. for ribi := range cageRibCount {
  96. baseRib := trans.Scale([cageRadius*cageScale, cageRadius, 0.0],
  97. [for _, v := range prim.Ngon(cageFacets); if v.y ~threshold:>= 0.0 {v}])
  98. rib := topology.ExtrudeAlong(baseRib, cageRibCrossSection)
  99. trans.Translate(cageCenter, trans.Rotate([90.0+types.Float(ribi)*360.0/types.Float(cageRibCount), 0.0, 0.0], rib))
  100. cage &= rib
  101. }
  102.  
  103. out &= cage
  104.  
  105. # Blades hub
  106. bladesHubRadius := 0.1
  107. bladesHubFacets := types.Int(4.0*smoothness)
  108. bladesHubDomeScale := 0.75
  109. bladesHubSideLength := 0.15
  110. bladesHubOffset := 0.04
  111.  
  112. bladesHub := trans.Scale([bladesHubRadius, bladesHubRadius, bladesHubRadius*bladesHubDomeScale],
  113. [for _, v := range prim.Sphere(bladesHubFacets*2, bladesHubFacets*4); if v.z ~threshold:<= 0.0 {v}])
  114. bladesHubEquator := [for _, v := range bladesHub; if v.z ~threshold:>= 0.0 {v}]
  115. bladesHubExtend := trans.Translate([0.0, 0.0, bladesHubSideLength],
  116. util.DeepCopy(bladesHubEquator).(bladesHubEquator))
  117.  
  118. face.Face(bladesHubExtend...)
  119. topology.Quads(bladesHubEquator, bladesHubExtend, true)
  120.  
  121. bladesHub &= bladesHubExtend
  122.  
  123. trans.Translate(cageCenter + [bladesHubOffset+bladesHubSideLength-(bladesHubDomeScale*bladesHubRadius+bladesHubSideLength)/2.0, 0.0, 0.0],
  124. trans.Rotate([0.0, -90.0, 0.0],
  125. bladesHub))
  126.  
  127. out &= bladesHub
  128.  
  129. # Blades
  130. bladesCount := 3
  131. bladesAngleGap := 20.0
  132. bladesLength := cageRadius*0.70
  133. bladesRoundRadius := bladesLength/4.0
  134. bladesRoundFacets := types.Int(6.0*smoothness)
  135. bladesTwistAngle := 15.0
  136.  
  137. blades := [{0, 0, 0}][:0]
  138. bladesHalfAngle := (360.0/types.Float(bladesCount)-bladesAngleGap)/2.0
  139. bladesRoundVert := func(k=0) {
  140. a := types.Float(k)*(90.0+bladesHalfAngle)/types.Float(bladesRoundFacets)-bladesHalfAngle
  141. return {bladesRoundRadius*math.Cos(a), bladesRoundRadius*math.Sin(a), 0.0}
  142. }
  143. for i := range bladesCount {
  144. vs := [for j := range bladesRoundFacets+1 {bladesRoundVert(j)}]
  145. vs += {(bladesLength-(1.0+math.Sin(bladesHalfAngle))*bladesRoundRadius)*math.Tan(bladesHalfAngle)-bladesRoundRadius*math.Cos(bladesHalfAngle), bladesLength-bladesRoundRadius, 0.0}
  146. vs &= util.Reverse(trans.Scale([-1.0, 1.0, 1.0], util.DeepCopy(vs).(vs))).(vs)
  147. vs &= [{0, 0, 0}]
  148. vs = trans.Rotate([0.0, bladesTwistAngle, 360.0*types.Float(i)/types.Float(bladesCount)], vs)
  149. blades &= vs
  150. face.Face(vs...)
  151. face.Face(util.Reverse(vs).(vs)...)
  152. }
  153.  
  154. trans.Translate(cageCenter + [bladesHubSideLength-(bladesHubDomeScale*bladesHubRadius+bladesHubSideLength)/2.0, 0.0, 0.0],
  155. trans.Rotate([0.0, -90.0, 0.0],
  156. blades))
  157.  
  158. out &= blades
  159.  
  160. # Oscillate peg
  161. pegOffset := -0.13
  162. pegOverlap := 0.015
  163. pegLoc := [pegOffset, 0.0, backTop-pegOverlap]
  164. pegBaseRadius := 0.035
  165. pegBaseHeight := 0.03
  166. pegBaseFacets := types.Int(14.0*smoothness)
  167. pegRadius := 0.017
  168. pegHeight := 0.05
  169. pegFacets := types.Int(10.0*smoothness)
  170. pegTopRadius := 0.035
  171. pegTopHeight := 0.02
  172. pegTopFacets := types.Int(14.0*smoothness)
  173.  
  174. peg := trans.Scale([pegTopRadius, pegTopRadius, pegTopHeight],
  175. trans.Translate([0.0, 0.0, 0.5],
  176. prim.Cylinder(pegTopFacets, true)))
  177. peg = trans.Translate([0.0, 0.0, pegHeight], peg)
  178. peg &= trans.Scale([pegRadius, pegRadius, pegHeight],
  179. trans.Translate([0.0, 0.0, 0.5],
  180. prim.Cylinder(pegFacets)))
  181. peg = trans.Translate([0.0, 0.0, pegBaseHeight], peg)
  182. peg &= trans.Scale([pegBaseRadius, pegBaseRadius, pegBaseHeight],
  183. trans.Translate([0.0, 0.0, 0.5],
  184. prim.Cylinder(pegBaseFacets, true)))
  185. peg = trans.Translate(pegLoc, peg)
  186.  
  187. out &= peg
  188.  
  189. # Switch
  190. switchBaseRadius := 0.03
  191. switchBaseFacets := types.Int(2.0*smoothness)
  192. switchDistFromBase := 0.09
  193. switchFulcrumRadius := 0.013
  194. switchFulcrumFacets := types.Int(2.0*smoothness)
  195. switchFulcrumOverlap := 0.008
  196. switchHandleRadius := 0.008
  197. switchHandleFacets := types.Int(2.0*smoothness)
  198. switchHandleLength := 0.05
  199. switchHandleAngle := 15.0
  200.  
  201. switchBase := trans.Scale([switchBaseRadius, switchBaseRadius, switchBaseRadius],
  202. prim.Sphere(switchBaseFacets*2, switchBaseFacets*4))
  203. switchBase = [for _, v := range switchBase; if v.z ~threshold:>= 0.0 {v}]
  204.  
  205. switchFulcrum := trans.Scale([switchFulcrumRadius, switchFulcrumRadius, switchFulcrumRadius],
  206. prim.Sphere(switchFulcrumFacets*2, switchFulcrumFacets*4))
  207. switchFulcrum = [for _, v := range switchFulcrum; if v.z ~threshold:>= 0.0 {v}]
  208. switchFulcrum = trans.Translate([0.0, 0.0, switchBaseRadius-switchFulcrumOverlap], switchFulcrum)
  209.  
  210. switchHandle := trans.Scale([switchHandleRadius, switchHandleRadius, switchHandleRadius],
  211. prim.Sphere(switchHandleFacets*2, switchHandleFacets*4))
  212. switchHandle = [for _, v := range switchHandle; if v.z ~threshold:>= 0.0 {v}]
  213. switchHandleEquator := [for _, v := range switchHandle; if v.z ~threshold:<= 0.0 {v}]
  214. switchHandle = trans.Translate([0.0, 0.0, switchHandleLength-switchHandleRadius], switchHandle)
  215. switchHandlePoint := {0, 0, -(switchBaseRadius-switchFulcrumOverlap)}
  216. topology.BTris(switchHandlePoint, switchHandleEquator, true)
  217. switchHandle &= [switchHandlePoint]
  218. switchHandle = trans.Rotate([switchHandleAngle, 0.0, 0.0], switchHandle)
  219. switchHandle = trans.Translate([0.0, 0.0, switchBaseRadius-switchFulcrumOverlap], switchHandle)
  220.  
  221. switch := switchBase & switchFulcrum & switchHandle
  222.  
  223. switch = trans.Translate([baseRadius-switchDistFromBase, 0.0, 0.0], switch)
  224.  
  225. out &= switch
  226.  
  227. # Motor axle
  228. axleRadius := 0.017
  229. axleFacets := types.Int(8.0*smoothness)
  230.  
  231. axleHeight := cageCenter[0] - backRef[0]
  232.  
  233. axle := trans.Translate(backRef,
  234. trans.Rotate([0.0, 90.0, 0.0],
  235. trans.Scale([axleRadius, axleRadius, axleHeight],
  236. trans.Translate([0.0, 0.0, 0.5],
  237. prim.Cylinder(axleFacets)))))
  238.  
  239. out &= axle
  240.  
  241. return out
  242. }
  243.  
  244. # Display it
  245. util.Display(deskFan(1.0))
  246.  
  247. #all := [{0, 0, 0}][:0]
  248. #for i, s := range [1.0, 2.0, 4.0, 8.0] {
  249. # all &= trans.Translate([0.0, types.Float(i)*1.5, 0.0],
  250. # deskFan(s))
  251. #}
  252. #util.Display(all)
Advertisement
Add Comment
Please, Sign In to add comment