Part of #84.
Goal
Port the bevel gear math from BOSL2 and build the first solid via Route A: a stack of
closed section wires fed to ThruSectionsBuilder. This is the faithful port. It mirrors what
BOSL2 does, with no booleans.
Time-box: half a day.
Question this spike answers
Does OCCT loft a stack of ~1100-point closed section wires into a valid solid, and how slow is it?
Scope
Straight/zerol teeth only (spiral = 0), no backing, no bore, single gear.
Math to port (all pure functions, low risk)
From gears.scad:
| BOSL2 |
Line |
Notes |
bevel_pitch_angle(teeth, mate_teeth, drive_angle) |
4142 |
atan(sin S / (N_mate/N + cos S)) |
pitch_radius() |
3928 |
|
outer_radius() |
3985 |
|
_root_radius_basic() |
4069 |
|
_base_radius() |
4105 |
|
circular_pitch() / module_value() |
3744 / 3803 |
pitch-system conversions |
cone radii + face_width default |
2518-2526 |
default_face_width = min(ocone_rad/3, 10*mod) |
The 2D involute tooth profile can start from the existing implementation at
recipes/04-spur-gear/main.swift:38-48 rather than porting BOSL2's full
_gear_tooth_profile() (gears.scad:3366). The undercut, rounding and clipping machinery is
explicitly deferred (see #84).
Construction (Route A)
Port the per-slice transform stack at gears.scad:2546-2564:
scale(u) -> xrot(pitch_angle) -> back(u*pr) -> zrot(ang/sin(pitch_angle)) -> up(...)
where u = dist / ocone_rad. For each of slices+1 stations build one closed section wire
containing all teeth tooth profiles around the full circle, then:
let loft = ThruSectionsBuilder(isSolid: true, isRuled: false)
// addWire per slice
Relevant OCCTSwift API notes:
ThruSectionsBuilder(isSolid:isRuled:precision:), addWire(_:), build(), shape
checkCompatibility(_:) reorders wires to avoid twists; likely needed here
- Upstream warns that mixing closed and open profiles causes a SIGSEGV inside OCCT
(BRepFill_CompatibleWires). All our sections are closed, so keep it that way.
Acceptance criteria
Prediction on record
Route A works and gets us a picture quickly, but produces a bloated B-Rep. Recording the numbers
is the point. They are the input to the Route A vs Route B decision in #86.
Part of #84.
Goal
Port the bevel gear math from BOSL2 and build the first solid via Route A: a stack of
closed section wires fed to
ThruSectionsBuilder. This is the faithful port. It mirrors whatBOSL2 does, with no booleans.
Time-box: half a day.
Question this spike answers
Scope
Straight/zerol teeth only (
spiral = 0), no backing, no bore, single gear.Math to port (all pure functions, low risk)
From
gears.scad:bevel_pitch_angle(teeth, mate_teeth, drive_angle)atan(sin S / (N_mate/N + cos S))pitch_radius()outer_radius()_root_radius_basic()_base_radius()circular_pitch()/module_value()face_widthdefaultdefault_face_width = min(ocone_rad/3, 10*mod)The 2D involute tooth profile can start from the existing implementation at
recipes/04-spur-gear/main.swift:38-48rather than porting BOSL2's full_gear_tooth_profile()(gears.scad:3366). The undercut, rounding and clipping machinery isexplicitly deferred (see #84).
Construction (Route A)
Port the per-slice transform stack at gears.scad:2546-2564:
where
u = dist / ocone_rad. For each ofslices+1stations build one closed section wirecontaining all
teethtooth profiles around the full circle, then:Relevant OCCTSwift API notes:
ThruSectionsBuilder(isSolid:isRuled:precision:),addWire(_:),build(),shapecheckCompatibility(_:)reorders wires to avoid twists; likely needed here(
BRepFill_CompatibleWires). All our sections are closed, so keep it that way.Acceptance criteria
isValid == trueflag for downstream filleting and STEP export
Prediction on record
Route A works and gets us a picture quickly, but produces a bloated B-Rep. Recording the numbers
is the point. They are the input to the Route A vs Route B decision in #86.