jenncad 1.0.0.pre.alpha2 → 1.0.0.pre.alpha6

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: ef018e45bc6303b2a45c2ad3340d714cb340288465936f23293961fbc2615cd4
4
- data.tar.gz: 1ee41eb205053ad3ea4e0d1b8c76b4fa13c98f212393e71008e96f1303b0f9c7
3
+ metadata.gz: 8dc72aa8cfaaa41cf4b96038f454073f708502cea9d9ce84a13fc28203ff4dc2
4
+ data.tar.gz: c5f0cbe4442bf7b59c39ee2f69e2096d0166fa4ae336c48029f8856606da3d9a
5
5
  SHA512:
6
- metadata.gz: b9541672a102b371b7a517be6d015ca1bc6e4f81fae97761399514733870bc1b0c67094b6a6e177c1c5af7d85416067e9b6dab024bff275b4537013f88072fc2
7
- data.tar.gz: 44d0ae2e9aefb56e1964cf2e0fdf0590be5fc600abea1d65f3edcf40fca03a57bf6e107020dd26ec2ffac6a3f4c9f6b6f3688cdbcb72489766984b3011c8abd3
6
+ metadata.gz: 425dda2b4dda1793baa9ef4d6f30155325acc949df98c2ca214b7abb931a1a9aa7757f6b906a89cf12d7a17c4447ef3b92b3b999120d455cfb8693a2b5cfe0af
7
+ data.tar.gz: 706f8e591aab9c10702577c09fc95a4e5e7cd1444cb3fbda88e715872e4aab67fb8b35449a97a27a1b874325e3804cf20377884ebb67896484e9bc9cee5a6625
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+
2
+ # jenncad
3
+ Create physical objects in Ruby, OpenScad export
4
+
5
+ This is a successor to my older project CrystalScad.
6
+
7
+ # Installation
8
+
9
+ A packaged release is not yet available, please build your own package in the meantime:
10
+
11
+ $ git clone git@github.com:jglauche/jenncad.git
12
+ $ cd jenncad
13
+ $ rake install
14
+
15
+ This will create a gem and a binary jenncad.
16
+
17
+ # Using Jenncad
18
+
19
+ **To create a new project directory, run:**
20
+
21
+ $ jenncad create meow
22
+
23
+
24
+
25
+
26
+ This will generate a directory meow/ and an executable ruby file meow.rb in its directory
27
+
28
+ $ cd meow
29
+ $ ./meow
30
+
31
+ This will generate a dummy project which generates a dummy cube as OpenSCAD output:
32
+
33
+ $ cat output/meow.scad
34
+ > $fn=64;
35
+ > translate([-5, -5, 0])cube([10, 10, 10.0]);
36
+
37
+ **Automatically refresh OpenSCAD output while developing**
38
+
39
+ Jenncad bundles the observr gem which will check if files were changed while developing. In the project directory run:
40
+
41
+ $ jenncad
42
+ This should display something like:
43
+ > refreshing...
44
+ > ok
45
+ > JennCad running, refreshing on file changes. Press ctrl+c to exit
46
+
47
+ **Note:** This does not check for new files in the project. You will have to restart it when you create a new part in a new file
48
+
49
+ **Create new part**
50
+
51
+ In your project directory, run:
52
+
53
+ $ jenncad new cat
54
+ part parts/cat.rb created. In your meow.rb add to class Meow:
55
+ def cat
56
+ Cat.new(config)
57
+ end
58
+
59
+
60
+ You will have to link the part to the project manually into the meow.rb file in your project directory. When you add it, your meow.rb should look like this:
61
+
62
+ #!/usr/bin/env ruby
63
+ require "jenncad"
64
+ include JennCad
65
+
66
+ class Meow < Project
67
+ def config
68
+ {}
69
+ end
70
+
71
+ def meow
72
+ cube(10,10,10)
73
+ end
74
+
75
+ def cat
76
+ Cat.new(config)
77
+ end
78
+
79
+ end
80
+ Meow.new.run
81
+
82
+
83
+
data/jenncad.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |gem|
22
22
  gem.required_ruby_version = ">= 2.6.0"
23
23
  gem.add_runtime_dependency "geo3d"
24
24
  gem.add_runtime_dependency "deep_merge"
25
- gem.add_runtime_dependency "hanami-cli"
25
+ gem.add_runtime_dependency "hanami-cli", "0.3.1"
26
26
  gem.add_runtime_dependency "activesupport"
27
27
  gem.add_runtime_dependency "observr"
28
28
  end
@@ -1,6 +1,7 @@
1
1
  module JennCad
2
2
  module Commands
3
3
  extend Hanami::CLI::Registry
4
+ MAGIC = "jenncad-append-project-magic"
4
5
 
5
6
  class Run < Hanami::CLI::Command
6
7
  argument :name, required: false
@@ -122,10 +123,34 @@ module JennCad
122
123
  f.puts " end"
123
124
  f.puts "end"
124
125
  end
125
- puts "part #{filename} created. In your #{executable} add to class #{executable_class}:"
126
- puts " def #{name}"
127
- puts " #{classname}.new(config)"
128
- puts " end"
126
+
127
+ lines = File.readlines(executable)
128
+ magic_line = nil;
129
+ lines.each_with_index do |l, i|
130
+ if l.rindex(MAGIC)
131
+ magic_line = i
132
+ end
133
+ end
134
+ puts "part #{filename} created."
135
+ if !magic_line
136
+ puts "In your #{executable} add to class #{executable_class}:"
137
+ puts " def #{name}"
138
+ puts " #{classname}.new(config)"
139
+ puts " end"
140
+ puts ""
141
+ puts "For jenncad to insert this line automatically, add this line to your project file before the \"end\"-statement of your class:"
142
+ puts "##{MAGIC}"
143
+ else
144
+ data = "\n"
145
+ data += " def #{name}\n"
146
+ data += " #{classname}.new(config)\n"
147
+ data += " end\n"
148
+ lines.insert(magic_line, data)
149
+ f = File.open(executable, "w")
150
+ f.write(lines.join)
151
+ f.close
152
+ end
153
+
129
154
 
130
155
  end
131
156
 
@@ -152,9 +177,7 @@ module JennCad
152
177
  f.puts " {}"
153
178
  f.puts " end"
154
179
  f.puts ""
155
- f.puts " def #{name}"
156
- f.puts " cube(10,10,10)"
157
- f.puts " end"
180
+ f.puts " # #{MAGIC}"
158
181
  f.puts "end"
159
182
  f.puts ""
160
183
  f.puts "#{classname}.new.run"
@@ -94,7 +94,12 @@ module JennCad::Exporters
94
94
  if !v.kind_of?(Array) && !v.kind_of?(TrueClass) && !v.kind_of?(FalseClass) && v == v.to_i
95
95
  v = v.to_i
96
96
  end
97
- res << "#{k}=#{v}"
97
+ if v.kind_of? String
98
+ q = "\""
99
+ else
100
+ q = ""
101
+ end
102
+ res << "#{k}=#{q}#{v}#{q}"
98
103
  end
99
104
  res.join(",").gsub("size=","")
100
105
  else
@@ -165,6 +170,8 @@ module JennCad::Exporters
165
170
  new_obj(part, :projection, collect_params(part), parse(part.parts))
166
171
  when JennCad::Primitives::Polygon
167
172
  new_obj(part, :polygon, collect_params(part))
173
+ when JennCad::StlImport
174
+ new_obj(part, :import, collect_params(part))
168
175
  when JennCad::Part
169
176
  parse(part.part)
170
177
  when nil
@@ -192,8 +199,11 @@ module JennCad::Exporters
192
199
  end
193
200
 
194
201
  def collect_params(part)
202
+ if part.respond_to? :openscad_params
203
+ return part.openscad_params
204
+ end
195
205
  res = {}
196
- [:d, :h, :d1, :d2, :size, :fn, :points].each do |var|
206
+ [:d, :h, :d1, :d2, :size, :fn, :points, :file].each do |var|
197
207
  if part.respond_to? var
198
208
  res[var] = part.send var
199
209
  end
@@ -221,6 +231,8 @@ module JennCad::Exporters
221
231
  OpenScadObject.new(:translate, t.coordinates, transform(part, &block))
222
232
  when JennCad::Rotate, JennCad::Mirror
223
233
  OpenScadObject.new(demodulize(t.class).downcase, t.coordinates, transform(part, &block))
234
+ when JennCad::Scale
235
+ OpenScadObject.new(:scale, t.scale, transform(part, &block))
224
236
  when JennCad::Multmatrix
225
237
  OpenScadObject.new(:multmatrix, t.m, transform(part, &block))
226
238
  else
@@ -237,7 +249,7 @@ module JennCad::Exporters
237
249
 
238
250
  # accept aggregation
239
251
  def register_module(part)
240
- @modules[part.name] = OpenScadObject.new(:module,part.name, parse(part.part))
252
+ @modules[part.name] = OpenScadObject.new(:module, part.name, parse(part.part))
241
253
  end
242
254
 
243
255
  def handle_import(part)
@@ -0,0 +1,16 @@
1
+ module JennCad::Features
2
+ class Aggregation < Feature
3
+ attr_accessor :parts
4
+
5
+ def initialize(name=nil, part=nil)
6
+ super({})
7
+ @name = name
8
+ @parts = [part] # NOTE: single length arrayto make checking children easier
9
+ end
10
+
11
+ def part
12
+ @parts.first
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,95 @@
1
+ module JennCad::Features
2
+ class Climb < Feature
3
+ def initialize(opts, block)
4
+ @opts = {
5
+ offset: :auto,
6
+ step: nil,
7
+ steps: nil,
8
+ bottom: nil,
9
+ top: nil,
10
+ z: nil,
11
+ }.deep_merge!(opts)
12
+ if @opts[:step].nil? && @opts[:steps].nil?
13
+ raise "please define at least one of :step or :steps for climb"
14
+ end
15
+ super(@opts)
16
+ @block = block
17
+ end
18
+
19
+ def z_or_referenced
20
+ case z = @opts[:z]
21
+ when nil
22
+ referenced_z.z
23
+ else
24
+ z
25
+ end
26
+ end
27
+
28
+ def get_step(z)
29
+ case step = @opts[:step]
30
+ when nil, :auto, 0, 0.0
31
+ steps = @opts[:steps]
32
+ (z / steps).floor
33
+ else
34
+ step.to_f
35
+ end
36
+ end
37
+
38
+ def get_offset(z)
39
+ case offset = @opts[:offset]
40
+ when :auto
41
+ step = get_step(z)
42
+ ((z % step) + step) / 2.0
43
+ when nil, 0, 0.0
44
+ 0.0
45
+ else
46
+ offset
47
+ end
48
+ end
49
+
50
+ def climb_from_bottom(offset, step, n)
51
+ n.times.map{ |i| @block.yield.mz(offset+step*i) }.union
52
+ end
53
+
54
+ def climb_from_top(z, offset, step, n)
55
+ n.times.map{ |i| @block.yield.mz(z-offset-step*i) }.union
56
+ end
57
+
58
+ def to_openscad
59
+ ref_z = z_or_referenced
60
+ step = get_step(ref_z)
61
+ steps, top, bottom = @opts.values_at(:steps, :top, :bottom)
62
+
63
+ offset = get_offset(ref_z)
64
+
65
+ lo = (ref_z-offset*2).to_f % step.to_f
66
+ unless lo.to_f == 0.0
67
+ puts "[Warning]: climb has leftover offset #{lo}"
68
+ end
69
+
70
+ if steps
71
+ top = steps
72
+ bottom = steps
73
+ end
74
+
75
+ unless top or bottom
76
+ climb_from_bottom(offset, step, ((ref_z-offset*2) / step).floor + 1 )
77
+ else
78
+ res = nil
79
+ if top
80
+ res += climb_from_top(ref_z, offset, step, top)
81
+ end
82
+ if bottom
83
+ res += climb_from_bottom(offset, step, bottom)
84
+ end
85
+ res
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ def climb(args, &block)
92
+ Climb.new(args, block)
93
+ end
94
+
95
+ end
@@ -0,0 +1,35 @@
1
+ module JennCad::Features
2
+ module Cuttable
3
+ def cut(args, &block)
4
+ if args[:x]
5
+ l = args[:x].min * @opts[:y] / 2.0
6
+ r = args[:x].max * @opts[:y] / 2.0
7
+ prepare_cut(l, r, &block).flip_x
8
+ elsif args[:y]
9
+ l = args[:y].min * @opts[:y] / 2.0
10
+ r = args[:y].max * @opts[:y] / 2.0
11
+ prepare_cut(l, r, &block).flip_y
12
+ elsif args[:z]
13
+ raise "cut for Z is not implemented yet"
14
+ end
15
+ end
16
+
17
+ def prepare_cut(l, r, &block)
18
+ part = block.call
19
+ if part.z.to_f > 0.0
20
+ part.opts[:margins][:z] = 0.2
21
+ if l == 0.0
22
+ part.mz(r+0.1)
23
+ else
24
+ part.mz(l+part.z.to_f-0.2)
25
+ end
26
+ else
27
+ part.opts[:margins][:z] = 0.2
28
+ part.z = l.abs + r.abs + 0.2
29
+ part.mz(-0.1)
30
+ end
31
+ end
32
+
33
+
34
+ end
35
+ end
@@ -0,0 +1,4 @@
1
+ module JennCad::Features
2
+ class Feature < JennCad::Thing
3
+ end
4
+ end
@@ -1,4 +1,4 @@
1
- module JennCad::Primitives
1
+ module JennCad::Features
2
2
  class OpenScadImport < Aggregation
3
3
  attr_accessor :import, :args
4
4
 
@@ -0,0 +1,10 @@
1
+ module JennCad::Features
2
+ class StlImport < Feature
3
+ attr_accessor :file, :args
4
+
5
+ def initialize(file, args={})
6
+ @file = file
7
+ @args = args
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ require "jenncad/features/feature"
2
+ require "jenncad/features/aggregation"
3
+ require "jenncad/features/cuttable"
4
+ require "jenncad/features/openscad_include"
5
+ require "jenncad/features/climb"
6
+ require "jenncad/features/stl_import"
7
+
8
+
9
+ module JennCad
10
+ include Features
11
+ end
data/lib/jenncad/part.rb CHANGED
@@ -2,11 +2,10 @@ module JennCad
2
2
  # Part should be inherited from the user when making parts
3
3
  class Part < Thing
4
4
 
5
- def to_openscad #make_openscad_compatible
6
- auto_color
7
- a = Aggregation.new(self.class.to_s, self.part) #make_openscad_compatible!(self.part))
5
+ def to_openscad
6
+ a = Aggregation.new(self.class.to_s, self.part)
8
7
  a.transformations = @transformations
9
- a.color(color)
8
+ a.color(:auto)
10
9
  a
11
10
  end
12
11
 
@@ -12,8 +12,7 @@ class Array
12
12
  else
13
13
  res = part
14
14
  end
15
- # FIXME: I added 0.01 to all for now to fix z-fighting issues; this should not be hardcoded like this
16
- res, z = res.move(z:z), z + res.z.to_f + 0.01 unless skip_z
15
+ res, z = res.mz(z), z + res.z.to_f unless skip_z
17
16
  res
18
17
  end
19
18
  .union
@@ -1,10 +1,10 @@
1
1
  module JennCad::Primitives
2
2
  class Cube < Primitive
3
+ extend JennCad::Features::Cuttable
3
4
 
4
- def initialize(args)
5
- if args.kind_of?(Array) && args[0].kind_of?(Hash)
6
- args = args.first
7
- end
5
+
6
+ def feed_opts(args)
7
+ # FIXME: this doesn't seem to work
8
8
  if args.kind_of? Array
9
9
  m = {}
10
10
  if args.last.kind_of? Hash
@@ -12,7 +12,13 @@ module JennCad::Primitives
12
12
  end
13
13
  args = [:x, :y, :z].zip(args.flatten).to_h
14
14
  args.deep_merge!(m)
15
+ @opts.deep_merge!(args)
16
+ else
17
+ @opts.deep_merge!(args)
15
18
  end
19
+ end
20
+
21
+ def initialize(args)
16
22
  @opts = {
17
23
  x: 0,
18
24
  y: 0,
@@ -26,10 +32,18 @@ module JennCad::Primitives
26
32
  center_y: false,
27
33
  center_x: false,
28
34
  center_z: false,
29
- }.deep_merge!(args)
30
- handle_margins
35
+ }
36
+ if args.kind_of? Array
37
+ args.each do |a|
38
+ feed_opts(parse_xyz_shortcuts(a))
39
+ end
40
+ else
41
+ feed_opts(parse_xyz_shortcuts(args))
42
+ end
43
+
31
44
 
32
- super(args)
45
+ handle_margins
46
+ super(z: @opts[:z])
33
47
  @h = @z.dup
34
48
  @calc_h = @z.dup
35
49
  end
@@ -41,30 +55,34 @@ module JennCad::Primitives
41
55
 
42
56
  def not_centered
43
57
  @opts[:center] = false
58
+ self
44
59
  end
45
60
  alias :nc :not_centered
46
61
 
47
62
  def cx
48
63
  nc
49
64
  @opts[:center_x] = true
65
+ self
50
66
  end
51
67
 
52
68
  def cy
53
69
  nc
54
70
  @opts[:center_y] = true
71
+ self
55
72
  end
56
73
 
57
74
  def cz
58
75
  nc
59
76
  @opts[:center_z] = true
77
+ self
60
78
  end
61
79
 
62
80
  def centered_axis
63
81
  return [:x, :y] if @opts[:center]
64
82
  a = []
65
83
  a << :x if @opts[:center_x]
66
- a << :y if @opts[:center_x]
67
- a << :z if @opts[:center_x]
84
+ a << :y if @opts[:center_y]
85
+ a << :z if @opts[:center_z]
68
86
  a
69
87
  end
70
88
 
@@ -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
@@ -43,6 +43,20 @@ module JennCad::Primitives
43
43
  super(args)
44
44
  end
45
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
+
46
60
  def handle_fn
47
61
  case @opts[:fn]
48
62
  when nil, 0
@@ -70,6 +84,20 @@ module JennCad::Primitives
70
84
  @d = @opts[:d].to_f + @opts[:margins][:d].to_f
71
85
  @r = @d / 2.0
72
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
73
101
  end
74
102
 
75
103
  def h
@@ -1,10 +1,10 @@
1
1
  module JennCad::Primitives
2
- attr_accessor :center_bool, :convexity, :twist, :slices, :height
2
+ attr_accessor :center_bool, :convexity, :twist, :slices
3
3
  class LinearExtrude < JennCad::Thing
4
- def initialize(part, args)
4
+ def initialize(part, args={})
5
5
  @transformations = []
6
6
  @parts = [part]
7
- @height = args[:h] || args[:height]
7
+ @z = args[:h] || args[:height]
8
8
  @center_bool = args[:center]
9
9
  @convexity = args[:convexity]
10
10
  @twist = args[:twist]
@@ -12,6 +12,10 @@ module JennCad::Primitives
12
12
  @fn = args[:fn]
13
13
  end
14
14
 
15
+ def height
16
+ @z
17
+ end
18
+
15
19
  def openscad_params
16
20
  res = {}
17
21
  [:height, :convexity, :twist, :slices, :fn].each do |n|
@@ -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
- class RoundedCube < Primitive
2
+ class RoundedCube < Cube
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)
@@ -22,6 +23,10 @@ module JennCad::Primitives
22
23
  z: nil,
23
24
  r: nil,
24
25
  flat_edges: nil,
26
+ center: true,
27
+ center_y: false,
28
+ center_x: false,
29
+ center_z: false,
25
30
  margins: {
26
31
  r: 0,
27
32
  d: 0,
@@ -40,16 +45,16 @@ module JennCad::Primitives
40
45
  # make diameter not bigger than any side
41
46
  @d = [@d, @x, @y].min
42
47
  res = HullObject.new(
43
- cylinder(d:@d, h:@z+z_margin).moveh(x: -@x + @d, y: @y - @d),
44
- cylinder(d:@d).moveh(x: @x - @d, y: @y - @d),
45
- cylinder(d:@d).moveh(x: -@x + @d, y: -@y + @d),
46
- cylinder(d:@d).moveh(x: @x - @d, y: -@y + @d),
47
- )
48
+ cylinder(d:@d, h:z+z_margin),
49
+ cylinder(d:@d).move(x: @x - @d, y: 0),
50
+ cylinder(d:@d).move(x: 0, y: @y - @d),
51
+ cylinder(d:@d).move(x: @x - @d, y: @y - @d),
52
+ ).moveh(xy: @d)
48
53
 
49
54
  res += flat_edge(@opts[:flat_edges])
50
55
 
51
56
  res.transformations = @transformations
52
- res
57
+ res.moveh(centered_axis.to_h{|a| [a, -@opts[a]] })
53
58
  end
54
59
 
55
60
  def flat_edge(edge)
@@ -55,6 +55,7 @@ module JennCad::Primitives
55
55
  part.opts[:margins] ||= {}
56
56
  if part.referenced_z && part.z != 0.0
57
57
  case part
58
+ when JennCad::Circle
58
59
  when JennCad::BooleanObject
59
60
  when JennCad::Aggregation
60
61
  else
@@ -1,6 +1,4 @@
1
1
  require "jenncad/primitives/primitive"
2
- require "jenncad/primitives/aggregation"
3
- require "jenncad/primitives/openscad_include"
4
2
  require "jenncad/primitives/circle"
5
3
  require "jenncad/primitives/cylinder"
6
4
  require "jenncad/primitives/sphere"
@@ -38,7 +38,11 @@ module JennCad
38
38
  OpenScadImport.new(import, name, args)
39
39
  end
40
40
 
41
- def extrude(args)
41
+ def stl(file, args={})
42
+ StlImport.new(file, args)
43
+ end
44
+
45
+ def extrude(args={})
42
46
  LinearExtrude.new(self, args)
43
47
  end
44
48
 
data/lib/jenncad/thing.rb CHANGED
@@ -6,7 +6,8 @@ module JennCad
6
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
+ attr_accessor :anchor
10
11
 
11
12
  def initialize(args={})
12
13
  @transformations = []
@@ -28,6 +29,41 @@ module JennCad
28
29
  @opts[key] = val
29
30
  end
30
31
 
32
+ def set_anchor(args)
33
+ self.anchor ||= {}
34
+ args.each do |key, val|
35
+ self.anchor[key] = val
36
+ end
37
+ end
38
+
39
+ def movea(key)
40
+ a = self.anchor[key]
41
+ unless a
42
+ puts "Error: Anchor #{key} not found"
43
+ puts "Available anchor: #{self.anchor}"
44
+ return self
45
+ else
46
+ self.movei(a)
47
+ end
48
+ end
49
+
50
+ def movei(args)
51
+ to = {}
52
+ [:x, :y, :z].each do |key|
53
+ if args[key]
54
+ to[key] = args[key]*-1
55
+ end
56
+ end
57
+ move(to)
58
+ end
59
+
60
+
61
+ def auto_extrude
62
+ ret = self.extrude
63
+ ret.set_option(:auto_extrude, true)
64
+ ret
65
+ end
66
+
31
67
  def rotate(args)
32
68
  @transformations ||= []
33
69
  @transformations << Rotate.new(args)
@@ -49,17 +85,22 @@ module JennCad
49
85
 
50
86
  def flip(direction)
51
87
  case self
88
+ when UnionObject
89
+ ref = self.parts.first
90
+ rz = self.z.to_f + self.calc_h.to_f
52
91
  when BooleanObject
53
92
  ref = self.parts.first
93
+ rz = ref.calc_z + ref.calc_h
54
94
  else
55
95
  ref = self
96
+ rz = self.z + self.calc_h
56
97
  end
57
98
 
58
99
  case direction
59
100
  when :x
60
- self.ry(90).mh(x: -ref.z, z: ref.x)
101
+ self.ry(90).mh(x: -rz, z: ref.x)
61
102
  when :y
62
- self.rx(90).mh(y: ref.z, z: ref.y)
103
+ self.rx(90).mh(y: rz, z: ref.y)
63
104
  end
64
105
  end
65
106
 
@@ -91,17 +132,43 @@ module JennCad
91
132
  [v.x,v.y,v.z]
92
133
  end
93
134
 
94
- # todo: check if that works
95
135
  def rotate_around(point,args)
96
- x,y,z= point.x, point.y, point.z
136
+ x,y,z= point[:x], point[:y], point[:z]
97
137
  self.move(x:-x,y:-y,z:-z).rotate(args).move(x:x,y:y,z:z)
98
138
  end
99
139
 
140
+ def parse_xyz_shortcuts(args)
141
+ [:x, :y, :z].each do |key|
142
+ args[key] ||= 0.0
143
+ end
144
+
145
+ if args[:xy]
146
+ args[:x] += args[:xy]
147
+ args[:y] += args[:xy]
148
+ end
149
+ if args[:xyz]
150
+ args[:x] += args[:xyz]
151
+ args[:y] += args[:xyz]
152
+ args[:z] += args[:xyz]
153
+ end
154
+ if args[:xz]
155
+ args[:x] += args[:xz]
156
+ args[:z] += args[:xz]
157
+ end
158
+ if args[:yz]
159
+ args[:y] += args[:yz]
160
+ args[:z] += args[:yz]
161
+ end
162
+ return args
163
+ end
164
+
100
165
  def move(args)
101
166
  if args.kind_of? Array
102
167
  x,y,z = args
103
168
  return move(x:x, y:y, z:z)
104
169
  end
170
+ args = parse_xyz_shortcuts(args)
171
+
105
172
  @transformations ||= []
106
173
  if args[:prepend]
107
174
  @transformations.prepend(Move.new(args))
@@ -134,9 +201,9 @@ module JennCad
134
201
  x,y,z = args
135
202
  args = {x: x, y: y, z: z}
136
203
  end
137
- args[:x] = args[:x] / 2.0 unless args[:x] == nil
138
- args[:y] = args[:y] / 2.0 unless args[:y] == nil
139
- args[:z] = args[:z] / 2.0 unless args[:z] == nil
204
+ [:x, :y, :z, :xy, :xyz, :xz, :yz].each do |key|
205
+ args[key] = args[key] / 2.0 unless args[key] == nil
206
+ end
140
207
 
141
208
  move(args)
142
209
  end
@@ -223,8 +290,7 @@ module JennCad
223
290
  end
224
291
  res
225
292
  end
226
-
227
- def make_openscad_compatible
293
+ =begin def make_openscad_compatible
228
294
  make_openscad_compatible!(self)
229
295
  end
230
296
 
@@ -245,39 +311,111 @@ module JennCad
245
311
  end
246
312
  item
247
313
  end
314
+ =end
315
+
316
+ def has_explicit_color?
317
+ if option(:auto_color) == false
318
+ return true
319
+ end
320
+ return false
321
+ end
322
+
323
+ def only_color?(parts, lvl=0)
324
+ return true if parts == nil
325
+
326
+ parts.each do |part|
327
+ # puts " " * lvl + "[only_color?] #{part}"
328
+ if part.has_explicit_color?
329
+ # puts " " * lvl + "found explicit color here"
330
+ return false
331
+ end
332
+ if !only_color?(part.parts, lvl+1)
333
+ return false
334
+ end
335
+ end
336
+ true
337
+ end
338
+
339
+ def set_auto_color_for_children(col, parts, lvl=0)
340
+ return if parts == nil
341
+
342
+ parts.each do |part|
343
+ unless part.has_explicit_color?
344
+ if only_color?(part.parts, lvl+1)
345
+ # puts " " * lvl + "children have no explicit color, setting it here"
346
+ part.set_auto_color(col)
347
+ else
348
+ # puts " " * lvl + "[set_auto_color_for_children] #{part}"
349
+ set_auto_color_for_children(col, part.parts, lvl+1)
350
+ end
351
+ else
352
+ # puts " " * lvl + "[set_auto_color_for_children] this part has a color, ignoring their children"
353
+ end
354
+
355
+ end
356
+ end
357
+
358
+ def set_auto_color(col)
359
+ set_option :color, col
360
+ set_option :auto_color, true
361
+ end
248
362
 
249
363
  def color(args=nil)
250
- case args
251
- when nil
364
+ if args == nil
252
365
  return option(:color)
253
- when :auto
254
- return auto_color!
366
+ end
367
+
368
+ if args == :auto
369
+ ac = auto_color
370
+ unless ac.nil?
371
+ #puts "auto color to #{ac}"
372
+ if only_color?(get_contents)
373
+ set_option :color, ac
374
+ set_option :auto_color, true
375
+ else
376
+ set_auto_color_for_children(ac, get_contents)
377
+ end
378
+
379
+ end
380
+ return self
381
+ end
382
+
383
+ c = color_parse(args)
384
+ unless c.nil?
385
+ set_option :color, c
386
+ set_option :auto_color, false
387
+ end
388
+
389
+ self
390
+ end
391
+
392
+ def color_parse(args=nil)
393
+ case args
255
394
  when :none
256
395
  set_option :no_auto_color, true
257
396
  when :random
258
- set_option :color, Color.random
397
+ return Color.random
259
398
  when Array
260
- set_option :color, Color.parse(args)
399
+ return Color.parse(args)
261
400
  when /(?<=#)(?<!^)(\h{6}|\h{3})/
262
- set_option :color, args
401
+ return args
263
402
  when /(?<!^)(\h{6}|\h{3})/
264
- set_option :color, "##{args}"
403
+ return "##{args}"
265
404
  when String
266
- set_option :color, args
267
- else
268
- puts "meow"
405
+ return args
269
406
  end
270
- self
407
+ nil
271
408
  end
272
409
 
273
410
  def auto_color
274
411
  if option(:color) == nil && !option(:no_auto_color)
275
- auto_color!
412
+ return auto_color!
276
413
  end
414
+ nil
277
415
  end
278
416
 
279
417
  def auto_color!
280
- color($jenncad_profile.colors.pop)
418
+ color_parse($jenncad_profile.colors.pop)
281
419
  end
282
420
 
283
421
  def color_or_fallback
@@ -285,12 +423,44 @@ module JennCad
285
423
  option(:color)
286
424
  end
287
425
 
288
- def openscad(file)
289
- if @parts == nil
290
- if self.respond_to? :part
291
- @parts = [part]
426
+ def get_contents
427
+ return @parts unless @parts.nil?
428
+ if self.respond_to? :part
429
+ return [part]
430
+ end
431
+ end
432
+
433
+ def calculated_h
434
+ return @z unless @z.nil? || @z == 0
435
+ return @h unless @h.nil? || @h == 0
436
+ return @calc_h unless @calc_h.nil? || @calc_h == 0
437
+ return @calc_z unless @calc_z.nil? || @calc_z == 0
438
+ end
439
+
440
+ def find_calculated_h(parts)
441
+ return if parts == nil
442
+ parts.each do |part|
443
+ if z = calculated_h
444
+ return z
445
+ end
446
+ get_calculated_h(part.get_contents)
447
+ end
448
+ end
449
+
450
+ def set_heights_for_auto_extrude(parts, parent=nil)
451
+ return if parts.nil?
452
+ parts.each do |part|
453
+ if part.option(:auto_extrude)
454
+ part.z = parent.calculated_h
292
455
  end
456
+ set_heights_for_auto_extrude(part.get_contents, part)
293
457
  end
458
+ end
459
+
460
+ def openscad(file)
461
+ set_heights_for_auto_extrude(get_contents)
462
+
463
+ @parts = get_contents
294
464
 
295
465
  JennCad::Exporters::OpenScad.new(self).save(file)
296
466
  end
@@ -1,7 +1,9 @@
1
1
  module JennCad
2
+ attr_accessor :scale
2
3
  class Scale < Transformation
3
4
  def initialize(args)
4
5
  super(args)
6
+ @scale = args
5
7
  end
6
8
  end
7
9
  end
@@ -1,4 +1,4 @@
1
1
  module JennCad
2
- VERSION = "1.0.0-alpha2"
2
+ VERSION = "1.0.0-alpha6"
3
3
  end
4
4
 
data/lib/jenncad.rb CHANGED
@@ -20,10 +20,10 @@ require "jenncad/part"
20
20
  require "jenncad/project"
21
21
  require "jenncad/commands"
22
22
 
23
+ require "jenncad/features"
23
24
  require "jenncad/primitives"
24
25
 
25
26
 
26
-
27
27
  require "jenncad/transformation/transformation"
28
28
  require "jenncad/transformation/move"
29
29
  require "jenncad/transformation/rotate"
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.alpha2
4
+ version: 1.0.0.pre.alpha6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jennifer Glauche
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-28 00:00:00.000000000 Z
11
+ date: 2022-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: geo3d
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: hanami-cli
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.3.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.3.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activesupport
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +88,7 @@ executables:
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
+ - README.md
91
92
  - Rakefile
92
93
  - bin/jenncad
93
94
  - examples/old/cube.rb
@@ -108,10 +109,16 @@ files:
108
109
  - lib/jenncad/extras/din934.rb
109
110
  - lib/jenncad/extras/hardware.rb
110
111
  - lib/jenncad/extras/iso7380.rb
112
+ - lib/jenncad/features.rb
113
+ - lib/jenncad/features/aggregation.rb
114
+ - lib/jenncad/features/climb.rb
115
+ - lib/jenncad/features/cuttable.rb
116
+ - lib/jenncad/features/feature.rb
117
+ - lib/jenncad/features/openscad_include.rb
118
+ - lib/jenncad/features/stl_import.rb
111
119
  - lib/jenncad/part.rb
112
120
  - lib/jenncad/patches/array.rb
113
121
  - lib/jenncad/primitives.rb
114
- - lib/jenncad/primitives/aggregation.rb
115
122
  - lib/jenncad/primitives/boolean_object.rb
116
123
  - lib/jenncad/primitives/circle.rb
117
124
  - lib/jenncad/primitives/cube.rb
@@ -119,7 +126,6 @@ files:
119
126
  - lib/jenncad/primitives/hull_object.rb
120
127
  - lib/jenncad/primitives/intersection_object.rb
121
128
  - lib/jenncad/primitives/linear_extrude.rb
122
- - lib/jenncad/primitives/openscad_include.rb
123
129
  - lib/jenncad/primitives/polygon.rb
124
130
  - lib/jenncad/primitives/primitive.rb
125
131
  - lib/jenncad/primitives/projection.rb
@@ -147,7 +153,7 @@ homepage: ''
147
153
  licenses:
148
154
  - LGPL-3
149
155
  metadata: {}
150
- post_install_message:
156
+ post_install_message:
151
157
  rdoc_options: []
152
158
  require_paths:
153
159
  - lib
@@ -162,8 +168,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
168
  - !ruby/object:Gem::Version
163
169
  version: 1.3.1
164
170
  requirements: []
165
- rubygems_version: 3.0.3
166
- signing_key:
171
+ rubygems_version: 3.0.9
172
+ signing_key:
167
173
  specification_version: 4
168
174
  summary: TBD
169
175
  test_files: []
@@ -1,12 +0,0 @@
1
- module JennCad::Primitives
2
- class Aggregation < Primitive
3
- attr_accessor :part
4
-
5
- def initialize(name=nil, part=nil)
6
- super({})
7
- @name = name
8
- @part = part
9
- end
10
-
11
- end
12
- end