Hex standoff
A standoff holds a circuit board or a panel at a distance from the part below it. Its stud screws into the part, and a screw from above goes into its tapped hole. Its body is a hexagon, so that a spanner can turn it. As a solid, it is a hexagon padded into the body, the stud padded from its top and the tapped hole pocketed from its bottom. The threads are not modeled. The stud is its major diameter of 4, and the tapped hole is the tapping drill of 3.3, as CAD systems model them before a thread is added as a cosmetic feature. Model the standoff 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.

[1]:
import math
import netgen.occ as occ
import planex as px
The body
The body is sketched on the xy plane, its axis the \(z\) axis. It is a Hexagon 7 across its flats, a profile tool that keeps it regular and makes that width a dimension, hex.af. Its center is the origin, and its first side is vertical, so that two of its flats face along \(x\). px.Pad extrudes it 15 up (Figure 1):
[3]:
base = px.Sketch(auto_constraint=True)
base.Hexagon(7, center=(0.5, 0.5), id="hex") # 7 across flats, its center placed roughly
base.Constrain("hex.circle.center", "origin", px.Coincident) # the center of the hexagon's construction circle
base.Constrain("hex.Line.1", px.Vertical) # the hexagon does not turn: two flats face along x
print("status", base.status, "| degrees of freedom", base.dof)
body = px.Pad(base, 15)
status full | degrees of freedom 0
(a) The hexagon, every dimension and tie
(b) The body, padded 15
The stud
The stud, 4 across and 6 long, is sketched on the body’s top, its face highest in \(z\), around the axis, and padded 6 up from it. + fuses it with the body (Figure 2):
[5]:
stud = px.Sketch(body.faces.Max(occ.Z))
stud.Circle(4 / 2, id="stud")
stud.Constrain("stud.center", "origin", px.Coincident)
stud.Constrain("stud", px.Diameter, 4, id="stud_d")
body = body + px.Pad(stud, 6) # + fuses two solids
The tapped hole
The tapped hole, the tapping drill of 3.3 for the M4 thread, 8 deep, is sketched on the body’s bottom, its face lowest in \(z\), and pocketed 8 against the face’s normal, up into the body (Figure 3):
[7]:
hole = px.Sketch(body.faces.Min(occ.Z))
hole.Circle(3.3 / 2, id="hole")
hole.Constrain("hole.center", "origin", px.Coincident)
hole.Constrain("hole", px.Diameter, 3.3, id="hole_d")
body = px.Pocket(body, hole, 8) # 8 deep, against the face's normal: up into the body
The checks
These are the volume, the mass in brass CuZn39Pb3 (8.47 g/cm³) and the center of mass, with the origin on the axis at the bottom, to compare with your own model. The volume is the hexagon’s area, \(\sqrt{3} / 2\) times the square of its width across flats, times 15, plus the stud, less the hole. The standoff is symmetric about its axis, so its center of mass lies on it, at the height where the moments of the three parts balance:
[9]:
parts = [(math.sqrt(3) / 2 * 7**2 * 15, 15 / 2), (math.pi * 2**2 * 6, 15 + 6 / 2), (-math.pi * 1.65**2 * 8, 8 / 2)]
exact = sum(v for v, z in parts)
c = body.center
print("volume", round(body.mass, 3), "mm³, exact", round(exact, 3))
print("mass", round(body.mass * 8.47e-6 * 1000, 3), "g")
print("center of mass", round(c.z, 4), "above the bottom, exact", round(sum(v * z for v, z in parts) / exact, 4),
"| off the axis by", round(math.hypot(c.x, c.y), 6))
volume 643.503 mm³, exact 643.503
mass 5.45 g
center of mass 9.1024 above the bottom, exact 9.1024 | off the axis by 0.0
The standoff as STEP, for another CAD system:
[10]:
body.WriteStep("hex_standoff.step")
The standoff as STEP: hex_standoff.step