forked from 1b-agent/opencadstudio-upstream
Align EXTRUDE command state and path behavior
This commit is contained in:
1 parent
847d218c35
commit
d23a910de7
6 files changed
+294
-75
No files matched your search
@@ -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
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user