diff --git a/prototype/circles.py b/prototype/circles.py
index d191102..d8d9e55 100644
--- a/prototype/circles.py
+++ b/prototype/circles.py
@@ -3,176 +3,7 @@ import matplotlib.pyplot as plt
import math
import operator
-# scale in inkscape
-# 1 unit = 0.283 mm
-svg_scale = 1000.0/282.222
-
-def svg_circle(id, name, c, r):
- # create circle object in svg notation
- text = [' \n'.format(c[0])]
-
- return text
-
-def svg_puzzle(p, size, angle):
- # convert angle to radians
- angle = angle / 360.0 * 2.0 * np.pi
-
-
- # compute points
- """
- v1 and v2 are orthogonal vectors
-
- construction of points (starting at p):
-
- p3 <------ -2 v1 ------ p2
- ^
- |
- v2
- |
- |
- p4 <-- -v1 -- p -- v1 --> p1
-
- then between points p2 and p3 with draw an arc
- """
- v1 = np.array([np.cos(angle), np.sin(angle)])
- v2 = np.array([v1[1], -v1[0]])
- p1 = p + size * v1
- p2 = p1 + size * v2
- p3 = p2 - 2.0 * size * v1
- p4 = p - size * v1
-
- # convert to svg units
- p1 *= svg_scale
- p2 *= svg_scale
- p3 *= svg_scale
- p4 *= svg_scale
-
- radius_scaled = 1.25 * size * svg_scale
-
- text = [' \n'.format(p1[0], p1[1], p2[0], p2[1], radius_scaled, radius_scaled, p3[0], p3[1], p4[0], p4[1])]
-
- return text
-
-def svg_line_puzzle(start, end, puzzle_scale=1.0, linewidth=0.50):
- # draws a line from start to end with a simple jigsaw puzzle style cutout in the middle
- # the size of the cutout can be controlled with the puzzle_scale parameter
- # compute points
- """
- v1 and v2 are orthogonal vectors
-
- construction of points (starting at p (middle between start and end)):
-
- p2 ------- 2 v1 -----> p3
- ^
- |
- v2
- |
- |
- start --- p1 <-- -v1 -- p -- v1 --> p4 --- end
-
- then between points p2 and p3 with draw an arc
- """
- v = end - start
- dist = np.linalg.norm(v)
- size = dist / 10.0 * puzzle_scale # size of the cutout
- v = v / dist
- angle = math.atan2(v[1], v[0]) # angle of v
-
- # midpoint between start and end
- p = np.mean([start, end], axis=0)
-
- v1 = np.array([np.cos(angle), np.sin(angle)])
- v2 = np.array([v1[1], -v1[0]])
- p1 = p - size * v1
- p2 = p1 + size * v2
- p3 = p2 + 2.0 * size * v1
- p4 = p + size * v1
-
- # convert to svg units
- p1 *= svg_scale
- p2 *= svg_scale
- p3 *= svg_scale
- p4 *= svg_scale
- start *= svg_scale
- end *= svg_scale
-
- radius_scaled = 1.25 * size * svg_scale
-
- text = [' \n'.format(linewidth, start[0], start[1], p1[0], p1[1], p2[0], p2[1], radius_scaled, radius_scaled,
- p3[0], p3[1], p4[0], p4[1], end[0], end[1])]
-
- return text
-
-def svg_half_circle(id, name, c, r, angle, orientation_flag=1):
- # draws half a circle centered at c with radius r
- # angle specifies how the half circle should be rotated
- # for the default angle of zero, it draws the top half of the circle
-
- # convert angle to radians
- angle = angle/360.0 * 2.0 * np.pi
-
- # compute starting point
- v = np.array([np.cos(angle), np.sin(angle)])
- begin = c + r * v # in millimeters
- begin *= svg_scale # in svg units
-
- # compute end point
- end = c - r * v # in millimeters
- end *= svg_scale # in svg units
-
- radius_scaled = r * svg_scale # radius in svg units
-
- text = [' \n'.format(begin[0], begin[1], radius_scaled, radius_scaled, orientation_flag, orientation_flag,
- end[0], end[1])]
-
- return text
-
-def svg_arc(p1, p2, r, large_arc, sweep):
- begin = p1 * svg_scale
- end = p2 * svg_scale
- radius_scaled = r * svg_scale
- text = [' \n'.format(begin[0], begin[1], radius_scaled, radius_scaled, large_arc, sweep,
- end[0], end[1])]
-
- return text
-
-def svg_rectangle(id, name, c, width, heigth, angle):
- x = np.sqrt(c[0]**2 + c[1]**2) - width/2
- y = - heigth
- text = ['\n '
- '\n '
- '\n'
- .format(angle, x, y ,width, heigth)]
-
- return text
-
-
-def svg_line(p1, p2, width=1.0):
- text = [''.format(p1[0], p1[1], p2[0], p2[1], width)]
-
- return text
+from svg_utils import *
# this function reads and processes data for optimal circle packaging obtained form packomania.com
@@ -568,8 +399,8 @@ class PlateLayout:
f_lines.remove(f_lines[-1])
# output plate as svg
- text = svg_circle(0, 'plate', (0,0), self.target_plate_radius)
- f_lines = f_lines + text
+ # text = svg_circle(0, 'plate', (0,0), self.target_plate_radius)
+ # f_lines = f_lines + text
output_all = False
if output_all:
@@ -586,8 +417,8 @@ class PlateLayout:
pass
- def output_segment(self, f_lines, k):
+ def output_segment(self, f_lines, k):
# k = which segment?
k_next = (k + 1) % self.N
@@ -602,102 +433,44 @@ class PlateLayout:
vunit2 = np.array([np.cos(a2), np.sin(a2)])
p2 = vunit2 * self.target_center_hole_radius
- text = svg_arc(p1, p2, self.target_center_hole_radius, 0, 1)
- f_lines = f_lines + text
-
+ f_lines += svg_arc(p1, p2, self.target_center_hole_radius, 0, 1)
# big circles arcs
- c = self.tube_1_coords[k]
- angle = self.tube_1_angles[k]
- text = svg_half_circle(k, 'big circle', c, self.target_radius_1, angle)
- f_lines = f_lines + text
-
- c = self.tube_1_coords[k_next]
- angle = self.tube_1_angles[k_next]
- text = svg_half_circle(k_next, 'big circle', c, self.target_radius_1, angle, orientation_flag=0)
- f_lines = f_lines + text
+ f_lines += svg_half_circle(k, 'big circle', self.tube_1_coords[k], self.target_radius_1, self.tube_1_angles[k])
+ f_lines += svg_half_circle(k_next, 'big circle', self.tube_1_coords[k_next], self.target_radius_1,
+ self.tube_1_angles[k_next], orientation_flag=0)
# small circle
- c = self.tube_2_coords[k]
- text = svg_circle(k, 'small circle', c, self.target_radius_2)
- f_lines = f_lines + text
+ f_lines += svg_circle(k, 'small circle', self.tube_2_coords[k], self.target_radius_2)
# gear pos for big circle
- c = self.tube_1_tangents[k_next]
- circle_midpoint = self.tube_1_coords[k_next]
- v = np.array(c[0]) - np.array(circle_midpoint)
- v = v / np.linalg.norm(v)
+ f_lines += svg_gear_marking(self.tube_1_tangents[k_next], self.tube_1_coords[k_next])
- marking_length = 5.0
-
- p1 = c[0]
- p2 = c[0] + v * marking_length
-
- text = svg_line(p1, p2)
- f_lines = f_lines + text
-
- # rectangle for big circles
- c = self.tube_1_cuts[k_next]
- text = svg_rectangle(k_next, 'cut', c['center'], c['length'], c['width'], c['angle_deg'])
- f_lines = f_lines + text
+ # cutout rectangle for big circles
+ f_lines += svg_rectangle(k_next, 'cut', self.tube_1_cuts[k_next])
# gear pos for small circle
- c = self.tube_2_tangents[k]
- circle_midpoint = self.tube_2_coords[k]
- v = np.array(c[0]) - np.array(circle_midpoint)
- v = v/np.linalg.norm(v)
+ f_lines += svg_gear_marking(self.tube_2_tangents[k], self.tube_2_coords[k])
- marking_length = 5.0
+ # cutout rectangle for small circles
+ f_lines += svg_rectangle(k, 'cut', self.tube_2_cuts[k])
- p1 = c[0]
- p2 = c[0] + v * marking_length
+ # first segment border
+ f_lines += svg_segment_border_inner(self.tube_1_angles[k], self.target_center_hole_radius,
+ self.tube_1_coords[k], self.target_radius_1)
+ f_lines += svg_segment_border_outer(self.tube_1_angles[k], self.target_plate_radius, self.plate_module,
+ self.tube_1_coords[k], self.target_radius_1)
- text = svg_line(p1, p2)
- f_lines = f_lines + text
+ # second segment border
+ f_lines += svg_segment_border_inner(self.tube_1_angles[k_next], self.target_center_hole_radius,
+ self.tube_1_coords[k_next], self.target_radius_1)
+ f_lines += svg_segment_border_outer(self.tube_1_angles[k_next], self.target_plate_radius, self.plate_module,
+ self.tube_1_coords[k_next], self.target_radius_1)
- # rectangle for small circles
- c = self.tube_2_cuts[k]
- text = svg_rectangle(k, 'cut', c['center'], c['length'], c['width'], c['angle_deg'])
- f_lines = f_lines + text
-
- # segment border (right)
- a = self.tube_1_angles[k]
- a = a / 360.0 * 2.0 * np.pi
- r1 = np.linalg.norm(np.array(self.tube_1_coords[k])) - self.target_radius_1
- vunit = np.array([np.cos(a), np.sin(a)])
- p1 = vunit * self.target_center_hole_radius
- p2 = vunit * r1
- #text = svg_line(p1, p2, 0.1)
- text = svg_line_puzzle(p1, p2)
- f_lines = f_lines + text
-
- r2 = np.linalg.norm(np.array(self.tube_1_coords[k])) + self.target_radius_1
- p3 = vunit * r2
- r3 = self.target_plate_radius - self.plate_module
- p4 = vunit * r3
- text = svg_line_puzzle(p3, p4)
- #text = svg_line(p3, p4, 0.1)
- f_lines = f_lines + text
-
- # segment border (left)
- a = self.tube_1_angles[k_next]
- a = a / 360.0 * 2.0 * np.pi
- r1 = np.linalg.norm(np.array(self.tube_1_coords[k_next])) - self.target_radius_1
- vunit = np.array([np.cos(a), np.sin(a)])
- p1 = vunit * self.target_center_hole_radius
- p2 = vunit * r1
- #text = svg_line(p1, p2, 0.1)
- text = svg_line_puzzle(p1, p2)
- f_lines = f_lines + text
-
- r2 = np.linalg.norm(np.array(self.tube_1_coords[k_next])) + self.target_radius_1
- p3 = vunit * r2
- r3 = self.target_plate_radius - self.plate_module
- p4 = vunit * r3
- #text = svg_line(p3, p4, 0.1)
- text = svg_line_puzzle(p3, p4)
- f_lines = f_lines + text
+ # find outmost points for segment cut lines
+ # in addition we rotate the points by 0.9 degrees because we also rotated the gear path
+ # by this amount above
r_pitch_minus_module = self.target_plate_radius - self.plate_module
a1 = (self.tube_1_angles[k] - 0.9) / 360.0 * 2.0 * np.pi
vunit1 = np.array([np.cos(a1), np.sin(a1)])
@@ -726,6 +499,7 @@ class PlateLayout:
coordinates.append(c_running)
pass
+ # find nodes on gear path with minimal distance to segment cuts
dist_1 = [np.linalg.norm(c - outer_point_1 * svg_scale) for c in coordinates]
dist_2 = [np.linalg.norm(c - outer_point_2 * svg_scale) for c in coordinates]
@@ -736,24 +510,13 @@ class PlateLayout:
coordinates = coordinates[min_dist_index_1:min_dist_index_2+1]
else:
coordinates = coordinates[min_dist_index_1:] + coordinates[0:min_dist_index_2]
- print("TODO: check this")
coordinates_data_raw_new = "".join(['{},{} '.format(c[0], c[1]) for c in coordinates])
+ # keep only those nodes from the gear path that are between the segment cuts
gear_data_new = gear_data[0:index_start] + "M " + coordinates_data_raw_new + gear_data[index_end+1:]
f_lines[j] = gear_data_new
-
-
-
- # find minimum distance and keep only points between the two distances
- # problem: does not consider manual rotation of the plate
- # -> rotate points outer_point_1 and outer_point_2 before computing the distance
- # ...
-
- pass
- #f_lines[k] = gear_data[0:index+1] + gear_data[-2:]
-
return f_lines
def output_whole(self, f_lines):
diff --git a/prototype/svg_utils.py b/prototype/svg_utils.py
new file mode 100644
index 0000000..0984c53
--- /dev/null
+++ b/prototype/svg_utils.py
@@ -0,0 +1,222 @@
+import numpy as np
+import math
+
+# scale in inkscape
+# 1 unit = 0.28222 mm
+svg_scale = 1000.0 / 282.222
+
+
+def svg_circle(id, name, c, r):
+ # create circle object centered at point c with radius r
+ text = [' \n'.format(c[0])]
+
+ return text
+
+
+def svg_puzzle(p, size, angle):
+ # convert angle to radians
+ angle = angle / 360.0 * 2.0 * np.pi
+
+ # compute points
+ """
+ v1 and v2 are orthogonal vectors
+
+ construction of points (starting at p):
+
+ p3 <------ -2 v1 ------ p2
+ ^
+ |
+ v2
+ |
+ |
+ p4 <-- -v1 -- p -- v1 --> p1
+
+ then between points p2 and p3 with draw an arc
+ """
+ v1 = np.array([np.cos(angle), np.sin(angle)])
+ v2 = np.array([v1[1], -v1[0]])
+ p1 = p + size * v1
+ p2 = p1 + size * v2
+ p3 = p2 - 2.0 * size * v1
+ p4 = p - size * v1
+
+ # convert to svg units
+ p1 *= svg_scale
+ p2 *= svg_scale
+ p3 *= svg_scale
+ p4 *= svg_scale
+
+ radius_scaled = 1.25 * size * svg_scale
+
+ text = [' \n'.format(p1[0], p1[1], p2[0], p2[1], radius_scaled, radius_scaled, p3[0], p3[1], p4[0], p4[1])]
+
+ return text
+
+
+def svg_line_puzzle(start, end, puzzle_scale=1.0, linewidth=0.50):
+ # draws a line from start to end with a simple jigsaw puzzle style cutout in the middle
+ # the size of the cutout can be controlled with the puzzle_scale parameter
+ # compute points
+ """
+ v1 and v2 are orthogonal vectors
+
+ construction of points (starting at p (middle between start and end)):
+
+ p2 ------- 2 v1 -----> p3
+ ^
+ |
+ v2
+ |
+ |
+ start --- p1 <-- -v1 -- p -- v1 --> p4 --- end
+
+ then between points p2 and p3 with draw an arc
+ """
+ v = end - start
+ dist = np.linalg.norm(v)
+ size = dist / 10.0 * puzzle_scale # size of the cutout
+ v = v / dist
+ angle = math.atan2(v[1], v[0]) # angle of v
+
+ # midpoint between start and end
+ p = np.mean([start, end], axis=0)
+
+ v1 = np.array([np.cos(angle), np.sin(angle)])
+ v2 = np.array([v1[1], -v1[0]])
+ p1 = p - size * v1
+ p2 = p1 + size * v2
+ p3 = p2 + 2.0 * size * v1
+ p4 = p + size * v1
+
+ # convert to svg units
+ p1 *= svg_scale
+ p2 *= svg_scale
+ p3 *= svg_scale
+ p4 *= svg_scale
+ start *= svg_scale
+ end *= svg_scale
+
+ radius_scaled = 1.25 * size * svg_scale
+
+ text = [' \n'.format(linewidth, start[0], start[1], p1[0], p1[1], p2[0], p2[1], radius_scaled, radius_scaled,
+ p3[0], p3[1], p4[0], p4[1], end[0], end[1])]
+
+ return text
+
+
+def svg_half_circle(id, name, c, r, angle, orientation_flag=1):
+ # draws half a circle centered at c with radius r
+ # angle specifies how the half circle should be rotated
+ # the orientation flag determines if the upper or the lower half of the circle is drawn
+
+ # convert angle to radians
+ angle = angle / 360.0 * 2.0 * np.pi
+
+ # compute starting point
+ v = np.array([np.cos(angle), np.sin(angle)])
+ begin = c + r * v # in millimeters
+ begin *= svg_scale # in svg units
+
+ # compute end point
+ end = c - r * v # in millimeters
+ end *= svg_scale # in svg units
+
+ radius_scaled = r * svg_scale # radius in svg units
+
+ text = [' \n'.format(begin[0], begin[1], radius_scaled, radius_scaled, orientation_flag, orientation_flag,
+ end[0], end[1])]
+
+ return text
+
+
+def svg_arc(p1, p2, r, large_arc, sweep):
+ begin = p1 * svg_scale
+ end = p2 * svg_scale
+ radius_scaled = r * svg_scale
+ text = [' \n'.format(begin[0], begin[1], radius_scaled, radius_scaled, large_arc, sweep,
+ end[0], end[1])]
+
+ return text
+
+
+def svg_rectangle(id, name, c):
+ center = c['center']
+ width = c['length']
+ height = c['width']
+ angle = c['angle_deg']
+ x = np.sqrt(center[0] ** 2 + center[1] ** 2) - width / 2
+ y = - height
+ text = ['\n '
+ '\n '
+ '\n'
+ .format(angle, x, y, width, height)]
+
+ return text
+
+
+def svg_line(p1, p2, width=1.0):
+ text = [''.format(p1[0],
+ p1[1],
+ p2[0],
+ p2[1],
+ width)]
+
+ return text
+
+
+def svg_gear_marking(tangent_coord, circle_midpoint, marking_length=5.0):
+ c = tangent_coord
+ v = np.array(c[0]) - np.array(circle_midpoint)
+ v = v / np.linalg.norm(v)
+
+ p1 = c[0]
+ p2 = c[0] + v * marking_length
+
+ text = svg_line(p1, p2)
+
+ return text
+
+def svg_segment_border_inner(angle, center_hole_radius, circle_pos, circle_radius):
+ a = angle
+ a = a / 360.0 * 2.0 * np.pi
+ r1 = np.linalg.norm(np.array(circle_pos)) - circle_radius
+ vunit = np.array([np.cos(a), np.sin(a)])
+ p1 = vunit * center_hole_radius
+ p2 = vunit * r1
+ text = svg_line_puzzle(p1, p2)
+
+ return text
+
+def svg_segment_border_outer(angle, plate_pitch_radius, plate_gear_module, circle_pos, circle_radius):
+ a = angle
+ a = a / 360.0 * 2.0 * np.pi
+ vunit = np.array([np.cos(a), np.sin(a)])
+ r2 = np.linalg.norm(np.array(circle_pos)) + circle_radius
+ p3 = vunit * r2
+ r3 = plate_pitch_radius - plate_gear_module
+ p4 = vunit * r3
+ text = svg_line_puzzle(p3, p4)
+
+ return text
\ No newline at end of file