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

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.
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