diff --git a/Cargo.lock b/Cargo.lock index d7220eec9..9bd3648bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -878,7 +878,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=7d7f8dabe64cbacdeea7063d3ebde5d170f9a365#7d7f8dabe64cbacdeea7063d3ebde5d170f9a365" +source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=5a4c287236e03a23be4d5099a45b16346e9f9442#5a4c287236e03a23be4d5099a45b16346e9f9442" dependencies = [ "acadrust", "cavalier_contours", diff --git a/Cargo.toml b/Cargo.toml index e32fb16e7..1b2017efb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ rfd = "0.17" clap = { version = "4", features = ["derive"] } env_logger = "0.11" acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "a0f7d444f1607bc4b2c881060cbe7ea1014253cb", features = ["serde"] } -cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "7d7f8dabe64cbacdeea7063d3ebde5d170f9a365", features = ["acis", "offset"] } +cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "5a4c287236e03a23be4d5099a45b16346e9f9442", features = ["acis", "offset"] } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } flate2 = "1" image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] } diff --git a/src/scene/model/sweep_model.rs b/src/scene/model/sweep_model.rs index c8a7d127d..cc2738e8a 100644 --- a/src/scene/model/sweep_model.rs +++ b/src/scene/model/sweep_model.rs @@ -28,7 +28,7 @@ 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 { - let planar: PlanarCurve = entity_curve(entity)?; + let planar = entity_curve(entity).or_else(|| planar_polygon_entity(entity))?; if !planar.curve.is_closed() { return None; } @@ -156,6 +156,57 @@ fn planar_polygon_entity(entity: &EntityType) -> Option { )) } +fn region_profiles(entity: &EntityType) -> Option<(Plane, Vec>)> { + let EntityType::Region(region) = entity else { + return None; + }; + let plane = planar_polygon_entity(entity)?.plane; + let mut profiles = Vec::with_capacity(region.wires.len()); + for wire in ®ion.wires { + let mut points = wire + .points + .iter() + .map(|point| [point.x, point.y, point.z]) + .collect::>(); + if points.len() > 2 && points.first() == points.last() { + points.pop(); + } + if points.len() < 3 { + return None; + } + let scale = points + .iter() + .flatten() + .map(|value| value.abs()) + .fold(1.0_f64, f64::max); + if points + .iter() + .any(|point| !plane.contains(*point, scale * 1e-9)) + { + return None; + } + let vertices = points + .iter() + .map(|point| { + plane + .project(*point) + .map(|position| cadkernel::geom2d::PolylineVertex { + position, + bulge: 0.0, + }) + }) + .collect::>>()?; + profiles.push( + Curve::Polyline(cadkernel::geom2d::Polyline { + vertices, + closed: true, + }) + .segments(), + ); + } + (!profiles.is_empty()).then_some((plane, profiles)) +} + /// A circle as four arcs. fn quarters(centre: [f64; 2], radius: f64) -> Vec { use std::f64::consts::FRAC_PI_2; @@ -219,6 +270,14 @@ pub fn extruded_direction( direction: [f64; 3], taper_angle: f64, ) -> Option { + if let Some((plane, profiles)) = + region_profiles(entity).filter(|(_, profiles)| profiles.len() > 1) + { + if taper_angle.abs() > 1e-12 { + return None; + } + return brep::extrude_region(plane, &profiles, direction); + } let profile = profile_of(entity)?; brep::extrude_tapered(profile.plane, &profile.pieces, direction, taper_angle) } @@ -228,8 +287,10 @@ pub fn extruded_surface( direction: [f64; 3], taper_angle: f64, ) -> Option { - let (profile, closed) = extrusion_profile_of(entity)?; - let _ = closed; + if matches!(entity, EntityType::Region(region) if region.wires.len() > 1) { + return None; + } + let (profile, _) = extrusion_profile_of(entity)?; brep::extrude_surface_tapered( profile.plane, &profile.pieces, @@ -243,6 +304,12 @@ pub fn extruded_along_path( path: &EntityType, taper_angle: f64, ) -> Option { + if matches!(entity, EntityType::Region(region) if region.wires.len() > 1) { + if taper_angle.abs() > 1e-12 { + return None; + } + return extruded_direction(entity, straight_path_direction(path)?, 0.0); + } let profile = profile_of(entity)?; if let EntityType::Polyline3D(path) = path { let points = path @@ -417,6 +484,9 @@ pub fn embedded_path(entity: &EntityType) -> Option { } fn embedded_planar_entity(entity: &EntityType) -> Option<(EmbeddedEntity, [f64; 16])> { + if matches!(entity, EntityType::Region(region) if region.wires.len() > 1) { + return None; + } if !matches!(entity, EntityType::Polyline3D(_)) { if let Some(embedded) = embedded_path(entity) { return Some((embedded, glam::DMat4::IDENTITY.to_cols_array()));