SWEEP: reference messages, 3D polyline profiles and Scale Reference

- 3D polyline profiles are recorded as wire bodies, like 3D polyline paths.
- Refused sweeps print the modeling error code and "Unable to sweep N
  selected objects."; a scaled sweep rejects closed and cornered spatial
  paths with the reference messages and asks for the path again.
- Scale > Reference asks for start and end reference lengths (start / end).
- Bank stays on for later sweeps until a twist angle is entered.
- Refused twist/scale edits in Properties print the modeling error code.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-07 09:26:29 +03:00
1 parent 7a8ec02003
commit 1a18fdd0cf
6 files changed
+149 -57

No files matched your search

+52 -7
View File
@@ -9,20 +9,25 @@ use kernel::brep::Body;
use crate::command::{ExtrudeMode, SweepOptions};
use super::sweep_model::{embedded_path, embedded_revolve_profile};
/// A 3D polyline profile or path as the reference records it: a wire body.
fn embedded_sweep_profile(entity: &EntityType) -> Option<(codec::entities::EmbeddedEntity, [f64; 16])> {
if let EntityType::Region(region) = entity {
Some((codec::entities::EmbeddedEntity::Region(region.clone()), glam::DMat4::IDENTITY.to_cols_array()))
} else {
embedded_revolve_profile(entity)
match entity {
EntityType::Region(region) => Some((codec::entities::EmbeddedEntity::Region(region.clone()), glam::DMat4::IDENTITY.to_cols_array())),
EntityType::Polyline3D(value) => Some((polyline_wire(value)?, glam::DMat4::IDENTITY.to_cols_array())),
_ => embedded_revolve_profile(entity),
}
}
/// The sweep path as the reference records it: a 3D polyline as a wire
/// body, anything else as its embedded entity.
fn embedded_sweep_path(path: &EntityType) -> Option<codec::entities::EmbeddedEntity> {
let EntityType::Polyline3D(value) = path else {
return embedded_path(path);
};
match path {
EntityType::Polyline3D(value) => polyline_wire(value),
_ => embedded_path(path),
}
}
fn polyline_wire(value: &codec::entities::Polyline3D) -> Option<codec::entities::EmbeddedEntity> {
let points = value.vertices.iter()
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z])
.collect::<Vec<_>>();
@@ -41,6 +46,46 @@ pub fn is_sweep_profile(entity: &EntityType) -> bool {
})
}
/// The modeling error code the reference reports for a refused sweep.
pub fn sweep_refusal_code(refusal: kernel::brep::SweepRefusal) -> u32 {
match refusal {
kernel::brep::SweepRefusal::Scale => 5016,
kernel::brep::SweepRefusal::Twist => 115065,
kernel::brep::SweepRefusal::Bank => 115007,
}
}
/// Why the reference refuses a path for a scaled sweep: scaling needs an
/// open path, and a spatial path must be smooth.
pub fn scaled_sweep_path_refusal(path: &EntityType) -> Option<&'static str> {
let (closed, smooth) = match crate::entities::curve::entity_curve(path) {
Some(planar) => (planar.curve.is_closed(), true),
None => match path {
EntityType::Polyline3D(value) => {
let points = value.vertices.iter()
.map(|vertex| glam::DVec3::new(vertex.position.x, vertex.position.y, vertex.position.z))
.collect::<Vec<_>>();
let directions = points.windows(2)
.filter_map(|pair| (pair[1] - pair[0]).try_normalize())
.collect::<Vec<_>>();
let straight = directions.windows(2).all(|pair| pair[0].dot(pair[1]) >= 1.0 - 1e-9);
(value.is_closed(), straight && !value.is_closed())
}
EntityType::Spline(value) => (value.flags.closed, value.degree > 1),
_ => (false, true),
},
};
if closed {
Some("Cannot use scale option when path curve is closed.
The selected path curve is not valid.")
} else if !smooth {
Some("Path curve must be smooth when using scale option.
The selected path curve is not valid.")
} else {
None
}
}
pub fn is_sweep_path(entity: &EntityType) -> bool {
match embedded_path(entity) {
Some(codec::entities::EmbeddedEntity::Spline(value)) => {
+1 -1
View File
@@ -13,7 +13,7 @@ use codec::EntityType;
use crate::entities::curve::entity_curve;
pub use super::sweep_command_model::{
is_sweep_path, is_sweep_profile, sweep_record, sweep_selection_options, swept_surface_entity, swept_with_options,
is_sweep_path, is_sweep_profile, scaled_sweep_path_refusal, sweep_record, sweep_refusal_code, sweep_selection_options, swept_surface_entity, swept_with_options,
};
/// A drawn profile, as the kernel wants it: the plane it lies in and the
+13
View File
@@ -1370,6 +1370,19 @@ impl Scene {
self.rebuild_solid_history(handle, operation)
}
/// The modeler error code the reference reports when it refuses a sweep
/// property edit (twist or scale along a path with a corner).
pub fn solid_history_property_refusal(&self, handle: Handle, field: &str, value: &str) -> Option<u32> {
let mut operation = crate::scene::model::solid_history::primitive_property_operation(&self.document, handle)?;
if !crate::scene::model::solid_history::apply_primitive_property(&mut operation, field, value) {
return None;
}
let codec::objects::SolidHistoryOperation::Sweep(record) = &operation else {
return None;
};
kernel::acis::sweep_history_refusal(record).map(crate::scene::model::sweep_model::sweep_refusal_code)
}
pub fn apply_solid_position_property(
&mut self,
handle: Handle,