Skip to content

Commit 7d3a40b

Browse files
feat(geometry): honor IfcSweptDiskSolid StartParam/EndParam (#606)
The swept-disk solid processor read attribute 1 (Radius) but ignored attributes 3 (StartParam) and 4 (EndParam) entirely. Files where the directrix is an IfcCompositeCurve or IfcPolyline and the trim params restrict the sweep to a sub-range of the curve rendered the whole curve instead — most visibly in rebar models from Revit/Tekla, where a 2 m bar declared as IFCSWEPTDISKSOLID(#dir, r, $, 0., 1.) over a 3-segment composite curve rendered as 12 m with all the end-hooks unfolded into the bar. Dispatch now honors trim parameters for the two directrix types whose IFC parameterisation is unambiguous from the entity: - IfcCompositeCurve (and subtypes via is_subtype_of): segment- index based, each segment contributes 1.0 to the parameter. - IfcPolyline: point-index based, each segment between consecutive points contributes 1.0. Boundary segments are truncated by linear interpolation along the sampled polyline — exact for piecewise-linear input, an approximation for curved parents (acceptable for rebar). Out-of-range params clamp; inverted (start >= end) ranges return an empty mesh. Other directrix types (IfcLine, IfcCircle, IfcTrimmedCurve, IfcBSplineCurve) still ignore trim — their parameterisations are length / angle / knot-based and need separate handling — flagged as a known limitation. Adds 11 unit tests in profiles::tests covering: full-range identity, exact-half boundaries, strict-interior comparisons, two-point partial trim, fractional multi-segment trim with dedup, out-of-range clamping, inverted ranges, SameSense=F reverse-then-trim semantics, and direct- polyline-directrix paths.
1 parent cf77e6a commit 7d3a40b

3 files changed

Lines changed: 494 additions & 4 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@ifc-lite/wasm": patch
3+
---
4+
5+
Honor `IfcSweptDiskSolid.StartParam` / `EndParam` for `IfcCompositeCurve` and `IfcPolyline` directrices. Previously these were silently ignored, so a swept disk solid like `IFCSWEPTDISKSOLID(#dir, 0.0095, $, 0., 1.)` with a 3-segment composite-curve directrix swept the entire curve instead of just segment `[0,1]` — most visible in rebar models authored by Revit/Tekla, where bars rendered 3-5× their real length with end hooks unfolded into the bar geometry.
6+
7+
The dispatch now honors trim parameters for the two directrix types whose IFC parameterisation is unambiguous from the entity:
8+
9+
- `IfcCompositeCurve` (and subtypes via `is_subtype_of`): segment-index based, each segment contributes 1.0 to the parameter.
10+
- `IfcPolyline`: point-index based, each segment between consecutive points contributes 1.0.
11+
12+
Boundary segments are truncated by linear interpolation along the sampled polyline (exact for piecewise-linear input). Out-of-range params clamp; inverted ranges (`StartParam ≥ EndParam`) produce empty geometry. Other directrix types (`IfcLine`, `IfcCircle`, `IfcTrimmedCurve`, `IfcBSplineCurve`) still ignore trim — their parameterisations are length / angle / knot-based and need separate handling — flagged as a known limitation.
13+
14+
Adds 11 unit tests in `profiles::tests` covering: full-range identity, exact-half boundaries, strict-interior comparisons, two-point partial trim, fractional multi-segment trim with dedup, out-of-range clamping, inverted ranges, `SameSense=F` reverse-then-trim semantics, and direct-polyline-directrix paths.

rust/geometry/src/processors/swept.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,46 @@ impl GeometryProcessor for SweptDiskSolidProcessor {
4848
// Get inner radius if hollow
4949
let _inner_radius = entity.get_float(2);
5050

51+
// StartParam / EndParam (optional IfcParameterValue). Per IFC spec, when the
52+
// directrix is an IfcCompositeCurve the curve is parameterised so that segment
53+
// index `i` covers parameter range [i, i+1]. Without honoring these, files that
54+
// intend e.g. only the first segment to be swept render every segment — the
55+
// common rebar case where a 2 m bar reads as 12 m with hooks unfolded.
56+
let start_param = entity.get_float(3);
57+
let end_param = entity.get_float(4);
58+
5159
// Resolve the directrix curve
5260
let directrix = decoder
5361
.resolve_ref(directrix_attr)?
5462
.ok_or_else(|| Error::geometry("Failed to resolve Directrix".to_string()))?;
5563

56-
// Get points along the curve
57-
let curve_points = self
58-
.profile_processor
59-
.get_curve_points(&directrix, decoder)?;
64+
// Get points along the curve, honoring trim parameters where the directrix's
65+
// parameterisation is well-defined and obvious from the entity:
66+
// - IfcCompositeCurve (and IfcCompositeCurveOnSurface): segment-index based,
67+
// each segment contributes 1.0 to the parameter.
68+
// - IfcPolyline: point-index based, each segment between consecutive points
69+
// contributes 1.0 to the parameter.
70+
// Other directrix types (IfcLine, IfcCircle, IfcTrimmedCurve, IfcBSplineCurve)
71+
// have length-, angle-, or knot-based parameterisations and fall back to the
72+
// full sampler. Files using those with explicit StartParam/EndParam will still
73+
// render the full curve — flagged as a known limitation.
74+
let has_trim = start_param.is_some() || end_param.is_some();
75+
let curve_points = if has_trim
76+
&& directrix.ifc_type.is_subtype_of(IfcType::IfcCompositeCurve)
77+
{
78+
self.profile_processor
79+
.get_composite_curve_points_trimmed(
80+
&directrix,
81+
decoder,
82+
start_param,
83+
end_param,
84+
)?
85+
} else if has_trim && directrix.ifc_type == IfcType::IfcPolyline {
86+
self.profile_processor
87+
.get_polyline_points_trimmed(&directrix, decoder, start_param, end_param)?
88+
} else {
89+
self.profile_processor.get_curve_points(&directrix, decoder)?
90+
};
6091

6192
if curve_points.len() < 2 {
6293
return Ok(Mesh::new()); // Not enough points

0 commit comments

Comments
 (0)