Straight Rack

Straight Rack render

gears/rack/straight_rack.pyOBJECT_OT_add_rack (object.add_rack, "Add Gear Rack")

Straight involute rack — the "gear of infinite radius" that converts a mating spur/helical pinion's rotation into linear motion. See README.md for family-wide conventions, and helical_rack.md / herringbone_rack.md for the twisted variants that reuse this file's tooth-profile math.

This used to live combined with the spur gear as gears/external/involute_gear_rack.py — split out into its own rack/ subfamily alongside the helical and herringbone racks (own menu category, Mechanisms > Gears > Rack), matching the external//ring// planetary//bevel/ folder-per-subfamily shape.

Properties

Property Type Default Range Notes
targetObject pointergears with bmech_moduleMatch Target; runs sync_module_pa, and if the target has bmech_tooth_count, also updates tooth_count_rack
moduleFloat (mm)1.00.1–50.0Must match the mating gear's module
pressure_angle_degFloat (°)20.010–45
length_modeEnumTOOTH_COUNTTOOTH_COUNT / MATCH_GEARSee below
tooth_count_rackInt102–1000Used directly in TOOTH_COUNT mode; fallback in MATCH_GEAR mode if no target is set
width_mmFloat (mm)6.00.1–100 (soft)Solidify modifier depth

No bore properties — a rack has no hub to bore.

length_mode

Whenever a target is set (independent of length_mode), an additional small X shift is applied via gear_matching.rack_phase_align_x so the rack spawns with teeth-into-gaps rather than an arbitrary phase — see helical_rack.md#phase-alignment for the full derivation (it applies identically here; the shear that file adds on top doesn't change the Z=0 phase this alignment targets).

module/pressure_angle_deg are frozen in the redo panel whenever any target is set (sync_module_pa always drives both), matching the convention every other gear generator in this family follows — see README.md. tooth_count_rack is handled differently: rather than graying it out, the panel replaces it entirely with a read-only "Teeth from target: N" label when length_mode == 'MATCH_GEAR' and a target with bmech_tooth_count is set, since in that mode the property isn't meaningfully "the same field, temporarily driven" — the rack's length is a wholly different concept (spanning the target's circumference) than the manual tooth count it replaces.

Build method

Same flat-profile-plus-Solidify approach as the spur gear: build_rack_profile() tiles build_rack_tooth_profile() (straight flanks at pressure_angle_deg from vertical, with a quarter-circle root fillet of radius ROOT_FILLET_COEFF * module = 0.38 * module — the rack tooth profile is the only builder in this library that fillets the root; gear teeth elsewhere use a bare dedendum-circle arc) across X, then closes the profile with a rectangular base extending dedendum + module below the root line for a solid foundation.

build_rack_profile() deduplicates adjacent points (including the wraparound from its last point back to its first) before returning. Each tooth's own end point (x_root_right) is mathematically identical to the next tooth's start point (x_root_left) — tiling teeth by simple concatenation puts a literal duplicate vertex at every tooth-to-tooth junction. bm.faces.new() (in profile_to_mesh_object) already auto-closes the polygon loop from its last vertex back to its first, so an explicit "return to start" point at the end of the profile was also an unnecessary duplicate, not just the inter-tooth ones. Two adjacent polygon vertices at the identical XY position produce a genuine zero-area side-wall face once Solidify extrudes the profile — invisible if you only inspect the raw pre-modifier mesh (obj.data), since Solidify runs as a live, unapplied modifier here (see below) and the defect only exists in the evaluated result. Confirmed before this fix: exactly tooth_count_rack zero-area faces for any tooth count (one per junction).

Unlike the spur/helical gears, the rack's Solidify modifier ("Thickness") is never applied — it's left live on the output object. This is deliberate, not an oversight (there's no bore-hole step here that would need the modifier baked first), but it does mean any manifoldness check against obj.data directly is checking the flat, single-sided, pre-extrusion profile — not what the rack actually looks like. Check the evaluated mesh (obj.evaluated_get(depsgraph).to_mesh()) instead, the way you would for any object with a live, non-applied modifier.

Output

One object, name Rack (or Rack.001, etc.), stamped gear_matching.stamp_gear(obj, "rack", module, pressure_angle_deg) — note no tooth_count is stamped on a rack (a rack's "tooth count" isn't a meshing constraint the way a gear's is).