jenncad 1.0.0.pre.alpha14 → 1.0.0.pre.alpha17

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  module JennCad::Primitives
2
- class Cylinder < Primitive
3
- attr_accessor :d, :d1, :d2, :r, :fn
2
+ class Cylinder < Circle
3
+ attr_accessor :d, :d1, :d2, :r, :fn, :anchors
4
4
  def initialize(args)
5
5
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
6
6
  args = args.first
@@ -24,6 +24,7 @@ module JennCad::Primitives
24
24
  r2: nil,
25
25
  z: nil,
26
26
  r: 0,
27
+ cz: false,
27
28
  margins: {
28
29
  r: 0,
29
30
  d: 0,
@@ -31,7 +32,7 @@ module JennCad::Primitives
31
32
  },
32
33
  fn: nil,
33
34
  }.deep_merge!(args)
34
-
35
+ init(args)
35
36
  # FIXME:
36
37
  # - margins calculation needs to go to output
37
38
  # - assinging these variables has to stop
@@ -40,7 +41,24 @@ module JennCad::Primitives
40
41
  @z = args[:z] || args[:h]
41
42
  handle_radius_diameter
42
43
  handle_fn
43
- super(args)
44
+ @dimensions = [:x, :y, :z]
45
+ set_anchors
46
+ end
47
+
48
+ def set_anchors
49
+ set_anchors_2d
50
+ # TODO: figure out if we also want to have "corners"
51
+ # - possibly move it like a cube
52
+ # - points at 45 ° angles might not be that useful unless you can get the point on the circle at a given angle
53
+ # - inner/outer points could be useful for small $fn values
54
+
55
+ if @opts[:cz]
56
+ set_anchor :bottom_face, z: -@z/2.0
57
+ set_anchor :top_face, z: @z/2.0
58
+ else
59
+ set_anchor :bottom_face, z: 0
60
+ set_anchor :top_face, z: @z
61
+ end
44
62
  end
45
63
 
46
64
  def openscad_params
@@ -60,51 +78,19 @@ module JennCad::Primitives
60
78
  # Centers the cylinder around it's center point by height
61
79
  # This will transform the cylinder around the center point.
62
80
  def cz
81
+ @opts[:cz] = true
82
+ @transformations ||= []
63
83
  @transformations << Move.new(z: -@z / 2.0)
84
+ set_anchors
64
85
  self
65
86
  end
66
87
 
67
- def handle_fn
68
- case @opts[:fn]
69
- when nil, 0
70
- $fn = auto_dn!
71
- else
72
- @fn = @opts[:fn]
73
- end
74
- end
75
-
76
- def auto_dn!
77
- case @d
78
- when (16..)
79
- @fn = (@d*4).ceil
80
- else
81
- @fn = 64
82
- end
83
- end
84
-
85
- def handle_radius_diameter
86
- case @opts[:d]
87
- when 0, nil
88
- @r = @opts[:r].to_d + @opts[:margins][:r].to_d
89
- @d = @r * 2.0
90
- else
91
- @d = @opts[:d].to_d + @opts[:margins][:d].to_d
92
- @r = @d / 2.0
93
- end
94
-
95
- case @opts[:d1]
96
- when 0, nil
97
- else
98
- @d1 = @opts[:d1].to_d + @opts[:margins][:d].to_d
99
- @d2 = @opts[:d2].to_d + @opts[:margins][:d].to_d
100
- end
101
-
102
- case @opts[:r1]
103
- when 0, nil
104
- else
105
- @d1 = 2 * @opts[:r1].to_d + @opts[:margins][:d].to_d
106
- @d2 = 2 * @opts[:r2].to_d + @opts[:margins][:d].to_d
107
- end
88
+ def z=(val)
89
+ @z = val
90
+ @h = val
91
+ opts[:h] = val
92
+ opts[:z] = val
93
+ set_anchors
108
94
  end
109
95
 
110
96
  def h
@@ -4,7 +4,7 @@ module JennCad::Primitives
4
4
  def initialize(part, args={})
5
5
  @transformations = []
6
6
  @parts = [part]
7
- @z = args[:h] || args[:height]
7
+ @z = args[:h] || args[:height] || args[:z]
8
8
  @center_bool = args[:center]
9
9
  @convexity = args[:convexity]
10
10
  @twist = args[:twist]
@@ -1,9 +1,12 @@
1
1
  module JennCad::Primitives
2
2
  class Polygon < Primitive
3
- attr_accessor :points
3
+ attr_accessor :points, :paths
4
4
  def initialize(args)
5
- super
6
5
  @points = args[:points]
6
+ @paths = args[:paths]
7
+ @convexity = args[:convexity] || 10
8
+ @dimensions = [:x, :y]
9
+ super
7
10
  end
8
11
  end
9
12
  end
@@ -0,0 +1,35 @@
1
+ module JennCad::Primitives
2
+ class Polyhedron < Primitive
3
+ attr_accessor :points, :faces, :convexity
4
+ def initialize(args)
5
+ @opts = args
6
+ @points = args[:points]
7
+ @faces = args[:faces]
8
+ @convexity = args[:convexity] || 10
9
+
10
+ super
11
+ end
12
+
13
+ def face(i)
14
+ unless @faces[i]
15
+ $log.error "polyhedron: Cannot find face #{i}"
16
+ return self
17
+ end
18
+ face = 0
19
+ poly_faces = []
20
+ poly_points = []
21
+ @faces[i].each do |f|
22
+ point = @points[f]
23
+ if point.nil?
24
+ $log.error "polyhedron: Cannot find point #{f} for face #{i}"
25
+ end
26
+ poly_points << point
27
+ poly_faces << face
28
+ face += 1
29
+ #poly_points << [point[0], point[1]]
30
+ end
31
+ #polygon(points: poly_points)
32
+ polyhedron(points: poly_points, faces: [poly_faces, poly_faces.reverse])
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,7 @@
1
1
  module JennCad::Primitives
2
2
  class Primitive < JennCad::Thing
3
+ attr_accessor :dimensions
4
+
3
5
  def initialize(*args)
4
6
  super(*args)
5
7
  end
@@ -7,7 +9,9 @@ module JennCad::Primitives
7
9
  def handle_margins
8
10
  @x = @opts[:x].to_d + @opts[:margins][:x].to_d
9
11
  @y = @opts[:y].to_d + @opts[:margins][:y].to_d
10
- @z = @opts[:z].to_d + @opts[:margins][:z].to_d
12
+ if @opts[:z]
13
+ @z = @opts[:z].to_d + @opts[:margins][:z].to_d
14
+ end
11
15
  end
12
16
 
13
17
  def handle_diameter
@@ -20,5 +24,20 @@ module JennCad::Primitives
20
24
  end
21
25
  end
22
26
 
27
+ def feed_opts(args)
28
+ if args.kind_of? Array
29
+ m = {}
30
+ if args.last.kind_of? Hash
31
+ m = args.last
32
+ end
33
+ args = [:x, :y, :z].zip(args.flatten).to_h
34
+ args.deep_merge!(m)
35
+ @opts.deep_merge!(args)
36
+ else
37
+ @opts.deep_merge!(args)
38
+ end
39
+ end
40
+
41
+
23
42
  end
24
43
  end
@@ -4,6 +4,7 @@ module JennCad::Primitives
4
4
  include JennCad::Features::Cuttable
5
5
 
6
6
  def initialize(args)
7
+
7
8
  if args.kind_of?(Array) && args[0].kind_of?(Hash)
8
9
  args = args.first
9
10
  end
@@ -35,20 +36,43 @@ module JennCad::Primitives
35
36
  z: 0,
36
37
  },
37
38
  }.deep_merge!(args)
39
+ if args.kind_of? Array
40
+ args.each do |a|
41
+ feed_opts(parse_xyz_shortcuts(a))
42
+ end
43
+ else
44
+ feed_opts(parse_xyz_shortcuts(args))
45
+ end
46
+ init(args)
47
+
48
+
38
49
  handle_margins
39
50
  handle_diameter
40
- super(opts)
51
+ if @opts[:z] && opts[:z].to_d > 0
52
+ @dimensions = [:x, :y, :z]
53
+ else
54
+ @dimensions = [:x, :y]
55
+ end
56
+
41
57
  end
42
58
 
43
59
  def to_openscad
44
- return cube(@opts) if @d == 0
60
+ # FIXME: this check needs to be done on object creation
61
+ # otherwise it fails to position it
62
+ if @d == 0
63
+ if @z.to_d > 0
64
+ return cube(@opts)
65
+ else
66
+ return square(@opts)
67
+ end
68
+ end
45
69
  # make diameter not bigger than any side
46
70
  d = [@d, @x, @y].min
47
71
  res = HullObject.new(
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),
72
+ circle(d: d),
73
+ circle(d: d).move(x: @x - d, y: 0),
74
+ circle(d: d).move(x: 0, y: @y - d),
75
+ circle(d: d).move(x: @x - d, y: @y - d),
52
76
  )
53
77
  res = res.move(xy: d/2.0)
54
78
 
@@ -56,6 +80,10 @@ module JennCad::Primitives
56
80
  res += apply_flat_edge(edge)
57
81
  end
58
82
 
83
+ if @z.to_d > 0
84
+ res = res.extrude(z: @z + z_margin)
85
+ end
86
+
59
87
  res = union(res) # put everything we have in a parent union that we can apply the transformations of this object of
60
88
  res.transformations = @transformations
61
89
 
@@ -64,23 +92,25 @@ module JennCad::Primitives
64
92
  res
65
93
  end
66
94
 
67
- def flat(edge)
95
+ def flat(*edges)
68
96
  @opts[:flat_edges] ||= []
69
- @opts[:flat_edges] << edge
97
+ edges.each do |edge|
98
+ @opts[:flat_edges] << edge
99
+ end
70
100
  self
71
101
  end
72
102
 
73
103
  private
74
104
  def apply_flat_edge(edge)
75
105
  case edge
76
- when :up
77
- cube(x: @x, y: @y/2.0, z: @z).nc.moveh(y:@y)
78
- when :down
79
- cube(x: @x, y: @y/2.0, z: @z).nc
106
+ when :up, :top
107
+ square(x: @x, y: @y/2.0).nc.moveh(y:@y)
108
+ when :down, :bottom
109
+ square(x: @x, y: @y/2.0).nc
80
110
  when :right
81
- cube(x: @x/2.0, y: @y, z: @z).nc.moveh(x:@x)
111
+ square(x: @x/2.0, y: @y).nc.moveh(x:@x)
82
112
  when :left
83
- cube(x: @x/2.0, y: @y, z: @z).nc
113
+ square(x: @x/2.0, y: @y).nc
84
114
  else
85
115
  nil
86
116
  end
@@ -14,16 +14,21 @@ module JennCad::Primitives
14
14
  args = [:d, :z].zip(args.flatten).to_h
15
15
  args.deep_merge!(m)
16
16
  end
17
-
18
- args[:z] ||= args[:h]
17
+ args = parse_xyz_shortcuts(args)
18
+ if args[:z].to_d > 0
19
+ args[:h] = args[:z]
20
+ else
21
+ args[:z] = nil
22
+ end
19
23
 
20
24
  @opts = {
21
25
  d: 0,
22
26
  a: 0,
23
- z: nil,
24
27
  r: nil,
25
28
  x: 0,
26
29
  y: 0,
30
+ z: nil,
31
+ cz: false,
27
32
  margins: {
28
33
  r: 0,
29
34
  d: 0,
@@ -33,9 +38,13 @@ module JennCad::Primitives
33
38
 
34
39
  super(opts)
35
40
 
36
- @d = @opts[:d]
37
- @a = @opts[:a]
38
- @h = @opts[:h]
41
+ @d = @opts[:d].to_d
42
+ @a = @opts[:a].to_d
43
+ @h = @opts[:h].to_d
44
+ @z = @h
45
+ @x = @opts[:x].to_d
46
+ @y = @opts[:y].to_d
47
+
39
48
  @r = @opts[:r] || nil
40
49
  if @r
41
50
  @d = @r * 2
@@ -54,7 +63,61 @@ module JennCad::Primitives
54
63
 
55
64
  # TODO: this needs anchors like cube
56
65
  # TODO: color on this needs to apply to hull, not on the cylinders.
66
+ set_anchors
67
+ end
68
+
69
+ def cz
70
+ @opts[:cz] = true
71
+ @transformations << Move.new(z: -@z / 2.0)
72
+ set_anchors
73
+ self
74
+ end
75
+
76
+
77
+ def set_anchors
78
+ @anchors = {} # reset anchors
79
+ if @opts[:d]
80
+ rad = @opts[:d] / 2.0
81
+ else
82
+ rad = @opts[:r]
83
+ end
57
84
 
85
+ if @x > 0
86
+ set_anchor :left, x: - rad
87
+ set_anchor :right, x: @x + rad
88
+ elsif @x < 0
89
+ set_anchor :left, x: @x - rad
90
+ set_anchor :right, x: rad
91
+ else
92
+ set_anchor :left, x: -rad
93
+ set_anchor :right, x: rad
94
+ end
95
+ if @y > 0
96
+ set_anchor :bottom, y: - rad
97
+ set_anchor :top, y: @y + rad
98
+ elsif @y < 0
99
+ set_anchor :bottom, y: @y - rad
100
+ set_anchor :top, y: rad
101
+ else
102
+ set_anchor :bottom, y: -rad
103
+ set_anchor :top, y: rad
104
+ end
105
+
106
+ set_anchor :center1, xy: 0
107
+ set_anchor :center2, x: @x, y: @y
108
+
109
+ # TODO: figure out if we also want to have "corners"
110
+ # - possibly move it like a cube
111
+ # - points at 45 ° angles might not be that useful unless you can get the point on the circle at a given angle
112
+ # - inner/outer points could be useful for small $fn values
113
+
114
+ if @opts[:cz]
115
+ set_anchor :bottom_face, z: -@z/2.0
116
+ set_anchor :top_face, z: @z/2.0
117
+ else
118
+ set_anchor :bottom_face, z: 0
119
+ set_anchor :top_face, z: @z
120
+ end
58
121
  end
59
122
 
60
123
  def to_openscad
@@ -0,0 +1,181 @@
1
+ module JennCad::Primitives
2
+ class Square < Primitive
3
+ attr_accessor :corners, :sides
4
+
5
+ def initialize(args)
6
+ @opts = {
7
+ x: 0,
8
+ y: 0,
9
+ margins: {
10
+ x: 0,
11
+ y: 0,
12
+ },
13
+ center: true,
14
+ center_y: false,
15
+ center_x: false,
16
+ }
17
+ if args.kind_of? Array
18
+ args.each do |a|
19
+ feed_opts(parse_xyz_shortcuts(a))
20
+ end
21
+ else
22
+ feed_opts(parse_xyz_shortcuts(args))
23
+ end
24
+ init(args)
25
+
26
+ handle_margins
27
+ set_anchors
28
+ @x = args[:x]
29
+ @y = args[:y]
30
+ @dimensions = [:x, :y]
31
+ end
32
+
33
+
34
+ # used for openscad export
35
+ def size
36
+ [@x, @y]
37
+ end
38
+
39
+ def set_anchors
40
+ set_anchors_2d
41
+ end
42
+
43
+ def set_anchors_2d
44
+ @anchors = {} # this resets anchors
45
+
46
+ if @opts[:center] || @opts[:center_x]
47
+ left = -@opts[:x] / 2.0
48
+ right = @opts[:x] / 2.0
49
+ mid_x = 0
50
+ else
51
+ left = 0
52
+ right = @opts[:x]
53
+ mid_x = @opts[:x] / 2.0
54
+ end
55
+ if @opts[:center] || @opts[:center_y]
56
+ bottom = -@opts[:y] / 2.0
57
+ top = @opts[:y] / 2.0
58
+ mid_y = 0
59
+ else
60
+ bottom = 0
61
+ top = @opts[:y]
62
+ mid_y = @opts[:y] / 2.0
63
+ end
64
+
65
+ set_anchor :left, x: left, y: mid_y
66
+ set_anchor :right, x: right, y: mid_y
67
+ set_anchor :top, x: mid_x, y: top
68
+ set_anchor :bottom, x: mid_x, y: bottom
69
+ set_anchor :top_left, x: left, y: top
70
+ set_anchor :top_right, x: right, y: top
71
+ set_anchor :bottom_left, x: left, y: bottom
72
+ set_anchor :bottom_right, x: right, y: bottom
73
+
74
+ # we need to re-do the inner ones, if they were defined
75
+ if @inner_anchor_defs && @inner_anchor_defs.size > 0
76
+ @inner_anchor_defs.each do |anch|
77
+ inner_anchors(anch[:dist], anch[:prefix], true)
78
+ end
79
+ end
80
+
81
+ self
82
+ end
83
+
84
+ def inner_anchors(dist, prefix=:inner_, recreate=false)
85
+ if dist.nil?
86
+ $log.error "Distance of nil passed to inner anchors. Please check the variable name you passed along"
87
+ return self
88
+ end
89
+
90
+ @inner_anchor_defs ||= []
91
+ @inner_anchor_defs << { "dist": dist, "prefix": prefix } unless recreate
92
+
93
+ # $log.info "dist: #{dist}, prefix: #{prefix}"
94
+ sides = {
95
+ left: {x: dist, y: 0},
96
+ right: {x: -dist, y: 0},
97
+ top: {x: 0, y: -dist},
98
+ bottom: {x: 0, y: dist},
99
+ }
100
+ corners = {
101
+ top_left: {x: dist, y: -dist},
102
+ top_right: {x: -dist, y: -dist},
103
+ bottom_left: {x: dist, y: dist},
104
+ bottom_right: {x: -dist, y: dist},
105
+ }
106
+ new_sides = []
107
+ new_corners = []
108
+
109
+ sides.merge(corners).each do |key, vals|
110
+ new_dist = anchor(key).dup
111
+ new_dist[:x] += vals[:x]
112
+ new_dist[:y] += vals[:y]
113
+ name = [prefix, key].join.to_sym
114
+ # $log.info "Set anchor #{name} , new dist #{new_dist}"
115
+ set_anchor name, new_dist
116
+ if sides.include? key
117
+ new_sides << name
118
+ end
119
+ if corners.include? key
120
+ new_corners << name
121
+ end
122
+ end
123
+
124
+ sides_name = [prefix, "sides"].join
125
+ corners_name = [prefix, "corners"].join
126
+ all_name = [prefix, "all"].join
127
+ self.class.__send__(:attr_accessor, sides_name.to_sym)
128
+ self.class.__send__(:attr_accessor, corners_name.to_sym)
129
+ self.class.__send__(:attr_accessor, all_name.to_sym)
130
+ self.__send__("#{sides_name}=", new_sides)
131
+ self.__send__("#{corners_name}=", new_corners)
132
+ self.__send__("#{all_name}=", new_corners+new_sides)
133
+
134
+
135
+ self
136
+ end
137
+
138
+
139
+
140
+ def not_centered
141
+ @opts[:center] = false
142
+ set_anchors
143
+ self
144
+ end
145
+ alias :nc :not_centered
146
+
147
+ def cx
148
+ nc
149
+ @opts[:center_x] = true
150
+ set_anchors
151
+ self
152
+ end
153
+ alias :center_x :cx
154
+
155
+ def cy
156
+ nc
157
+ @opts[:center_y] = true
158
+ set_anchors
159
+ self
160
+ end
161
+ alias :center_y :cy
162
+
163
+
164
+
165
+ def centered_axis
166
+ return [:x, :y] if @opts[:center]
167
+ a = []
168
+ a << :x if @opts[:center_x]
169
+ a << :y if @opts[:center_y]
170
+ a << :z if @opts[:center_z]
171
+ a
172
+ end
173
+
174
+ def to_openscad
175
+ self.mh(centered_axis.to_h{|a| [a, -@opts[a]] }) # center cube
176
+ end
177
+
178
+
179
+
180
+ end
181
+ end
@@ -57,35 +57,47 @@ module JennCad::Primitives
57
57
  others.each do |part|
58
58
  #puts part.inspect
59
59
  #puts "#{part.calc_z+part.calc_h} ; #{compare_h}"
60
+ add_z = nil
60
61
  if part.respond_to? :z
61
62
  part.opts[:margins] ||= {}
62
- if part.referenced_z && part.z != 0.0
63
+ if part.referenced_z && part.z != 0.0 && part.is_3d?
63
64
  case part
64
- when JennCad::Circle
65
65
  when JennCad::BooleanObject
66
66
  else
67
- $log.debug part if part.opts[:debug]
67
+ # $log.debug part if part.opts[:debug]
68
68
  part.opts[:margins][:z] ||= 0.0
69
69
  unless part.opts[:margins][:z] == 0.2
70
+ $log.debug "fixing possible z fighting for referenced object: #{part.class} #{part.z} 0.1 down" if part.opts[:debug]
70
71
  part.opts[:margins][:z] = 0.2
71
72
  part.mz(-0.1)
72
73
  end
73
74
  end
74
75
  elsif part.z == compare_h
75
76
  $log.debug "fixing possible z fighting: #{part.class} #{part.z}" if part.opts[:debug]
76
- part.opts[:margins][:z] += 0.008
77
- part.mz(-0.004)
77
+ add_z = 0.008
78
+ move_z = -0.004
78
79
  elsif part.calc_z == compare_z
79
80
  # puts "z fighting at bottom: #{part.calc_z}"
80
- part.opts[:margins][:z] += 0.004
81
+ add_z = 0.004
81
82
  # part.z+=0.004
82
- part.mz(-0.002)
83
+ move_z = -0.002
83
84
  elsif part.calc_z.to_d+part.calc_h.to_d == compare_h
84
85
  # puts "z fighting at top: #{compare_h}"
85
86
  #part.z+=0.004
86
- part.opts[:margins][:z] += 0.004
87
- part.mz(0.002)
87
+ add_z = 0.004
88
+ move_z = 0.002
88
89
  end
90
+
91
+ if add_z && part.is_3d?
92
+ if part.kind_of? Part
93
+ part.modify_values(part, {z: add_z}, {mode: :add})
94
+ end
95
+ part.opts[:margins][:z] += add_z
96
+ part.mz(move_z)
97
+ end
98
+
99
+
100
+
89
101
  end
90
102
  end
91
103
  end
@@ -1,10 +1,12 @@
1
1
  require "jenncad/primitives/primitive"
2
2
  require "jenncad/primitives/circle"
3
+ require "jenncad/primitives/square"
3
4
  require "jenncad/primitives/cylinder"
4
5
  require "jenncad/primitives/sphere"
5
6
  require "jenncad/primitives/cube"
6
7
  require "jenncad/primitives/rounded_cube"
7
8
  require "jenncad/primitives/polygon"
9
+ require "jenncad/primitives/polyhedron"
8
10
  require "jenncad/primitives/slot"
9
11
  require "jenncad/primitives/boolean_object"
10
12
  require "jenncad/primitives/union_object"