jenncad 1.0.0.pre.alpha13 → 1.0.0.pre.alpha16

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ module JennCad::Primitives
2
+ class Polyhedron < Primitive
3
+ attr_accessor :points, :faces, :convexity
4
+ def initialize(args)
5
+ @opts = args
6
+ @points = args[:points]
7
+ @faces = args[:faces]
8
+ @convexity = args[:convexity] || 10
9
+
10
+ super
11
+ end
12
+
13
+ def face(i)
14
+ unless @faces[i]
15
+ $log.error "polyhedron: Cannot find face #{i}"
16
+ return self
17
+ end
18
+ face = 0
19
+ poly_faces = []
20
+ poly_points = []
21
+ @faces[i].each do |f|
22
+ point = @points[f]
23
+ if point.nil?
24
+ $log.error "polyhedron: Cannot find point #{f} for face #{i}"
25
+ end
26
+ poly_points << point
27
+ poly_faces << face
28
+ face += 1
29
+ #poly_points << [point[0], point[1]]
30
+ end
31
+ #polygon(points: poly_points)
32
+ polyhedron(points: poly_points, faces: [poly_faces, poly_faces.reverse])
33
+ end
34
+ end
35
+ end
@@ -5,14 +5,14 @@ module JennCad::Primitives
5
5
  end
6
6
 
7
7
  def handle_margins
8
- @x = @opts[:x] + @opts[:margins][:x]
9
- @y = @opts[:y] + @opts[:margins][:y]
10
- @z = @opts[:z] + @opts[:margins][:z]
8
+ @x = @opts[:x].to_d + @opts[:margins][:x].to_d
9
+ @y = @opts[:y].to_d + @opts[:margins][:y].to_d
10
+ @z = @opts[:z].to_d + @opts[:margins][:z].to_d
11
11
  end
12
12
 
13
13
  def handle_diameter
14
- @d = opts[:d]
15
- @r = opts[:r]
14
+ @d = opts[:d].to_d
15
+ @r = opts[:r].to_d
16
16
  if @d
17
17
  @r = @d/2.0
18
18
  elsif @r
@@ -64,18 +64,20 @@ module JennCad::Primitives
64
64
  res
65
65
  end
66
66
 
67
- def flat(edge)
67
+ def flat(*edges)
68
68
  @opts[:flat_edges] ||= []
69
- @opts[:flat_edges] << edge
69
+ edges.each do |edge|
70
+ @opts[:flat_edges] << edge
71
+ end
70
72
  self
71
73
  end
72
74
 
73
75
  private
74
76
  def apply_flat_edge(edge)
75
77
  case edge
76
- when :up
78
+ when :up, :top
77
79
  cube(x: @x, y: @y/2.0, z: @z).nc.moveh(y:@y)
78
- when :down
80
+ when :down, :bottom
79
81
  cube(x: @x, y: @y/2.0, z: @z).nc
80
82
  when :right
81
83
  cube(x: @x/2.0, y: @y, z: @z).nc.moveh(x:@x)
@@ -14,16 +14,21 @@ module JennCad::Primitives
14
14
  args = [:d, :z].zip(args.flatten).to_h
15
15
  args.deep_merge!(m)
16
16
  end
17
-
18
- args[:z] ||= args[:h]
17
+ args = parse_xyz_shortcuts(args)
18
+ if args[:z].to_d > 0
19
+ args[:h] = args[:z]
20
+ else
21
+ args[:z] = nil
22
+ end
19
23
 
20
24
  @opts = {
21
25
  d: 0,
22
26
  a: 0,
23
- z: nil,
24
27
  r: nil,
25
28
  x: 0,
26
29
  y: 0,
30
+ z: nil,
31
+ cz: false,
27
32
  margins: {
28
33
  r: 0,
29
34
  d: 0,
@@ -33,9 +38,13 @@ module JennCad::Primitives
33
38
 
34
39
  super(opts)
35
40
 
36
- @d = @opts[:d]
37
- @a = @opts[:a]
38
- @h = @opts[:h]
41
+ @d = @opts[:d].to_d
42
+ @a = @opts[:a].to_d
43
+ @h = @opts[:h].to_d
44
+ @z = @h
45
+ @x = @opts[:x].to_d
46
+ @y = @opts[:y].to_d
47
+
39
48
  @r = @opts[:r] || nil
40
49
  if @r
41
50
  @d = @r * 2
@@ -54,7 +63,61 @@ module JennCad::Primitives
54
63
 
55
64
  # TODO: this needs anchors like cube
56
65
  # TODO: color on this needs to apply to hull, not on the cylinders.
66
+ set_anchors
67
+ end
68
+
69
+ def cz
70
+ @opts[:cz] = true
71
+ @transformations << Move.new(z: -@z / 2.0)
72
+ set_anchors
73
+ self
74
+ end
75
+
76
+
77
+ def set_anchors
78
+ @anchors = {} # reset anchors
79
+ if @opts[:d]
80
+ rad = @opts[:d] / 2.0
81
+ else
82
+ rad = @opts[:r]
83
+ end
57
84
 
85
+ if @x > 0
86
+ set_anchor :left, x: - rad
87
+ set_anchor :right, x: @x + rad
88
+ elsif @x < 0
89
+ set_anchor :left, x: @x - rad
90
+ set_anchor :right, x: rad
91
+ else
92
+ set_anchor :left, x: -rad
93
+ set_anchor :right, x: rad
94
+ end
95
+ if @y > 0
96
+ set_anchor :bottom, y: - rad
97
+ set_anchor :top, y: @y + rad
98
+ elsif @y < 0
99
+ set_anchor :bottom, y: @y - rad
100
+ set_anchor :top, y: rad
101
+ else
102
+ set_anchor :bottom, y: -rad
103
+ set_anchor :top, y: rad
104
+ end
105
+
106
+ set_anchor :center1, xy: 0
107
+ set_anchor :center2, x: @x, y: @y
108
+
109
+ # TODO: figure out if we also want to have "corners"
110
+ # - possibly move it like a cube
111
+ # - points at 45 ° angles might not be that useful unless you can get the point on the circle at a given angle
112
+ # - inner/outer points could be useful for small $fn values
113
+
114
+ if @opts[:cz]
115
+ set_anchor :bottom_face, z: -@z/2.0
116
+ set_anchor :top_face, z: @z/2.0
117
+ else
118
+ set_anchor :bottom_face, z: 0
119
+ set_anchor :top_face, z: @z
120
+ end
58
121
  end
59
122
 
60
123
  def to_openscad
@@ -79,16 +142,16 @@ module JennCad::Primitives
79
142
  end
80
143
 
81
144
  def end_vector
82
- if @a.to_f == 0.0
145
+ if @a.to_d == 0.0
83
146
  return [@len_x, 0] if @len_x
84
147
  return [0, @len_y] if @len_y
85
148
  end
86
149
  if @len_x
87
- x = cos(PI*@a/180.0)*@len_x.to_f
88
- y = sin(PI*@a/180.0)*@len_x.to_f
150
+ x = cos(PI*@a/180.0)*@len_x.to_d
151
+ y = sin(PI*@a/180.0)*@len_x.to_d
89
152
  else
90
- x = -1* sin(PI*@a/180.0)*@len_y.to_f
91
- y = cos(PI*@a/180.0)*@len_y.to_f
153
+ x = -1* sin(PI*@a/180.0)*@len_y.to_d
154
+ y = cos(PI*@a/180.0)*@len_y.to_d
92
155
  end
93
156
  [x,y]
94
157
  end
@@ -2,13 +2,13 @@ module JennCad::Primitives
2
2
  class SubtractObject < BooleanObject
3
3
  def inherit_z
4
4
  @z = 0
5
- @calc_z = parts.first.calc_z.to_f
5
+ @calc_z = parts.first.calc_z.to_d
6
6
 
7
7
  only_additives_of(@parts).each do |p|
8
8
  if option(:debug)
9
9
  $log.debug "inherit_z checks for: #{p}"
10
10
  end
11
- z = p.z.to_f
11
+ z = p.z.to_d
12
12
  @z = z if z > @z
13
13
  end
14
14
  $log.debug "inherit_z called, biggest z found: #{@z}" if option(:debug)
@@ -57,6 +57,7 @@ module JennCad::Primitives
57
57
  others.each do |part|
58
58
  #puts part.inspect
59
59
  #puts "#{part.calc_z+part.calc_h} ; #{compare_h}"
60
+ add_z = nil
60
61
  if part.respond_to? :z
61
62
  part.opts[:margins] ||= {}
62
63
  if part.referenced_z && part.z != 0.0
@@ -64,28 +65,40 @@ module JennCad::Primitives
64
65
  when JennCad::Circle
65
66
  when JennCad::BooleanObject
66
67
  else
67
- $log.debug part if part.opts[:debug]
68
+ # $log.debug part if part.opts[:debug]
68
69
  part.opts[:margins][:z] ||= 0.0
69
70
  unless part.opts[:margins][:z] == 0.2
71
+ $log.debug "fixing possible z fighting for referenced object: #{part.class} #{part.z} 0.1 down" if part.opts[:debug]
70
72
  part.opts[:margins][:z] = 0.2
71
73
  part.mz(-0.1)
72
74
  end
73
75
  end
74
76
  elsif part.z == compare_h
75
77
  $log.debug "fixing possible z fighting: #{part.class} #{part.z}" if part.opts[:debug]
76
- part.opts[:margins][:z] += 0.008
77
- part.mz(-0.004)
78
+ add_z = 0.008
79
+ move_z = -0.004
78
80
  elsif part.calc_z == compare_z
79
81
  # puts "z fighting at bottom: #{part.calc_z}"
80
- part.opts[:margins][:z] += 0.004
82
+ add_z = 0.004
81
83
  # part.z+=0.004
82
- part.mz(-0.002)
83
- elsif part.calc_z.to_f+part.calc_h.to_f == compare_h
84
+ move_z = -0.002
85
+ elsif part.calc_z.to_d+part.calc_h.to_d == compare_h
84
86
  # puts "z fighting at top: #{compare_h}"
85
87
  #part.z+=0.004
86
- part.opts[:margins][:z] += 0.004
87
- part.mz(0.002)
88
+ add_z = 0.004
89
+ move_z = 0.002
88
90
  end
91
+
92
+ if add_z
93
+ if part.kind_of? Part
94
+ part.modify_values(part, {z: add_z}, {mode: :add})
95
+ end
96
+ part.opts[:margins][:z] += add_z
97
+ part.mz(move_z)
98
+ end
99
+
100
+
101
+
89
102
  end
90
103
  end
91
104
  end
@@ -5,6 +5,7 @@ require "jenncad/primitives/sphere"
5
5
  require "jenncad/primitives/cube"
6
6
  require "jenncad/primitives/rounded_cube"
7
7
  require "jenncad/primitives/polygon"
8
+ require "jenncad/primitives/polyhedron"
8
9
  require "jenncad/primitives/slot"
9
10
  require "jenncad/primitives/boolean_object"
10
11
  require "jenncad/primitives/union_object"
@@ -18,6 +18,10 @@ module JennCad
18
18
  Polygon.new(args).set_parent(self)
19
19
  end
20
20
 
21
+ def polyhedron(args)
22
+ Polyhedron.new(args).set_parent(self)
23
+ end
24
+
21
25
  def slot(*args)
22
26
  Slot.new(args).set_parent(self)
23
27
  end
@@ -93,8 +97,8 @@ module JennCad
93
97
  private
94
98
  def boolean_operation(part, klass)
95
99
  if part.respond_to? :transformations
96
- # Since ruby doesn't provide a way to make a deep clone, this seems to be the simplest solution that will effectively do that:
97
- part = Marshal.load(Marshal.dump(part))
100
+ # Clone the part in place
101
+ part = part.fix
98
102
  end
99
103
 
100
104
  case self
@@ -103,7 +107,12 @@ module JennCad
103
107
  when klass
104
108
  add_or_new(part)
105
109
  else
106
- klass.new(self,part)
110
+ own_part = if self.respond_to? :transformations
111
+ self.fix # clone self
112
+ else
113
+ self
114
+ end
115
+ klass.new(own_part,part)
107
116
  end
108
117
  end
109
118
  end
data/lib/jenncad/thing.rb CHANGED
@@ -33,25 +33,102 @@ module JennCad
33
33
  @opts[key] = val
34
34
  end
35
35
 
36
+ def set_flag(key)
37
+ set_option(key, true)
38
+ self
39
+ end
40
+
41
+ def unset_flag(key)
42
+ set_option(key, false)
43
+ self
44
+ end
45
+
46
+
47
+ def cut_to(face, part=nil, args={})
48
+ an = anchor(face, part)
49
+ unless an
50
+ $log.error "Cannot find anchor to cut_to"
51
+ return self
52
+ end
53
+ if an[:z].to_d == 0.0
54
+ $log.error "cut_to only supports cuts to an anchor with Z set. This anchor: #{an}"
55
+ return self
56
+ end
57
+ modify_values(self, z: an[:z].to_d)
58
+ self.name="#{self.class}_cut_to_#{an[:z].to_f}"
59
+ self
60
+ end
61
+
62
+ def modify_values(parts, value, opts = {})
63
+ case parts
64
+ when Array
65
+ parts.each do |pa|
66
+ modify_values(pa, value, opts)
67
+ end
68
+ else
69
+ if parts.kind_of?(BooleanObject)
70
+ modify_values(parts.only_additives_of(parts), value, opts)
71
+ elsif parts.kind_of?(Part)
72
+ modify_values(parts.part, value, opts)
73
+ modify_values(parts.get_contents, value, opts)
74
+ parts.modify_values!(value, opts)
75
+ elsif parts.kind_of?(Primitive)
76
+ parts.modify_values!(value, opts)
77
+ end
78
+ end
79
+ end
80
+
81
+ def modify_values!(values, opts)
82
+ $log.info "Modify value! #{self.class} #{values}" if self.debug?
83
+ values.each do |key, val|
84
+ if @opts
85
+ case opts[:mode]
86
+ when :add
87
+ @opts[key] = @opts[key].to_d + val.to_d
88
+ when :sub
89
+ @opts[key] = @opts[key].to_d - val.to_d
90
+ else
91
+ @opts[key] = val
92
+ end
93
+ end
94
+ if self.respond_to? key
95
+ self.send("#{key}=", @opts[key])
96
+ end
97
+ end
98
+ $log.info "Modified value now: #{self.inspect}" if self.debug?
99
+ end
100
+
101
+
102
+ def debug?
103
+ option(:debug) || false
104
+ end
105
+
106
+ def fixate
107
+ Marshal.load(Marshal.dump(self))
108
+ end
109
+ alias :fix :fixate
110
+
36
111
  def set_parent(parent)
37
112
  @parent = parent
38
113
  self
39
114
  end
40
115
 
41
- def anchor(name, thing=nil)
116
+ def anchor(name, thing=nil, args={})
42
117
  if thing
43
- res = thing.anchor(name)
118
+ res = thing.anchor(name, nil, args)
44
119
  return res unless res.nil?
45
120
  end
46
121
  @anchors ||= {}
47
122
  if anch = @anchors[name]
48
123
  return anch
124
+ elsif args[:fail_quick] && args[:fail_quick] == true
125
+ return
49
126
  elsif @parent
50
127
  return @parent.anchor(name)
51
128
  elsif self.respond_to? :get_contents
52
129
  con = get_contents
53
130
  if con.respond_to? :anchor
54
- con.anchor(name)
131
+ con.anchor(name, nil, fail_quick: true)
55
132
  end
56
133
  end
57
134
  end
@@ -64,6 +141,32 @@ module JennCad
64
141
  end
65
142
  alias :sa :set_anchor
66
143
 
144
+ def set_anchor_from(name, new_name, args={})
145
+ unless name.kind_of? Symbol or name.kind_of? String
146
+ $log.error "set_anchor_from: name must be a string or symbol. Supplied: #{name}"
147
+ return
148
+ end
149
+ unless new_name.kind_of? Symbol or new_name.kind_of? String
150
+ $log.error "set_anchor_from: new_name must be a string or symbol. Supplied: #{new_name}"
151
+ return
152
+ end
153
+
154
+
155
+ a = anchor(name, args[:from]).dup
156
+ if !a
157
+ $log.error "set_anchor_from couldn't find anchor #{name}"
158
+ return
159
+ end
160
+
161
+ [:x, :y, :z, :xy, :xz, :xyz, :yz].each do |key|
162
+ a[key] ||= 0.to_d
163
+ args[key] ||= 0.to_d
164
+ a[key] += args[key]
165
+ end
166
+ set_anchor new_name, a
167
+ end
168
+ alias :saf :set_anchor_from
169
+
67
170
  def auto_extrude
68
171
  ret = self.extrude
69
172
  ret.set_option(:auto_extrude, true)
@@ -93,7 +196,7 @@ module JennCad
93
196
  case self
94
197
  when UnionObject
95
198
  ref = self.parts.first
96
- rz = self.z.to_f + self.calc_h.to_f
199
+ rz = self.z.to_d + self.calc_h.to_d
97
200
  when BooleanObject
98
201
  ref = self.parts.first
99
202
  rz = ref.calc_z + ref.calc_h
@@ -121,7 +224,7 @@ module JennCad
121
224
  alias :fy :flip_y
122
225
 
123
226
  def radians(a)
124
- a.to_f/180.0*PI
227
+ a.to_d/180.0*PI
125
228
  end
126
229
 
127
230
  # experiment
@@ -180,22 +283,65 @@ module JennCad
180
283
  return args
181
284
  end
182
285
 
286
+ # reset last move
287
+ def reset_last_move
288
+ lt = @transformations.last
289
+ unless lt.class == Move
290
+ $log.error "Tried to call rst_move but last object is a #{lt.class}"
291
+ return self
292
+ end
293
+ @transformations.delete_at(-1)
294
+
295
+ self
296
+ end
297
+ alias :rstlm :reset_last_move
298
+
299
+ # resets all transformations
300
+ def reset
301
+ @transformations = []
302
+ self
303
+ end
304
+ alias :rst :reset
305
+
306
+
183
307
  def move(args={})
308
+ return self if args.nil? or args.empty?
309
+
184
310
  if args.kind_of? Array
185
311
  x,y,z = args
186
312
  return move(x:x, y:y, z:z)
187
313
  end
188
314
  args = parse_xyz_shortcuts(args)
189
315
 
316
+ if args[:x].to_d == 0.0 && args[:y].to_d == 0.0 && args[:z].to_d == 0.0
317
+ return self
318
+ end
319
+
190
320
  @transformations ||= []
191
321
  if args[:prepend]
192
322
  @transformations.prepend(Move.new(args))
193
323
  else
194
- @transformations << Move.new(args)
324
+ lt = @transformations.last
325
+
326
+ chain = if args[:chain]
327
+ args[:chain]
328
+ else
329
+ $jenncad_profile.chain_moves
330
+ end
331
+
332
+ if lt && lt.class == Move && chain == false
333
+ $log.debug "#{self} at move: Adding to previous move #{lt.inspect} , args: #{args}" if self.debug?
334
+ lt.x += args[:x].to_d
335
+ lt.y += args[:y].to_d
336
+ lt.z += args[:z].to_d
337
+ else
338
+ $log.debug "#{self} at move: Adding move of #{args} to transformations" if self.debug?
339
+ @transformations << Move.new(args)
340
+ end
195
341
  end
196
- @calc_x += args[:x].to_f
197
- @calc_y += args[:y].to_f
198
- @calc_z += args[:z].to_f
342
+ @calc_x += args[:x].to_d
343
+ @calc_y += args[:y].to_d
344
+ @calc_z += args[:z].to_d
199
345
  self
200
346
  end
201
347
  alias :translate :move
@@ -214,30 +360,42 @@ module JennCad
214
360
  end
215
361
 
216
362
  # move to anchor
217
- def movea(key, thing=nil)
218
- an = anchor(key, thing)
363
+ def movea(key, thing=nil, args={})
364
+ if thing.kind_of? Hash # if you leave out thing, args may be interpreted as thing
365
+ args = thing
366
+ thing = nil
367
+ end
368
+
369
+ an = anchor(key, thing, args)
219
370
 
220
371
  unless an
221
372
  $log.error "Error: Anchor #{key} not found"
222
373
  $log.error "Available anchors: #{@anchors}"
223
374
  return self
224
375
  else
225
- self.move(an.dup)
376
+ m = an.dup
377
+ if args[:chain]
378
+ m[:chain] = args[:chain]
379
+ end
380
+ if args[:inverted]
381
+ self.movei(m)
382
+ else
383
+ self.move(m)
384
+ end
226
385
  end
227
386
  end
387
+ alias :ma :movea
228
388
 
229
389
  # move to anchor - inverted
230
- def moveai(key, thing=nil)
231
- an = anchor(key, thing)
232
- unless an
233
- $log.error "Error: Anchor #{key} not found"
234
- $log.error "Available anchors: #{@anchors}"
235
- return self
236
- else
237
- self.movei(an.dup)
390
+ def moveai(key, thing=nil, args={})
391
+ if thing.kind_of? Hash # if you leave out thing, args may be interpreted as thing
392
+ args = thing
393
+ thing = nil
238
394
  end
395
+ args[:inverted] = true
396
+ movea(key, thing, args)
239
397
  end
240
-
398
+ alias :mai :moveai
241
399
 
242
400
  # move half
243
401
  def moveh(args={})
@@ -272,6 +430,7 @@ module JennCad
272
430
  to[key] = args[key]*-1
273
431
  end
274
432
  end
433
+ to[:chain] = args[:chain]
275
434
  move(to)
276
435
  end
277
436
 
@@ -335,7 +494,7 @@ module JennCad
335
494
  end
336
495
 
337
496
  def top_of(other_object)
338
- self.move(z:other_object.z+other_object.calc_z.to_f)
497
+ self.move(z:other_object.z+other_object.calc_z.to_d)
339
498
  end
340
499
 
341
500
  def on_top_of(other_object)
@@ -456,6 +615,8 @@ module JennCad
456
615
  return "##{args}"
457
616
  when String
458
617
  return args
618
+ when Symbol
619
+ return args.to_s
459
620
  end
460
621
  nil
461
622
  end
@@ -480,7 +641,7 @@ module JennCad
480
641
  return @parts unless @parts.nil?
481
642
 
482
643
  if @cache
483
- return @cache
644
+ return @cache unless option(:no_cache) == true
484
645
  end
485
646
 
486
647
  if self.respond_to? :part
@@ -564,7 +725,7 @@ module JennCad
564
725
  end
565
726
 
566
727
  def referenced_z
567
- return false if @z.to_f != 0.0
728
+ return false if @z.to_d != 0.0
568
729
  return option(:zref) if option(:zref)
569
730
  return false
570
731
  end
@@ -579,7 +740,7 @@ module JennCad
579
740
  when nil, false
580
741
  @z + z_margin
581
742
  else
582
- ref.z.to_f + ref.z_margin.to_f
743
+ ref.z.to_d + ref.z_margin.to_d
583
744
  end
584
745
  end
585
746
 
@@ -588,9 +749,16 @@ module JennCad
588
749
  when nil, {}
589
750
  0.0
590
751
  else
591
- m[:z].to_f
752
+ m[:z].to_d
592
753
  end
593
754
  end
594
755
 
756
+
757
+ def to_mod(name)
758
+ a = Aggregation.new(name, self)
759
+ a.transformations = @transformations
760
+ a
761
+ end
762
+
595
763
  end
596
764
  end
@@ -16,7 +16,7 @@ module JennCad
16
16
 
17
17
  def self.check_color_array(a)
18
18
  if a.max > 1.0
19
- a.map{|l| l.to_f/255.0}
19
+ a.map{|l| l.to_d/255.0}
20
20
  else
21
21
  a
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module JennCad
2
- VERSION = "1.0.0-alpha13"
2
+ VERSION = "1.0.0-alpha16"
3
3
  end
data/lib/jenncad.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  require "logger"
2
2
  $log = Logger.new(STDOUT)
3
3
 
4
+ require 'bigdecimal/util'
4
5
  require "geo3d"
5
6
  require "deep_merge"
6
7
  require "fileutils"
7
8
  require "observr"
8
- require "hanami/cli"
9
9
  require "active_support"
10
10
 
11
11
  include Math