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 +4 -4
- data/README.md +83 -0
- data/jenncad.gemspec +1 -1
- data/lib/jenncad/commands.rb +30 -7
- data/lib/jenncad/exporters/openscad.rb +15 -3
- data/lib/jenncad/features/aggregation.rb +16 -0
- data/lib/jenncad/features/climb.rb +95 -0
- data/lib/jenncad/features/cuttable.rb +35 -0
- data/lib/jenncad/features/feature.rb +4 -0
- data/lib/jenncad/{primitives → features}/openscad_include.rb +1 -1
- data/lib/jenncad/features/stl_import.rb +10 -0
- data/lib/jenncad/features.rb +11 -0
- data/lib/jenncad/part.rb +3 -4
- data/lib/jenncad/patches/array.rb +1 -2
- data/lib/jenncad/primitives/cube.rb +27 -9
- data/lib/jenncad/primitives/cylinder.rb +29 -1
- data/lib/jenncad/primitives/linear_extrude.rb +7 -3
- data/lib/jenncad/primitives/rotate_extrude.rb +1 -1
- data/lib/jenncad/primitives/rounded_cube.rb +12 -7
- data/lib/jenncad/primitives/subtract_object.rb +1 -0
- data/lib/jenncad/primitives.rb +0 -2
- data/lib/jenncad/shortcuts.rb +5 -1
- data/lib/jenncad/thing.rb +198 -28
- data/lib/jenncad/transformation/scale.rb +2 -0
- data/lib/jenncad/version.rb +1 -1
- data/lib/jenncad.rb +1 -1
- metadata +18 -12
- data/lib/jenncad/primitives/aggregation.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8dc72aa8cfaaa41cf4b96038f454073f708502cea9d9ce84a13fc28203ff4dc2
|
4
|
+
data.tar.gz: c5f0cbe4442bf7b59c39ee2f69e2096d0166fa4ae336c48029f8856606da3d9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/jenncad/commands.rb
CHANGED
@@ -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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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 "
|
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
|
-
|
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,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
|
6
|
-
|
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(
|
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
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
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
|
-
}
|
30
|
-
|
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
|
-
|
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[:
|
67
|
-
a << :z if @opts[:
|
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
|
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
|
-
@
|
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,6 +1,7 @@
|
|
1
1
|
module JennCad::Primitives
|
2
|
-
class RoundedCube <
|
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
|
44
|
-
cylinder(d:@d).
|
45
|
-
cylinder(d:@d).
|
46
|
-
cylinder(d:@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)
|
data/lib/jenncad/primitives.rb
CHANGED
data/lib/jenncad/shortcuts.rb
CHANGED
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, :
|
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: -
|
101
|
+
self.ry(90).mh(x: -rz, z: ref.x)
|
61
102
|
when :y
|
62
|
-
self.rx(90).mh(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
|
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
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
251
|
-
when nil
|
364
|
+
if args == nil
|
252
365
|
return option(:color)
|
253
|
-
|
254
|
-
|
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
|
-
|
397
|
+
return Color.random
|
259
398
|
when Array
|
260
|
-
|
399
|
+
return Color.parse(args)
|
261
400
|
when /(?<=#)(?<!^)(\h{6}|\h{3})/
|
262
|
-
|
401
|
+
return args
|
263
402
|
when /(?<!^)(\h{6}|\h{3})/
|
264
|
-
|
403
|
+
return "##{args}"
|
265
404
|
when String
|
266
|
-
|
267
|
-
else
|
268
|
-
puts "meow"
|
405
|
+
return args
|
269
406
|
end
|
270
|
-
|
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
|
-
|
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
|
289
|
-
|
290
|
-
|
291
|
-
|
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
|
data/lib/jenncad/version.rb
CHANGED
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.
|
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:
|
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:
|
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:
|
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.
|
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: []
|