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

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