jenncad 1.0.0.pre.alpha1 → 1.0.0.pre.alpha2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81f68c07dc7fd50719d6ce024f56eb25712ef97c9b31568dcfa6658d9fa01596
4
- data.tar.gz: 3c877488f386a7d7c6f8dd3b1543ca84641316ae2dbd5d6bcbb4577fbf94ae7c
3
+ metadata.gz: ef018e45bc6303b2a45c2ad3340d714cb340288465936f23293961fbc2615cd4
4
+ data.tar.gz: 1ee41eb205053ad3ea4e0d1b8c76b4fa13c98f212393e71008e96f1303b0f9c7
5
5
  SHA512:
6
- metadata.gz: 9a95e7f398d275b81bfb4c9bbe21d3bd0e306708f0ef514e8391f50837eab066ec7aaca3ee46e4bbb08cd4a0c3fbee009b899b87aea2b5fe86ea5a74f6294ee3
7
- data.tar.gz: 5425a1f502e12c8b8300995f921b2e9ce1d10f214728f5f2b6508610aa783f76907f3ffcc9bb40ed88e997302a12a896dc7afa9c544d6e3f0216750e4914e37f
6
+ metadata.gz: b9541672a102b371b7a517be6d015ca1bc6e4f81fae97761399514733870bc1b0c67094b6a6e177c1c5af7d85416067e9b6dab024bff275b4537013f88072fc2
7
+ data.tar.gz: 44d0ae2e9aefb56e1964cf2e0fdf0590be5fc600abea1d65f3edcf40fca03a57bf6e107020dd26ec2ffac6a3f4c9f6b6f3688cdbcb72489766984b3011c8abd3
data/jenncad.gemspec CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |gem|
19
19
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
20
  gem.require_paths = ["lib"]
21
21
 
22
- gem.required_ruby_version = ">= 2.5.0"
22
+ gem.required_ruby_version = ">= 2.6.0"
23
23
  gem.add_runtime_dependency "geo3d"
24
24
  gem.add_runtime_dependency "deep_merge"
25
25
  gem.add_runtime_dependency "hanami-cli"
26
26
  gem.add_runtime_dependency "activesupport"
27
+ gem.add_runtime_dependency "observr"
27
28
  end
@@ -17,8 +17,8 @@ module JennCad
17
17
  end
18
18
 
19
19
  def colors
20
- @colors ||= []
21
- if @colors.empty?
20
+ case @colors
21
+ when nil, []
22
22
  @colors = auto_colors
23
23
  end
24
24
  @colors
@@ -0,0 +1,248 @@
1
+ module JennCad::Exporters
2
+ class OpenScadObject
3
+ def initialize(cmd, args, children=[])
4
+ @command = cmd
5
+ @args = args
6
+ case children
7
+ when Array
8
+ @children = children
9
+ else
10
+ @children = [children]
11
+ end
12
+ end
13
+
14
+ def nl
15
+ "\n"
16
+ end
17
+
18
+ def to_s
19
+ case @command
20
+ when nil
21
+ ""
22
+ when :head
23
+ res = "$fn=64;"+nl
24
+ @children.each do |c|
25
+ res += c.to_s+nl
26
+ end
27
+ res
28
+ when :module
29
+ handle_module
30
+ when String, Symbol
31
+ handle_command
32
+ else
33
+ end
34
+ end
35
+
36
+ def handle_module
37
+ res = "module #{@args}(){"+nl
38
+ res += tabs(1, @children.map{|c| c.handle_command(2) })
39
+ res += "}"
40
+ res
41
+ end
42
+
43
+ def handle_command(i=1)
44
+ case @children.size
45
+ when 0
46
+ "#{@command}(#{handle_args});"
47
+ when 1
48
+ "#{@command}(#{handle_args})#{@children.first.handle_command(i+1)}"
49
+ when (1..)
50
+ res = "#{@command}(#{handle_args}){"
51
+ res += nl
52
+ inner = @children.map do |c|
53
+ next if c == nil
54
+ c.handle_command(i+1)
55
+ end
56
+ res += tabs(i, inner.compact)
57
+ res += nl
58
+ res += tabs(i-1,["}"])+nl
59
+ res
60
+ end
61
+ end
62
+
63
+ def tabs(i,a)
64
+ a.map{ |l|
65
+ " " * i + l
66
+ }.join(nl)
67
+ end
68
+
69
+ def handle_args
70
+ case @args
71
+ when String, Symbol
72
+ return "\"#{@args}\""
73
+ when Array
74
+ return @args.map do |l|
75
+ if l == nil
76
+ 0
77
+ elsif l.kind_of? Array
78
+ l # skipping check of 2-dmin Arrays for now (used in multmatrix)
79
+ elsif l.to_i == l.to_f
80
+ l.to_i
81
+ else
82
+ l.to_f
83
+ end
84
+ end
85
+ when Hash
86
+ res = []
87
+ @args.each do |k,v|
88
+ if k.to_s == "fn"
89
+ k = "$fn"
90
+ end
91
+ if v == nil
92
+ next
93
+ end
94
+ if !v.kind_of?(Array) && !v.kind_of?(TrueClass) && !v.kind_of?(FalseClass) && v == v.to_i
95
+ v = v.to_i
96
+ end
97
+ res << "#{k}=#{v}"
98
+ end
99
+ res.join(",").gsub("size=","")
100
+ else
101
+ ""
102
+ end
103
+ end
104
+ end
105
+
106
+ class OpenScad
107
+ include ActiveSupport::Inflector
108
+ def initialize(part)
109
+ @imports = []
110
+ @modules = {}
111
+ @global_fn = 64
112
+ @object_tree = OpenScadObject.new(:head, nil, parse(part))
113
+ end
114
+
115
+ def save(file)
116
+ File.open(file,"w") do |f|
117
+ @imports.uniq.each do |val|
118
+ f.puts "use <#{val}.scad>\n"
119
+ end
120
+
121
+ @modules.each do |key, val|
122
+ f.puts val.to_s
123
+ end
124
+ f.puts @object_tree.to_s
125
+ end
126
+ end
127
+
128
+ def parse(part)
129
+ if part.respond_to? :to_openscad
130
+ part = part.to_openscad
131
+ end
132
+
133
+ if part.respond_to? :analyze_z_fighting
134
+ part = part.analyze_z_fighting
135
+ end
136
+
137
+ case part
138
+ when Array
139
+ part.map{ |p| parse(p) }
140
+ when JennCad::OpenScadImport
141
+ handle_import(part)
142
+ when JennCad::Aggregation
143
+ handle_aggregation(part)
144
+ when JennCad::UnionObject
145
+ bool('union', part)
146
+ when JennCad::SubtractObject
147
+ bool('difference', part)
148
+ when JennCad::IntersectionObject
149
+ bool('intersection', part)
150
+ when JennCad::HullObject
151
+ bool('hull', part)
152
+ when JennCad::Primitives::Circle
153
+ prim('circle', part)
154
+ when JennCad::Primitives::Cylinder
155
+ prim('cylinder', part)
156
+ when JennCad::Primitives::Sphere
157
+ prim('sphere', part)
158
+ when JennCad::Primitives::Cube
159
+ prim('cube', part)
160
+ when JennCad::Primitives::LinearExtrude
161
+ new_obj(part, :linear_extrude, part.openscad_params, parse(part.parts))
162
+ when JennCad::Primitives::RotateExtrude
163
+ new_obj(part, :rotate_extrude, part.openscad_params, parse(part.parts))
164
+ when JennCad::Primitives::Projection
165
+ new_obj(part, :projection, collect_params(part), parse(part.parts))
166
+ when JennCad::Primitives::Polygon
167
+ new_obj(part, :polygon, collect_params(part))
168
+ when JennCad::Part
169
+ parse(part.part)
170
+ when nil
171
+ new_obj(part, nil)
172
+ else
173
+ puts "unknown part #{part.class}"
174
+ OpenScadObject.new(nil,nil)
175
+ end
176
+ end
177
+
178
+ def new_obj(part, cmd, args=nil, children=[])
179
+ transform(part) do
180
+ apply_color(part) do
181
+ OpenScadObject.new(cmd, args, children)
182
+ end
183
+ end
184
+ end
185
+
186
+ def bool(type, part)
187
+ new_obj(part, type, nil, parse(part.parts))
188
+ end
189
+
190
+ def prim(type, part)
191
+ new_obj(part, type, collect_params(part))
192
+ end
193
+
194
+ def collect_params(part)
195
+ res = {}
196
+ [:d, :h, :d1, :d2, :size, :fn, :points].each do |var|
197
+ if part.respond_to? var
198
+ res[var] = part.send var
199
+ end
200
+ end
201
+ case res[:fn]
202
+ when @global_fn
203
+ res[:fn] = nil
204
+ else
205
+ end
206
+ res
207
+ end
208
+
209
+ def apply_color(part, &block)
210
+ return block.yield if part.nil? or part.color_or_fallback.nil?
211
+ OpenScadObject.new("color", part.color_or_fallback, block.yield)
212
+ end
213
+
214
+ def transform(part, &block)
215
+ return block.yield if part.transformations.nil?
216
+
217
+ case t = part.transformations.pop
218
+ when nil, []
219
+ block.yield
220
+ when JennCad::Move
221
+ OpenScadObject.new(:translate, t.coordinates, transform(part, &block))
222
+ when JennCad::Rotate, JennCad::Mirror
223
+ OpenScadObject.new(demodulize(t.class).downcase, t.coordinates, transform(part, &block))
224
+ when JennCad::Multmatrix
225
+ OpenScadObject.new(:multmatrix, t.m, transform(part, &block))
226
+ else
227
+ puts "unknown transformation #{t}"
228
+ end
229
+ end
230
+
231
+ def handle_aggregation(part, tabindex=0)
232
+ register_module(part) unless @modules[part.name]
233
+ transform(part) do
234
+ new_obj(part, part.name, nil)
235
+ end
236
+ end
237
+
238
+ # accept aggregation
239
+ def register_module(part)
240
+ @modules[part.name] = OpenScadObject.new(:module,part.name, parse(part.part))
241
+ end
242
+
243
+ def handle_import(part)
244
+ @imports << part.import
245
+ new_obj(part, part.name, part.args)
246
+ end
247
+ end
248
+ end
data/lib/jenncad/part.rb CHANGED
@@ -2,13 +2,16 @@ module JennCad
2
2
  # Part should be inherited from the user when making parts
3
3
  class Part < Thing
4
4
 
5
- def make_openscad_compatible
5
+ def to_openscad #make_openscad_compatible
6
6
  auto_color
7
- a = Aggregation.new(self.class.to_s, make_openscad_compatible!(self.part))
7
+ a = Aggregation.new(self.class.to_s, self.part) #make_openscad_compatible!(self.part))
8
8
  a.transformations = @transformations
9
9
  a.color(color)
10
10
  a
11
11
  end
12
12
 
13
+ def part
14
+ end
15
+
13
16
  end
14
17
  end
@@ -19,11 +19,32 @@ class Array
19
19
  .union
20
20
  end
21
21
 
22
- def union(&block)
23
- if block
24
- UnionObject.new(block.yield)
25
- else
26
- UnionObject.new(self)
27
- end
22
+ def union
23
+ UnionObject.new(self)
24
+ end
25
+ alias u union
26
+
27
+ def subtraction
28
+ SubtractObject.new(self)
28
29
  end
30
+ alias subtract subtraction
31
+ alias sub subtraction
32
+ alias s subtraction
33
+
34
+ def intersection
35
+ IntersectionObject.new(self)
36
+ end
37
+ alias intersect intersection
38
+ alias i intersection
39
+
40
+ def hull
41
+ HullObject.new(self)
42
+ end
43
+ alias h hull
44
+
45
+
46
+ def random
47
+ self[Random.rand(size)]
48
+ end
49
+
29
50
  end
@@ -10,6 +10,16 @@ module JennCad::Primitives
10
10
  after_add
11
11
  end
12
12
 
13
+ def add_or_new(part)
14
+ case @transformations
15
+ when nil, []
16
+ add(part)
17
+ self
18
+ else
19
+ self.class.new(self, part)
20
+ end
21
+ end
22
+
13
23
  def add(part)
14
24
  @parts << part
15
25
  after_add
@@ -39,7 +49,7 @@ module JennCad::Primitives
39
49
 
40
50
  def inherit_zref
41
51
  return if @parts.first == nil
42
- return if @parts.first.z.to_f == 0.0
52
+ #return if @parts.first.z.to_f == 0.0
43
53
  get_primitives(@parts[1..-1]).flatten.each do |part|
44
54
  if part.z.to_f == 0.0
45
55
  part.set_option :zref, @parts.first
@@ -1,6 +1,5 @@
1
1
  module JennCad::Primitives
2
2
  class Cube < Primitive
3
- attr_accessor :x,:y,:z
4
3
 
5
4
  def initialize(args)
6
5
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
@@ -37,33 +36,41 @@ module JennCad::Primitives
37
36
 
38
37
  # used for openscad export
39
38
  def size
40
- [@x, @y, @z]
39
+ [@x, @y, z+z_margin]
41
40
  end
42
41
 
43
- def center_xy
44
- set_option :center, true
45
- self
42
+ def not_centered
43
+ @opts[:center] = false
46
44
  end
45
+ alias :nc :not_centered
47
46
 
48
- def center_x
49
- set_option :center_x, true
50
- self
47
+ def cx
48
+ nc
49
+ @opts[:center_x] = true
51
50
  end
52
51
 
53
- def center_y
54
- set_option :center_y, true
55
- self
52
+ def cy
53
+ nc
54
+ @opts[:center_y] = true
56
55
  end
57
56
 
58
- def center_z
59
- set_option :center_z, true
60
- self
57
+ def cz
58
+ nc
59
+ @opts[:center_z] = true
61
60
  end
62
61
 
63
- # def center
64
- # @transformations << Move.new({x:-@x/2,y:-@y/2,z:-@z/2})
65
- # self
66
- # end
62
+ def centered_axis
63
+ return [:x, :y] if @opts[:center]
64
+ a = []
65
+ a << :x if @opts[:center_x]
66
+ a << :y if @opts[:center_x]
67
+ a << :z if @opts[:center_x]
68
+ a
69
+ end
70
+
71
+ def to_openscad
72
+ self.mh(centered_axis.to_h{|a| [a, -@opts[a]] }) # center cube
73
+ end
67
74
 
68
75
  end
69
76
  end
@@ -18,6 +18,10 @@ module JennCad::Primitives
18
18
 
19
19
  @opts = {
20
20
  d: 0,
21
+ d1: nil,
22
+ d2: nil,
23
+ r1: nil,
24
+ r2: nil,
21
25
  z: nil,
22
26
  r: 0,
23
27
  margins: {
@@ -31,21 +35,45 @@ module JennCad::Primitives
31
35
  # FIXME:
32
36
  # - margins calculation needs to go to output
33
37
  # - assinging these variables has to stop
34
- # - r/d need to be automatically calculated by each other
35
38
  # - r+z margin not implemented atm
36
39
  # - need to migrate classes to provide all possible outputs (and non-conflicting ones) to openscad exporter
37
- @d = args[:d] + @opts[:margins][:d]
38
40
  @z = args[:z] || args[:h]
39
- @r = args[:r]
40
- @fn = args[:fn]
41
- if @fn == nil && @d > 16
42
- @fn = (@d*4).ceil
43
- end
41
+ handle_radius_diameter
42
+ handle_fn
44
43
  super(args)
45
44
  end
46
45
 
46
+ def handle_fn
47
+ case @opts[:fn]
48
+ when nil, 0
49
+ $fn = auto_fn!
50
+ else
51
+ @fn = @opts[:fn]
52
+ end
53
+ end
54
+
55
+ def auto_fn!
56
+ case @d
57
+ when (16..)
58
+ @fn = (@d*4).ceil
59
+ else
60
+ @fn = 64
61
+ end
62
+ end
63
+
64
+ def handle_radius_diameter
65
+ case @opts[:d]
66
+ when 0, nil
67
+ @r = @opts[:r].to_f + @opts[:margins][:r].to_f
68
+ @d = @r * 2.0
69
+ else
70
+ @d = @opts[:d].to_f + @opts[:margins][:d].to_f
71
+ @r = @d / 2.0
72
+ end
73
+ end
74
+
47
75
  def h
48
- z
76
+ z + z_margin
49
77
  end
50
78
 
51
79
  end
@@ -40,21 +40,13 @@ module JennCad::Primitives
40
40
  # make diameter not bigger than any side
41
41
  @d = [@d, @x, @y].min
42
42
  res = HullObject.new(
43
- cylinder(d:@d, h:@z).moveh(x: -@x + @d, y: @y - @d),
43
+ cylinder(d:@d, h:@z+z_margin).moveh(x: -@x + @d, y: @y - @d),
44
44
  cylinder(d:@d).moveh(x: @x - @d, y: @y - @d),
45
45
  cylinder(d:@d).moveh(x: -@x + @d, y: -@y + @d),
46
46
  cylinder(d:@d).moveh(x: @x - @d, y: -@y + @d),
47
47
  )
48
48
 
49
- if @opts[:flat_edges]
50
- if @opts[:flat_edges].kind_of?(Array)
51
- @opts[:flat_edges].each do |e|
52
- res += flat_edge(e)
53
- end
54
- else
55
- res += flat_edge(@opts[:flat_edges])
56
- end
57
- end
49
+ res += flat_edge(@opts[:flat_edges])
58
50
 
59
51
  res.transformations = @transformations
60
52
  res
@@ -62,6 +54,9 @@ module JennCad::Primitives
62
54
 
63
55
  def flat_edge(edge)
64
56
  case edge
57
+ when Array
58
+ #ruby2.7 test- edge.map(&self.:flat_edge)
59
+ edge.map{|x| flat_edge(x) }
65
60
  when :up
66
61
  cube(@x, @y/2.0, @z).moveh(y:@y/2.0)
67
62
  when :down
@@ -70,6 +65,8 @@ module JennCad::Primitives
70
65
  cube(@x/2.0, @y, @z).moveh(x:@x/2.0)
71
66
  when :left
72
67
  cube(@x/2.0, @y, @z).moveh(x:-@x/2.0)
68
+ else
69
+ nil
73
70
  end
74
71
  end
75
72
 
@@ -44,37 +44,41 @@ module JennCad::Primitives
44
44
  else
45
45
  compare_z(others, first_h.first, first_z.first)
46
46
  end
47
+ self
47
48
  end
48
49
 
49
- # FIXME
50
- # this won't work reliable with Aggregations at the moment;
51
- # they don't have calc_z for comparing with the top
52
- # and it will try to move the Aggregation which it should not do
53
- # (it should move the calls to the Aggregation, not the Aggregation itself)
54
50
  def compare_z(others,compare_h,compare_z)
55
51
  others.each do |part|
56
52
  #puts part.inspect
57
53
  #puts "#{part.calc_z+part.calc_h} ; #{compare_h}"
58
54
  if part.respond_to? :z
55
+ part.opts[:margins] ||= {}
59
56
  if part.referenced_z && part.z != 0.0
60
57
  case part
61
58
  when JennCad::BooleanObject
59
+ when JennCad::Aggregation
62
60
  else
63
- part.z+=0.2
64
- part.translate(z:-0.1)
61
+ pp part if part.opts[:debug]
62
+ part.opts[:margins][:z] ||= 0.0
63
+ unless part.opts[:margins][:z] == 0.2
64
+ part.opts[:margins][:z] = 0.2
65
+ part.mz(-0.1)
66
+ end
65
67
  end
66
68
  elsif part.z == compare_h
67
69
  # puts "fixing possible z fighting: #{part.class} #{part.z}"
68
- part.z+=0.008
69
- part.translate(z:-0.004)
70
+ part.opts[:margins][:z] += 0.008
71
+ part.mz(-0.004)
70
72
  elsif part.calc_z == compare_z
71
73
  # puts "z fighting at bottom: #{part.calc_z}"
72
- part.z+=0.004
73
- part.translate(z:-0.002)
74
+ part.opts[:margins][:z] += 0.004
75
+ # part.z+=0.004
76
+ part.mz(-0.002)
74
77
  elsif part.calc_z.to_f+part.calc_h.to_f == compare_h
75
78
  # puts "z fighting at top: #{compare_h}"
76
- part.z+=0.004
77
- part.translate(z:0.002)
79
+ #part.z+=0.004
80
+ part.opts[:margins][:z] += 0.004
81
+ part.mz(0.002)
78
82
  end
79
83
  end
80
84
  end
@@ -0,0 +1,22 @@
1
+ require "jenncad/primitives/primitive"
2
+ require "jenncad/primitives/aggregation"
3
+ require "jenncad/primitives/openscad_include"
4
+ require "jenncad/primitives/circle"
5
+ require "jenncad/primitives/cylinder"
6
+ require "jenncad/primitives/sphere"
7
+ require "jenncad/primitives/cube"
8
+ require "jenncad/primitives/rounded_cube"
9
+ require "jenncad/primitives/polygon"
10
+ require "jenncad/primitives/slot"
11
+ require "jenncad/primitives/boolean_object"
12
+ require "jenncad/primitives/union_object"
13
+ require "jenncad/primitives/subtract_object"
14
+ require "jenncad/primitives/hull_object"
15
+ require "jenncad/primitives/intersection_object"
16
+ require "jenncad/primitives/projection"
17
+ require "jenncad/primitives/linear_extrude"
18
+ require "jenncad/primitives/rotate_extrude"
19
+
20
+ module JennCad
21
+ include Primitives
22
+ end