Align EXTRUDE command state and path behavior

This commit is contained in:
ramox81 committed 2026-09-02 11:29:59 +03:00
1 parent 847d218c35
commit d23a910de7
6 files changed
+294 -75

No files matched your search

+26 -8
View File
@@ -323,7 +323,30 @@ fn sweep_path_length(value: &SolidHistorySweep) -> Option<f64> {
use acadrust::entities::EmbeddedEntity;
use acadrust::EntityType;
let entity = match value.path_entity.as_ref()? {
let path_entity = value.path_entity.as_ref()?;
if let EmbeddedEntity::Spline(path) = path_entity {
if path.degree == 1 && path.control_points.len() >= 2 && path.weights.is_empty() {
let transform = glam::DMat4::from_cols_array(&value.path_entity_transform);
if !transform.is_finite() || transform.determinant().abs() <= 1e-12 {
return None;
}
return Some(
path.control_points
.windows(2)
.map(|pair| {
let start = transform.transform_point3(glam::DVec3::new(
pair[0].x, pair[0].y, pair[0].z,
));
let end = transform.transform_point3(glam::DVec3::new(
pair[1].x, pair[1].y, pair[1].z,
));
end.distance(start)
})
.sum(),
);
}
}
let entity = match path_entity {
EmbeddedEntity::Line(value) => EntityType::Line(value.clone()),
EmbeddedEntity::Arc(value) => EntityType::Arc(value.clone()),
EmbeddedEntity::Circle(value) => EntityType::Circle(value.clone()),
@@ -1076,7 +1099,7 @@ fn apply_extrusion_geometry_property(
}
PROP_EXTRUSION_HEIGHT => {
let height = crate::entities::common::parse_length(text)?;
if !height.is_finite() || height.abs() <= 1e-9 {
if !height.is_finite() || height <= 1e-9 {
return Some(false);
}
let direction = glam::DVec3::new(
@@ -1087,12 +1110,7 @@ fn apply_extrusion_geometry_property(
let Some(unit) = direction.try_normalize() else {
return Some(false);
};
let sign = if height.signum() == value.end_draft_distance.signum() {
1.0
} else {
-1.0
};
let updated = unit * height.abs() * sign;
let updated = unit * height;
if (updated - direction).length_squared() <= 1e-24 {
return Some(false);
}
+113 -22
View File
@@ -3,7 +3,7 @@
use cadkernel::brep::{self, Body};
use cadkernel::geom2d::{Arc, Curve, EllipseArc, Line};
use cadkernel::space::{PlanarCurve, Plane, Vec3};
use acadrust::entities::{EmbeddedEntity, LwPolyline, LwVertex};
use acadrust::entities::{EmbeddedEntity, LwPolyline, LwVertex, Spline};
use acadrust::objects::{
SolidHistoryNodeBase, SolidHistoryOperation, SolidHistorySweep,
};
@@ -229,22 +229,75 @@ pub fn extruded_surface(
taper_angle: f64,
) -> Option<Body> {
let (profile, closed) = extrusion_profile_of(entity)?;
if closed {
brep::extrude_surface_tapered(
profile.plane,
&profile.pieces,
direction,
taper_angle,
)
} else if taper_angle.abs() <= 1e-12 {
brep::extrude_surface(profile.plane, &profile.pieces, direction)
} else {
None
}
let _ = closed;
brep::extrude_surface_tapered(
profile.plane,
&profile.pieces,
direction,
taper_angle,
)
}
pub fn extruded_along_path(entity: &EntityType, path: &EntityType) -> Option<Body> {
swept(entity, path)
pub fn extruded_along_path(
entity: &EntityType,
path: &EntityType,
taper_angle: f64,
) -> Option<Body> {
let profile = profile_of(entity)?;
if let EntityType::Polyline3D(path) = path {
let points = path
.vertices
.iter()
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z])
.collect::<Vec<_>>();
if taper_angle.abs() > 1e-12 {
if points.len() != 2 {
return None;
}
return brep::extrude_tapered(
profile.plane,
&profile.pieces,
(Vec3::from(points[1]) - Vec3::from(points[0])).to_array(),
taper_angle,
);
}
return brep::sweep_along_polyline3d(profile.plane, &profile.pieces, &points);
}
if taper_angle.abs() <= 1e-12 {
return swept(entity, path);
}
let curve = entity_curve(path)?;
let Curve::Line(line) = curve.curve else {
return None;
};
let direction = Vec3::from(curve.plane.point_at(line.end))
- Vec3::from(curve.plane.point_at(line.start));
brep::extrude_tapered(
profile.plane,
&profile.pieces,
direction.to_array(),
taper_angle,
)
}
pub fn straight_path_direction(path: &EntityType) -> Option<[f64; 3]> {
if let EntityType::Polyline3D(path) = path {
if path.vertices.len() != 2 {
return None;
}
let start = &path.vertices[0].position;
let end = &path.vertices[1].position;
return Some([end.x - start.x, end.y - start.y, end.z - start.z]);
}
let curve = entity_curve(path)?;
let Curve::Line(line) = curve.curve else {
return None;
};
Some(
(Vec3::from(curve.plane.point_at(line.end))
- Vec3::from(curve.plane.point_at(line.start)))
.to_array(),
)
}
/// Signed distance of a drag along a profile's normal.
@@ -346,13 +399,28 @@ pub fn embedded_path(entity: &EntityType) -> Option<EmbeddedEntity> {
EntityType::Ellipse(value) => Some(EmbeddedEntity::Ellipse(value.clone())),
EntityType::LwPolyline(value) => Some(EmbeddedEntity::LwPolyline(value.clone())),
EntityType::Spline(value) => Some(EmbeddedEntity::Spline(value.clone())),
EntityType::Polyline3D(value) if !value.is_closed() && value.vertices.len() >= 2 => {
let mut spline = Spline::from_control_points(
1,
value
.vertices
.iter()
.map(|vertex| vertex.position)
.collect(),
);
spline.flags.linear = true;
spline.flags.planar = false;
Some(EmbeddedEntity::Spline(spline))
}
_ => None,
}
}
fn embedded_planar_entity(entity: &EntityType) -> Option<(EmbeddedEntity, [f64; 16])> {
if let Some(embedded) = embedded_path(entity) {
return Some((embedded, glam::DMat4::IDENTITY.to_cols_array()));
if !matches!(entity, EntityType::Polyline3D(_)) {
if let Some(embedded) = embedded_path(entity) {
return Some((embedded, glam::DMat4::IDENTITY.to_cols_array()));
}
}
let (profile, closed) = extrusion_profile_of(entity)?;
let mut polyline = LwPolyline::new();
@@ -406,11 +474,7 @@ pub fn extrusion_history(
taper_angle: f64,
reference_point: [f64; 3],
) -> Option<SolidHistoryOperation> {
let signed_height = extrusion_profile_of(profile)
.and_then(|(profile, _)| profile.plane.normal())
.map(|normal| Vec3::from(direction).dot(Vec3::from(normal)))
.filter(|value| value.is_finite())
.unwrap_or_else(|| Vec3::from(direction).length());
let signed_height = Vec3::from(direction).length();
let mut base = SolidHistoryNodeBase::new(1);
base.transform = glam::DMat4::IDENTITY.to_cols_array();
let (sweep_entity, sweep_entity_transform) = embedded_planar_entity(profile)?;
@@ -442,6 +506,33 @@ pub fn extrusion_history(
}))
}
pub fn sweep_history(
profile: &EntityType,
path: &EntityType,
taper_angle: f64,
reference_point: [f64; 3],
) -> Option<SolidHistoryOperation> {
let mut base = SolidHistoryNodeBase::new(1);
base.transform = glam::DMat4::IDENTITY.to_cols_array();
let (sweep_entity, sweep_entity_transform) = embedded_planar_entity(profile)?;
Some(SolidHistoryOperation::Sweep(SolidHistorySweep {
base,
operation_major: 1,
sweep_entity: Some(sweep_entity),
path_entity: Some(embedded_path(path)?),
draft_angle: taper_angle,
scale_factor: 1.0,
sweep_entity_transform,
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.
pub fn polysolid(
entity: &EntityType,