"""External retaining ring (circlip) for shafts of the DIN 471 pattern, shafts 10 to 34 mm, as the published FreeCAD-library models draw them. The ring lies on the XY plane (from z = 0 to its thickness s), its bore centred on the origin (the shaft's axis along Z), the lugs with their holes toward +X. Each size's outline is the reference model's own (lines and arcs, each arc by its ends and midpoint); the model is a flat plate of constant thickness. See the README for the models and authors. """ import cadquery as cq from steve import Model size = "20" # Shaft diameter d1 (mm) material = "spring-steel" # Material # mm. Measured on each reference model: its largest planar face gives the ring's plane; s is the model's extent across # it; the outline is the OCCT section at mid-thickness, every edge read exactly (line ends; each arc's ends and # midpoint), placed with the bore arc's centre at the origin and the lug holes toward +X, rounded to 1e-4 mm. # {d1: (s, [outline, hole, hole])}: a loop is x0, y0, then ("L", x, y) a line to or ("A", xm, ym, x, y) an arc through # (xm, ym) to; ("C", cx, cy, r) a circle. RINGS = { # d1 = 10: step.parts din471_retaining_ring_m10, FreeCAD-library DIN471_CLASS_A_M10RetainingRings.step; # s = 1.0, bore (d3) 9.2966, outline area 61.5094 mm^2 on the model 10: (1.0, [ [4.1213, -4.1346, ('L', 5.9421, -4.1346), ('A', 6.7601, -3.892, 7.3134, -3.2426), ('A', 7.7312, -2.0562, 7.958, -0.819), ('L', 4.5756, -0.819), ('A', -4.6483, 0.0, 4.5756, 0.819), ('L', 7.958, 0.819), ('A', 7.7312, 2.0562, 7.3134, 3.2426), ('A', 6.7601, 3.892, 5.9421, 4.1346), ('L', 4.1213, 4.1346), ('A', -6.5794, 0.0, 4.1213, -4.1346)], [('C', 5.7, 2.5, 0.75)], [('C', 5.7, -2.5, 0.75)], ]), # d1 = 12: step.parts din471_retaining_ring_m12, FreeCAD-library DIN471_CLASS_A_M12RetainingRings.step; # s = 1.0, bore (d3) 11.0, outline area 67.6073 mm^2 on the model 12: (1.0, [ [5.498, 0.15, ('L', 8.758, 0.1499), ('A', 8.6548, 1.3486, 8.3884, 2.5218), ('A', 8.1164, 2.9619, 7.661, 3.2071), ('L', 6.0001, 3.6), ('A', 5.5769, 3.8145, 5.3002, 4.2), ('A', -7.3, -0.0182, 5.3222, -4.17), ('A', 5.5945, -3.8059, 5.9999, -3.6), ('L', 7.6607, -3.2072), ('A', 8.1162, -2.962, 8.3882, -2.522), ('A', 8.6547, -1.3488, 8.758, -0.1501), ('L', 5.498, -0.15), ('A', -5.5, 0.0004, 5.498, 0.15)], [('C', 7.1199, -1.54, 0.85)], [('C', 7.1201, 1.54, 0.85)], ]), # d1 = 14: step.parts din471_retaining_ring_m14, FreeCAD-library DIN471_CLASS_A_M14RetainingRings.step; # s = 1.0, bore (d3) 12.8, outline area 94.503 mm^2 on the model 14: (1.0, [ [6.3983, 0.147, ('L', 9.8983, 0.1832), ('A', 9.745, 1.7456, 9.3466, 3.2642), ('A', 9.0738, 3.6757, 8.6374, 3.9065), ('L', 6.9988, 4.3024), ('A', 6.5247, 4.4807, 6.1987, 4.8684), ('A', -8.6, -0.0018, 6.2013, -4.864), ('A', 6.55, -4.4632, 7.0547, -4.2976), ('L', 8.6951, -3.8348), ('A', 9.1114, -3.5982, 9.3701, -3.1951), ('A', 9.7526, -1.7016, 9.8986, -0.1668), ('L', 6.3984, -0.1425), ('A', -6.4, -0.0012, 6.3983, 0.147)], [('C', 8.2005, -1.7972, 0.85)], [('C', 8.1995, 1.8028, 0.85)], ]), # d1 = 16: step.parts din471_retaining_ring_m16, FreeCAD-library DIN471_CLASS_A_M16RetainingRings.step; # s = 1.0, bore (d3) 14.7, outline area 109.0171 mm^2 on the model 16: (1.0, [ [7.9978, -4.65, ('L', 9.8012, -4.1482), ('A', 10.2219, -3.9097, 10.4815, -3.5017), ('A', 10.8904, -1.8774, 11.049, -0.21), ('L', 7.349, -0.1212), ('A', -7.35, 0.0, 7.349, 0.1212), ('L', 11.049, 0.21), ('A', 10.8904, 1.8774, 10.4815, 3.5017), ('A', 10.2219, 3.9097, 9.8012, 4.1482), ('L', 7.9978, 4.65), ('A', 7.5499, 4.7805, 7.21, 5.1), ('A', -3.0637, 8.7733, -9.55, 0.0), ('A', -3.0637, -8.7733, 7.21, -5.1), ('A', 7.5499, -4.7805, 7.9978, -4.65)], [('C', 9.15, -2.0, 0.85)], [('C', 9.15, 2.0, 0.85)], ]), # d1 = 18: step.parts din471_retaining_ring_m18, FreeCAD-library DIN471_CLASS_A_M18RetainingRings.step; # s = 1.2, bore (d3) 16.6, outline area 129.3663 mm^2 on the model 18: (1.2, [ [10.7415, -4.6379, ('A', 11.1509, -4.4136, 11.4139, -4.0278), ('A', 11.96, -2.1453, 12.1976, -0.1996), ('L', 8.2976, -0.2), ('A', -8.3, -0.0021, 8.2976, 0.2), ('L', 12.1976, 0.2004), ('A', 11.9049, 2.3991, 11.2189, 4.5084), ('L', 8.7656, 5.1751), ('A', 8.3188, 5.3776, 8.0222, 5.7682), ('A', -10.7, -0.0024, 8.0236, -5.7683), ('A', 8.3202, -5.3777, 8.7668, -5.175), ('L', 10.7415, -4.6379)], [('C', 10.1997, 2.3002, 1.0)], [('C', 10.2003, -2.2998, 1.0)], ]), # d1 = 20: step.parts din471_retaining_ring_m20, FreeCAD-library DIN471_CLASS_A_M20RetainingRings.step; # s = 1.2, bore (d3) 18.6, outline area 155.5462 mm^2 on the model 20: (1.2, [ [9.2986, -0.1602, ('A', -9.3, -0.002, 9.2986, 0.1602), ('L', 13.2986, 0.2337), ('A', 13.0287, 2.6749, 12.3145, 5.0249), ('L', 9.7099, 5.753), ('A', 9.2202, 5.9772, 8.9177, 6.4229), ('A', -11.9, -0.0023, 8.9191, -6.4229), ('A', 9.2215, -5.9771, 9.7112, -5.7529), ('L', 11.8325, -5.1593), ('A', 12.2431, -4.9295, 12.5031, -4.5374), ('A', 13.0792, -2.418, 13.2986, -0.2328), ('L', 9.2986, -0.1602)], [('C', 11.1997, 2.5002, 1.0)], [('C', 11.2002, -2.4998, 1.0)], ]), # d1 = 22: step.parts din471_retaining_ring_m22, FreeCAD-library DIN471_CLASS_A_M22RetainingRings.step; # s = 1.2, bore (d3) 20.6, outline area 186.9612 mm^2 on the model 22: (1.2, [ [10.0827, -6.8387, ('A', 10.3353, -6.5356, 10.6855, -6.3538), ('L', 12.8908, -5.7455), ('A', 13.2984, -5.5207, 13.56, -5.1357), ('A', 14.2397, -2.735, 14.4978, -0.2534), ('L', 10.2978, -0.2135), ('A', -10.3, 0.0, 10.2978, 0.2135), ('L', 14.4978, 0.2534), ('A', 14.2397, 2.735, 13.56, 5.1357), ('A', 13.2984, 5.5207, 12.8908, 5.7455), ('L', 10.6855, 6.3538), ('A', 10.3353, 6.5356, 10.0827, 6.8387), ('A', -13.1, 0.0, 10.0827, -6.8387)], [('C', 12.3, -2.75, 1.0)], [('C', 12.3, 2.75, 1.0)], ]), # d1 = 24: step.parts din471_retaining_ring_m24, FreeCAD-library DIN471_CLASS_A_M24RetainingRings.step; # s = 1.2, bore (d3) 22.1773, outline area 216.3393 mm^2 on the model 24: (1.2, [ [13.7647, -6.2178, ('A', 14.1732, -5.9964, 14.4375, -5.6144), ('A', 15.1956, -3.0094, 15.4876, -0.3121), ('L', 11.0876, -0.1561), ('A', -11.0886, 0.0, 11.0876, 0.1561), ('L', 15.4876, 0.3121), ('A', 15.1956, 3.0094, 14.4375, 5.6144), ('A', 14.1732, 5.9964, 13.7647, 6.2178), ('L', 11.7665, 6.7542), ('A', 11.2834, 6.9037, 10.9351, 7.2705), ('A', -14.0886, 0.0, 10.9351, -7.2705), ('A', 11.2834, -6.9037, 11.7665, -6.7542), ('L', 13.7647, -6.2178)], [('C', 13.25, 3.0, 1.0)], [('C', 13.25, -3.0, 1.0)], ]), # d1 = 26: step.parts din471_external_retaining_ring_m26, FreeCAD-library DIN471_CLASS_A_M26RetainingRings.step; # s = 1.2, bore (d3) 24.1999, outline area 238.6832 mm^2 on the model 26: (1.2, [ [14.8315, -6.521, ('A', 15.2313, -6.2976, 15.4897, -5.9193), ('A', 16.2952, -3.1197, 16.5989, -0.2223), ('L', 12.0989, -0.1571), ('A', -0.1051, -12.0995, -12.0999, 0.053), ('A', -0.1051, 12.2055, 12.0989, 0.2631), ('L', 16.5989, 0.3283), ('A', 16.2952, 3.2257, 15.4897, 6.0253), ('A', 15.2313, 6.4036, 14.8315, 6.627), ('L', 13.0012, 7.1502), ('A', 12.4555, 7.2829, 12.0012, 7.613), ('A', -15.1999, 0.053, 12.0012, -7.507), ('A', 12.4555, -7.1769, 13.0012, -7.0442), ('L', 14.8315, -6.521)], [('C', 14.3012, 3.253, 1.0)], [('C', 14.3012, -3.147, 1.0)], ]), # d1 = 28: step.parts din471_external_retaining_ring_m28, FreeCAD-library DIN471_CLASS_A_M28RetainingRings.step; # s = 1.5, bore (d3) 25.9, outline area 264.2574 mm^2 on the model 28: (1.5, [ [12.9483, 0.2098, ('L', 17.6484, 0.3128), ('A', 17.3269, 3.3676, 16.4807, 6.3205), ('A', 16.2118, 6.7095, 15.7942, 6.9314), ('L', 13.7322, 7.4575), ('A', 13.1852, 7.702, 12.7012, 8.055), ('A', -16.15, 0.0, 12.7012, -8.055), ('A', 13.1852, -7.702, 13.7322, -7.4575), ('L', 15.7942, -6.9314), ('A', 16.2118, -6.7095, 16.4807, -6.3205), ('A', 17.3269, -3.3676, 17.6483, -0.3128), ('L', 12.9483, -0.2098), ('A', -12.95, 0.0, 12.9483, 0.2098)], [('C', 15.2001, 3.4, 1.0)], [('C', 15.2, -3.4, 1.0)], ]), # d1 = 30: step.parts din471_retaining_ring_m30, FreeCAD-library DIN471_CLASS_A_M30RetainingRings.step; # s = 1.5, bore (d3) 27.9987, outline area 321.2757 mm^2 on the model 30: (1.5, [ [17.6469, -7.0418, ('A', 18.6243, -3.7595, 18.9966, -0.355), ('L', 13.9966, -0.276), ('A', -13.9994, 0.0, 13.9966, 0.276), ('L', 18.9966, 0.355), ('A', 18.6243, 3.7595, 17.6469, 7.0418), ('A', 17.3789, 7.4218, 16.968, 7.6394), ('L', 14.5822, 8.2553), ('A', 14.0253, 8.5855, 13.6395, 9.1054), ('A', -17.5994, 0.0, 13.6395, -9.1054), ('A', 14.0253, -8.5855, 14.5822, -8.2553), ('L', 16.968, -7.6394), ('A', 17.3789, -7.4218, 17.6469, -7.0418)], [('C', 16.3679, -3.7076, 1.0)], [('C', 16.3679, 3.7076, 1.0)], ]), # d1 = 32: step.parts din471_external_retaining_ring_m32, FreeCAD-library DIN471_CLASS_A_M32RetainingRings.step; # s = 1.5, bore (d3) 29.4739, outline area 345.7124 mm^2 on the model 32: (1.5, [ [17.85, -7.9776, ('A', 18.2554, -7.759, 18.5198, -7.382), ('A', 19.5474, -3.9212, 19.9341, -0.3318), ('L', 14.7341, -0.2904), ('A', -14.7369, 0.0, 14.7341, 0.2904), ('L', 19.9341, 0.3318), ('A', 19.5474, 3.9212, 18.5198, 7.382), ('A', 18.2554, 7.759, 17.85, 7.9776), ('L', 15.4868, 8.6115), ('A', 14.8458, 8.9745, 14.3796, 9.545), ('A', -18.4079, 0.0, 14.3796, -9.545), ('A', 14.8458, -8.9745, 15.4868, -8.6115), ('L', 17.85, -7.9776)], [('C', 17.3207, 3.9, 1.25)], [('C', 17.3207, -3.9, 1.25)], ]), # d1 = 34: step.parts din471_retaining_ring_m34, FreeCAD-library DIN471_CLASS_A_M34RetainingRings.step; # s = 1.5, bore (d3) 31.6321, outline area 381.0868 mm^2 on the model 34: (1.5, [ [21.1723, 0.4026, ('A', 20.756, 4.1973, 19.6652, 7.8556), ('A', 19.3954, 8.2368, 18.9819, 8.454), ('L', 16.6191, 9.0521), ('A', 16.0305, 9.3414, 15.5672, 9.8056), ('A', -19.6161, 0.0, 15.5672, -9.8056), ('A', 16.0305, -9.3414, 16.6191, -9.0521), ('L', 18.9819, -8.454), ('A', 19.3954, -8.2368, 19.6652, -7.8556), ('A', 20.756, -4.1973, 21.1723, -0.4026), ('L', 15.811, -0.3996), ('A', -15.8161, 0.0, 15.811, 0.3996), ('L', 21.1723, 0.4026)], [('C', 18.3, -4.1, 1.25)], [('C', 18.3, 4.1, 1.25)], ]), } MATERIALS = {"spring-steel": ("steel-c60e", "#3a3c3f"), "stainless": ("stainless-420c", "#c9ccd0")} def loop_wire(loop): if isinstance(loop[0], (tuple, list)): # ("C", cx, cy, r) _, cx, cy, r = loop[0] return cq.Wire.makeCircle(r, cq.Vector(cx, cy, 0), cq.Vector(0, 0, 1)) x, y = loop[0], loop[1] edges = [] for seg in loop[2:]: start = cq.Vector(x, y, 0) if seg[0] == "L": x, y = seg[1], seg[2] edges.append(cq.Edge.makeLine(start, cq.Vector(x, y, 0))) else: x, y = seg[3], seg[4] edges.append(cq.Edge.makeThreePointArc(start, cq.Vector(seg[1], seg[2], 0), cq.Vector(x, y, 0))) return cq.Wire.assembleEdges(edges) s, outline = RINGS[int(size)] loops = [loop_wire(loop) for loop in outline] ring = cq.Solid.extrudeLinear(cq.Face.makeFromWires(loops[0], loops[1:]), cq.Vector(0, 0, s)) material_id, colour = MATERIALS[material] model = Model() model.add("ring", cq.Workplane("XY").add(ring), name="Retaining ring") model.material(material_id, color=colour) # DIN 471: spring steel (C75S); closest library grade C60E result = model.result()