jenncad 1.0.0.pre.alpha1 → 1.0.0.pre.alpha4

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.
@@ -1,6 +1,6 @@
1
1
  module JennCad::Primitives
2
2
  class Cube < Primitive
3
- attr_accessor :x,:y,:z
3
+ extend JennCad::Features::Cuttable
4
4
 
5
5
  def initialize(args)
6
6
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
@@ -37,33 +37,41 @@ module JennCad::Primitives
37
37
 
38
38
  # used for openscad export
39
39
  def size
40
- [@x, @y, @z]
40
+ [@x, @y, z+z_margin]
41
41
  end
42
42
 
43
- def center_xy
44
- set_option :center, true
45
- self
43
+ def not_centered
44
+ @opts[:center] = false
46
45
  end
46
+ alias :nc :not_centered
47
47
 
48
- def center_x
49
- set_option :center_x, true
50
- self
48
+ def cx
49
+ nc
50
+ @opts[:center_x] = true
51
51
  end
52
52
 
53
- def center_y
54
- set_option :center_y, true
55
- self
53
+ def cy
54
+ nc
55
+ @opts[:center_y] = true
56
56
  end
57
57
 
58
- def center_z
59
- set_option :center_z, true
60
- self
58
+ def cz
59
+ nc
60
+ @opts[:center_z] = true
61
61
  end
62
62
 
63
- # def center
64
- # @transformations << Move.new({x:-@x/2,y:-@y/2,z:-@z/2})
65
- # self
66
- # end
63
+ def centered_axis
64
+ return [:x, :y] if @opts[:center]
65
+ a = []
66
+ a << :x if @opts[:center_x]
67
+ a << :y if @opts[:center_x]
68
+ a << :z if @opts[:center_x]
69
+ a
70
+ end
71
+
72
+ def to_openscad
73
+ self.mh(centered_axis.to_h{|a| [a, -@opts[a]] }) # center cube
74
+ end
67
75
 
68
76
  end
69
77
  end
@@ -1,6 +1,6 @@
1
1
  module JennCad::Primitives
2
2
  class Cylinder < Primitive
3
- attr_accessor :d, :r, :fn
3
+ attr_accessor :d, :d1, :d2, :r, :fn
4
4
  def initialize(args)
5
5
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
6
6
  args = args.first
@@ -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,73 @@ 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 openscad_params
47
+ res = {}
48
+ if @opts[:d1]
49
+ [:d1, :d2, :h, :fn].each do |n|
50
+ res[n] = self.send n
51
+ end
52
+ else
53
+ [:d, :h, :fn].each do |n|
54
+ res[n] = self.send n
55
+ end
56
+ end
57
+ res
58
+ end
59
+
60
+ def handle_fn
61
+ case @opts[:fn]
62
+ when nil, 0
63
+ $fn = auto_fn!
64
+ else
65
+ @fn = @opts[:fn]
66
+ end
67
+ end
68
+
69
+ def auto_fn!
70
+ case @d
71
+ when (16..)
72
+ @fn = (@d*4).ceil
73
+ else
74
+ @fn = 64
75
+ end
76
+ end
77
+
78
+ def handle_radius_diameter
79
+ case @opts[:d]
80
+ when 0, nil
81
+ @r = @opts[:r].to_f + @opts[:margins][:r].to_f
82
+ @d = @r * 2.0
83
+ else
84
+ @d = @opts[:d].to_f + @opts[:margins][:d].to_f
85
+ @r = @d / 2.0
86
+ end
87
+
88
+ case @opts[:d1]
89
+ when 0, nil
90
+ else
91
+ @d1 = @opts[:d1].to_f + @opts[:margins][:d].to_f
92
+ @d2 = @opts[:d2].to_f + @opts[:margins][:d].to_f
93
+ end
94
+
95
+ case @opts[:r1]
96
+ when 0, nil
97
+ else
98
+ @d1 = 2 * @opts[:r1].to_f + @opts[:margins][:d].to_f
99
+ @d2 = 2 * @opts[:r2].to_f + @opts[:margins][:d].to_f
100
+ end
101
+ end
102
+
47
103
  def h
48
- z
104
+ z + z_margin
49
105
  end
50
106
 
51
107
  end
@@ -1,5 +1,5 @@
1
1
  module JennCad::Primitives
2
- attr_accessor :convexity
2
+ attr_accessor :cut, :convexity
3
3
  class RotateExtrude < JennCad::Thing
4
4
  def initialize(part, args)
5
5
  @transformations = []
@@ -1,6 +1,7 @@
1
1
  module JennCad::Primitives
2
2
  class RoundedCube < Primitive
3
3
  attr_accessor :d, :r
4
+ include JennCad::Features::Cuttable
4
5
 
5
6
  def initialize(args)
6
7
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
@@ -40,21 +41,13 @@ module JennCad::Primitives
40
41
  # make diameter not bigger than any side
41
42
  @d = [@d, @x, @y].min
42
43
  res = HullObject.new(
43
- cylinder(d:@d, h:@z).moveh(x: -@x + @d, y: @y - @d),
44
+ cylinder(d:@d, h:z+z_margin).moveh(x: -@x + @d, y: @y - @d),
44
45
  cylinder(d:@d).moveh(x: @x - @d, y: @y - @d),
45
46
  cylinder(d:@d).moveh(x: -@x + @d, y: -@y + @d),
46
47
  cylinder(d:@d).moveh(x: @x - @d, y: -@y + @d),
47
48
  )
48
49
 
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
50
+ res += flat_edge(@opts[:flat_edges])
58
51
 
59
52
  res.transformations = @transformations
60
53
  res
@@ -62,6 +55,9 @@ module JennCad::Primitives
62
55
 
63
56
  def flat_edge(edge)
64
57
  case edge
58
+ when Array
59
+ #ruby2.7 test- edge.map(&self.:flat_edge)
60
+ edge.map{|x| flat_edge(x) }
65
61
  when :up
66
62
  cube(@x, @y/2.0, @z).moveh(y:@y/2.0)
67
63
  when :down
@@ -70,6 +66,8 @@ module JennCad::Primitives
70
66
  cube(@x/2.0, @y, @z).moveh(x:@x/2.0)
71
67
  when :left
72
68
  cube(@x/2.0, @y, @z).moveh(x:-@x/2.0)
69
+ else
70
+ nil
73
71
  end
74
72
  end
75
73
 
@@ -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,20 @@
1
+ require "jenncad/primitives/primitive"
2
+ require "jenncad/primitives/circle"
3
+ require "jenncad/primitives/cylinder"
4
+ require "jenncad/primitives/sphere"
5
+ require "jenncad/primitives/cube"
6
+ require "jenncad/primitives/rounded_cube"
7
+ require "jenncad/primitives/polygon"
8
+ require "jenncad/primitives/slot"
9
+ require "jenncad/primitives/boolean_object"
10
+ require "jenncad/primitives/union_object"
11
+ require "jenncad/primitives/subtract_object"
12
+ require "jenncad/primitives/hull_object"
13
+ require "jenncad/primitives/intersection_object"
14
+ require "jenncad/primitives/projection"
15
+ require "jenncad/primitives/linear_extrude"
16
+ require "jenncad/primitives/rotate_extrude"
17
+
18
+ module JennCad
19
+ include Primitives
20
+ end
@@ -38,6 +38,10 @@ module JennCad
38
38
  OpenScadImport.new(import, name, args)
39
39
  end
40
40
 
41
+ def stl(file, args={})
42
+ StlImport.new(file, args)
43
+ end
44
+
41
45
  def extrude(args)
42
46
  LinearExtrude.new(self, args)
43
47
  end
@@ -54,56 +58,47 @@ module JennCad
54
58
  UnionObject.new(*args)
55
59
  end
56
60
 
57
- def +(args)
58
- return args if self == nil
59
- if self.kind_of?(UnionObject) && self.transformations.size == 0
60
- self.add(args)
61
- return self
62
- else
63
- UnionObject.new(self,args)
64
- end
65
- end
66
-
67
61
  def subtraction(*args)
68
62
  SubtractObject.new(*args)
69
63
  end
70
64
 
71
- def -(args)
72
- if self.kind_of?(SubtractObject) && self.transformations.size == 0
73
- self.add(args)
74
- return self
75
- else
76
- SubtractObject.new(self,args)
77
- end
78
- end
79
-
80
65
  def intersection(*args)
81
66
  IntersectionObject.new(*args)
82
67
  end
83
68
 
84
- def *(args)
85
- if self.kind_of?(IntersectionObject) && self.transformations.size == 0
86
- self.add(args)
87
- return self
88
- else
89
- IntersectionObject.new(self,args)
90
- end
91
- end
92
-
93
69
  def hull(*args)
94
70
  HullObject.new(*args)
95
71
  end
96
72
 
97
- def &(args)
98
- if self.kind_of?(HullObject) && self.transformations.size == 0
99
- self.add(args)
100
- return self
101
- else
102
- HullObject.new(self,args)
103
- end
73
+ def +(part)
74
+ boolean_operation(part, UnionObject)
75
+ end
76
+
77
+ def -(part)
78
+ boolean_operation(part, SubtractObject)
79
+ end
80
+
81
+ def *(part)
82
+ boolean_operation(part, IntersectionObject)
83
+ end
84
+
85
+ def &(part)
86
+ boolean_operation(part, HullObject)
104
87
  end
105
88
 
106
89
  def assemble(partlib=nil, z_skip = false, z=0, &block)
107
90
  block.yield.assemble(partlib, z_skip, z)
108
91
  end
92
+
93
+ private
94
+ def boolean_operation(part, klass)
95
+ case self
96
+ when nil
97
+ part
98
+ when klass
99
+ add_or_new(part)
100
+ else
101
+ klass.new(self,part)
102
+ end
103
+ end
109
104
  end
data/lib/jenncad/thing.rb CHANGED
@@ -3,10 +3,10 @@ module JennCad
3
3
  attr_accessor :opts
4
4
  attr_accessor :parts
5
5
  attr_accessor :transformations, :name
6
- attr_accessor :x, :y, :z, :diameter
6
+ attr_accessor :x, :y, :diameter
7
7
  attr_accessor :calc_x, :calc_y, :calc_z, :calc_h
8
8
  attr_accessor :shape
9
- attr_accessor :angle, :cut, :fn
9
+ attr_accessor :angle, :fn
10
10
 
11
11
  def initialize(args={})
12
12
  @transformations = []
@@ -35,37 +35,46 @@ module JennCad
35
35
  end
36
36
  alias :rt :rotate
37
37
 
38
- def center
39
- return @center if @center
40
- case shape.to_s
41
- when "cube"
42
- [@x/2.0,@y/2.0,@z/2.0]
43
- when "cylinder"
44
- [0,0,@z/2.0]
45
- else
46
- [0,0,0]
47
- end
38
+ def rx(v)
39
+ rt(x:v)
48
40
  end
49
41
 
50
- def flip_x
51
- if self.kind_of?(BooleanObject)
42
+ def ry(v)
43
+ rt(y:v)
44
+ end
45
+
46
+ def rz(v)
47
+ rt(z:v)
48
+ end
49
+
50
+ def flip(direction)
51
+ case self
52
+ when UnionObject
53
+ ref = self.parts.first
54
+ rz = self.z.to_f + self.calc_h.to_f
55
+ when BooleanObject
52
56
  ref = self.parts.first
57
+ rz = ref.calc_z + ref.calc_h
53
58
  else
54
59
  ref = self
60
+ rz = self.z + self.calc_h
55
61
  end
56
62
 
57
- self.rotate(y:90).moveh(x: -ref.z, z: ref.x)
63
+ case direction
64
+ when :x
65
+ self.ry(90).mh(x: -rz, z: ref.x)
66
+ when :y
67
+ self.rx(90).mh(y: rz, z: ref.y)
68
+ end
69
+ end
70
+
71
+ def flip_x
72
+ flip(:x)
58
73
  end
59
74
  alias :fx :flip_x
60
75
 
61
76
  def flip_y
62
- if self.kind_of?(BooleanObject)
63
- ref = self.parts.first
64
- else
65
- ref = self
66
- end
67
-
68
- self.rotate(x:90).moveh(y: ref.z, z: ref.y)
77
+ flip(:y)
69
78
  end
70
79
  alias :fy :flip_y
71
80
 
@@ -242,26 +251,109 @@ module JennCad
242
251
  item
243
252
  end
244
253
 
254
+ def has_explicit_color?
255
+ if option(:auto_color) == false
256
+ return true
257
+ end
258
+ return false
259
+ end
260
+
261
+ def only_color?(parts, lvl=0)
262
+ return true if parts == nil
263
+
264
+ parts.each do |part|
265
+ # puts " " * lvl + "[only_color?] #{part}"
266
+ if part.has_explicit_color?
267
+ # puts " " * lvl + "found explicit color here"
268
+ return false
269
+ end
270
+ if !only_color?(part.parts, lvl+1)
271
+ return false
272
+ end
273
+ end
274
+ true
275
+ end
276
+
277
+ def set_auto_color_for_children(col, parts, lvl=0)
278
+ return if parts == nil
279
+
280
+ parts.each do |part|
281
+ unless part.has_explicit_color?
282
+ if only_color?(part.parts, lvl+1)
283
+ # puts " " * lvl + "children have no explicit color, setting it here"
284
+ part.set_auto_color(col)
285
+ else
286
+ # puts " " * lvl + "[set_auto_color_for_children] #{part}"
287
+ set_auto_color_for_children(col, part.parts, lvl+1)
288
+ end
289
+ else
290
+ # puts " " * lvl + "[set_auto_color_for_children] this part has a color, ignoring their children"
291
+ end
292
+
293
+ end
294
+ end
295
+
296
+ def set_auto_color(col)
297
+ set_option :color, col
298
+ set_option :auto_color, true
299
+ end
300
+
245
301
  def color(args=nil)
246
- return option(:color) if args == nil
302
+ if args == nil
303
+ return option(:color)
304
+ end
305
+
247
306
  if args == :auto
248
- return auto_color!
249
- elsif args == :none
250
- set_option :no_auto_color, true
307
+ ac = auto_color
308
+ unless ac.nil?
309
+ #puts "auto color to #{ac}"
310
+ if only_color?(self.parts)
311
+ set_option :color, ac
312
+ set_option :auto_color, true
313
+ else
314
+ set_auto_color_for_children(ac, self.parts)
315
+ end
316
+
317
+ end
251
318
  return self
252
319
  end
253
- set_option :color, args
320
+
321
+ c = color_parse(args)
322
+ unless c.nil?
323
+ set_option :color, c
324
+ set_option :auto_color, false
325
+ end
326
+
254
327
  self
255
328
  end
256
329
 
330
+ def color_parse(args=nil)
331
+ case args
332
+ when :none
333
+ set_option :no_auto_color, true
334
+ when :random
335
+ return Color.random
336
+ when Array
337
+ return Color.parse(args)
338
+ when /(?<=#)(?<!^)(\h{6}|\h{3})/
339
+ return args
340
+ when /(?<!^)(\h{6}|\h{3})/
341
+ return "##{args}"
342
+ when String
343
+ return args
344
+ end
345
+ nil
346
+ end
347
+
257
348
  def auto_color
258
349
  if option(:color) == nil && !option(:no_auto_color)
259
- auto_color!
350
+ return auto_color!
260
351
  end
352
+ nil
261
353
  end
262
354
 
263
355
  def auto_color!
264
- color($jenncad_profile.colors.pop)
356
+ color_parse($jenncad_profile.colors.pop)
265
357
  end
266
358
 
267
359
  def color_or_fallback
@@ -273,14 +365,10 @@ module JennCad
273
365
  if @parts == nil
274
366
  if self.respond_to? :part
275
367
  @parts = [part]
276
- else
277
- # FIXME: -> move logic OpenScad
278
- #puts "[Error in openscad export] Could not find @parts or part for #{self}"
279
- #exit
280
368
  end
281
369
  end
282
370
 
283
- OpenScad.new(self).save(file)
371
+ JennCad::Exporters::OpenScad.new(self).save(file)
284
372
  end
285
373
 
286
374
  def referenced_z
@@ -289,19 +377,27 @@ module JennCad
289
377
  return false
290
378
  end
291
379
 
380
+ def z=(args)
381
+ set_option(:z, args)
382
+ @z = args
383
+ end
384
+
292
385
  def z
293
- ref = referenced_z
294
- if ref
295
- return ref.z.to_f + ref.z_margin.to_f
386
+ case ref = referenced_z
387
+ when nil, false
388
+ @z + z_margin
389
+ else
390
+ ref.z.to_f + ref.z_margin.to_f
296
391
  end
297
- @z
298
392
  end
299
393
 
300
394
  def z_margin
301
- if option(:margins)
302
- return option(:margins)[:z].to_f
395
+ case m = option(:margins)
396
+ when nil, {}
397
+ 0.0
398
+ else
399
+ m[:z].to_f
303
400
  end
304
- 0.0
305
401
  end
306
402
 
307
403
  end