cleaned up code for segment output
This commit is contained in:
parent
903fbdba07
commit
6ac2c864c5
|
@ -3,176 +3,7 @@ import matplotlib.pyplot as plt
|
||||||
import math
|
import math
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
# scale in inkscape
|
from svg_utils import *
|
||||||
# 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 = [' <circle\n',
|
|
||||||
' id="circle{}"\n'.format(id),
|
|
||||||
' inkscape:label="{}"\n'.format(name),
|
|
||||||
' style="fill:none;stroke:#000000;stroke-width:0.1mm"\n',
|
|
||||||
' r="{}mm"\n'.format(r),
|
|
||||||
' cy="{}mm"\n'.format(c[1]),
|
|
||||||
' cx="{}mm" />\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 = [' <path \n '
|
|
||||||
' id="path666" \n '
|
|
||||||
' style="fill:none;stroke:#ff0000;stroke-width:1.60000002" \n'
|
|
||||||
' d="M {} {} L {} {} A {} {} 0 1 0 {} {} L {} {}"'
|
|
||||||
' />\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 = [' <path \n '
|
|
||||||
' id="path666" \n '
|
|
||||||
' style="fill:none;stroke:#000000;stroke-width:{}mm" \n'
|
|
||||||
' d="M {} {} L {} {} L {} {} A {} {} 0 1 1 {} {} L {} {} L {} {}"'
|
|
||||||
' />\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 = [' <path \n '
|
|
||||||
' id="path666" \n '
|
|
||||||
' style="fill:none;stroke:#000000;stroke-width:0.60000002" \n'
|
|
||||||
' d="M {} {} A {} {} 0 {} {} {} {}"'
|
|
||||||
' />\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 = [' <path \n '
|
|
||||||
' id="path666" \n '
|
|
||||||
' style="fill:none;stroke:#000000;stroke-width:0.60000002" \n'
|
|
||||||
' d="M {} {} A {} {} 0 {} {} {} {}"'
|
|
||||||
' />\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 = ['<g transform="rotate({})">\n '
|
|
||||||
'<rect x="{}mm" y="{}mm" width="{}mm" height="{}mm" style="fill:none;stroke-width:0.1mm;stroke:rgb(0,0,0)" />\n '
|
|
||||||
'</g>\n'
|
|
||||||
.format(angle, x, y ,width, heigth)]
|
|
||||||
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
def svg_line(p1, p2, width=1.0):
|
|
||||||
text = ['<line x1="{}mm" y1="{}mm" x2="{}mm" y2="{}mm" style="stroke:rgb(0,0,0);stroke-width:{}mm" />'.format(p1[0], p1[1], p2[0], p2[1], width)]
|
|
||||||
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
# this function reads and processes data for optimal circle packaging obtained form packomania.com
|
# 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])
|
f_lines.remove(f_lines[-1])
|
||||||
|
|
||||||
# output plate as svg
|
# output plate as svg
|
||||||
text = svg_circle(0, 'plate', (0,0), self.target_plate_radius)
|
# text = svg_circle(0, 'plate', (0,0), self.target_plate_radius)
|
||||||
f_lines = f_lines + text
|
# f_lines = f_lines + text
|
||||||
|
|
||||||
output_all = False
|
output_all = False
|
||||||
if output_all:
|
if output_all:
|
||||||
|
@ -586,8 +417,8 @@ class PlateLayout:
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def output_segment(self, f_lines, k):
|
|
||||||
|
|
||||||
|
def output_segment(self, f_lines, k):
|
||||||
# k = which segment?
|
# k = which segment?
|
||||||
k_next = (k + 1) % self.N
|
k_next = (k + 1) % self.N
|
||||||
|
|
||||||
|
@ -602,102 +433,44 @@ class PlateLayout:
|
||||||
vunit2 = np.array([np.cos(a2), np.sin(a2)])
|
vunit2 = np.array([np.cos(a2), np.sin(a2)])
|
||||||
p2 = vunit2 * self.target_center_hole_radius
|
p2 = vunit2 * self.target_center_hole_radius
|
||||||
|
|
||||||
text = svg_arc(p1, p2, self.target_center_hole_radius, 0, 1)
|
f_lines += svg_arc(p1, p2, self.target_center_hole_radius, 0, 1)
|
||||||
f_lines = f_lines + text
|
|
||||||
|
|
||||||
|
|
||||||
# big circles arcs
|
# big circles arcs
|
||||||
c = self.tube_1_coords[k]
|
f_lines += svg_half_circle(k, 'big circle', self.tube_1_coords[k], self.target_radius_1, self.tube_1_angles[k])
|
||||||
angle = self.tube_1_angles[k]
|
f_lines += svg_half_circle(k_next, 'big circle', self.tube_1_coords[k_next], self.target_radius_1,
|
||||||
text = svg_half_circle(k, 'big circle', c, self.target_radius_1, angle)
|
self.tube_1_angles[k_next], orientation_flag=0)
|
||||||
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
|
|
||||||
|
|
||||||
# small circle
|
# small circle
|
||||||
c = self.tube_2_coords[k]
|
f_lines += svg_circle(k, 'small circle', self.tube_2_coords[k], self.target_radius_2)
|
||||||
text = svg_circle(k, 'small circle', c, self.target_radius_2)
|
|
||||||
f_lines = f_lines + text
|
|
||||||
|
|
||||||
# gear pos for big circle
|
# gear pos for big circle
|
||||||
c = self.tube_1_tangents[k_next]
|
f_lines += svg_gear_marking(self.tube_1_tangents[k_next], self.tube_1_coords[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)
|
|
||||||
|
|
||||||
marking_length = 5.0
|
# cutout rectangle for big circles
|
||||||
|
f_lines += svg_rectangle(k_next, 'cut', self.tube_1_cuts[k_next])
|
||||||
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
|
|
||||||
|
|
||||||
# gear pos for small circle
|
# gear pos for small circle
|
||||||
c = self.tube_2_tangents[k]
|
f_lines += svg_gear_marking(self.tube_2_tangents[k], self.tube_2_coords[k])
|
||||||
circle_midpoint = self.tube_2_coords[k]
|
|
||||||
v = np.array(c[0]) - np.array(circle_midpoint)
|
|
||||||
v = v/np.linalg.norm(v)
|
|
||||||
|
|
||||||
marking_length = 5.0
|
# cutout rectangle for small circles
|
||||||
|
f_lines += svg_rectangle(k, 'cut', self.tube_2_cuts[k])
|
||||||
|
|
||||||
p1 = c[0]
|
# first segment border
|
||||||
p2 = c[0] + v * marking_length
|
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)
|
# second segment border
|
||||||
f_lines = f_lines + text
|
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
|
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
|
a1 = (self.tube_1_angles[k] - 0.9) / 360.0 * 2.0 * np.pi
|
||||||
vunit1 = np.array([np.cos(a1), np.sin(a1)])
|
vunit1 = np.array([np.cos(a1), np.sin(a1)])
|
||||||
|
@ -726,6 +499,7 @@ class PlateLayout:
|
||||||
coordinates.append(c_running)
|
coordinates.append(c_running)
|
||||||
pass
|
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_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]
|
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]
|
coordinates = coordinates[min_dist_index_1:min_dist_index_2+1]
|
||||||
else:
|
else:
|
||||||
coordinates = coordinates[min_dist_index_1:] + coordinates[0:min_dist_index_2]
|
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])
|
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:]
|
gear_data_new = gear_data[0:index_start] + "M " + coordinates_data_raw_new + gear_data[index_end+1:]
|
||||||
f_lines[j] = gear_data_new
|
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
|
return f_lines
|
||||||
|
|
||||||
def output_whole(self, f_lines):
|
def output_whole(self, f_lines):
|
||||||
|
|
222
prototype/svg_utils.py
Normal file
222
prototype/svg_utils.py
Normal file
|
@ -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 = [' <circle\n',
|
||||||
|
' id="circle{}"\n'.format(id),
|
||||||
|
' inkscape:label="{}"\n'.format(name),
|
||||||
|
' style="fill:none;stroke:#000000;stroke-width:0.1mm"\n',
|
||||||
|
' r="{}mm"\n'.format(r),
|
||||||
|
' cy="{}mm"\n'.format(c[1]),
|
||||||
|
' cx="{}mm" />\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 = [' <path \n '
|
||||||
|
' id="path666" \n '
|
||||||
|
' style="fill:none;stroke:#ff0000;stroke-width:1.60000002" \n'
|
||||||
|
' d="M {} {} L {} {} A {} {} 0 1 0 {} {} L {} {}"'
|
||||||
|
' />\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 = [' <path \n '
|
||||||
|
' id="path666" \n '
|
||||||
|
' style="fill:none;stroke:#000000;stroke-width:{}mm" \n'
|
||||||
|
' d="M {} {} L {} {} L {} {} A {} {} 0 1 1 {} {} L {} {} L {} {}"'
|
||||||
|
' />\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 = [' <path \n '
|
||||||
|
' id="path666" \n '
|
||||||
|
' style="fill:none;stroke:#000000;stroke-width:0.60000002" \n'
|
||||||
|
' d="M {} {} A {} {} 0 {} {} {} {}"'
|
||||||
|
' />\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 = [' <path \n '
|
||||||
|
' id="path666" \n '
|
||||||
|
' style="fill:none;stroke:#000000;stroke-width:0.60000002" \n'
|
||||||
|
' d="M {} {} A {} {} 0 {} {} {} {}"'
|
||||||
|
' />\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 = ['<g transform="rotate({})">\n '
|
||||||
|
'<rect x="{}mm" y="{}mm" width="{}mm" height="{}mm" style="fill:none;stroke-width:0.1mm;stroke:rgb(0,0,0)" />\n '
|
||||||
|
'</g>\n'
|
||||||
|
.format(angle, x, y, width, height)]
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def svg_line(p1, p2, width=1.0):
|
||||||
|
text = ['<line x1="{}mm" y1="{}mm" x2="{}mm" y2="{}mm" style="stroke:rgb(0,0,0);stroke-width:{}mm" />'.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
|
Loading…
Reference in New Issue
Block a user