jenncad 1.0.0.pre.alpha12 → 1.0.0.pre.alpha15

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: ceeccb1511db4a12b24c38116c2daa1835f9a64f3c62fe8446feea6712c9f200
4
- data.tar.gz: 5b25c737ac0ba61039f7a54d8810a6fd94f2057ca2c482027683105adc767e54
3
+ metadata.gz: 3eebd115b8e6783b61fff33f1b002f935f3d2c2023df70df9ff3b9850f12245f
4
+ data.tar.gz: 806a99e1195f98ee1e8450030f9e2809c11217af7bf19e8cac88ad9408146a40
5
5
  SHA512:
6
- metadata.gz: e509d98347b1a96093fb62ccea12c3e71733f3af4e946694286783e54958245b99373c9721b338bc4da17ddac531a7b215b8394364b4af31aa82c3be8a183cc0
7
- data.tar.gz: 14ecaa2c0698e5fad95d311f373f2399f98eaa5b1e0220dce807053ce7ea0b505f879dce042006232cac8b6d25dd6e9c08eb1a713f78a09aba9c47c1e9bbdf08
6
+ metadata.gz: a120ac12bfe18f3532560c10452ae9460d21bd8ba2e4d287669b9b23cdf903476541fed341b81ce7feb8e906ccc8087a7a0f46f5f49e63d66b6421cd8e4d0984
7
+ data.tar.gz: 06e239cea5a153ecb3b8ab1873574bc8d9a03e51d1c0d75e5fe72f393e1584971bbc2ba388d9da82ce58cc79c2f949e206962be9052da29b0a24e351c176a53d
@@ -16,6 +16,18 @@ module JennCad
16
16
  )
17
17
  end
18
18
 
19
+ # By default, jenncad will add coordinates of subsequent moves in the output
20
+ # i.e.
21
+ # .move(x: 10, y: 20).move(x: 10) would result depending on the value of this option:
22
+ #
23
+ # true = translate([10,20, 0])translate([10, 0, 0])
24
+ # false = translate([20, 20, 0])
25
+ #
26
+ # defaults to false
27
+ def chain_moves
28
+ false
29
+ end
30
+
19
31
  def colors
20
32
  case @colors
21
33
  when nil, []
@@ -45,11 +45,11 @@ module JennCad::Exporters
45
45
  def handle_command(i=1)
46
46
  case @children.size
47
47
  when 0
48
- "#{@modifier}#{@command}(#{handle_args});"
48
+ "#{@modifier}#{@command}(#{handle_args(@args)});"
49
49
  when 1
50
- "#{@modifier}#{@command}(#{handle_args})#{@children.first.handle_command(i+1)}"
50
+ "#{@modifier}#{@command}(#{handle_args(@args)})#{@children.first.handle_command(i+1)}"
51
51
  when (1..)
52
- res = "#{@modifier}#{@command}(#{handle_args}){"
52
+ res = "#{@modifier}#{@command}(#{handle_args(@args)}){"
53
53
  res += nl
54
54
  inner = @children.map do |c|
55
55
  next if c == nil
@@ -68,17 +68,19 @@ module JennCad::Exporters
68
68
  }.join(nl)
69
69
  end
70
70
 
71
- def handle_args
72
- case @args
71
+ def handle_args(args)
72
+ case args
73
73
  when String, Symbol
74
- return "\"#{@args}\""
74
+ return "\"#{args}\""
75
75
  when Array
76
- return @args.map do |l|
76
+ return args.map do |l|
77
77
  if l == nil
78
78
  0
79
79
  elsif l.kind_of? Array
80
80
  l # skipping check of 2-dmin Arrays for now (used in multmatrix)
81
- elsif l.to_i == l.to_f
81
+ elsif l == 0
82
+ 0
83
+ elsif l == l.to_i
82
84
  l.to_i
83
85
  else
84
86
  l.to_f
@@ -86,15 +88,19 @@ module JennCad::Exporters
86
88
  end
87
89
  when Hash
88
90
  res = []
89
- @args.each do |k,v|
91
+ args.each do |k,v|
90
92
  if k.to_s == "fn"
91
93
  k = "$fn"
92
94
  end
93
95
  if v == nil
94
96
  next
95
97
  end
96
- if !v.kind_of?(Array) && !v.kind_of?(TrueClass) && !v.kind_of?(FalseClass) && v == v.to_i
98
+ if v.kind_of?(Array)
99
+ v = handle_args(v)
100
+ elsif !v.kind_of?(TrueClass) && !v.kind_of?(FalseClass) && v == v.to_i
97
101
  v = v.to_i
102
+ elsif v.kind_of? BigDecimal
103
+ v = v.to_f
98
104
  end
99
105
  if v.kind_of? String
100
106
  q = "\""
@@ -245,7 +251,8 @@ module JennCad::Exporters
245
251
 
246
252
  def handle_aggregation(part, tabindex=0)
247
253
  register_module(part) unless @modules[part.name]
248
- transform(part) do
254
+ $log.debug "aggregation #{part.name} transformations: #{part.transformations.inspect}" if part && part.option(:debug)
255
+ transform(part.clone) do
249
256
  new_obj(part, part.name, nil)
250
257
  end
251
258
  end
@@ -64,7 +64,7 @@ module JennCad::Extras
64
64
  if show
65
65
  res.color("Gainsboro")
66
66
  thread_length=Data[@size][:thread_length]
67
- if total_length.to_f <= thread_length
67
+ if total_length.to_d <= thread_length
68
68
  res+= cylinder(d:@size+addtional_diameter, h:total_length).color("DarkGray")
69
69
  else
70
70
  res+= cylinder(d:@size+addtional_diameter, h:total_length-thread_length)
@@ -48,7 +48,7 @@ module JennCad::Extras
48
48
  14=> {head_side_to_side:22,head_length:9},
49
49
  16=> {head_side_to_side:24,head_length:10},
50
50
  }
51
- head_dia = chart[@size][:head_side_to_side].to_f + head_margin.to_f
51
+ head_dia = chart[@size][:head_side_to_side].to_d + head_margin.to_d
52
52
  res = cylinder(d:(head_dia/Math.sqrt(3))*2,fn:6,h:chart[@size][:head_length]).move(z:-chart[@size][:head_length])
53
53
  total_length = @length + additional_length
54
54
  res+= cylinder(d:@size+addtional_diameter, h:total_length)
@@ -36,7 +36,7 @@ module JennCad::Extras
36
36
 
37
37
  # ISO 7380
38
38
  def bolt_7380(additional_length=0, addtional_diameter=0, head_margin=0)
39
- if head_margin.to_f != 0
39
+ if head_margin.to_d != 0
40
40
  puts "[warning] :head_margin is not implemented for 7380 bolts"
41
41
  end
42
42
  chart_iso7380 = {
@@ -5,7 +5,7 @@ module JennCad::Features
5
5
  def initialize(name=nil, part=nil)
6
6
  super({})
7
7
  @name = name.gsub(".","_")
8
- @parts = [part] # NOTE: single length arrayto make checking children easier
8
+ @parts = [part]
9
9
  end
10
10
 
11
11
  def z
@@ -1,6 +1,8 @@
1
1
  module JennCad::Features
2
2
  class Climb < Feature
3
3
  def initialize(opts, block)
4
+ $log.warn "DEPRECATED feature: climb. Please use x.of (multiples_of example)"
5
+
4
6
  @opts = {
5
7
  offset: :auto,
6
8
  step: nil,
@@ -31,7 +33,7 @@ module JennCad::Features
31
33
  steps = @opts[:steps]
32
34
  (z / steps).floor
33
35
  else
34
- step.to_f
36
+ step.to_d
35
37
  end
36
38
  end
37
39
 
@@ -62,8 +64,8 @@ module JennCad::Features
62
64
 
63
65
  offset = get_offset(ref_z)
64
66
 
65
- lo = (ref_z-offset*2).to_f % step.to_f
66
- unless lo.to_f == 0.0
67
+ lo = (ref_z-offset*2).to_d % step.to_d
68
+ unless lo.to_d == 0.0
67
69
  puts "[Warning]: climb has leftover offset #{lo}"
68
70
  end
69
71
 
@@ -16,12 +16,12 @@ module JennCad::Features
16
16
 
17
17
  def prepare_cut(l, r, &block)
18
18
  part = block.call
19
- if part.z.to_f > 0.0
19
+ if part.z.to_d > 0.0
20
20
  part.opts[:margins][:z] = 0.2
21
21
  if l == 0.0
22
22
  part.mz(r+0.1)
23
23
  else
24
- part.mz(l+part.z.to_f-0.2)
24
+ part.mz(l+part.z.to_d-0.2)
25
25
  end
26
26
  else
27
27
  part.opts[:margins][:z] = 0.2
@@ -0,0 +1,14 @@
1
+ class Integer
2
+ def of(part=nil, anchor=:top_face)
3
+ return nil if part.nil?
4
+ num = self - 1
5
+
6
+ res = part.fix
7
+ num.times do
8
+ res += part.movea(anchor)
9
+ end
10
+ res
11
+ end
12
+ end
13
+
14
+
@@ -1,7 +1,7 @@
1
1
  module JennCad
2
2
  class RoundCorner
3
3
  attr_accessor :start_point, :end_point, :input_a, :output_a, :a, :l, :od, :id, :thing, :angle, :current_angle, :direction, :from, :ccw
4
- def initialize(args, &thing)
4
+ def initialize(args)
5
5
  @start_point = args[:start_point]
6
6
  @end_point = args[:end_point]
7
7
  @a = args[:a]
@@ -11,7 +11,13 @@ module JennCad
11
11
  @id = args[:id]
12
12
  @input_a = args[:input_a] || 0
13
13
  @output_a = args[:output_a] || 0
14
- @thing = thing
14
+ thing = Marshal.load(args[:thing])
15
+
16
+ @thing_dia = thing.d || thing.y
17
+ unless @thing_dia
18
+ $log.error "ERROR: cannot find diameter or y of thing #{thing.inspect}"
19
+ return
20
+ end
15
21
  @angle = args[:angle]
16
22
  @current_angle = args[:current_angle]
17
23
  @direction = args[:direction]
@@ -57,11 +63,7 @@ module JennCad
57
63
  end
58
64
 
59
65
  def positions
60
- td = thing.yield.d || thing.yield.y
61
- unless td
62
- puts "ERROR: cannot find diameter or y of thing #{thing.yield.inspect}"
63
- return
64
- end
66
+ td = @thing_dia
65
67
  l = td + @id
66
68
  l2 = td / 2.0 + @id / 2.0
67
69
  r = 0
@@ -101,7 +103,7 @@ module JennCad
101
103
  end
102
104
 
103
105
  def part
104
- d = thing.yield.d
106
+ d = @thing_dia
105
107
  len = d * 2 + @id
106
108
  x = Math::sin((@a/180.0)*Math::PI)*len
107
109
  y = Math::cos((@a/180.0)*Math::PI)*len
@@ -134,15 +136,15 @@ module JennCad
134
136
  end
135
137
 
136
138
  class Line
137
- attr_accessor :start_point, :end_point, :l, :thing, :angle, :current_angle, :direction
138
- def initialize(args, &thing)
139
+ attr_accessor :start_point, :end_point, :l, :angle, :current_angle, :direction
140
+ def initialize(args)
139
141
  @start_point = args[:start_point]
140
142
  @end_point = args[:end_point]
141
143
  @angle = args[:angle]
142
144
  @current_angle = args[:current_angle]
143
145
  @direction = args[:direction]
144
146
  @l = args[:l]
145
- @thing = thing
147
+ @thing = args[:thing]
146
148
  end
147
149
 
148
150
  def sp_margin(margin)
@@ -181,8 +183,8 @@ module JennCad
181
183
 
182
184
  def part
183
185
  hull(
184
- @thing.yield.move(x: @start_point[:x], y: @start_point[:y]),
185
- @thing.yield.move(x: @end_point[:x], y: @end_point[:y])
186
+ Marshal.load(@thing).move(x: @start_point[:x], y: @start_point[:y]),
187
+ Marshal.load(@thing).move(x: @end_point[:x], y: @end_point[:y])
186
188
  )
187
189
  end
188
190
  end
@@ -191,7 +193,7 @@ module JennCad
191
193
 
192
194
  attr_accessor :elements, :lpos, :thing, :angle, :current_angle, :direction
193
195
  def initialize(args)
194
- @thing = args[:part] #// cylinder(d: @d, z: @z)
196
+ @thing = store_thing_from(args[:part])
195
197
  @part = new_thing
196
198
  @angle = args[:a] || 0
197
199
  @current_angle = args[:a] || 0
@@ -207,10 +209,14 @@ module JennCad
207
209
  super(args)
208
210
  end
209
211
 
210
- def new_thing
211
- r = @thing.clone
212
+ def store_thing_from(thing)
213
+ r = Marshal.load(Marshal.dump(thing)) # make sure we don't edit the object in memory
212
214
  r.transformations = []
213
- r
215
+ Marshal.dump(r)
216
+ end
217
+
218
+ def new_thing
219
+ Marshal.load(@thing)
214
220
  end
215
221
 
216
222
  def corner(args)
@@ -232,8 +238,9 @@ module JennCad
232
238
  from: args[:from],
233
239
  to: args[:to],
234
240
  a: args[:a],
235
- direction: @direction
236
- ){ new_thing }
241
+ direction: @direction,
242
+ thing: thing,
243
+ )
237
244
 
238
245
  _, ox, oy, x, y = rc.positions
239
246
  @lpos[:x] += x + ox
@@ -292,7 +299,7 @@ module JennCad
292
299
  return
293
300
  end
294
301
 
295
- @steps << Line.new(start_point: { x: @lpos[:x], y: @lpos[:y] }, end_point: { x: @lpos[:x] + x, y: @lpos[:y] + y }, angle: @angle, current_angle: @current_angle, direction: @direction, l: l){ new_thing }
302
+ @steps << Line.new(start_point: { x: @lpos[:x], y: @lpos[:y] }, end_point: { x: @lpos[:x] + x, y: @lpos[:y] + y }, angle: @angle, current_angle: @current_angle, direction: @direction, l: l, thing: thing)
296
303
 
297
304
  add_lpos({x: x, y: y})
298
305
  end
@@ -5,6 +5,8 @@ require "jenncad/features/openscad_include"
5
5
  require "jenncad/features/climb"
6
6
  require "jenncad/features/stl_import"
7
7
  require "jenncad/features/path"
8
+ require "jenncad/features/multiples_of"
9
+
8
10
 
9
11
 
10
12
 
data/lib/jenncad/part.rb CHANGED
@@ -3,9 +3,13 @@ module JennCad
3
3
  class Part < Thing
4
4
 
5
5
  def to_openscad
6
- a = Aggregation.new(self.class.to_s, self.part)
6
+ a = Aggregation.new(self.class.to_s, self.get_contents)
7
7
  a.transformations = @transformations
8
- a.color(:auto)
8
+ if self.has_explicit_color?
9
+ a.color(self.color)
10
+ else
11
+ a.color(:auto)
12
+ end
9
13
  a
10
14
  end
11
15
 
@@ -12,7 +12,7 @@ class Array
12
12
  else
13
13
  res = part
14
14
  end
15
- res, z = res.mz(z), z + res.z.to_f unless skip_z
15
+ res, z = res.mz(z), z + res.z.to_d unless skip_z
16
16
  res
17
17
  end
18
18
  .union
@@ -7,21 +7,29 @@ module JennCad::Primitives
7
7
  else
8
8
  @parts = parts
9
9
  end
10
+ if parts.first && parts.first.respond_to?(:debug?) && parts.first.debug?
11
+ $log.debug("Creating new #{self.class} for part #{parts}")
12
+ end
13
+
10
14
  @parent = @parts.first.parent
15
+
11
16
  after_add
12
17
  end
13
18
 
14
19
  def add_or_new(part)
15
20
  case @transformations
16
21
  when nil, []
22
+ $log.debug("adding new part to existing boolean object") if part && part.debug?
17
23
  add(part)
18
24
  self
19
25
  else
26
+ $log.debug("add_or_new: creating new boolean object") if part.debug?
20
27
  self.class.new(self, part)
21
28
  end
22
29
  end
23
30
 
24
31
  def add(part)
32
+ return if part.nil?
25
33
  @parts << part
26
34
  after_add
27
35
  end
@@ -41,25 +49,25 @@ module JennCad::Primitives
41
49
  end
42
50
 
43
51
  def inherit_z
44
- heights = @parts.map{|l| l.calc_z.to_f}.uniq
52
+ heights = @parts.map{|l| l.calc_z.to_d}.uniq
45
53
  if heights.size > 1
46
54
  total_heights = []
47
55
  @parts.each do |p|
48
- total_heights << p.z.to_f + p.calc_z.to_f
56
+ total_heights << p.z.to_d + p.calc_z.to_d
49
57
  end
50
58
  @z = total_heights.max
51
59
  @calc_z = heights.min
52
60
  else
53
- @calc_z = heights.first.to_f
61
+ @calc_z = heights.first.to_d
54
62
  @z = @parts.map(&:z).compact.max
55
63
  end
56
64
  end
57
65
 
58
66
  def inherit_zref
59
67
  return if @parts.first == nil
60
- #return if @parts.first.z.to_f == 0.0
68
+ #return if @parts.first.z.to_d == 0.0
61
69
  get_primitives(@parts[1..-1]).flatten.each do |part|
62
- if part.z.to_f == 0.0
70
+ if part.z.to_d == 0.0
63
71
  part.set_option :zref, @parts.first
64
72
  end
65
73
  end
@@ -82,6 +82,13 @@ module JennCad::Primitives
82
82
  set_anchor :top_right, x: right, y: top
83
83
  set_anchor :bottom_left, x: left, y: bottom
84
84
  set_anchor :bottom_right, x: right, y: bottom
85
+ if @opts[:center_z]
86
+ set_anchor :bottom_face, z: -@z/2.0
87
+ set_anchor :top_face, z: @z/2.0
88
+ else
89
+ set_anchor :bottom_face, z: 0
90
+ set_anchor :top_face, z: @z
91
+ end
85
92
 
86
93
  # we need to re-do the inner ones, if they were defined
87
94
  if @inner_anchor_defs && @inner_anchor_defs.size > 0
@@ -1,6 +1,6 @@
1
1
  module JennCad::Primitives
2
2
  class Cylinder < Primitive
3
- attr_accessor :d, :d1, :d2, :r, :fn
3
+ attr_accessor :d, :d1, :d2, :r, :fn, :anchors
4
4
  def initialize(args)
5
5
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
6
6
  args = args.first
@@ -24,6 +24,7 @@ module JennCad::Primitives
24
24
  r2: nil,
25
25
  z: nil,
26
26
  r: 0,
27
+ cz: false,
27
28
  margins: {
28
29
  r: 0,
29
30
  d: 0,
@@ -41,6 +42,35 @@ module JennCad::Primitives
41
42
  handle_radius_diameter
42
43
  handle_fn
43
44
  super(args)
45
+ set_anchors
46
+ end
47
+
48
+ def set_anchors
49
+ @anchors = {} # reset anchors
50
+ if @opts[:d]
51
+ rad = @opts[:d] / 2.0
52
+ else
53
+ rad = @opts[:r]
54
+ end
55
+
56
+ # Similar to cube
57
+ set_anchor :left, x: -rad
58
+ set_anchor :right, x: rad
59
+ set_anchor :top, y: rad
60
+ set_anchor :bottom, y: -rad
61
+
62
+ # TODO: figure out if we also want to have "corners"
63
+ # - possibly move it like a cube
64
+ # - points at 45 ° angles might not be that useful unless you can get the point on the circle at a given angle
65
+ # - inner/outer points could be useful for small $fn values
66
+
67
+ if @opts[:cz]
68
+ set_anchor :bottom_face, z: -@z/2.0
69
+ set_anchor :top_face, z: @z/2.0
70
+ else
71
+ set_anchor :bottom_face, z: 0
72
+ set_anchor :top_face, z: @z
73
+ end
44
74
  end
45
75
 
46
76
  def openscad_params
@@ -60,20 +90,22 @@ module JennCad::Primitives
60
90
  # Centers the cylinder around it's center point by height
61
91
  # This will transform the cylinder around the center point.
62
92
  def cz
93
+ @opts[:cz] = true
63
94
  @transformations << Move.new(z: -@z / 2.0)
95
+ set_anchors
64
96
  self
65
97
  end
66
98
 
67
99
  def handle_fn
68
100
  case @opts[:fn]
69
101
  when nil, 0
70
- $fn = auto_fn!
102
+ $fn = auto_dn!
71
103
  else
72
104
  @fn = @opts[:fn]
73
105
  end
74
106
  end
75
107
 
76
- def auto_fn!
108
+ def auto_dn!
77
109
  case @d
78
110
  when (16..)
79
111
  @fn = (@d*4).ceil
@@ -85,25 +117,25 @@ module JennCad::Primitives
85
117
  def handle_radius_diameter
86
118
  case @opts[:d]
87
119
  when 0, nil
88
- @r = @opts[:r].to_f + @opts[:margins][:r].to_f
120
+ @r = @opts[:r].to_d + @opts[:margins][:r].to_d
89
121
  @d = @r * 2.0
90
122
  else
91
- @d = @opts[:d].to_f + @opts[:margins][:d].to_f
123
+ @d = @opts[:d].to_d + @opts[:margins][:d].to_d
92
124
  @r = @d / 2.0
93
125
  end
94
126
 
95
127
  case @opts[:d1]
96
128
  when 0, nil
97
129
  else
98
- @d1 = @opts[:d1].to_f + @opts[:margins][:d].to_f
99
- @d2 = @opts[:d2].to_f + @opts[:margins][:d].to_f
130
+ @d1 = @opts[:d1].to_d + @opts[:margins][:d].to_d
131
+ @d2 = @opts[:d2].to_d + @opts[:margins][:d].to_d
100
132
  end
101
133
 
102
134
  case @opts[:r1]
103
135
  when 0, nil
104
136
  else
105
- @d1 = 2 * @opts[:r1].to_f + @opts[:margins][:d].to_f
106
- @d2 = 2 * @opts[:r2].to_f + @opts[:margins][:d].to_f
137
+ @d1 = 2 * @opts[:r1].to_d + @opts[:margins][:d].to_d
138
+ @d2 = 2 * @opts[:r2].to_d + @opts[:margins][:d].to_d
107
139
  end
108
140
  end
109
141
 
@@ -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
@@ -36,10 +36,25 @@ module JennCad::Primitives
36
36
  @d = @opts[:d]
37
37
  @a = @opts[:a]
38
38
  @h = @opts[:h]
39
- @r = @opts[:r]
39
+ @r = @opts[:r] || nil
40
+ if @r
41
+ @d = @r * 2
42
+ end
40
43
  @fn = @opts[:fn]
41
44
  @len_x = @opts[:x]
42
45
  @len_y = @opts[:y]
46
+ tx = @opts[:tx] || @opts[:total_x] || nil
47
+ ty = @opts[:ty] || @opts[:total_y] || nil
48
+ if tx
49
+ @len_x = tx - @d
50
+ end
51
+ if ty
52
+ @len_y = ty - @d
53
+ end
54
+
55
+ # TODO: this needs anchors like cube
56
+ # TODO: color on this needs to apply to hull, not on the cylinders.
57
+
43
58
  end
44
59
 
45
60
  def to_openscad
@@ -64,16 +79,16 @@ module JennCad::Primitives
64
79
  end
65
80
 
66
81
  def end_vector
67
- if @a.to_f == 0.0
82
+ if @a.to_d == 0.0
68
83
  return [@len_x, 0] if @len_x
69
84
  return [0, @len_y] if @len_y
70
85
  end
71
86
  if @len_x
72
- x = cos(PI*@a/180.0)*@len_x.to_f
73
- y = sin(PI*@a/180.0)*@len_x.to_f
87
+ x = cos(PI*@a/180.0)*@len_x.to_d
88
+ y = sin(PI*@a/180.0)*@len_x.to_d
74
89
  else
75
- x = -1* sin(PI*@a/180.0)*@len_y.to_f
76
- y = cos(PI*@a/180.0)*@len_y.to_f
90
+ x = -1* sin(PI*@a/180.0)*@len_y.to_d
91
+ y = cos(PI*@a/180.0)*@len_y.to_d
77
92
  end
78
93
  [x,y]
79
94
  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)
@@ -80,7 +80,7 @@ module JennCad::Primitives
80
80
  part.opts[:margins][:z] += 0.004
81
81
  # part.z+=0.004
82
82
  part.mz(-0.002)
83
- elsif part.calc_z.to_f+part.calc_h.to_f == compare_h
83
+ elsif part.calc_z.to_d+part.calc_h.to_d == compare_h
84
84
  # puts "z fighting at top: #{compare_h}"
85
85
  #part.z+=0.004
86
86
  part.opts[:margins][:z] += 0.004
@@ -92,13 +92,23 @@ module JennCad
92
92
 
93
93
  private
94
94
  def boolean_operation(part, klass)
95
+ if part.respond_to? :transformations
96
+ # Clone the part in place
97
+ part = part.fix
98
+ end
99
+
95
100
  case self
96
101
  when nil
97
102
  part
98
103
  when klass
99
104
  add_or_new(part)
100
105
  else
101
- klass.new(self,part)
106
+ own_part = if self.respond_to? :transformations
107
+ self.fix # clone self
108
+ else
109
+ self
110
+ end
111
+ klass.new(own_part,part)
102
112
  end
103
113
  end
104
114
  end
data/lib/jenncad/thing.rb CHANGED
@@ -20,6 +20,7 @@ module JennCad
20
20
  @anchors = {}
21
21
  @parent = args[:parent]
22
22
  @opts ||= args
23
+ @cache = nil
23
24
  end
24
25
 
25
26
  def option(key)
@@ -32,6 +33,23 @@ module JennCad
32
33
  @opts[key] = val
33
34
  end
34
35
 
36
+ def set_flag(key)
37
+ set_option(key, true)
38
+ end
39
+
40
+ def unset_flag(key)
41
+ set_option(key, false)
42
+ end
43
+
44
+ def debug?
45
+ option(:debug) || false
46
+ end
47
+
48
+ def fixate
49
+ Marshal.load(Marshal.dump(self))
50
+ end
51
+ alias :fix :fixate
52
+
35
53
  def set_parent(parent)
36
54
  @parent = parent
37
55
  self
@@ -39,13 +57,19 @@ module JennCad
39
57
 
40
58
  def anchor(name, thing=nil)
41
59
  if thing
42
- return thing.anchor(name)
60
+ res = thing.anchor(name)
61
+ return res unless res.nil?
43
62
  end
44
63
  @anchors ||= {}
45
64
  if anch = @anchors[name]
46
65
  return anch
47
66
  elsif @parent
48
67
  return @parent.anchor(name)
68
+ elsif self.respond_to? :get_contents
69
+ con = get_contents
70
+ if con.respond_to? :anchor
71
+ con.anchor(name)
72
+ end
49
73
  end
50
74
  end
51
75
  alias :a :anchor
@@ -57,6 +81,22 @@ module JennCad
57
81
  end
58
82
  alias :sa :set_anchor
59
83
 
84
+ def set_anchor_from(name, new_name, args={})
85
+ a = anchor(name).dup
86
+ if !a
87
+ log.error "set_anchor_from couldn't find anchor #{name}"
88
+ return
89
+ end
90
+
91
+ [:x, :y, :z, :xy, :xz, :xyz, :yz].each do |key|
92
+ a[key] ||= 0.to_d
93
+ args[key] ||= 0.to_d
94
+ a[key] += args[key]
95
+ end
96
+ set_anchor new_name, a
97
+ end
98
+ alias :saf :set_anchor_from
99
+
60
100
  def auto_extrude
61
101
  ret = self.extrude
62
102
  ret.set_option(:auto_extrude, true)
@@ -86,7 +126,7 @@ module JennCad
86
126
  case self
87
127
  when UnionObject
88
128
  ref = self.parts.first
89
- rz = self.z.to_f + self.calc_h.to_f
129
+ rz = self.z.to_d + self.calc_h.to_d
90
130
  when BooleanObject
91
131
  ref = self.parts.first
92
132
  rz = ref.calc_z + ref.calc_h
@@ -114,7 +154,7 @@ module JennCad
114
154
  alias :fy :flip_y
115
155
 
116
156
  def radians(a)
117
- a.to_f/180.0*PI
157
+ a.to_d/180.0*PI
118
158
  end
119
159
 
120
160
  # experiment
@@ -174,21 +214,43 @@ module JennCad
174
214
  end
175
215
 
176
216
  def move(args={})
217
+ return self if args.nil? or args.empty?
218
+
177
219
  if args.kind_of? Array
178
220
  x,y,z = args
179
221
  return move(x:x, y:y, z:z)
180
222
  end
181
223
  args = parse_xyz_shortcuts(args)
182
224
 
225
+ if args[:x].to_d == 0.0 && args[:y].to_d == 0.0 && args[:z].to_d == 0.0
226
+ return self
227
+ end
228
+
183
229
  @transformations ||= []
184
230
  if args[:prepend]
185
231
  @transformations.prepend(Move.new(args))
186
232
  else
187
- @transformations << Move.new(args)
233
+ lt = @transformations.last
234
+
235
+ chain = if args[:chain]
236
+ args[:chain]
237
+ else
238
+ $jenncad_profile.chain_moves
239
+ end
240
+
241
+ if lt && lt.class == Move && chain == false
242
+ $log.debug "#{self} at move: Adding to previous move #{lt.inspect} , args: #{args}" if self.debug?
243
+ lt.x += args[:x].to_d
244
+ lt.y += args[:y].to_d
245
+ lt.z += args[:z].to_d
246
+ else
247
+ $log.debug "#{self} at move: Adding move of #{args} to transformations" if self.debug?
248
+ @transformations << Move.new(args)
249
+ end
188
250
  end
189
- @calc_x += args[:x].to_f
190
- @calc_y += args[:y].to_f
191
- @calc_z += args[:z].to_f
251
+ @calc_x += args[:x].to_d
252
+ @calc_y += args[:y].to_d
253
+ @calc_z += args[:z].to_d
192
254
  self
193
255
  end
194
256
  alias :translate :move
@@ -207,27 +269,39 @@ module JennCad
207
269
  end
208
270
 
209
271
  # move to anchor
210
- def movea(key, thing=nil)
272
+ def movea(key, thing=nil, args={})
273
+ if thing.kind_of? Hash # if you leave out thing, args may be interpreted as thing
274
+ args = thing
275
+ thing = nil
276
+ end
277
+
211
278
  an = anchor(key, thing)
279
+
212
280
  unless an
213
281
  $log.error "Error: Anchor #{key} not found"
214
282
  $log.error "Available anchors: #{@anchors}"
215
283
  return self
216
284
  else
217
- self.move(an.dup)
285
+ m = an.dup
286
+ if args[:chain]
287
+ m[:chain] = args[:chain]
288
+ end
289
+ if args[:inverted]
290
+ self.movei(m)
291
+ else
292
+ self.move(m)
293
+ end
218
294
  end
219
295
  end
220
296
 
221
297
  # move to anchor - inverted
222
- def moveai(key, thing=nil)
223
- an = anchor(key, thing)
224
- unless an
225
- $log.error "Error: Anchor #{key} not found"
226
- $log.error "Available anchors: #{@anchors}"
227
- return self
228
- else
229
- self.movei(an.dup)
298
+ def moveai(key, thing=nil, args={})
299
+ if thing.kind_of? Hash # if you leave out thing, args may be interpreted as thing
300
+ args = thing
301
+ thing = nil
230
302
  end
303
+ args[:inverted] = true
304
+ movea(key, thing, args)
231
305
  end
232
306
 
233
307
 
@@ -264,6 +338,7 @@ module JennCad
264
338
  to[key] = args[key]*-1
265
339
  end
266
340
  end
341
+ to[:chain] = args[:chain]
267
342
  move(to)
268
343
  end
269
344
 
@@ -327,7 +402,7 @@ module JennCad
327
402
  end
328
403
 
329
404
  def top_of(other_object)
330
- self.move(z:other_object.z+other_object.calc_z.to_f)
405
+ self.move(z:other_object.z+other_object.calc_z.to_d)
331
406
  end
332
407
 
333
408
  def on_top_of(other_object)
@@ -341,36 +416,14 @@ module JennCad
341
416
  def get_children(item, stop_at)
342
417
  res = [item]
343
418
  if item.respond_to?(:parts) && item.parts != nil
344
- item.parts.each do |part|
345
- unless stop_at != nil && part.kind_of?(stop_at)
346
- res << get_children(part, stop_at)
419
+ item.parts.each do |pa|
420
+ unless stop_at != nil && pa.kind_of?(stop_at)
421
+ res << get_children(pa, stop_at)
347
422
  end
348
423
  end
349
424
  end
350
425
  res
351
426
  end
352
- =begin def make_openscad_compatible
353
- make_openscad_compatible!(self)
354
- end
355
-
356
- def make_openscad_compatible!(item)
357
- if item.respond_to?(:parts) && item.parts != nil
358
- item.parts.each_with_index do |part, i|
359
- if part.respond_to? :to_openscad
360
- item.parts[i] = part.to_openscad
361
- else
362
- item.parts[i] = part.make_openscad_compatible
363
- end
364
- end
365
- elsif item.respond_to? :part
366
- item = item.part.make_openscad_compatible
367
- end
368
- if item.respond_to? :to_openscad
369
- item = item.to_openscad
370
- end
371
- item
372
- end
373
- =end
374
427
 
375
428
  def inherit_color(other)
376
429
  self.set_option(:color, other.option(:color))
@@ -386,11 +439,14 @@ module JennCad
386
439
 
387
440
  def only_color?(parts, lvl=0)
388
441
  return true if parts == nil
442
+ unless parts.kind_of? Array
443
+ parts = [parts]
444
+ end
389
445
 
390
446
  parts.each do |part|
391
- # puts " " * lvl + "[only_color?] #{part}"
447
+ #puts " " * lvl + "[only_color?] #{part}"
392
448
  if part.has_explicit_color?
393
- # puts " " * lvl + "found explicit color here"
449
+ #puts " " * lvl + "found explicit color here: #{part.color}"
394
450
  return false
395
451
  end
396
452
  if !only_color?(part.parts, lvl+1)
@@ -406,14 +462,14 @@ module JennCad
406
462
  parts.each do |part|
407
463
  unless part.has_explicit_color?
408
464
  if only_color?(part.parts, lvl+1)
409
- # puts " " * lvl + "children have no explicit color, setting it here"
465
+ #puts " " * lvl + "children have no explicit color, setting it here"
410
466
  part.set_auto_color(col)
411
467
  else
412
- # puts " " * lvl + "[set_auto_color_for_children] #{part}"
468
+ #puts " " * lvl + "[set_auto_color_for_children] #{part}"
413
469
  set_auto_color_for_children(col, part.parts, lvl+1)
414
470
  end
415
471
  else
416
- # puts " " * lvl + "[set_auto_color_for_children] this part has a color, ignoring their children"
472
+ #puts " " * lvl + "[set_auto_color_for_children] this part has a color #{part.color}, ignoring their children"
417
473
  end
418
474
 
419
475
  end
@@ -467,6 +523,8 @@ module JennCad
467
523
  return "##{args}"
468
524
  when String
469
525
  return args
526
+ when Symbol
527
+ return args.to_s
470
528
  end
471
529
  nil
472
530
  end
@@ -489,8 +547,15 @@ module JennCad
489
547
 
490
548
  def get_contents
491
549
  return @parts unless @parts.nil?
550
+
551
+ if @cache
552
+ return @cache
553
+ end
554
+
492
555
  if self.respond_to? :part
493
- return [part]
556
+ # cache things to prevent calling the code in #part multiple times
557
+ @cache = part
558
+ return @cache
494
559
  end
495
560
  end
496
561
 
@@ -503,6 +568,9 @@ module JennCad
503
568
 
504
569
  def find_calculated_h(parts)
505
570
  return if parts == nil
571
+ unless parts.kind_of? Array
572
+ parts = [parts]
573
+ end
506
574
  parts.each do |part|
507
575
  if z = calculated_h
508
576
  return z
@@ -513,6 +581,10 @@ module JennCad
513
581
 
514
582
  def set_heights_for_auto_extrude(parts, parent=nil)
515
583
  return if parts.nil?
584
+ unless parts.kind_of? Array
585
+ parts = [parts]
586
+ end
587
+
516
588
  parts.each do |part|
517
589
  if part.option(:auto_extrude)
518
590
  part.z = parent.calculated_h
@@ -561,7 +633,7 @@ module JennCad
561
633
  end
562
634
 
563
635
  def referenced_z
564
- return false if @z.to_f != 0.0
636
+ return false if @z.to_d != 0.0
565
637
  return option(:zref) if option(:zref)
566
638
  return false
567
639
  end
@@ -576,7 +648,7 @@ module JennCad
576
648
  when nil, false
577
649
  @z + z_margin
578
650
  else
579
- ref.z.to_f + ref.z_margin.to_f
651
+ ref.z.to_d + ref.z_margin.to_d
580
652
  end
581
653
  end
582
654
 
@@ -585,7 +657,7 @@ module JennCad
585
657
  when nil, {}
586
658
  0.0
587
659
  else
588
- m[:z].to_f
660
+ m[:z].to_d
589
661
  end
590
662
  end
591
663
 
@@ -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,4 +1,3 @@
1
1
  module JennCad
2
- VERSION = "1.0.0-alpha12"
2
+ VERSION = "1.0.0-alpha15"
3
3
  end
4
-
data/lib/jenncad.rb CHANGED
@@ -1,6 +1,7 @@
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"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jenncad
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.alpha12
4
+ version: 1.0.0.pre.alpha15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jennifer Glauche
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-30 00:00:00.000000000 Z
11
+ date: 2022-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: geo3d
@@ -122,6 +122,7 @@ files:
122
122
  - lib/jenncad/features/climb.rb
123
123
  - lib/jenncad/features/cuttable.rb
124
124
  - lib/jenncad/features/feature.rb
125
+ - lib/jenncad/features/multiples_of.rb
125
126
  - lib/jenncad/features/openscad_include.rb
126
127
  - lib/jenncad/features/path.rb
127
128
  - lib/jenncad/features/stl_import.rb