solidruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +3 -0
  4. data/COPYING +674 -0
  5. data/Gemfile +2 -0
  6. data/Guardfile +24 -0
  7. data/LICENSE.md +675 -0
  8. data/README.md +180 -0
  9. data/Rakefile +10 -0
  10. data/bin/solidruby +61 -0
  11. data/examples/chamfered_cube.rb +39 -0
  12. data/examples/filleted_cube.rb +39 -0
  13. data/examples/gear.rb +11 -0
  14. data/examples/knurls.rb +12 -0
  15. data/examples/nut_support.rb +17 -0
  16. data/examples/openscad_examples/old/example001.rb +42 -0
  17. data/examples/openscad_examples/old/example002.rb +45 -0
  18. data/examples/openscad_examples/old/example003.rb +37 -0
  19. data/examples/openscad_examples/old/example004.rb +22 -0
  20. data/examples/openscad_examples/old/example005.rb +45 -0
  21. data/examples/openscad_examples/old/example006.rb +85 -0
  22. data/examples/openscad_examples/old/example007.dxf +2410 -0
  23. data/examples/openscad_examples/old/example007.rb +107 -0
  24. data/examples/openscad_examples/old/example008.rb +61 -0
  25. data/examples/openscad_examples/old/example009.dxf +3894 -0
  26. data/examples/openscad_examples/old/example009.rb.old +48 -0
  27. data/examples/openscad_examples/old/example010.dat +51 -0
  28. data/examples/openscad_examples/old/example010.rb +23 -0
  29. data/examples/openscad_examples/old/example011.rb +42 -0
  30. data/examples/openscad_examples/old/example012.rb +22 -0
  31. data/examples/openscad_examples/old/example012.stl +450 -0
  32. data/examples/openscad_examples/old/example013.dxf +2276 -0
  33. data/examples/openscad_examples/old/example013.rb +30 -0
  34. data/examples/openscad_examples/old/example014.rb +30 -0
  35. data/examples/openscad_examples/old/example015.rb +46 -0
  36. data/examples/openscad_examples/old/example016.rb +75 -0
  37. data/examples/openscad_examples/old/example016.stl +0 -0
  38. data/examples/pipe.rb +38 -0
  39. data/examples/pipe_bug.rb +16 -0
  40. data/examples/printed_gear.rb +12 -0
  41. data/examples/printed_gear2.rb +16 -0
  42. data/examples/printed_thread.rb +9 -0
  43. data/examples/printed_thread2.rb +13 -0
  44. data/examples/stack.rb +21 -0
  45. data/examples/threads.rb +183 -0
  46. data/examples/threads2.rb +93 -0
  47. data/examples/threads3.rb +46 -0
  48. data/lib/solidruby.rb +60 -0
  49. data/lib/solidruby/assemblies/assembly.rb +176 -0
  50. data/lib/solidruby/assemblies/bolt.rb +158 -0
  51. data/lib/solidruby/assemblies/gear.rb +131 -0
  52. data/lib/solidruby/assemblies/linear_bearing.rb +84 -0
  53. data/lib/solidruby/assemblies/nut.rb +153 -0
  54. data/lib/solidruby/assemblies/pipe.rb +153 -0
  55. data/lib/solidruby/assemblies/ruler.rb +44 -0
  56. data/lib/solidruby/assemblies/tslot.rb +141 -0
  57. data/lib/solidruby/assemblies/tslot_machining.rb +62 -0
  58. data/lib/solidruby/assemblies/washer.rb +57 -0
  59. data/lib/solidruby/bill_of_material.rb +43 -0
  60. data/lib/solidruby/csg_modelling/csg_modelling.rb +43 -0
  61. data/lib/solidruby/csg_modelling/difference.rb +41 -0
  62. data/lib/solidruby/csg_modelling/hull.rb +23 -0
  63. data/lib/solidruby/csg_modelling/intersection.rb +24 -0
  64. data/lib/solidruby/csg_modelling/minkowski.rb +23 -0
  65. data/lib/solidruby/csg_modelling/union.rb +41 -0
  66. data/lib/solidruby/csg_modifiers/color.rb +41 -0
  67. data/lib/solidruby/csg_modifiers/csg_modifier.rb +50 -0
  68. data/lib/solidruby/csg_modifiers/linear_extrude.rb +34 -0
  69. data/lib/solidruby/csg_modifiers/projection.rb +29 -0
  70. data/lib/solidruby/csg_modifiers/rotate_extrude.rb +30 -0
  71. data/lib/solidruby/extra.rb +58 -0
  72. data/lib/solidruby/helpers/chamfer.rb +27 -0
  73. data/lib/solidruby/helpers/fillet.rb +28 -0
  74. data/lib/solidruby/helpers/position.rb +267 -0
  75. data/lib/solidruby/helpers/rounded_cube.rb +37 -0
  76. data/lib/solidruby/helpers/triangle.rb +167 -0
  77. data/lib/solidruby/primitives/circle.rb +26 -0
  78. data/lib/solidruby/primitives/cube.rb +123 -0
  79. data/lib/solidruby/primitives/cylinder.rb +72 -0
  80. data/lib/solidruby/primitives/import.rb +42 -0
  81. data/lib/solidruby/primitives/polygon.rb +26 -0
  82. data/lib/solidruby/primitives/polyhedron.rb +30 -0
  83. data/lib/solidruby/primitives/primitive.rb +19 -0
  84. data/lib/solidruby/primitives/render.rb +48 -0
  85. data/lib/solidruby/primitives/sphere.rb +49 -0
  86. data/lib/solidruby/primitives/square.rb +88 -0
  87. data/lib/solidruby/primitives/surface.rb +44 -0
  88. data/lib/solidruby/primitives/text.rb +43 -0
  89. data/lib/solidruby/printed_thread.rb +163 -0
  90. data/lib/solidruby/rubyscad_bridge.rb +376 -0
  91. data/lib/solidruby/screw_thread.rb +170 -0
  92. data/lib/solidruby/solidruby.rb +150 -0
  93. data/lib/solidruby/solidruby_object.rb +176 -0
  94. data/lib/solidruby/transformations/mirror.rb +22 -0
  95. data/lib/solidruby/transformations/rotate.rb +22 -0
  96. data/lib/solidruby/transformations/scale.rb +22 -0
  97. data/lib/solidruby/transformations/transformation.rb +29 -0
  98. data/lib/solidruby/transformations/translate.rb +32 -0
  99. data/lib/solidruby/version.rb +18 -0
  100. data/lib/templates/assembly.tt +13 -0
  101. data/lib/templates/gitignore.tt +3 -0
  102. data/lib/templates/guardfile.tt +4 -0
  103. data/lib/templates/main.tt +20 -0
  104. data/lib/templates/params.tt +3 -0
  105. data/lib/templates/printed.tt +9 -0
  106. data/manual/manual.html +417 -0
  107. data/solidruby.gemspec +35 -0
  108. metadata +277 -0
@@ -0,0 +1,131 @@
1
+ # This file is part of SolidRuby.
2
+ #
3
+ # SolidRuby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # SolidRuby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with SolidRuby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module SolidRuby::Assemblies
17
+ class Gear < Assembly
18
+ # this library is to be used to easily work with gears and their distances to each other
19
+
20
+ attr_reader :module, :teeth, :height, :hub_dia, :hub_height
21
+
22
+ def initialize(args = {})
23
+ @module = args[:module] || 1.0
24
+ @teeth = args[:teeth] || 1.0
25
+ @bore = args[:bore] || 0.0
26
+ @height = args[:height] || 3.0
27
+ @hub_dia = args[:hub_dia] || 0.0
28
+ @hub_height = args[:hub_height] || 0.0
29
+ @output_margin_dia = args[:output_margin_dia] || 2
30
+ @output_margin_height = args[:output_margin_height] || 1
31
+ super(args)
32
+ end
33
+
34
+ def show
35
+ res = cylinder(d: @module * @teeth, h: @height)
36
+
37
+ if @hub_height.to_f > 0 && @hub_dia.to_f > 0
38
+ res += cylinder(d: @hub_dia, h: @hub_height).translate(z: @height)
39
+ end
40
+
41
+ if @bore.to_f > 0.0
42
+ res -= cylinder(d: @bore, h: @height + @hub_height + 0.2).translate(z: -0.1)
43
+ end
44
+ res.color('darkgray')
45
+ end
46
+
47
+ def output
48
+ res = cylinder(d: @module * @teeth + @output_margin_dia, h: @height + @output_margin_height)
49
+ if @hub_height.to_f > 0 && @hub_dia.to_f > 0
50
+ res += cylinder(d: @hub_dia + @output_margin_dia, h: @hub_height + @output_margin_height).translate(z: @height)
51
+ end
52
+
53
+ res
54
+ end
55
+
56
+ def distance_to(other_gear)
57
+ if @module != other_gear.module
58
+ raise 'You cannot use two gears with different gear modules.'
59
+ return
60
+ end
61
+ (@module.to_f * (@teeth.to_f + other_gear.teeth.to_f)) / 2.0
62
+ end
63
+
64
+ def ratio(other_gear)
65
+ @teeth.to_f / other_gear.teeth.to_f
66
+ end
67
+ end
68
+
69
+ # Acts the same as Gear, but does produce printable output
70
+ class PrintedGear < Gear
71
+ def initialize(args = {})
72
+ super
73
+ @pressure_angle = args[:pressure_angle] || 20
74
+ @clearance = args[:clearance] || 0.0
75
+ @backlash = args[:backlash] || 0.0
76
+ @twist = args[:twist] || 0.0
77
+ @teeth_to_hide = args[:teeth_to_hide] || 0.0
78
+
79
+ @rotation = args[:rotation] || 0.0 # rotation in teeth
80
+ end
81
+
82
+ def show
83
+ output
84
+ end
85
+
86
+ # ported from publicDomainGearV1.1.scad
87
+ def output
88
+ p = @module * @teeth / 2.0
89
+ c = p + @module - @clearance # radius of pitch circle
90
+ b = p * Math.cos(radians(@pressure_angle)) # radius of base circle
91
+ r = p - (c - p) - @clearance # radius of root circle
92
+ t = (@module * Math::PI) / 2.0 - @backlash / 2.0 # tooth thickness at pitch circle
93
+ k = -iang(b, p) - t / 2.0 / p / Math::PI * 180 # angle to where involute meets base circle on each side of tooth
94
+
95
+ points = [
96
+ [0, -@hub_dia / 10.0],
97
+ polar(r, -181 / @teeth.to_f),
98
+ polar(r, r < b ? k : -180 / @teeth.to_f),
99
+ q7(0 / 5, r, b, c, k, 1), q7(1 / 5, r, b, c, k, 1), q7(2 / 5, r, b, c, k, 1), q7(3 / 5, r, b, c, k, 1), q7(4 / 5, r, b, c, k, 1), q7(5 / 5, r, b, c, k, 1),
100
+ q7(5 / 5, r, b, c, k, -1), q7(4 / 5, r, b, c, k, -1), q7(3 / 5, r, b, c, k, -1), q7(2 / 5, r, b, c, k, -1), q7(1 / 5, r, b, c, k, -1), q7(0 / 5, r, b, c, k, -1),
101
+ polar(r, r < b ? -k : 180 / @teeth.to_f),
102
+ polar(r, 181 / @teeth.to_f)
103
+ ]
104
+ paths = [(0..16).to_a]
105
+
106
+ res = SolidRubyObject.new
107
+ (0..@teeth - @teeth_to_hide - 1).each do |i|
108
+ res += polygon(points: points, paths: paths).linear_extrude(h: @height, convexity: 10, center: false, twist: @twist).rotate(z: i * 360 / @teeth.to_f)
109
+ end
110
+
111
+ res -= cylinder(h: @height + 0.2, d: @bore).translate(z: -0.1)
112
+ res.rotate(z: @rotation * 360.0 / @teeth)
113
+ end
114
+
115
+ def polar(r, theta)
116
+ [r * Math.sin(radians(theta)), r * Math.cos(radians(theta))] # convert polar to cartesian coordinates
117
+ end
118
+
119
+ def iang(r1, r2)
120
+ Math.sqrt((r2 / r1) * (r2 / r1) - 1) / Math::PI * 180 - degrees(Math.acos(r1 / r2)) # //unwind a string this many degrees to go from radius r1 to radius r2
121
+ end
122
+
123
+ def q7(f, r, b, r2, t, s)
124
+ q6(b, s, t, (1 - f) * [b, r].max + f * r2) # radius a fraction f up the curved side of the tooth
125
+ end
126
+
127
+ def q6(b, s, t, d)
128
+ polar(d, s * (iang(b, d) + t)) # point at radius d on the involute curve
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,84 @@
1
+ # This file is part of SolidRuby.
2
+ #
3
+ # SolidRuby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # SolidRuby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with SolidRuby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module SolidRuby::Assemblies
17
+ class Lm_uu < Assembly
18
+ def initialize(args = { inner_diameter: 10 })
19
+ @args = args
20
+ @lm_uu = {
21
+ 3 => { diameter: 7, length: 10 },
22
+ 4 => { diameter: 8, length: 12 },
23
+ 5 => { diameter: 10, length: 15 },
24
+ 6 => { diameter: 12, length: 19 },
25
+ 8 => { diameter: 15, length: 24 },
26
+ 10 => { diameter: 19, length: 29 },
27
+ 12 => { diameter: 21, length: 30 },
28
+ 13 => { diameter: 23, length: 32 },
29
+ 16 => { diameter: 28, length: 37 },
30
+ 20 => { diameter: 32, length: 42 },
31
+ 25 => { diameter: 40, length: 59 },
32
+ 30 => { diameter: 45, length: 64 },
33
+ 35 => { diameter: 52, length: 70 },
34
+ 40 => { diameter: 60, length: 80 },
35
+ 50 => { diameter: 80, length: 100 },
36
+ 60 => { diameter: 90, length: 110 }
37
+ }
38
+ @shell_thickness = 1.1
39
+ BillOfMaterial.bom.add(description) unless args[:no_bom] == true
40
+ end
41
+
42
+ def description
43
+ "LM#{@args[:inner_diameter]}UU Linear bearing"
44
+ end
45
+
46
+ def output
47
+ show
48
+ end
49
+
50
+ def dimensions
51
+ diameter = @lm_uu[@args[:inner_diameter]][:diameter]
52
+ length = @lm_uu[@args[:inner_diameter]][:length]
53
+ [diameter, length]
54
+ end
55
+
56
+ def show
57
+ diameter, length = dimensions
58
+ shell = cylinder(d: diameter, h: length)
59
+ shell -= cylinder(d: diameter - @shell_thickness * 2, h: length + 0.2).translate(z: -0.1)
60
+ shell = shell.color('LightGrey')
61
+
62
+ inner = cylinder(d: diameter - @shell_thickness * 2, h: length)
63
+ inner -= cylinder(d: @args[:inner_diameter], h: length + 0.2).translate(z: -0.1)
64
+ inner = inner.color('DimGray')
65
+
66
+ shell + inner
67
+ end
68
+ end
69
+
70
+ class Lm_luu < Lm_uu
71
+ def initialize(args = { inner_diameter: 10 })
72
+ @args = args
73
+ @lm_uu = {
74
+ 12 => { diameter: 21, length: 57 }
75
+ }
76
+ @shell_thickness = 1.1
77
+ BillOfMaterial.bom.add(description) unless args[:no_bom] == true
78
+ end
79
+
80
+ def description
81
+ "LM#{@args[:inner_diameter]}LUU (long) Linear bearing"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,153 @@
1
+ # This file is part of SolidRuby.
2
+ #
3
+ # SolidRuby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # SolidRuby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with SolidRuby. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+ module SolidRuby::Assemblies
17
+ class Nut < Assembly
18
+ attr_accessor :height
19
+ def initialize(size, args = {})
20
+ @size = size
21
+ @type = args[:type] ||= '934'
22
+ @material = args[:material] ||= '8.8'
23
+ @surface = args[:surface] ||= 'zinc plated'
24
+ @support = args[:support] ||= false
25
+ @support_layer_height = args[:support_layer_height] ||= 0.2
26
+ @margin = args[:margin] ||= 0.3 # default output margin
27
+
28
+ @slot = args[:slot] || nil
29
+ @slot_margin = args[:slot_margin] || 0.5
30
+ @slot_direction = args[:slot_direction] || 'z'
31
+ @cylinder_length = args[:cylinder_length] || 0 # for slot only
32
+
33
+ @transformations ||= []
34
+ @args = args
35
+ prepare_data
36
+ @height = args[:height] || @height
37
+
38
+ @direction = args[:direction] || @slot_direction
39
+
40
+ @bolt = nil
41
+ super(args)
42
+ end
43
+
44
+ def description
45
+ "M#{@size} Nut, DIN #{@type}, #{@material} #{@surface}"
46
+ end
47
+
48
+ def bolt(length = nil, args = {})
49
+ return @bolt if @bolt
50
+ @bolt = Bolt.new(@size, length, args)
51
+ case @direction
52
+ when 'z'
53
+ bolt.transformations << Rotate.new(x: 180)
54
+ bolt.transformations << Translate.new(z: length)
55
+ when '-z'
56
+ bolt.transformations << Translate.new(z: -length + @height)
57
+ when '-x'
58
+ bolt.transformations << Rotate.new(x: 180)
59
+ bolt.transformations << Translate.new(z: length)
60
+ when 'x'
61
+ bolt.transformations << Translate.new(z: -length + @height)
62
+ when '-y'
63
+ bolt.transformations << Rotate.new(x: 180)
64
+ bolt.transformations << Translate.new(z: length)
65
+ when 'y'
66
+ bolt.transformations << Translate.new(z: -length + @height)
67
+ end
68
+ @bolt.transformations += transformations.dup
69
+
70
+ @bolt
71
+ end
72
+
73
+ def prepare_data
74
+ chart_934 = {
75
+ 2.5 => { side_to_side: 5, height: 2, support_diameter: 2.8 },
76
+ 3 => { side_to_side: 5.5, height: 2.4, support_diameter: 3.5 },
77
+ 4 => { side_to_side: 7, height: 3.2, support_diameter: 4.4 },
78
+ 5 => { side_to_side: 8, height: 4, support_diameter: 5.3 },
79
+ 6 => { side_to_side: 10, height: 5, support_diameter: 6.3 },
80
+ 8 => { side_to_side: 13, height: 6.5, support_diameter: 8.3 },
81
+ 10 => { side_to_side: 17, height: 8, support_diameter: 10.3 },
82
+ 12 => { side_to_side: 19, height: 10, support_diameter: 12.3 }
83
+ }
84
+ # for securing nuts
85
+ chart_985 = {
86
+ 3 => { height: 4 },
87
+ 4 => { height: 5 },
88
+ 5 => { height: 5 },
89
+ 6 => { height: 6 }
90
+ }
91
+
92
+ @s = chart_934[@size][:side_to_side]
93
+ @height = chart_934[@size][:height]
94
+ @support_diameter = chart_934[@size][:support_diameter]
95
+ @height = chart_985[@size][:height] if @type == "985"
96
+ end
97
+
98
+ def add_support(layer_height = @support_layer_height)
99
+ res = cylinder(d: @support_diameter, h: @height - layer_height)
100
+ # on very small nuts, add a support base of one layer height, so the support won't fall over
101
+ res += cylinder(d:@s-1,h:layer_height) if @size < 6
102
+ res
103
+ end
104
+
105
+ def slot
106
+ case @slot_direction
107
+ when 'x'
108
+ pos = { x: @slot }
109
+ when 'y'
110
+ pos = { y: @slot }
111
+ when 'z'
112
+ pos = { z: @slot }
113
+ when '-x'
114
+ pos = { x: -@slot }
115
+ when '-y'
116
+ pos = { y: -@slot }
117
+ when '-z'
118
+ pos = { z: -@slot }
119
+ else
120
+ raise "Invalid slot direction #{@slot_direction}"
121
+ end
122
+ res = hull(
123
+ nut_934(false, @margin, @slot_margin),
124
+ nut_934(false, @margin, @slot_margin).translate(pos)
125
+ )
126
+ res += cylinder(d:@size+@margin,h:@cylinder_length) if @cylinder_length > 0
127
+ res
128
+ end
129
+
130
+ def output
131
+ add_to_bom
132
+ if @slot.nil?
133
+ return transform(nut_934(false, @margin))
134
+ else
135
+ return transform(slot)
136
+ end
137
+ end
138
+
139
+ def show
140
+ add_to_bom
141
+ transform(nut_934)
142
+ end
143
+
144
+ def nut_934(show = true, margin = 0, height_margin = 0)
145
+ @s += margin
146
+
147
+ res = cylinder(d: (@s / Math.sqrt(3)) * 2, h: @height + height_margin, fn: 6)
148
+ res -= cylinder(d: @size, h: @height) if show == true
149
+ res -= add_support if @support
150
+ res.color('Gainsboro')
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,153 @@
1
+ # This file is part of SolidRuby.
2
+ #
3
+ # SolidRuby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # SolidRuby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with SolidRuby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module SolidRuby::Assemblies
17
+ class Pipe < Assembly
18
+ attr_accessor :x, :y, :sum_x, :sum_y, :pipe, :bent_segments
19
+ # Warning: sum_x and sum_y are both a quick hack at the moment
20
+ # They will ONLY work on bends if you do same thing in the other direction
21
+ # for example
22
+ # pipe.cw(20,30)
23
+ # pipe.ccw(20,30)
24
+ # This might be fixed in the future.
25
+
26
+ def initialize(args = {})
27
+ # parameters
28
+ @diameter = args[:diameter] || 1
29
+ @fn = args[:fn] || 64
30
+ @bent_segments = args[:bent_segments] || 128
31
+ @line_rotation = args[:line_rotation] || 0 # z rotation in case needed with fn values
32
+
33
+ # variable initialization
34
+ @pipe = nil
35
+ @sum_x = 0
36
+ @sum_y = 0
37
+ end
38
+
39
+ def shape
40
+ circle(d: @diameter, fn: @fn)
41
+ end
42
+
43
+ def inner_shape
44
+ nil
45
+ end
46
+
47
+ # This will be called on bent, so this library can work with rectangle pipes, if you overwrite this and let it rotate z by 90
48
+ def apply_rotation(obj)
49
+ obj
50
+ end
51
+
52
+ # go clockwise
53
+ def cw(radius, angle, color = nil)
54
+ return false if angle > 360
55
+ # since bent can only do up to 90°, splitting it up in chunks in order to grow it
56
+ return cw(radius, 90, color) + cw(radius, angle - 90, color) if angle > 90
57
+
58
+ if @pipe.nil?
59
+ @pipe = bent_cw(radius, angle)
60
+ @pipe = @pipe.color(color) unless color.nil?
61
+ else
62
+ rotated_pipe = @pipe.rotate(z: -angle)
63
+ pipe_piece = bent_cw(radius, angle)
64
+ pipe_piece = pipe_piece.color(color) unless color.nil?
65
+ @pipe = pipe_piece + rotated_pipe.translate(x: x, y: y - radius)
66
+ end
67
+ end
68
+
69
+ # go counter clockwise
70
+ def ccw(radius, angle, color = nil)
71
+ return false if angle > 360
72
+ # since bent can only do up to 90°, splitting it up in chunks in order to grow it
73
+ return ccw(radius, 90, color) + ccw(radius, angle - 90, color) if angle > 90
74
+
75
+ if @pipe.nil?
76
+ @pipe = bent_ccw(radius, angle)
77
+ @pipe = @pipe.color(color) unless color.nil?
78
+ else
79
+ rotated_pipe = @pipe.rotate(z: angle)
80
+ pipe_piece = bent_ccw(radius, angle)
81
+ pipe_piece = pipe_piece.color(color) unless color.nil?
82
+ @pipe = pipe_piece + rotated_pipe.translate(x: x, y: y + radius)
83
+ end
84
+ end
85
+
86
+ def line(length, color = nil)
87
+ @pipe = if @pipe.nil?
88
+ create_line(length, color)
89
+ else
90
+ @pipe.translate(x: length) + create_line(length, color)
91
+ end
92
+ @sum_x += length
93
+ end
94
+
95
+ private
96
+
97
+ def create_line(length, color = nil)
98
+ res = shape.linear_extrude(h: length)
99
+ if inner_shape
100
+ res -= inner_shape.linear_extrude(h: length + 0.2).translate(z: -0.1)
101
+ end
102
+ res = res.color(color) if color
103
+ res.rotate(z: @line_rotation).rotate(y: 90)
104
+ end
105
+
106
+ def bent_cw(radius, angle)
107
+ res = apply_rotation(shape).translate(x: radius).rotate_extrude(fn: @bent_segments)
108
+ res -= apply_rotation(inner_shape).translate(x: radius).rotate_extrude(fn: @bent_segments) unless inner_shape.nil?
109
+
110
+ len = radius + @diameter / 2.0
111
+ @x = Math.sin(radians(angle)) * len
112
+ @y = Math.cos(radians(angle)) * len
113
+ cut = polygon(points: [[0, 0], [0, len], [@x, @y]]).scale(2)
114
+
115
+ # for working with it
116
+ len = radius #- @diameter / 2.0
117
+ @x = Math.sin(radians(angle)) * len
118
+ @y = Math.cos(radians(angle)) * len
119
+
120
+ @sum_x += @x
121
+ @sum_y += @y
122
+
123
+ res *= cut.linear_extrude(h: 100).translate(z: -50)
124
+
125
+ # Positioning it on 0
126
+ res.translate(y: -radius)
127
+ end
128
+
129
+ def bent_ccw(radius, angle)
130
+ res = apply_rotation(shape).translate(x: radius).rotate_extrude(fn: @bent_segments)
131
+ res -= apply_rotation(inner_shape).translate(x: radius).rotate_extrude(fn: @bent_segments) unless inner_shape.nil?
132
+
133
+ len = radius + @diameter / 2.0
134
+ @x = Math.sin(radians(angle)) * len
135
+ @y = Math.cos(radians(angle)) * len
136
+ cut = polygon(points: [[0, 0], [0, len], [@x, @y]]).scale(2)
137
+
138
+ # for working with it
139
+ len = radius #- @diameter / 2.0
140
+ @x = Math.sin(radians(angle)) * len
141
+ @y = -1 * Math.cos(radians(angle)) * len
142
+
143
+ @sum_x += @x
144
+ @sum_y += @y
145
+
146
+ res *= cut.linear_extrude(h: 100).translate(z: -50)
147
+ res = res.mirror(y: 1)
148
+ # Positioning it on 0
149
+
150
+ res.translate(y: radius)
151
+ end
152
+ end
153
+ end