Read a one-loop region's profile from its exact edges

A region keeps one display wire per edge, so a region of several edges
gave no polygon and could not be extruded (solid or surface), and a
circle region was extruded from its display polygon. Profiles of a region
with one boundary loop now come from the region's modeler edges.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-09 18:17:57 +03:00
1 parent 2192baba02
commit 8fc4f42a4d
1 file changed
+24 -5
+24 -5
View File
@@ -32,6 +32,9 @@ pub struct Profile {
/// is handed over as the arcs it is made of rather than as one curve with
/// nowhere for the sweep to start.
pub fn profile_of(entity: &EntityType) -> Option<Profile> {
if let Some(profile) = region_loop(entity) {
return (profile.pieces.len() >= 3).then_some(profile);
}
let planar = entity_curve(entity).or_else(|| planar_polygon_entity(entity))?;
if !planar.curve.is_closed() {
return None;
@@ -46,6 +49,9 @@ pub fn profile_of(entity: &EntityType) -> Option<Profile> {
/// An entity-level planar curve suitable for either a solid profile or an
/// open surface profile.
pub fn extrusion_profile_of(entity: &EntityType) -> Option<(Profile, bool)> {
if let Some(profile) = region_loop(entity) {
return Some((profile, true));
}
let planar = entity_curve(entity).or_else(|| planar_polygon_entity(entity))?;
let closed = planar.curve.is_closed();
let pieces = profile_pieces(&planar.curve, closed)?;
@@ -58,6 +64,22 @@ pub fn extrusion_profile_of(entity: &EntityType) -> Option<(Profile, bool)> {
))
}
/// A region of one boundary loop as that loop, read from the region's exact
/// edges (its display wires hold one wire per edge), a lone closed edge split
/// as a closed curve is.
fn region_loop(entity: &EntityType) -> Option<Profile> {
let EntityType::Region(_) = entity else { return None };
let (plane, loops, _) = super::presspull_model::profile_geometry(entity)?;
let [boundary] = loops.as_slice() else { return None };
let single = boundary.len() == 1;
let pieces = boundary
.iter()
.map(|piece| profile_pieces(piece, single))
.collect::<Option<Vec<_>>>()?
.concat();
Some(Profile { plane, pieces })
}
fn profile_pieces(curve: &Curve, closed: bool) -> Option<Vec<Curve>> {
let pieces = match curve {
Curve::Polyline(_) => curve.segments(),
@@ -291,11 +313,8 @@ pub fn extruded_surface(
direction: [f64; 3],
taper_angle: f64,
) -> Option<Body> {
// A region's surface is its one boundary loop, read from its exact edges.
if let EntityType::Region(_) = entity {
let (plane, loops, _) = super::presspull_model::profile_geometry(entity)?;
let [boundary] = loops.as_slice() else { return None };
return brep::extrude_surface_tapered(plane, boundary, direction, taper_angle);
if matches!(entity, EntityType::Region(region) if region.wires.len() > 1) {
return None;
}
let (profile, _) = extrusion_profile_of(entity)?;
brep::extrude_surface_tapered(