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, placement=0.5): # 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 = (1.0 - placement) * start + placement * 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, puzzle_scale=1.0, placement=0.5): 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, puzzle_scale=puzzle_scale, placement=placement) return text def svg_segment_border_outer(angle, plate_pitch_radius, plate_gear_module, circle_pos, circle_radius, puzzle_scale=1.0, placement=0.5): 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, puzzle_scale=puzzle_scale, placement=placement) return text