--- jupyter: description: 'An open-end spanner as a 2D CAD exercise: a dimensioned drawing to model in planex2d or any CAD system, a solution from Boolean operations on a disc and two slots, with fillets at chosen corners, and the area and centroid to check a model against.' --- # Open-end spanner An open-end spanner turns a nut of 13 across its flats. Its jaw is turned 15° to the handle, so that the spanner, turned over, reaches the nut again in a tight space after a turn of 30°. As faces, the spanner is a head and a handle united, less the jaw and a hole to hang it by, with fillets where the handle meets the head. Model the spanner from the drawing in planex2d or in any CAD system, then check its area and centroid against the values at the end of the page. A solution in planex2d follows. ![The open-end spanner exercise: a dimensioned drawing of a spanner with a round head, a jaw at 15 degrees to the handle and a hole at the handle's end](../_static/gallery/open-end-spanner.png){.result} ```python import math import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row ``` ## The head and the handle The head is a disc of radius 16 around the jaw's center, the origin. The handle is a `Slot` 110 long between the centers of its ends and 14 wide, from the origin along x, so that its far end is rounded with a radius of 7. `px.Unify` unites the two into one region (Figure 1): ```python head = px.Circle((0, 0), 16).Face() handle = px.QuickSketch().Slot(110, 14).Face() body = px.Unify([head, handle]) ``` ```python nbsphinx="hide-input" Row((px.Compound([head, handle]), "The head and the handle", {"fill": False}), (body, "United"), caption="The head and the handle") ``` ## The jaw and the hole The jaw is a slot 13 wide, the nut's width across its flats, from the jaw's center out through the head, turned 15° from the handle's axis. It points along 180° + 15°, and its round end at the center makes the bottom of the jaw. The hole to hang the spanner by, 6 across, is at the center of the handle's end. Both are subtracted with `-` (Figure 2): ```python t = math.radians(180 + 15) jaw = px.QuickSketch().Move((0, 0), dir=(math.cos(t), math.sin(t))).Slot(30, 13).Face() hole = px.Circle((110, 0), 6 / 2).Face() spanner = (body - jaw - hole).Face() # the one face of what is left ``` ```python nbsphinx="hide-input" Row((px.Compound([body, jaw, hole]), "The jaw and the hole on the body", {"fill": False}), (spanner, "Subtracted"), caption="The jaw and the hole") ``` ## The fillets The corners where the handle's edges meet the head are rounded with a radius of 8. `vertices(near=)` picks the corner nearest to a point, so the two are given roughly, and `Fillet` rounds just these two (Figure 3): ```python corners = [spanner.vertices(near=(15, 7)), spanner.vertices(near=(15, -7))] spanner.Fillet(corners, 8); ``` ```python nbsphinx="hide-input" Row((spanner, "The spanner with its two fillets", {}), caption="The fillets") ``` ## The checks These are the area and the centroid of the spanner, with the jaw's center at the origin and the handle along x, to compare with your own model (Figure 4): ```python c = spanner.center print("area", round(spanner.mass, 2), "mm²") print("centroid", tuple(round(v, 2) for v in c[:2])) ``` ```python nbsphinx="hide-input" Row((spanner, "The spanner, its centroid marked", {"marks": [c[:2]]}), caption="The spanner") ``` The spanner as DXF in millimeters, for another CAD system or a laser cutter: ```python spanner.WriteDXF("open_end_spanner.dxf", unit=px.mm, scale=1) # scale=1: the numbers as they are ``` The spanner as DXF: [open_end_spanner.dxf](open_end_spanner.dxf) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt from drawings import SheetFigure, View from gallery import save_figure # the face's outline, its sizes drawn from the operations: the jaw's axis along d, its width across it d = (math.cos(t), math.sin(t)) n = (-d[1], d[0]) fx = math.sqrt((16 + 8) ** 2 - (7 + 8) ** 2) # the fillets' centers, 8 from the head and from the handle's edges view = View([], lines=list(spanner.Polylines(1e-3)), axes=[((-24, 0), (120, 0), (0, 0)), ((0, -20), (0, 20), (0, 0)), ((110, -10), (110, 10), (110, 0)), ((-6 * d[0], -6 * d[1]), (30 * d[0], 30 * d[1]))], radii=[((0, 0), 16, (100, "outside")), ((110, 0), 7, (45, "outside")), ((fx, 15), 8, (245, "inside")), ((fx, -15), 8, (115, "inside"))], diameters=[((110, 0), 3, (315, "leader"))], angles=[((0, 0), (-1, 0), d, 36, 15, (24, 30))], measures=[((0, 0), (110, 0), -24, 110), ((60, -7), (60, 7), 60, 14), ((12 * d[0] - 6.5 * n[0], 12 * d[1] - 6.5 * n[1]), (12 * d[0] + 6.5 * n[0], 12 * d[1] + 6.5 * n[1]), (26 * d[0], 26 * d[1]), 13)]) drawing = SheetFigure([view], margin=22, notes=("planex2d.org", "2D exercise 16")) print("scale", drawing.planex_scale, "| paper", [round(v * 25.4) for v in drawing.get_size_inches()], "mm") save_figure(drawing, "open-end-spanner", dpi=200) plt.close(drawing) ```