diff --git a/prototype/circles.py b/prototype/circles.py index 7322204..186b5de 100644 --- a/prototype/circles.py +++ b/prototype/circles.py @@ -3,7 +3,17 @@ import matplotlib.pyplot as plt import math import operator -N = 5 # number of enclosed circles + +def svg_circle(id, name, c, r): + text = [' \n'.format(c[0])] + + return text # this function reads and processes data for optimal circle packaging obtained form packomania.com def read_circle_data(N): @@ -40,7 +50,6 @@ def sort_ccw(coords, center): return coords_sort - # compute the two tangential points at the circle with center c and radius r intersecting the point p def compute_tangent_points(p, c, r): b = sqrt((p[0] - c[0]) ** 2 + (p[1] - c[1]) ** 2) @@ -56,146 +65,301 @@ def compute_tangent_points(p, c, r): return (T1x, T1y), (T2x, T2y) -# read radius and center coordinates for enclosed circles -rtilde, coords = read_circle_data(N) -c = (0.0, 0.0) # center of big circle -R = 1.0 # radius of big circle +class PlateLayout: + def __init__(self, N, plate_radius): + self.N = N # number of enclosed circles + self.plate_radius = plate_radius -plt.xlim((-1, 1)) -plt.ylim((-1, 1)) -plt.gca().set_aspect('equal', 'box') + def compute_layout(self): + # read radius and center coordinates for enclosed circles + rtilde, coords = read_circle_data(self.N) -plt.ion() -plt.show() + c = (0.0, 0.0) # center of big circle + R = 1.0 # radius of big circle -for p in coords: - plt.plot(p[0], p[1], 'o') - circle = plt.Circle(p, rtilde, fill=False) - plt.gca().add_artist(circle) -circle = plt.Circle(c, R, fill=False) -plt.gca().add_artist(circle) + plt.xlim((-1, 1)) + plt.ylim((-1, 1)) + plt.gca().set_aspect('equal', 'box') -plt.plot(c[0], c[1], 'o') + plt.ion() + plt.show() -coords_2 = [] -for k in range(0, N): - p1 = coords[k] - p2 = coords[(k+1) % N] + for p in coords: + plt.plot(p[0], p[1], 'o') + circle = plt.Circle(p, rtilde, fill=False) + plt.gca().add_artist(circle) + circle = plt.Circle(c, R, fill=False) + plt.gca().add_artist(circle) - # midpoint between center of two circles - m = np.mean([p1, p2], axis=0) + plt.plot(c[0], c[1], 'o') - # vector in direction of midpoint - v = m - np.array(c) - v = v/np.linalg.norm(v) - #plt.plot(m[0], m[1], 'o') + coords_2 = [] + for k in range(0, self.N): + p1 = coords[k] + p2 = coords[(k+1) % self.N] + + # midpoint between center of two circles + m = np.mean([p1, p2], axis=0) + + # vector in direction of midpoint + v = m - np.array(c) + v = v/np.linalg.norm(v) + #plt.plot(m[0], m[1], 'o') - # optimization problem for computing position and radius for a maximal circle fitting in space between two big circles - # and being fully contained in enclosing circle - opti = casadi.Opti() + # optimization problem for computing position and radius for a maximal circle fitting in space between two big circles + # and being fully contained in enclosing circle + opti = casadi.Opti() - r = opti.variable(1) # radius of new circle - p = opti.variable(2) # center of new circle - lamb = opti.variable(1) # distance of center of new circle to center of enclosing circle + r = opti.variable(1) # radius of new circle + p = opti.variable(2) # center of new circle + lamb = opti.variable(1) # distance of center of new circle to center of enclosing circle - opti.minimize(-r) - opti.subject_to(p == c + v * lamb) - opti.subject_to((p[0] - p1[0])**2 + (p[1] - p1[1])**2 >= (rtilde + r)**2) - opti.subject_to(R == lamb + r) - opti.subject_to(r >= 0) - opti.subject_to(r <= R) + opti.minimize(-r) + opti.subject_to(p == c + v * lamb) + opti.subject_to((p[0] - p1[0])**2 + (p[1] - p1[1])**2 >= (rtilde + r)**2) + opti.subject_to(R == lamb + r) + opti.subject_to(r >= 0) + opti.subject_to(r <= R) - opti.solver('ipopt') + opti.solver('ipopt') - init_r = 0.1 - init_lamb = R - init_r - init_p = c + v * init_lamb + init_r = 0.1 + init_lamb = R - init_r + init_p = c + v * init_lamb - opti.set_initial(r, init_r) - opti.set_initial(p, init_p) - opti.set_initial(lamb, init_lamb) + opti.set_initial(r, init_r) + opti.set_initial(p, init_p) + opti.set_initial(lamb, init_lamb) - sol = opti.solve() + sol = opti.solve() - p = sol.value(p) - r = sol.value(r) - lamb = sol.value(lamb) + p = sol.value(p) + r = sol.value(r) + lamb = sol.value(lamb) - print("p = {}".format(p)) - print("r = {}".format(r)) - print("lambda = {}".format(lamb)) - print("v = {}".format(v)) + print("p = {}".format(p)) + print("r = {}".format(r)) + print("lambda = {}".format(lamb)) + print("v = {}".format(v)) - coords_2.append(p) + coords_2.append(p) - plt.plot(p[0], p[1], 'o') - circle = plt.Circle(p, r, fill=False) - plt.gca().add_artist(circle) + plt.plot(p[0], p[1], 'o') + circle = plt.Circle(p, r, fill=False) + plt.gca().add_artist(circle) + + tube1 = {} + tube2 = {} + + # postprocessing solution: + # - output radii for circles + # - output center coordinates, angle w.r.t. origin and distance from origin + outer_radius = self.plate_radius # desired plate radius in meters + tube1_radius = outer_radius * rtilde + tube2_radius = outer_radius * r + + print("\n------------------") + print("optimal values") + print("plate radius = {:6.3} m = {:6.2f} mm".format(outer_radius / 1000, outer_radius)) + print("big circles:") + print(" radius = {:6.3} m = {:6.2f} mm".format(tube1_radius / 1000, tube1_radius)) + print(" diameter = {:6.3} m = {:6.2f} mm".format(2 * tube1_radius / 1000, 2 * tube1_radius)) + print("small circles:") + print(" radius = {:6.3} m = {:6.2f} mm".format(tube2_radius, tube2_radius * 1000)) + print(" diameter = {:6.3} m = {:6.2f} mm".format(2*tube2_radius, 2*tube2_radius * 1000)) + + # compute coordinates and various measurements for fixed radii of plate and tubes + self.target_plate_radius = 155.0 + self.target_radius_1 = 50.0 + self.target_radius_2 = 20.0 + teeth = 360 + + D = 2 * self.target_plate_radius + m = D/teeth/math.pi + + print("plate radius = {:6.2f} mm".format(self.target_plate_radius)) + print("big circle radius = {:6.2f} mm".format(self.target_radius_1)) + print("small circle radius = {:6.2f} mm".format(self.target_radius_2)) + + print("number of teeth: N = {}".format(teeth)) + print("pitch diameter: D = {} mm".format(D)) + print("module: M = {} mm".format(m)) + + # plot plate + plt.figure(2) + plt.plot(0.0, 0.0, 'o') + circle = plt.Circle((0.0, 0.0), self.target_plate_radius, fill=False) + plt.gca().add_artist(circle) + plt.xlim((-self.target_plate_radius*1.1, self.target_plate_radius*1.1)) + plt.ylim((-self.target_plate_radius*1.1, self.target_plate_radius*1.1)) + plt.gca().set_aspect('equal', 'box') + + # plate coordinates + print("plate coordinates: (x,y) = ({:8.3f}, {:8.3f})".format(0.0, 0.0)) + + self.tube_1_coords = {} + self.tube_2_coords = {} + self.tube_1_tangents = {} + self.tube_1_tangent_angles = {} + self.tube_2_tangents = {} + self.tube_2_tangent_angles = {} + + print(" big circle coordinates:") + for k in range(0,self.N): + x = coords[k][0] * outer_radius + y = coords[k][1] * outer_radius + + angle = arctan2(y, x) * 360.0 / (2.0 * math.pi) + + self.tube_1_coords[k] = (x,y) + + print(" k = {}, (x,y) = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg".format(k, x, y, angle)) + + circle = plt.Circle((x,y), self.target_radius_1, fill=False) + plt.gca().add_artist(circle) + + print(" big circle tangent points: ") + for k in range(0, self.N): + x = coords[k][0] * outer_radius + y = coords[k][1] * outer_radius + + t1, t2 = compute_tangent_points((0, 0), (x, y), self.target_radius_1) + + angle1 = arctan2(t1[1], t1[0]) * 360.0 / (2.0 * math.pi) + angle2 = arctan2(t2[1], t2[0]) * 360.0 / (2.0 * math.pi) + + self.tube_1_tangents[k] = (t1, t2) + self.tube_1_tangent_angles[k] = (angle1, angle2) + + print( + " k = {}, t1 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg\n t2 = ({:8.3f}, {:8.3f}), angle " + "= {:8.3f} deg".format(k, t1[0], t1[1], angle1, t2[0], t2[1], angle2)) + + plt.plot(t1[0], t1[1], 'o') + plt.plot(t2[0], t2[1], 'o') -# postprocessing solution: -# - output radii for circles -# - output center coordinates, angle w.r.t. origin and distance from origin -outer_radius = 0.15 # desired plate radius in meters -tube1_radius = outer_radius * rtilde -tube2_radius = outer_radius * r + print(" small circle coordinates:") + for k in range(0,self.N): + x = coords_2[k][0] * outer_radius + y = coords_2[k][1] * outer_radius -print("\n------------------") -print("plate radius = {:6.3} m = {:6.2f} mm".format(outer_radius, outer_radius * 1000)) -print("big circles:") -print(" radius = {:6.3} m = {:6.2f} mm".format(tube1_radius, tube1_radius * 1000)) -print(" diameter = {:6.3} m = {:6.2f} mm".format(2*tube1_radius, 2*tube1_radius * 1000)) -print(" coordinates:") -for k in range(0,N): - x = coords[k][0] * 1000 - y = coords[k][1] * 1000 + angle = arctan2(y, x) * 360.0 / (2.0 * math.pi) - t1, t2 = compute_tangent_points((0,0),(x,y), rtilde * 1000) - plt.plot(t1[0] / 1000, t1[1] / 1000, 'o') - plt.plot(t2[0] / 1000, t2[1] / 1000, 'o') + self.tube_2_coords[k] = (x, y) - angle = arctan2(y,x) * 360.0 / (2.0 * math.pi) - dist = (x**2 + y**2)**0.5 + print(" k = {}, (x,y) = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg".format(k, x, y, angle)) - angle_t1 = arctan2(t1[1], t1[0]) * 360.0 / (2.0 * math.pi) - dist_t1 = (t1[0] ** 2 + t1[1] ** 2) ** 0.5 + circle = plt.Circle((x, y), self.target_radius_2, fill=False) + plt.gca().add_artist(circle) - angle_t2 = arctan2(t2[1], t2[0]) * 360.0 / (2.0 * math.pi) - dist_t2 = (t2[0] ** 2 + t2[1] ** 2) ** 0.5 - print(" k = {}, (x,y) = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(k, x, y, angle, dist)) - print(" t1 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t1[0], t1[1], angle_t1, - dist_t1)) - print(" t2 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t2[0], t2[1], angle_t2, - dist_t2)) -print("\n") + print(" small circle tangent points: ") + for k in range(0, self.N): + x = coords_2[k][0] * outer_radius + y = coords_2[k][1] * outer_radius -print("small circles:") -print(" radius = {:6.3} m = {:6.2f} mm".format(tube2_radius, tube2_radius * 1000)) -print(" diameter = {:6.3} m = {:6.2f} mm".format(2*tube2_radius, 2*tube2_radius * 1000)) -print(" coordinates:") -for k in range(0,N): - x = coords_2[k][0] * 1000 - y = coords_2[k][1] * 1000 + t1, t2 = compute_tangent_points((0, 0), (x, y), self.target_radius_2) + angle1 = arctan2(t1[1], t1[0]) * 360.0 / (2.0 * math.pi) + angle2 = arctan2(t2[1], t2[0]) * 360.0 / (2.0 * math.pi) + self.tube_2_tangents[k] = (t1, t2) + self.tube_2_tangent_angles[k] = (angle1, angle2) - t1, t2 = compute_tangent_points((0, 0), (x, y), r * 1000) - plt.plot(t1[0] / 1000, t1[1] / 1000, 'o') - plt.plot(t2[0] / 1000, t2[1] / 1000, 'o') + print(" k = {}, t1 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg\n t2 = ({:8.3f}, {:8.3f}), angle " + "= {:8.3f} deg".format(k, t1[0], t1[1], angle1, t2[0], t2[1], angle2)) - angle = arctan2(y, x) * 360.0 / (2.0 * math.pi) - dist = (x ** 2 + y ** 2) ** 0.5 + plt.plot(t1[0], t1[1], 'o') + plt.plot(t2[0], t2[1], 'o') - angle_t1 = arctan2(t1[1], t1[0]) * 360.0 / (2.0 * math.pi) - dist_t1 = (t1[0] ** 2 + t1[1] ** 2) ** 0.5 + # for k in range(0, self.N): + # + # t1, t2 = compute_tangent_points((0,0),(x,y), target_radius_1) + # self.tube_1_tangents[k] = (t1, t2) + # + # plt.plot(t1[0] / 1000, t1[1] / 1000, 'o') + # plt.plot(t2[0] / 1000, t2[1] / 1000, 'o') + # + # angle = arctan2(y,x) * 360.0 / (2.0 * math.pi) + # dist = (x**2 + y**2)**0.5 + # + # angle_t1 = arctan2(t1[1], t1[0]) * 360.0 / (2.0 * math.pi) + # dist_t1 = (t1[0] ** 2 + t1[1] ** 2) ** 0.5 + # + # angle_t2 = arctan2(t2[1], t2[0]) * 360.0 / (2.0 * math.pi) + # dist_t2 = (t2[0] ** 2 + t2[1] ** 2) ** 0.5 + # print(" k = {}, (x,y) = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(k, x, y, angle, dist)) + # print(" t1 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t1[0], t1[1], angle_t1, + # dist_t1)) + # print(" t2 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t2[0], t2[1], angle_t2, + # dist_t2)) + # print("\n") + # tube1['coords'] = tube_1_coords + # tube1['tangents'] = tube_1_tangents + # + # tube_2_coords = {} + # tube_2_tangents = {} + # print(" coordinates:") + # for k in range(0,self.N): + # x = coords_2[k][0] * 1000 + # y = coords_2[k][1] * 1000 + # + # tube_2_coords[k] = (x, y) + # + # t1, t2 = compute_tangent_points((0, 0), (x, y), r * 100) + # tube_2_tangents[k] = (t1, t2) + # plt.plot(t1[0] / 1000, t1[1] / 1000, 'o') + # plt.plot(t2[0] / 1000, t2[1] / 1000, 'o') + # + # angle = arctan2(y, x) * 360.0 / (2.0 * math.pi) + # dist = (x ** 2 + y ** 2) ** 0.5 + # + # angle_t1 = arctan2(t1[1], t1[0]) * 360.0 / (2.0 * math.pi) + # dist_t1 = (t1[0] ** 2 + t1[1] ** 2) ** 0.5 + # + # angle_t2 = arctan2(t2[1], t2[0]) * 360.0 / (2.0 * math.pi) + # dist_t2 = (t2[0] ** 2 + t2[1] ** 2) ** 0.5 + # print(" k = {}, (x,y) = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(k, x, y, angle, dist)) + # print(" t1 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t1[0], t1[1], angle_t1, + # dist_t1)) + # print(" t2 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t2[0], t2[1], angle_t2, + # dist_t2)) + # tube2['coords'] = tube_2_coords + # tube2['tangents'] = tube_2_tangents + # + # return tube1, tube2 - angle_t2 = arctan2(t2[1], t2[0]) * 360.0 / (2.0 * math.pi) - dist_t2 = (t2[0] ** 2 + t2[1] ** 2) ** 0.5 - print(" k = {}, (x,y) = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(k, x, y, angle, dist)) - print(" t1 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t1[0], t1[1], angle_t1, - dist_t1)) - print(" t2 = ({:8.3f}, {:8.3f}), angle = {:8.3f} deg, dist = {:8.3f} mm".format(t2[0], t2[1], angle_t2, - dist_t2)) + """ + input: file = svg with plate gear centered at (0,0) + """ + def generate_svg(self, file): + f = open(file) + f_lines = f.readlines() + f.close() -pass \ No newline at end of file + 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 + + # output big circles as svg + for k, c in self.tube_1_coords.items(): + text = svg_circle(k, 'big circle', c, self.target_radius_1) + f_lines = f_lines + text + pass + + # output small circles as svg + for k, c in self.tube_2_coords.items(): + text = svg_circle(k, 'small circle', c, self.target_radius_2) + f_lines = f_lines + text + pass + + f_lines.append('\n') + + fw = open('output.svg', 'w') + fw.writelines(f_lines) + fw.close() + + pass