--- jupyter: description: 'A fork lever as a 3D CAD exercise: a dimensioned drawing with a section through its middle plane to model in planex2d or any CAD system, a solution with bosses on both faces and a slot pocketed partway into the thickness, and the volume, mass and center of mass to check a model against.' --- # Fork lever A fork lever turns on a shaft through its hub and drives a link held in the fork at its other end by a pin. The fork is a slot through the middle of the lever's thickness, cut in from the end and stopped by an arc around the hub, so it is a pocket that does not go through the part. Model the lever from the drawing in planex2d or in any CAD system, then check its volume, mass and center of mass against the values at the end of the page. A solution in planex2d follows. ![The fork lever exercise: a dimensioned drawing of a lever with a hub boss on both faces, a slot through the middle of its thickness and a pin hole, in a front view, a section through its middle plane and an isometric](../_static/gallery/fork-lever.png){.result} ```python import math import netgen.occ as occ import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row, Views ``` ## The outline The outline is the lever's plan, sketched in the xy plane, which becomes the middle plane of its thickness. It is one chain from the bottom of the hub, a line, a half circle around the eye, a line back and a half circle around the hub. With `auto_constraint=True`, each joint of the chain becomes a tangency. The chain's two ends meet at the start, where a coincidence and a tangency close it. The hub's center is the origin, the eye's center lies on the horizontal axis 100 away, and the radii complete the sketch (Figure 1): ```python lever = px.Sketch(auto_constraint=True) lever.Move((0, -22), dir=(1, 0)).Line(100, id="lower").Arc(16, 180, id="eye").Line(100, id="upper").Arc(22, 180, id="hub") lever.Constrain("hub.end", "lower.start", px.Coincident) lever.Constrain("hub", "lower", px.Tangent) lever.Constrain("hub.center", "origin", px.Coincident) lever.Constrain("eye.center", "H", px.Coincident) lever.Constrain("hub.center", "eye.center", px.Distance, 100, id="length") lever.Constrain("hub", px.Radius, 22, id="hub_r") lever.Constrain("eye", px.Radius, 16, id="eye_r") print("status", lever.status, "| degrees of freedom", lever.dof) ``` ```python nbsphinx="hide-input" Row((lever, "Every dimension and tie of the outline", {"constraints": True}), caption="The outline") ``` ## The lever `px.Pad` extrudes the outline 12 to both sides of the xy plane, 24 in all, so that the plane lies in the middle of the thickness (Figure 2): ```python block = px.Pad(lever, 12, length2=12) ``` ```python nbsphinx="hide-input" Views(("The outline padded 24 thick", [(block, "shade"), (block, "ink")]), angles=(-60, 0, 30), caption="The lever") ``` ## The hub The hub stands 4 proud of both faces. A boss of 44, the hub's own diameter, is sketched on the top face, the face highest in $z$, and another on the bottom face, lowest in $z$. Each is padded 4 out of its face, along the face's normal, and fused with `+`. The bore of 20 is sketched on the top boss and cut through everything with `until=px.last` (Figure 3): ```python for face in (block.faces.Max(occ.Z), block.faces.Min(occ.Z)): boss = px.Sketch(face) boss.Circle(44 / 2, id="boss") boss.Constrain("boss.center", "origin", px.Coincident) boss.Constrain("boss", px.Diameter, 44, id="boss_d") block = block + px.Pad(boss, 4) bore = px.Sketch(block.faces.Max(occ.Z)) bore.Circle(20 / 2, id="bore") bore.Constrain("bore.center", "origin", px.Coincident) bore.Constrain("bore", px.Diameter, 20, id="bore_d") block = px.Pocket(block, bore, until=px.last) # through both bosses and the lever ``` ```python nbsphinx="hide-input" Views(("The bosses on both faces and the bore", [(block, "shade"), (block, "ink")]), angles=(-60, 0, 30), caption="The hub") ``` ## The fork The fork's slot, 12 wide, runs through the middle of the thickness from the eye's end to an arc of radius 45 around the hub. Its profile is a region in the middle plane: a rectangle over the lever's end less a disc of radius 45 around the hub, a Boolean subtraction of two faces. `px.Pocket` with `length2` cuts 6 to each side of the plane, and only where the region meets the lever (Figure 4): ```python region = px.QuickSketch().Move((0, -40)).Rectangle(140, 80).Face() - px.Face([px.Circle((0, 0), 45)]) block = px.Pocket(block, region, 6, length2=6) # 6 to each side of the middle plane: a slot 12 wide ``` ```python nbsphinx="hide-input" Row((region, "The region of the slot in the middle plane", {"dashed": [lever]}), (block, "The slot through the middle of the thickness", {"views": [(block, "shade"), (block, "ink")], "angles": (-60, 0, 60)}), caption="The fork") ``` The pin hole of 10 goes through the eye, sketched on the top face, and `until=px.last` takes it through the upper cheek, across the slot and through the lower cheek (Figure 5): ```python pin = px.Sketch(block.faces.Max(occ.Z)) pin.Circle(10 / 2, center=(100, 0), id="pin_hole") pin.Constrain("pin_hole", px.Diameter, 10, id="pin_d") pin.Constrain("pin_hole.center", "H", px.Coincident) pin.Constrain("pin_hole.center", "origin", px.Distance, 100, id="pin_at") block = px.Pocket(block, pin, until=px.last) ``` ```python nbsphinx="hide-input" Views(("The pin hole through both cheeks", [(block, "shade"), (block, "ink")]), angles=(-60, 0, 60), caption="The pin hole") ``` ## The checks These are the volume, the mass in steel S235 (7.85 g/cm³) and the center of mass, with the origin at the hub's center in the middle plane, to compare with your own model. The volume is the outline's area times 24, plus the two bosses, less the bore through 32, less the slot, and less the pin hole through the two cheeks, 12 of the thickness. The slot's area in plan is where the region and the outline overlap, their intersection `*`. The lever is symmetric about the middle plane and the plane $y = 0$, so its center of mass lies on the $x$ axis: ```python outline = lever.Face() slot = (outline * region).mass # the slot's area in plan exact = outline.mass * 24 + 2 * math.pi * 22**2 * 4 - math.pi * 10**2 * 32 - slot * 12 - math.pi * 5**2 * 12 c = block.center print("volume", round(block.mass, 1), "mm³, exact", round(exact, 1)) print("mass", round(block.mass * 7.85e-6, 3), "kg") print("center of mass", round(c.x, 2), "from the hub's axis, off the x axis by", round(math.hypot(c.y, c.z), 6)) ``` The lever as STEP, for another CAD system: ```python block.WriteStep("fork_lever.step") ``` The lever as STEP: [fork_lever.step](fork_lever.step) ```python nbsphinx="hidden" import sys sys.path.insert(0, "..") import matplotlib.pyplot as plt from drawings import Pictorial, SheetFigure, View from gallery import save_figure # the front view from the solid; below it the plan as a section through the middle plane z = 0 (the symmetry plane of # the thickness: no designation needed), the part below the plane seen from above, its cut faces hatched front = px.XZ # x to the right, z up below = block * occ.Box((-30, -30, -20), (130, 30, 0)) cut = [f for f in below.faces if abs(f.center.z) < 1e-6 and f.bounding_box[1].z - f.bounding_box[0].z < 1e-6] end = lever.Location("eye.center")[0] + lever.Measure("eye")["radius"] front_view = View([], solid=block, plane=front, axes=[((0, -20), (0, 20)), ((100, -16), (100, 16))], measures=[((-22, -12), (-22, 12), -34, 24), ((-22, -16), (-22, 16), -46, 32), ((end, -6), (end, 6), end + 10, 12), ((-22, 16), (22, 16), 26, "⌀44")]) plan = View([(lever, {"length": -32, "hub_r": (135, "outside"), "eye_r": (45, "outside")}), (bore, {"bore_d": (225, "inside")}, {}), (pin, {"pin_d": (300, "leader")}, {})], solid=below, plane=px.XY, hidden_edges=False, hatch=cut, at=(0, -70), axes=[((-28, 0), (end + 6, 0), (0, 0)), ((0, -28), (0, 28), (0, 0)), ((100, -20), (100, 20), (100, 0))], radii=[((0, 0), 45, (30, "inside"))]) pictorial = Pictorial(block, at=(80, -135), width=70, angles=(-60, 0, 30)) drawing = SheetFigure([front_view, plan, pictorial], margin=25, notes=("planex2d.org", "3D exercise 10"), first_angle=True) print("scale", drawing.planex_scale, "| paper", [round(v * 25.4) for v in drawing.get_size_inches()], "mm") save_figure(drawing, "fork-lever", dpi=200) plt.close(drawing) ```