jenncad 1.0.0.pre.alpha1
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 +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
|