forked from 1b-agent/opencadstudio-upstream
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
7a8ec02003
commit
1a18fdd0cf
6 files changed
+149
-57
No files matched your search
@@ -497,22 +497,34 @@ impl OpenCADStudio {
|
|||||||
let mut created_handles = Vec::new();
|
let mut created_handles = Vec::new();
|
||||||
let mut consumed = Vec::new();
|
let mut consumed = Vec::new();
|
||||||
for (handle, profile) in profiles {
|
for (handle, profile) in profiles {
|
||||||
let result = path.as_ref().zip(options).and_then(|(path, options)| {
|
// A refused sweep reports the modeler error code, as the
|
||||||
let mut record = sweep_model::sweep_record(&profile, path, options)?;
|
// reference does.
|
||||||
|
let result = (|| -> Result<_, Option<u32>> {
|
||||||
|
let (path, options) = path.as_ref().zip(options).ok_or(None)?;
|
||||||
|
let mut record = sweep_model::sweep_record(&profile, path, options).ok_or(None)?;
|
||||||
record.flags_294_296[0] |= picked_base;
|
record.flags_294_296[0] |= picked_base;
|
||||||
let (_, _, closed) = kernel::acis::sweep_profile_geometry(
|
let (_, _, closed) = kernel::acis::sweep_profile_geometry(
|
||||||
record.sweep_entity.as_ref()?,
|
record.sweep_entity.as_ref().ok_or(None)?,
|
||||||
record.sweep_entity_transform,
|
record.sweep_entity_transform,
|
||||||
)
|
)
|
||||||
.ok()?;
|
.map_err(|_| None)?;
|
||||||
let surface = mode == ExtrudeMode::Surface || !closed;
|
let surface = mode == ExtrudeMode::Surface || !closed;
|
||||||
let body =
|
let body = kernel::acis::rebuild_sweep_with_mode(&record, surface).map_err(|error| match error {
|
||||||
kernel::acis::rebuild_sweep_with_mode(&record, surface).ok()?;
|
kernel::acis::HistoryRebuildError::Refused(why) => Some(sweep_model::sweep_refusal_code(why)),
|
||||||
Some((body, record, surface))
|
_ => None,
|
||||||
});
|
})?;
|
||||||
let Some((body, record, surface)) = result else {
|
Ok((body, record, surface))
|
||||||
failed += 1;
|
})();
|
||||||
continue;
|
let (body, record, surface) = match result {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(code) => {
|
||||||
|
if let Some(code) = code {
|
||||||
|
self.command_line.push_output(&format!("Modeling Operation Error:
|
||||||
|
Error Code Number is {code}"));
|
||||||
|
}
|
||||||
|
failed += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let deletes_path =
|
let deletes_path =
|
||||||
crate::app::delobj_deletes_auxiliary(delete_objects, surface);
|
crate::app::delobj_deletes_auxiliary(delete_objects, surface);
|
||||||
@@ -550,14 +562,9 @@ impl OpenCADStudio {
|
|||||||
self.tabs[i].scene.select_entity(*handle, true);
|
self.tabs[i].scene.select_entity(*handle, true);
|
||||||
}
|
}
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
self.command_line.push_output(crate::tf!(
|
}
|
||||||
"SWEEP: created {created} object(s); {failed} source(s) could not be swept.",
|
if failed > 0 {
|
||||||
created = created_handles.len(), failed = failed
|
self.command_line.push_output(&format!("Unable to sweep {failed} selected objects."));
|
||||||
).as_ref());
|
|
||||||
} else {
|
|
||||||
self.command_line.push_error(
|
|
||||||
crate::t!("SWEEP: could not sweep the profile along the path.").as_ref(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Some(pending) = pending {
|
if let Some(pending) = pending {
|
||||||
self.commit_undo_delta(i, pending);
|
self.commit_undo_delta(i, pending);
|
||||||
|
|||||||
@@ -3938,11 +3938,21 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
|||||||
if crate::scene::model::solid_history::is_primitive_property(
|
if crate::scene::model::solid_history::is_primitive_property(
|
||||||
field,
|
field,
|
||||||
) {
|
) {
|
||||||
self.tabs[i].scene.apply_solid_history_property(
|
if !self.tabs[i].scene.apply_solid_history_property(
|
||||||
handle,
|
handle,
|
||||||
field,
|
field,
|
||||||
&val,
|
&val,
|
||||||
);
|
) {
|
||||||
|
if let Some(code) = self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.solid_history_property_refusal(handle, field, &val)
|
||||||
|
{
|
||||||
|
self.command_line.push_output(&format!(
|
||||||
|
"Modeling Operation Error:
|
||||||
|
Error Code Number is {code}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if self.tabs[i]
|
} else if self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.apply_solid_position_property(
|
.apply_solid_position_property(
|
||||||
|
|||||||
@@ -1606,6 +1606,10 @@ impl CadCommand for RevolveCommand {
|
|||||||
|
|
||||||
// ── SWEEP command ──────────────────────────────────────────────────────────
|
// ── SWEEP command ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Banking stays on for later sweeps until a twist angle is entered, as in
|
||||||
|
/// the reference.
|
||||||
|
static SWEEP_BANK: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||||
|
|
||||||
pub struct SweepCommand {
|
pub struct SweepCommand {
|
||||||
step: SweepStep,
|
step: SweepStep,
|
||||||
profiles: Vec<(Handle, EntityType)>,
|
profiles: Vec<(Handle, EntityType)>,
|
||||||
@@ -1618,6 +1622,7 @@ pub struct SweepCommand {
|
|||||||
reference_start: Option<DVec3>,
|
reference_start: Option<DVec3>,
|
||||||
reference_length: f64,
|
reference_length: f64,
|
||||||
new_length_start: Option<DVec3>,
|
new_length_start: Option<DVec3>,
|
||||||
|
end_length: f64,
|
||||||
isolines: usize,
|
isolines: usize,
|
||||||
color: [f32; 4],
|
color: [f32; 4],
|
||||||
}
|
}
|
||||||
@@ -1630,10 +1635,11 @@ enum SweepStep {
|
|||||||
Alignment,
|
Alignment,
|
||||||
BasePoint,
|
BasePoint,
|
||||||
Scale,
|
Scale,
|
||||||
|
/// The start reference length: a distance, or two points.
|
||||||
ReferenceLength,
|
ReferenceLength,
|
||||||
ReferenceEnd,
|
ReferenceEnd,
|
||||||
|
/// The end reference length: a distance, or two points.
|
||||||
NewLength,
|
NewLength,
|
||||||
NewLengthStart,
|
|
||||||
NewLengthEnd,
|
NewLengthEnd,
|
||||||
Twist,
|
Twist,
|
||||||
}
|
}
|
||||||
@@ -1648,10 +1654,14 @@ impl SweepCommand {
|
|||||||
preview_key: None,
|
preview_key: None,
|
||||||
preview_cache: Vec::new(),
|
preview_cache: Vec::new(),
|
||||||
mode: ExtrudeMode::Solid,
|
mode: ExtrudeMode::Solid,
|
||||||
options: SweepOptions::default(),
|
options: SweepOptions {
|
||||||
|
bank: SWEEP_BANK.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
..SweepOptions::default()
|
||||||
|
},
|
||||||
reference_start: None,
|
reference_start: None,
|
||||||
reference_length: 1.0,
|
reference_length: 1.0,
|
||||||
new_length_start: None,
|
new_length_start: None,
|
||||||
|
end_length: 1.0,
|
||||||
isolines,
|
isolines,
|
||||||
color,
|
color,
|
||||||
}
|
}
|
||||||
@@ -1715,10 +1725,13 @@ impl SweepCommand {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn length_anchor(&self) -> DVec3 {
|
/// The Reference scale is the start reference length over the end one.
|
||||||
self.reference_start
|
fn set_end_length(&mut self, length: f64) -> bool {
|
||||||
.or_else(|| self.selection_options().and_then(|options| options.base_point))
|
if !length.is_finite() || length <= 1e-12 {
|
||||||
.unwrap_or(DVec3::ZERO)
|
return false;
|
||||||
|
}
|
||||||
|
self.end_length = length;
|
||||||
|
self.set_scale(self.reference_length / length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,21 +1759,23 @@ impl CadCommand for SweepCommand {
|
|||||||
),
|
),
|
||||||
SweepStep::ReferenceLength => format!(
|
SweepStep::ReferenceLength => format!(
|
||||||
"{} <{}>:",
|
"{} <{}>:",
|
||||||
t!("SWEEP Specify reference length or first point"),
|
t!("SWEEP Specify start reference length"),
|
||||||
crate::entities::common::format_length(self.reference_length),
|
crate::entities::common::format_length(self.reference_length),
|
||||||
),
|
),
|
||||||
SweepStep::ReferenceEnd => t!("SWEEP Specify second reference point:").into_owned(),
|
SweepStep::ReferenceEnd | SweepStep::NewLengthEnd => t!("SWEEP Specify second point:").into_owned(),
|
||||||
SweepStep::NewLength => format!(
|
SweepStep::NewLength => format!(
|
||||||
"{} <{}>:",
|
"{} <{}>:",
|
||||||
t!("SWEEP Specify new length or [Points]"),
|
t!("SWEEP Specify end reference length"),
|
||||||
crate::entities::common::format_length(self.reference_length * self.options.scale),
|
crate::entities::common::format_length(self.end_length),
|
||||||
),
|
),
|
||||||
SweepStep::NewLengthStart => t!("SWEEP Specify first point of new length:").into_owned(),
|
|
||||||
SweepStep::NewLengthEnd => t!("SWEEP Specify second point of new length:").into_owned(),
|
|
||||||
SweepStep::Twist => format!(
|
SweepStep::Twist => format!(
|
||||||
"{} <{}>:",
|
"{} <{}>:",
|
||||||
t!("SWEEP Specify twist angle or [Bank]"),
|
t!("SWEEP Specify twist angle or [Bank]"),
|
||||||
crate::entities::common::format_angle(self.options.twist_angle),
|
if self.options.bank {
|
||||||
|
"Bank".to_string()
|
||||||
|
} else {
|
||||||
|
crate::entities::common::format_angle(self.options.twist_angle)
|
||||||
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1777,7 +1792,6 @@ impl CadCommand for SweepCommand {
|
|||||||
],
|
],
|
||||||
SweepStep::Alignment => vec![CmdOption::new("Yes", "YES"), CmdOption::new("No", "NO")],
|
SweepStep::Alignment => vec![CmdOption::new("Yes", "YES"), CmdOption::new("No", "NO")],
|
||||||
SweepStep::Scale => vec![CmdOption::new("Reference", "REFERENCE")],
|
SweepStep::Scale => vec![CmdOption::new("Reference", "REFERENCE")],
|
||||||
SweepStep::NewLength => vec![CmdOption::new("Points", "POINTS")],
|
|
||||||
SweepStep::Twist => vec![CmdOption::new("Bank", "BANK")],
|
SweepStep::Twist => vec![CmdOption::new("Bank", "BANK")],
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
}
|
}
|
||||||
@@ -1801,11 +1815,15 @@ impl CadCommand for SweepCommand {
|
|||||||
.filter(|(hovered, _)| *hovered == handle)
|
.filter(|(hovered, _)| *hovered == handle)
|
||||||
.map(|(_, entity)| entity.clone())
|
.map(|(_, entity)| entity.clone())
|
||||||
});
|
});
|
||||||
if path.as_ref().is_some_and(crate::scene::model::sweep_model::is_sweep_path) {
|
let Some(path) = path.filter(crate::scene::model::sweep_model::is_sweep_path) else {
|
||||||
self.finish(handle)
|
return CmdResult::NeedPoint;
|
||||||
} else {
|
};
|
||||||
CmdResult::NeedPoint
|
if (self.options.scale - 1.0).abs() > 1e-12 {
|
||||||
|
if let Some(message) = crate::scene::model::sweep_model::scaled_sweep_path_refusal(&path) {
|
||||||
|
return CmdResult::ReportMeasurement(message.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.finish(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_point(&mut self, point: DVec3) -> CmdResult {
|
fn on_point(&mut self, point: DVec3) -> CmdResult {
|
||||||
@@ -1827,15 +1845,12 @@ impl CadCommand for SweepCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SweepStep::NewLength => {
|
SweepStep::NewLength => {
|
||||||
self.set_scale(point.distance(self.length_anchor()) / self.reference_length);
|
|
||||||
}
|
|
||||||
SweepStep::NewLengthStart => {
|
|
||||||
self.new_length_start = Some(point);
|
self.new_length_start = Some(point);
|
||||||
self.step = SweepStep::NewLengthEnd;
|
self.step = SweepStep::NewLengthEnd;
|
||||||
}
|
}
|
||||||
SweepStep::NewLengthEnd => {
|
SweepStep::NewLengthEnd => {
|
||||||
if let Some(start) = self.new_length_start {
|
if let Some(start) = self.new_length_start {
|
||||||
self.set_scale(point.distance(start) / self.reference_length);
|
self.set_end_length(point.distance(start));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -1916,10 +1931,8 @@ impl CadCommand for SweepCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SweepStep::NewLength => {
|
SweepStep::NewLength => {
|
||||||
if "POINTS".starts_with(&keyword) {
|
if let Some(length) = crate::entities::common::parse_typed_length(value) {
|
||||||
self.step = SweepStep::NewLengthStart;
|
self.set_end_length(length);
|
||||||
} else if let Some(length) = crate::entities::common::parse_typed_length(value) {
|
|
||||||
self.set_scale(length / self.reference_length);
|
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -1927,11 +1940,13 @@ impl CadCommand for SweepCommand {
|
|||||||
SweepStep::Twist => {
|
SweepStep::Twist => {
|
||||||
if "BANK".starts_with(&keyword) {
|
if "BANK".starts_with(&keyword) {
|
||||||
self.options.bank = true;
|
self.options.bank = true;
|
||||||
|
SWEEP_BANK.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
self.step = SweepStep::PickPath;
|
self.step = SweepStep::PickPath;
|
||||||
} else if let Some(angle) = crate::entities::common::parse_angle(value) {
|
} else if let Some(angle) = crate::entities::common::parse_angle(value) {
|
||||||
if angle.is_finite() {
|
if angle.is_finite() {
|
||||||
self.options.twist_angle = angle;
|
self.options.twist_angle = angle;
|
||||||
self.options.bank = false;
|
self.options.bank = false;
|
||||||
|
SWEEP_BANK.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||||
self.step = SweepStep::PickPath;
|
self.step = SweepStep::PickPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1947,9 +1962,11 @@ impl CadCommand for SweepCommand {
|
|||||||
self.step = SweepStep::PickPath;
|
self.step = SweepStep::PickPath;
|
||||||
}
|
}
|
||||||
SweepStep::Mode => self.step = SweepStep::PickProfiles,
|
SweepStep::Mode => self.step = SweepStep::PickProfiles,
|
||||||
SweepStep::Alignment | SweepStep::Scale | SweepStep::Twist
|
SweepStep::Alignment | SweepStep::Scale | SweepStep::Twist => self.step = SweepStep::PickPath,
|
||||||
| SweepStep::NewLength => self.step = SweepStep::PickPath,
|
|
||||||
SweepStep::ReferenceLength => self.step = SweepStep::NewLength,
|
SweepStep::ReferenceLength => self.step = SweepStep::NewLength,
|
||||||
|
SweepStep::NewLength => {
|
||||||
|
self.set_end_length(self.end_length);
|
||||||
|
}
|
||||||
_ => return CmdResult::Cancel,
|
_ => return CmdResult::Cancel,
|
||||||
}
|
}
|
||||||
CmdResult::NeedPoint
|
CmdResult::NeedPoint
|
||||||
|
|||||||
@@ -9,20 +9,25 @@ use kernel::brep::Body;
|
|||||||
use crate::command::{ExtrudeMode, SweepOptions};
|
use crate::command::{ExtrudeMode, SweepOptions};
|
||||||
use super::sweep_model::{embedded_path, embedded_revolve_profile};
|
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])> {
|
fn embedded_sweep_profile(entity: &EntityType) -> Option<(codec::entities::EmbeddedEntity, [f64; 16])> {
|
||||||
if let EntityType::Region(region) = entity {
|
match entity {
|
||||||
Some((codec::entities::EmbeddedEntity::Region(region.clone()), glam::DMat4::IDENTITY.to_cols_array()))
|
EntityType::Region(region) => Some((codec::entities::EmbeddedEntity::Region(region.clone()), glam::DMat4::IDENTITY.to_cols_array())),
|
||||||
} else {
|
EntityType::Polyline3D(value) => Some((polyline_wire(value)?, glam::DMat4::IDENTITY.to_cols_array())),
|
||||||
embedded_revolve_profile(entity)
|
_ => embedded_revolve_profile(entity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sweep path as the reference records it: a 3D polyline as a wire
|
/// The sweep path as the reference records it: a 3D polyline as a wire
|
||||||
/// body, anything else as its embedded entity.
|
/// body, anything else as its embedded entity.
|
||||||
fn embedded_sweep_path(path: &EntityType) -> Option<codec::entities::EmbeddedEntity> {
|
fn embedded_sweep_path(path: &EntityType) -> Option<codec::entities::EmbeddedEntity> {
|
||||||
let EntityType::Polyline3D(value) = path else {
|
match path {
|
||||||
return embedded_path(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()
|
let points = value.vertices.iter()
|
||||||
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z])
|
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z])
|
||||||
.collect::<Vec<_>>();
|
.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 {
|
pub fn is_sweep_path(entity: &EntityType) -> bool {
|
||||||
match embedded_path(entity) {
|
match embedded_path(entity) {
|
||||||
Some(codec::entities::EmbeddedEntity::Spline(value)) => {
|
Some(codec::entities::EmbeddedEntity::Spline(value)) => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use codec::EntityType;
|
|||||||
|
|
||||||
use crate::entities::curve::entity_curve;
|
use crate::entities::curve::entity_curve;
|
||||||
pub use super::sweep_command_model::{
|
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
|
/// A drawn profile, as the kernel wants it: the plane it lies in and the
|
||||||
|
|||||||
@@ -1370,6 +1370,19 @@ impl Scene {
|
|||||||
self.rebuild_solid_history(handle, operation)
|
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(
|
pub fn apply_solid_position_property(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
|
|||||||
Reference in new issue
Block a user