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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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