forked from 1b-agent/opencadstudio-upstream
Restore sweep construction grips
This commit is contained in:
1 parent
bde9cc2715
commit
e2472c68b8
3 files changed
+194
-34
No files matched your search
@@ -3623,13 +3623,20 @@ impl OpenCADStudio {
|
|||||||
.get_entity(profile_handle)
|
.get_entity(profile_handle)
|
||||||
.cloned();
|
.cloned();
|
||||||
let path_ent = self.tabs[i].scene.document.get_entity(path_handle).cloned();
|
let path_ent = self.tabs[i].scene.document.get_entity(path_handle).cloned();
|
||||||
let result = profile_ent
|
let result = profile_ent.zip(path_ent).and_then(|(profile, path)| {
|
||||||
.zip(path_ent)
|
let reference_point = sweep_model::profile_of(&profile)?.plane.origin;
|
||||||
.and_then(|(profile, path)| sweep_model::swept(&profile, &path));
|
let solid = sweep_model::swept(&profile, &path)?;
|
||||||
|
let history = sweep_model::sweep_history(
|
||||||
|
&profile,
|
||||||
|
&path,
|
||||||
|
reference_point,
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|| solid_history::brep_op(&solid));
|
||||||
|
Some((solid, history))
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(solid) = result {
|
if let Some((solid, history)) = result {
|
||||||
let pending = self.begin_undo(i, "SWEEP", 1, true);
|
let pending = self.begin_undo(i, "SWEEP", 1, true);
|
||||||
let history = solid_history::brep_op(&solid);
|
|
||||||
let created = self.add_solid_model(empty_solid3d(), solid, history);
|
let created = self.add_solid_model(empty_solid3d(), solid, history);
|
||||||
if !created.is_null() {
|
if !created.is_null() {
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
use acadrust::entities::Solid3D;
|
use acadrust::entities::{EmbeddedEntity, Solid3D};
|
||||||
use acadrust::objects::{
|
use acadrust::objects::{
|
||||||
DynamicBlockData, ObjectType, SolidHistoryBox, SolidHistoryBrep, SolidHistoryCone,
|
DynamicBlockData, ObjectType, SolidHistoryBox, SolidHistoryBrep, SolidHistoryCone,
|
||||||
SolidHistoryCylinder, SolidHistoryNodeBase, SolidHistoryOperation,
|
SolidHistoryCylinder, SolidHistoryNodeBase, SolidHistoryOperation,
|
||||||
SolidHistoryPyramid, SolidHistorySphere, SolidHistorySweep, SolidHistoryTorus,
|
SolidHistoryPyramid, SolidHistorySphere, SolidHistorySweep, SolidHistoryTorus,
|
||||||
};
|
};
|
||||||
|
use acadrust::EntityType;
|
||||||
use cadkernel::brep::Body;
|
use cadkernel::brep::Body;
|
||||||
|
|
||||||
use crate::command::EntityTransform;
|
use crate::command::EntityTransform;
|
||||||
|
use crate::entities::traits::EntityTypeOps;
|
||||||
use crate::scene::model::object::{
|
use crate::scene::model::object::{
|
||||||
GripApply, GripDef, GripShape, PropSection, PropValue, Property,
|
GripApply, GripDef, GripShape, PropSection, PropValue, Property,
|
||||||
};
|
};
|
||||||
@@ -22,7 +24,8 @@ pub const GRIP_SIDES: usize = 10_007;
|
|||||||
pub const GRIP_MAJOR_RADIUS: usize = 10_008;
|
pub const GRIP_MAJOR_RADIUS: usize = 10_008;
|
||||||
pub const GRIP_MINOR_RADIUS: usize = 10_009;
|
pub const GRIP_MINOR_RADIUS: usize = 10_009;
|
||||||
pub const GRIP_TOP_RADIUS: usize = 10_010;
|
pub const GRIP_TOP_RADIUS: usize = 10_010;
|
||||||
pub const GRIP_POSITION: usize = 10_011;
|
pub const GRIP_SWEEP_PROFILE_FIRST: usize = 20_000;
|
||||||
|
pub const GRIP_SWEEP_PATH_FIRST: usize = 30_000;
|
||||||
pub const GRIP_BOX_CORNER_FIRST: usize = 10_100;
|
pub const GRIP_BOX_CORNER_FIRST: usize = 10_100;
|
||||||
pub const GRIP_BOX_FACE_X_MIN: usize = 10_110;
|
pub const GRIP_BOX_FACE_X_MIN: usize = 10_110;
|
||||||
pub const GRIP_BOX_FACE_X_MAX: usize = 10_111;
|
pub const GRIP_BOX_FACE_X_MAX: usize = 10_111;
|
||||||
@@ -1641,6 +1644,122 @@ fn local_point(transform: [f64; 16], point: glam::DVec3) -> Option<glam::DVec3>
|
|||||||
Some(matrix(transform)?.inverse().transform_point3(point))
|
Some(matrix(transform)?.inverse().transform_point3(point))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn embedded_entity(value: &EmbeddedEntity) -> Option<EntityType> {
|
||||||
|
Some(match value {
|
||||||
|
EmbeddedEntity::Point(value) => EntityType::Point(value.clone()),
|
||||||
|
EmbeddedEntity::Line(value) => EntityType::Line(value.clone()),
|
||||||
|
EmbeddedEntity::Arc(value) => EntityType::Arc(value.clone()),
|
||||||
|
EmbeddedEntity::Circle(value) => EntityType::Circle(value.clone()),
|
||||||
|
EmbeddedEntity::Ellipse(value) => EntityType::Ellipse(value.clone()),
|
||||||
|
EmbeddedEntity::Spline(value) => EntityType::Spline(value.clone()),
|
||||||
|
EmbeddedEntity::LwPolyline(value) => EntityType::LwPolyline(value.clone()),
|
||||||
|
EmbeddedEntity::Ray(value) => EntityType::Ray(value.clone()),
|
||||||
|
EmbeddedEntity::XLine(value) => EntityType::XLine(value.clone()),
|
||||||
|
EmbeddedEntity::Unknown { .. } => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_embedded_entity(value: EntityType) -> Option<EmbeddedEntity> {
|
||||||
|
Some(match value {
|
||||||
|
EntityType::Point(value) => EmbeddedEntity::Point(value),
|
||||||
|
EntityType::Line(value) => EmbeddedEntity::Line(value),
|
||||||
|
EntityType::Arc(value) => EmbeddedEntity::Arc(value),
|
||||||
|
EntityType::Circle(value) => EmbeddedEntity::Circle(value),
|
||||||
|
EntityType::Ellipse(value) => EmbeddedEntity::Ellipse(value),
|
||||||
|
EntityType::Spline(value) => EmbeddedEntity::Spline(value),
|
||||||
|
EntityType::LwPolyline(value) => EmbeddedEntity::LwPolyline(value),
|
||||||
|
EntityType::Ray(value) => EmbeddedEntity::Ray(value),
|
||||||
|
EntityType::XLine(value) => EmbeddedEntity::XLine(value),
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn embedded_grips(
|
||||||
|
value: Option<&EmbeddedEntity>,
|
||||||
|
base_transform: [f64; 16],
|
||||||
|
entity_transform: [f64; 16],
|
||||||
|
first_id: usize,
|
||||||
|
) -> Vec<GripDef> {
|
||||||
|
let Some(entity) = value.and_then(embedded_entity) else {
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let (Some(base), Some(entity_placement)) =
|
||||||
|
(matrix(base_transform), matrix(entity_transform))
|
||||||
|
else {
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let transform = base * entity_placement;
|
||||||
|
entity
|
||||||
|
.grips()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(index, grip)| {
|
||||||
|
let world = transform.transform_point3(grip.world);
|
||||||
|
if !world.is_finite() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let transform_vector = |vector: glam::DVec3| {
|
||||||
|
let vector = transform.transform_vector3(vector);
|
||||||
|
(vector.length_squared() > 1e-12).then(|| vector.normalize())
|
||||||
|
};
|
||||||
|
Some(GripDef {
|
||||||
|
id: first_id + index,
|
||||||
|
world,
|
||||||
|
is_midpoint: grip.is_midpoint,
|
||||||
|
shape: grip.shape,
|
||||||
|
dir: grip.dir.and_then(transform_vector),
|
||||||
|
axis: grip.axis.and_then(transform_vector),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_embedded_grip(
|
||||||
|
value: &mut Option<EmbeddedEntity>,
|
||||||
|
base_transform: [f64; 16],
|
||||||
|
entity_transform: [f64; 16],
|
||||||
|
index: usize,
|
||||||
|
apply: GripApply,
|
||||||
|
) -> bool {
|
||||||
|
let Some(mut entity) = value.as_ref().and_then(embedded_entity) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(source_grip) = entity.grips().get(index).cloned() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let (Some(base), Some(entity_placement)) =
|
||||||
|
(matrix(base_transform), matrix(entity_transform))
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let inverse = (base * entity_placement).inverse();
|
||||||
|
if !inverse.is_finite() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let apply = match apply {
|
||||||
|
GripApply::Absolute(world) => {
|
||||||
|
let local = inverse.transform_point3(world);
|
||||||
|
if !local.is_finite() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GripApply::Absolute(local)
|
||||||
|
}
|
||||||
|
GripApply::Translate(world_delta) => {
|
||||||
|
let local_delta = inverse.transform_vector3(world_delta);
|
||||||
|
if !local_delta.is_finite() || local_delta.length_squared() <= 1e-24 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GripApply::Translate(local_delta)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
entity.apply_grip(source_grip.id, apply);
|
||||||
|
let Some(entity) = into_embedded_entity(entity) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
*value = Some(entity);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn grip(
|
fn grip(
|
||||||
id: usize,
|
id: usize,
|
||||||
world: glam::DVec3,
|
world: glam::DVec3,
|
||||||
@@ -1862,17 +1981,20 @@ pub fn primitive_grips(
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
SolidHistoryOperation::Sweep(value) => add(
|
SolidHistoryOperation::Sweep(value) => {
|
||||||
GRIP_POSITION,
|
grips.extend(embedded_grips(
|
||||||
value.base.transform,
|
value.sweep_entity.as_ref(),
|
||||||
[
|
value.base.transform,
|
||||||
value.reference_point.x,
|
value.sweep_entity_transform,
|
||||||
value.reference_point.y,
|
GRIP_SWEEP_PROFILE_FIRST,
|
||||||
value.reference_point.z,
|
));
|
||||||
],
|
grips.extend(embedded_grips(
|
||||||
GripShape::Square,
|
value.path_entity.as_ref(),
|
||||||
None,
|
value.base.transform,
|
||||||
),
|
value.path_entity_transform,
|
||||||
|
GRIP_SWEEP_PATH_FIRST,
|
||||||
|
));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
grips
|
grips
|
||||||
@@ -1883,6 +2005,29 @@ pub fn apply_primitive_grip(
|
|||||||
grip_id: usize,
|
grip_id: usize,
|
||||||
apply: GripApply,
|
apply: GripApply,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if let SolidHistoryOperation::Sweep(value) = operation {
|
||||||
|
if let Some(index) = grip_id.checked_sub(GRIP_SWEEP_PATH_FIRST) {
|
||||||
|
return apply_embedded_grip(
|
||||||
|
&mut value.path_entity,
|
||||||
|
value.base.transform,
|
||||||
|
value.path_entity_transform,
|
||||||
|
index,
|
||||||
|
apply,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(index) = grip_id
|
||||||
|
.checked_sub(GRIP_SWEEP_PROFILE_FIRST)
|
||||||
|
.filter(|_| grip_id < GRIP_SWEEP_PATH_FIRST)
|
||||||
|
{
|
||||||
|
return apply_embedded_grip(
|
||||||
|
&mut value.sweep_entity,
|
||||||
|
value.base.transform,
|
||||||
|
value.sweep_entity_transform,
|
||||||
|
index,
|
||||||
|
apply,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let GripApply::Absolute(world) = apply else {
|
let GripApply::Absolute(world) = apply else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -2016,22 +2161,6 @@ pub fn apply_primitive_grip(
|
|||||||
}
|
}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
},
|
},
|
||||||
SolidHistoryOperation::Sweep(value) if grip_id == GRIP_POSITION => {
|
|
||||||
let Some(current) = matrix(value.base.transform) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let reference = current.transform_point3(glam::DVec3::new(
|
|
||||||
value.reference_point.x,
|
|
||||||
value.reference_point.y,
|
|
||||||
value.reference_point.z,
|
|
||||||
));
|
|
||||||
let delta = world - reference;
|
|
||||||
if !delta.is_finite() || delta.length_squared() <= 1e-24 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value.base.transform =
|
|
||||||
(glam::DMat4::from_translation(delta) * current).to_cols_array();
|
|
||||||
}
|
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -186,6 +186,30 @@ fn embedded_path(entity: &EntityType) -> Option<EmbeddedEntity> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sweep_history(
|
||||||
|
profile: &EntityType,
|
||||||
|
path: &EntityType,
|
||||||
|
reference_point: [f64; 3],
|
||||||
|
) -> Option<SolidHistoryOperation> {
|
||||||
|
let mut base = SolidHistoryNodeBase::new(1);
|
||||||
|
base.transform = glam::DMat4::IDENTITY.to_cols_array();
|
||||||
|
Some(SolidHistoryOperation::Sweep(SolidHistorySweep {
|
||||||
|
base,
|
||||||
|
operation_major: 1,
|
||||||
|
sweep_entity: Some(embedded_path(profile)?),
|
||||||
|
path_entity: Some(embedded_path(path)?),
|
||||||
|
scale_factor: 1.0,
|
||||||
|
sweep_entity_transform: glam::DMat4::IDENTITY.to_cols_array(),
|
||||||
|
path_entity_transform: glam::DMat4::IDENTITY.to_cols_array(),
|
||||||
|
reference_point: Vector3::new(
|
||||||
|
reference_point[0],
|
||||||
|
reference_point[1],
|
||||||
|
reference_point[2],
|
||||||
|
),
|
||||||
|
..SolidHistorySweep::default()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a history-backed wall solid along a supported planar curve.
|
/// Builds a history-backed wall solid along a supported planar curve.
|
||||||
pub fn polysolid(
|
pub fn polysolid(
|
||||||
entity: &EntityType,
|
entity: &EntityType,
|
||||||
|
|||||||
Reference in new issue
Block a user