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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +1 -0
  3. data/bin/jenncad +10 -0
  4. data/examples/old/cube.rb +12 -0
  5. data/examples/old/slot.rb +10 -0
  6. data/examples/old/test.rb +18 -0
  7. data/examples/old/test1.rb +21 -0
  8. data/examples/old/test2.rb +9 -0
  9. data/examples/old/test3.rb +15 -0
  10. data/examples/old/test4.rb +17 -0
  11. data/examples/old/test5.rb +31 -0
  12. data/jenncad.gemspec +27 -0
  13. data/lib/jenncad/commands.rb +169 -0
  14. data/lib/jenncad/default_profile.rb +40 -0
  15. data/lib/jenncad/extras/din912.rb +89 -0
  16. data/lib/jenncad/extras/din933.rb +64 -0
  17. data/lib/jenncad/extras/din934.rb +99 -0
  18. data/lib/jenncad/extras/hardware.rb +16 -0
  19. data/lib/jenncad/extras/iso7380.rb +58 -0
  20. data/lib/jenncad/jenncad.rb +3 -0
  21. data/lib/jenncad/openscad.rb +274 -0
  22. data/lib/jenncad/part.rb +14 -0
  23. data/lib/jenncad/patches/array.rb +29 -0
  24. data/lib/jenncad/primitives/aggregation.rb +12 -0
  25. data/lib/jenncad/primitives/boolean_object.rb +76 -0
  26. data/lib/jenncad/primitives/circle.rb +11 -0
  27. data/lib/jenncad/primitives/cube.rb +69 -0
  28. data/lib/jenncad/primitives/cylinder.rb +52 -0
  29. data/lib/jenncad/primitives/hull_object.rb +4 -0
  30. data/lib/jenncad/primitives/intersection_object.rb +4 -0
  31. data/lib/jenncad/primitives/linear_extrude.rb +25 -0
  32. data/lib/jenncad/primitives/openscad_include.rb +11 -0
  33. data/lib/jenncad/primitives/polygon.rb +9 -0
  34. data/lib/jenncad/primitives/primitive.rb +24 -0
  35. data/lib/jenncad/primitives/projection.rb +9 -0
  36. data/lib/jenncad/primitives/rotate_extrude.rb +20 -0
  37. data/lib/jenncad/primitives/rounded_cube.rb +77 -0
  38. data/lib/jenncad/primitives/slot.rb +82 -0
  39. data/lib/jenncad/primitives/sphere.rb +11 -0
  40. data/lib/jenncad/primitives/subtract_object.rb +84 -0
  41. data/lib/jenncad/primitives/union_object.rb +5 -0
  42. data/lib/jenncad/profile_loader.rb +34 -0
  43. data/lib/jenncad/project.rb +28 -0
  44. data/lib/jenncad/register.rb +31 -0
  45. data/lib/jenncad/shortcuts.rb +109 -0
  46. data/lib/jenncad/thing.rb +308 -0
  47. data/lib/jenncad/transformation/color.rb +8 -0
  48. data/lib/jenncad/transformation/mirror.rb +7 -0
  49. data/lib/jenncad/transformation/move.rb +7 -0
  50. data/lib/jenncad/transformation/multmatrix.rb +9 -0
  51. data/lib/jenncad/transformation/rotate.rb +7 -0
  52. data/lib/jenncad/transformation/scale.rb +7 -0
  53. data/lib/jenncad/transformation/transformation.rb +14 -0
  54. data/lib/jenncad/version.rb +4 -0
  55. data/lib/jenncad.rb +73 -0
  56. data/todo.txt +29 -0
  57. 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,11 @@
1
+ module JennCad::Primitives
2
+ class Sphere < Primitive
3
+ attr_accessor :d, :r, :fn
4
+ def initialize(args)
5
+ super
6
+ @d = args[:d]
7
+ @r = args[:r]
8
+ @fn = args[:fn]
9
+ end
10
+ end
11
+ 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,5 @@
1
+ module JennCad::Primitives
2
+ class UnionObject < BooleanObject
3
+
4
+ end
5
+ 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