"""Countersink for a metric countersunk head screw (head to ISO 7721), as a solid to cut with: ISO 15065's 90 degree countersink over its clearance hole. Axis along Z, the top face on the XY plane: the cone from the countersink diameter Dc at the top down to the hole d_h, then the hole running down to the depth. Dimensions in the README.""" from steve import Model thread = "M3" # Thread (ISO 15065 nominal size) depth = 10 # mm Depth of the hole, from the top face # thread: (hole d_h min. (nom.), d_h max., countersink Dc min. (nom.), Dc max., depth t approx.) in mm. ISO 15065:2005, Clause 3, Table 1, # "Dimensions of countersink" (official preview p. 2, https://cdn.standards.iteh.ai/samples/37365/57c8c6dac6864ac5a6f7bfa6fdd06111/ISO-15065-2005.pdf). # d_h is ISO 273's medium series clearance hole, tolerance H13 (the table's footnote a). COUNTERSINKS = { "M1.6": (1.80, 1.94, 3.6, 3.7, 0.95), "M2": (2.40, 2.54, 4.4, 4.5, 1.05), "M2.5": (2.90, 3.04, 5.5, 5.6, 1.35), "M3": (3.40, 3.58, 6.3, 6.5, 1.55), "M3.5": (3.90, 4.08, 8.2, 8.4, 2.25), "M4": (4.50, 4.68, 9.4, 9.6, 2.55), "M5": (5.50, 5.68, 10.40, 10.65, 2.58), "M6": (6.60, 6.82, 12.60, 12.85, 3.13), "M8": (9.00, 9.22, 17.30, 17.55, 4.28), "M10": (11.00, 11.27, 20.0, 20.3, 4.65), } # The countersink angle, ISO 15065:2005 Figure 1: 90 degrees (+-1). ANGLE = 90 if thread not in COUNTERSINKS: raise ValueError(f"no ISO 15065 countersink for {thread!r}: {', '.join(COUNTERSINKS)}") d_h, _d_h_max, d_c, _d_c_max, _t = COUNTERSINKS[thread] cone = (d_c - d_h) / 2 # the 90 degree cone's height from Dc to d_h if depth <= cone: raise ValueError(f"the depth must be more than the countersink's {cone:g} mm") model = Model() with model.sketch("profile_sketch", on="XZ", name="Profile") as sk: sk.polyline("profile", [(0, 0), (d_c / 2, 0), (d_h / 2, -cone), (d_h / 2, -depth), (0, -depth)], closed=True) model.revolve("countersink", "profile_sketch", axis="Z", name="Countersink") result = model.result()