jenncad 1.0.0.pre.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +1 -0
- data/bin/jenncad +10 -0
- data/examples/old/cube.rb +12 -0
- data/examples/old/slot.rb +10 -0
- data/examples/old/test.rb +18 -0
- data/examples/old/test1.rb +21 -0
- data/examples/old/test2.rb +9 -0
- data/examples/old/test3.rb +15 -0
- data/examples/old/test4.rb +17 -0
- data/examples/old/test5.rb +31 -0
- data/jenncad.gemspec +27 -0
- data/lib/jenncad/commands.rb +169 -0
- data/lib/jenncad/default_profile.rb +40 -0
- data/lib/jenncad/extras/din912.rb +89 -0
- data/lib/jenncad/extras/din933.rb +64 -0
- data/lib/jenncad/extras/din934.rb +99 -0
- data/lib/jenncad/extras/hardware.rb +16 -0
- data/lib/jenncad/extras/iso7380.rb +58 -0
- data/lib/jenncad/jenncad.rb +3 -0
- data/lib/jenncad/openscad.rb +274 -0
- data/lib/jenncad/part.rb +14 -0
- data/lib/jenncad/patches/array.rb +29 -0
- data/lib/jenncad/primitives/aggregation.rb +12 -0
- data/lib/jenncad/primitives/boolean_object.rb +76 -0
- data/lib/jenncad/primitives/circle.rb +11 -0
- data/lib/jenncad/primitives/cube.rb +69 -0
- data/lib/jenncad/primitives/cylinder.rb +52 -0
- data/lib/jenncad/primitives/hull_object.rb +4 -0
- data/lib/jenncad/primitives/intersection_object.rb +4 -0
- data/lib/jenncad/primitives/linear_extrude.rb +25 -0
- data/lib/jenncad/primitives/openscad_include.rb +11 -0
- data/lib/jenncad/primitives/polygon.rb +9 -0
- data/lib/jenncad/primitives/primitive.rb +24 -0
- data/lib/jenncad/primitives/projection.rb +9 -0
- data/lib/jenncad/primitives/rotate_extrude.rb +20 -0
- data/lib/jenncad/primitives/rounded_cube.rb +77 -0
- data/lib/jenncad/primitives/slot.rb +82 -0
- data/lib/jenncad/primitives/sphere.rb +11 -0
- data/lib/jenncad/primitives/subtract_object.rb +84 -0
- data/lib/jenncad/primitives/union_object.rb +5 -0
- data/lib/jenncad/profile_loader.rb +34 -0
- data/lib/jenncad/project.rb +28 -0
- data/lib/jenncad/register.rb +31 -0
- data/lib/jenncad/shortcuts.rb +109 -0
- data/lib/jenncad/thing.rb +308 -0
- data/lib/jenncad/transformation/color.rb +8 -0
- data/lib/jenncad/transformation/mirror.rb +7 -0
- data/lib/jenncad/transformation/move.rb +7 -0
- data/lib/jenncad/transformation/multmatrix.rb +9 -0
- data/lib/jenncad/transformation/rotate.rb +7 -0
- data/lib/jenncad/transformation/scale.rb +7 -0
- data/lib/jenncad/transformation/transformation.rb +14 -0
- data/lib/jenncad/version.rb +4 -0
- data/lib/jenncad.rb +73 -0
- data/todo.txt +29 -0
- metadata +155 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module JennCad::Primitives
|
2
|
+
attr_accessor :convexity
|
3
|
+
class RotateExtrude < JennCad::Thing
|
4
|
+
def initialize(part, args)
|
5
|
+
@transformations = []
|
6
|
+
@parts = [part]
|
7
|
+
@angle = args[:angle]
|
8
|
+
@cut = args[:cut]
|
9
|
+
@fn = args[:fn]
|
10
|
+
end
|
11
|
+
|
12
|
+
def openscad_params
|
13
|
+
res = {}
|
14
|
+
[:cut, :angle, :convexity, :fn].each do |n|
|
15
|
+
res[n] = self.send n
|
16
|
+
end
|
17
|
+
res
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module JennCad::Primitives
|
2
|
+
class RoundedCube < Primitive
|
3
|
+
attr_accessor :d, :r
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
if args.kind_of?(Array) && args[0].kind_of?(Hash)
|
7
|
+
args = args.first
|
8
|
+
end
|
9
|
+
if args.kind_of? Array
|
10
|
+
m = {}
|
11
|
+
if args.last.kind_of? Hash
|
12
|
+
m = args.last
|
13
|
+
end
|
14
|
+
args = [:x, :y, :z, :d].zip(args.flatten).to_h.compact
|
15
|
+
args.deep_merge!(m)
|
16
|
+
end
|
17
|
+
|
18
|
+
@opts = {
|
19
|
+
d: 5,
|
20
|
+
x: 0,
|
21
|
+
y: 0,
|
22
|
+
z: nil,
|
23
|
+
r: nil,
|
24
|
+
flat_edges: nil,
|
25
|
+
margins: {
|
26
|
+
r: 0,
|
27
|
+
d: 0,
|
28
|
+
x: 0,
|
29
|
+
y: 0,
|
30
|
+
z: 0,
|
31
|
+
},
|
32
|
+
}.deep_merge!(args)
|
33
|
+
handle_margins
|
34
|
+
handle_diameter
|
35
|
+
super(opts)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_openscad
|
39
|
+
return cube(@opts) if @d == 0
|
40
|
+
# make diameter not bigger than any side
|
41
|
+
@d = [@d, @x, @y].min
|
42
|
+
res = HullObject.new(
|
43
|
+
cylinder(d:@d, h:@z).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
|
+
|
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
|
58
|
+
|
59
|
+
res.transformations = @transformations
|
60
|
+
res
|
61
|
+
end
|
62
|
+
|
63
|
+
def flat_edge(edge)
|
64
|
+
case edge
|
65
|
+
when :up
|
66
|
+
cube(@x, @y/2.0, @z).moveh(y:@y/2.0)
|
67
|
+
when :down
|
68
|
+
cube(@x, @y/2.0, @z).moveh(y:-@y/2.0)
|
69
|
+
when :right
|
70
|
+
cube(@x/2.0, @y, @z).moveh(x:@x/2.0)
|
71
|
+
when :left
|
72
|
+
cube(@x/2.0, @y, @z).moveh(x:-@x/2.0)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module JennCad::Primitives
|
2
|
+
class Slot < Primitive
|
3
|
+
attr_accessor :d, :r, :h, :fn, :len_x, :len_y
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
if args.kind_of?(Array) && args[0].kind_of?(Hash)
|
7
|
+
args = args.first
|
8
|
+
end
|
9
|
+
if args.kind_of? Array
|
10
|
+
m = {}
|
11
|
+
if args.last.kind_of? Hash
|
12
|
+
m = args.last
|
13
|
+
end
|
14
|
+
args = [:d, :z].zip(args.flatten).to_h
|
15
|
+
args.deep_merge!(m)
|
16
|
+
end
|
17
|
+
|
18
|
+
args[:z] ||= args[:h]
|
19
|
+
|
20
|
+
@opts = {
|
21
|
+
d: 0,
|
22
|
+
a: 0,
|
23
|
+
z: nil,
|
24
|
+
r: nil,
|
25
|
+
x: 0,
|
26
|
+
y: 0,
|
27
|
+
margins: {
|
28
|
+
r: 0,
|
29
|
+
d: 0,
|
30
|
+
z: 0,
|
31
|
+
},
|
32
|
+
}.deep_merge!(args)
|
33
|
+
|
34
|
+
super(opts)
|
35
|
+
|
36
|
+
@d = @opts[:d]
|
37
|
+
@a = @opts[:a]
|
38
|
+
@h = @opts[:h]
|
39
|
+
@r = @opts[:r]
|
40
|
+
@fn = @opts[:fn]
|
41
|
+
@len_x = @opts[:x]
|
42
|
+
@len_y = @opts[:y]
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_openscad
|
46
|
+
c1 = cylinder(@opts)
|
47
|
+
c2 = cylinder(@opts)
|
48
|
+
if @len_x
|
49
|
+
c2.move(x:@len_x)
|
50
|
+
end
|
51
|
+
if @len_y
|
52
|
+
c2.move(y:@len_y)
|
53
|
+
end
|
54
|
+
res = c1 & c2
|
55
|
+
if @a != 0.0
|
56
|
+
res = res.rotate(z:@a)
|
57
|
+
end
|
58
|
+
if @transformations && @transformations.size > 0
|
59
|
+
res = UnionObject.new([res])
|
60
|
+
res.transformations = @transformations
|
61
|
+
return res
|
62
|
+
end
|
63
|
+
res
|
64
|
+
end
|
65
|
+
|
66
|
+
def end_vector
|
67
|
+
if @a.to_f == 0.0
|
68
|
+
return [@len_x, 0] if @len_x
|
69
|
+
return [0, @len_y] if @len_y
|
70
|
+
end
|
71
|
+
if @len_x
|
72
|
+
x = cos(PI*@a/180.0)*@len_x.to_f
|
73
|
+
y = sin(PI*@a/180.0)*@len_x.to_f
|
74
|
+
else
|
75
|
+
x = -1* sin(PI*@a/180.0)*@len_y.to_f
|
76
|
+
y = cos(PI*@a/180.0)*@len_y.to_f
|
77
|
+
end
|
78
|
+
[x,y]
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module JennCad::Primitives
|
2
|
+
class SubtractObject < BooleanObject
|
3
|
+
def inherit_z
|
4
|
+
@z = 0
|
5
|
+
@calc_z = parts.first.calc_z.to_f
|
6
|
+
only_additives_of(@parts).each do |p|
|
7
|
+
z = p.z.to_f
|
8
|
+
@z = z if z > @z
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_heights(obj)
|
13
|
+
res = []
|
14
|
+
obj.each do |part|
|
15
|
+
if part.respond_to? :calc_h
|
16
|
+
res << part.calc_h
|
17
|
+
end
|
18
|
+
end
|
19
|
+
res
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_z(obj)
|
23
|
+
res = []
|
24
|
+
obj.each do |part|
|
25
|
+
if part.respond_to? :calc_z
|
26
|
+
res << part.calc_z
|
27
|
+
end
|
28
|
+
end
|
29
|
+
res
|
30
|
+
end
|
31
|
+
|
32
|
+
def analyze_z_fighting
|
33
|
+
first = get_primitives(@parts.first).flatten
|
34
|
+
others = get_primitives(@parts[1..-1]).flatten
|
35
|
+
|
36
|
+
first_h = get_heights(first).uniq
|
37
|
+
first_z = get_z(first).uniq
|
38
|
+
#puts first.inspect
|
39
|
+
if first_h.size > 1
|
40
|
+
# puts "first item has multiple heights: #{first_h.inspect}"
|
41
|
+
first_h.each do |h|
|
42
|
+
compare_z(others, h, first_z.first)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
compare_z(others, first_h.first, first_z.first)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
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
|
+
def compare_z(others,compare_h,compare_z)
|
55
|
+
others.each do |part|
|
56
|
+
#puts part.inspect
|
57
|
+
#puts "#{part.calc_z+part.calc_h} ; #{compare_h}"
|
58
|
+
if part.respond_to? :z
|
59
|
+
if part.referenced_z && part.z != 0.0
|
60
|
+
case part
|
61
|
+
when JennCad::BooleanObject
|
62
|
+
else
|
63
|
+
part.z+=0.2
|
64
|
+
part.translate(z:-0.1)
|
65
|
+
end
|
66
|
+
elsif part.z == compare_h
|
67
|
+
# puts "fixing possible z fighting: #{part.class} #{part.z}"
|
68
|
+
part.z+=0.008
|
69
|
+
part.translate(z:-0.004)
|
70
|
+
elsif part.calc_z == compare_z
|
71
|
+
# puts "z fighting at bottom: #{part.calc_z}"
|
72
|
+
part.z+=0.004
|
73
|
+
part.translate(z:-0.002)
|
74
|
+
elsif part.calc_z.to_f+part.calc_h.to_f == compare_h
|
75
|
+
# puts "z fighting at top: #{compare_h}"
|
76
|
+
part.z+=0.004
|
77
|
+
part.translate(z:0.002)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module JennCad
|
2
|
+
class ProfileLoader
|
3
|
+
def initialize
|
4
|
+
load_profile
|
5
|
+
end
|
6
|
+
|
7
|
+
def profile_dir
|
8
|
+
File.expand_path(["~", ".config", "jenncad"].join("/"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def profile_path
|
12
|
+
[profile_dir, "profile.rb"].join("/")
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_profile
|
16
|
+
if File.exists?(profile_path)
|
17
|
+
require profile_path
|
18
|
+
check_profile
|
19
|
+
else
|
20
|
+
load_defaults
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_profile
|
25
|
+
unless defined?($jenncad_profile)
|
26
|
+
load_defaults
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_defaults
|
31
|
+
$jenncad_profile = JennCad::DefaultProfile.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module JennCad
|
2
|
+
class Project
|
3
|
+
def output_dir
|
4
|
+
"output"
|
5
|
+
end
|
6
|
+
|
7
|
+
def outputs
|
8
|
+
self.class.instance_methods(false) - [:config, :outputs, :output_dir]
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
# load all files in subdirectories
|
13
|
+
Dir.glob("*/**/*.rb").each do |file|
|
14
|
+
require "./#{file}"
|
15
|
+
end
|
16
|
+
FileUtils.mkdir_p(output_dir)
|
17
|
+
run_exports
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_exports
|
21
|
+
outputs.each do |name|
|
22
|
+
part = self.send(name)
|
23
|
+
part.openscad([output_dir,"#{name}.scad"].join("/"))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module JennCad
|
2
|
+
|
3
|
+
class Register
|
4
|
+
def initialize
|
5
|
+
@counts = {}
|
6
|
+
@objects = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def register(cl, args)
|
10
|
+
if @objects[cl] == nil || @objects[cl][args] == nil
|
11
|
+
register_new(cl, args)
|
12
|
+
end
|
13
|
+
return @objects[cl][args]
|
14
|
+
end
|
15
|
+
|
16
|
+
def register_new(cl,args)
|
17
|
+
@counts[cl] ||= {}
|
18
|
+
@objects[cl] ||= {}
|
19
|
+
if @counts[cl][args]
|
20
|
+
@counts[cl][args] += 1
|
21
|
+
else
|
22
|
+
@counts[cl][args] = 1
|
23
|
+
end
|
24
|
+
|
25
|
+
@objects[cl][args] = cl.send :new, args
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
$parts = Register.new
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module JennCad
|
2
|
+
def circle(args)
|
3
|
+
Circle.new(args)
|
4
|
+
end
|
5
|
+
|
6
|
+
def cylinder(*args)
|
7
|
+
Cylinder.new(args)
|
8
|
+
end
|
9
|
+
alias :cy :cylinder
|
10
|
+
alias :cyl :cylinder
|
11
|
+
|
12
|
+
def sphere(args)
|
13
|
+
Sphere.new(args)
|
14
|
+
end
|
15
|
+
alias :sp :sphere
|
16
|
+
|
17
|
+
def polygon(args)
|
18
|
+
Polygon.new(args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def slot(*args)
|
22
|
+
Slot.new(args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def cube(*args)
|
26
|
+
Cube.new(args)
|
27
|
+
end
|
28
|
+
alias :cu :cube
|
29
|
+
|
30
|
+
def rounded_cube(*args)
|
31
|
+
RoundedCube.new(args)
|
32
|
+
end
|
33
|
+
alias :rcube :rounded_cube
|
34
|
+
alias :rc :rounded_cube
|
35
|
+
|
36
|
+
# import/use OpenScad library
|
37
|
+
def import(import,name,args)
|
38
|
+
OpenScadImport.new(import, name, args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def extrude(args)
|
42
|
+
LinearExtrude.new(self, args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def rotate_extrude(args={})
|
46
|
+
RotateExtrude.new(self, args)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_2d(args={})
|
50
|
+
Projection.new(self, args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def union(*args)
|
54
|
+
UnionObject.new(*args)
|
55
|
+
end
|
56
|
+
|
57
|
+
def +(args)
|
58
|
+
return args if self == nil
|
59
|
+
if self.kind_of?(UnionObject) && self.transformations.size == 0
|
60
|
+
self.add(args)
|
61
|
+
return self
|
62
|
+
else
|
63
|
+
UnionObject.new(self,args)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def subtraction(*args)
|
68
|
+
SubtractObject.new(*args)
|
69
|
+
end
|
70
|
+
|
71
|
+
def -(args)
|
72
|
+
if self.kind_of?(SubtractObject) && self.transformations.size == 0
|
73
|
+
self.add(args)
|
74
|
+
return self
|
75
|
+
else
|
76
|
+
SubtractObject.new(self,args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def intersection(*args)
|
81
|
+
IntersectionObject.new(*args)
|
82
|
+
end
|
83
|
+
|
84
|
+
def *(args)
|
85
|
+
if self.kind_of?(IntersectionObject) && self.transformations.size == 0
|
86
|
+
self.add(args)
|
87
|
+
return self
|
88
|
+
else
|
89
|
+
IntersectionObject.new(self,args)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def hull(*args)
|
94
|
+
HullObject.new(*args)
|
95
|
+
end
|
96
|
+
|
97
|
+
def &(args)
|
98
|
+
if self.kind_of?(HullObject) && self.transformations.size == 0
|
99
|
+
self.add(args)
|
100
|
+
return self
|
101
|
+
else
|
102
|
+
HullObject.new(self,args)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def assemble(partlib=nil, z_skip = false, z=0, &block)
|
107
|
+
block.yield.assemble(partlib, z_skip, z)
|
108
|
+
end
|
109
|
+
end
|