forked from 1b-agent/opencadstudio-upstream
Complete revolve workflow and properties
This commit is contained in:
1 parent
e6429d5712
commit
2e112f9aeb
9 files changed
+913
-94
No files matched your search
@@ -68,6 +68,13 @@ pub const PROP_SCALE_ALONG_PATH: &str = "solid_history_scale_along_path";
|
||||
pub const PROP_SWEEP_LENGTH: &str = "solid_history_sweep_length";
|
||||
pub const PROP_EXTRUSION_HEIGHT: &str = "solid_history_extrusion_height";
|
||||
pub const PROP_TAPER_ANGLE: &str = "solid_history_taper_angle";
|
||||
pub const PROP_REVOLVE_ANGLE: &str = "solid_history_revolve_angle";
|
||||
pub const PROP_AXIS_POSITION_X: &str = "solid_history_axis_position_x";
|
||||
pub const PROP_AXIS_POSITION_Y: &str = "solid_history_axis_position_y";
|
||||
pub const PROP_AXIS_POSITION_Z: &str = "solid_history_axis_position_z";
|
||||
pub const PROP_AXIS_DIRECTION_X: &str = "solid_history_axis_direction_x";
|
||||
pub const PROP_AXIS_DIRECTION_Y: &str = "solid_history_axis_direction_y";
|
||||
pub const PROP_AXIS_DIRECTION_Z: &str = "solid_history_axis_direction_z";
|
||||
pub const PROP_PYRAMID_TYPE: &str = "solid_history_pyramid_type";
|
||||
pub const PROP_HISTORY: &str = "solid_history_record";
|
||||
pub const PROP_SHOW_HISTORY: &str = "solid_history_show";
|
||||
@@ -122,6 +129,7 @@ pub fn has_specialized_primitive_properties(
|
||||
| SolidHistoryOperation::Pyramid(_)
|
||||
| SolidHistoryOperation::Sweep(_)
|
||||
| SolidHistoryOperation::Extrusion(_)
|
||||
| SolidHistoryOperation::Revolve(_)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -147,10 +155,112 @@ pub fn reference_point(operation: &SolidHistoryOperation) -> Option<glam::DVec3>
|
||||
),
|
||||
SolidHistoryOperation::Torus(value) => world_point(value.base.transform, [0.0; 3]),
|
||||
SolidHistoryOperation::Pyramid(value) => world_point(value.base.transform, [0.0; 3]),
|
||||
SolidHistoryOperation::Revolve(value) => world_point(
|
||||
value.base.transform,
|
||||
[value.axis_point.x, value.axis_point.y, value.axis_point.z],
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn revolve_properties(
|
||||
document: &acadrust::CadDocument,
|
||||
handle: acadrust::Handle,
|
||||
value: &SolidHistoryRevolve,
|
||||
) -> Vec<PropSection> {
|
||||
let Some(axis_position) = world_point(
|
||||
value.base.transform,
|
||||
[value.axis_point.x, value.axis_point.y, value.axis_point.z],
|
||||
) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Some(axis_direction) = world_vector(
|
||||
value.base.transform,
|
||||
[value.direction.x, value.direction.y, value.direction.z],
|
||||
) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let (record_history, object_show_history, show_history_mode) =
|
||||
history_flags(document, handle).unwrap_or((false, false, 1));
|
||||
let (show_history, show_history_editable) =
|
||||
displayed_history_state(object_show_history, show_history_mode);
|
||||
let show_value = if show_history { "Yes" } else { "No" };
|
||||
vec![
|
||||
PropSection {
|
||||
title: t!("Geometry").into_owned(),
|
||||
props: vec![
|
||||
Property {
|
||||
label: t!("Solid type").into_owned(),
|
||||
field: "solid_history_type",
|
||||
value: PropValue::ReadOnly(t!("Revolve").into_owned()),
|
||||
},
|
||||
Property {
|
||||
label: t!("Angle of revolution").into_owned(),
|
||||
field: PROP_REVOLVE_ANGLE,
|
||||
value: PropValue::EditText(crate::entities::common::format_angle(
|
||||
value.revolve_angle,
|
||||
)),
|
||||
},
|
||||
crate::entities::common::edit_prop(
|
||||
t!("Axis position X").as_ref(),
|
||||
PROP_AXIS_POSITION_X,
|
||||
axis_position.x,
|
||||
),
|
||||
crate::entities::common::edit_prop(
|
||||
t!("Axis position Y").as_ref(),
|
||||
PROP_AXIS_POSITION_Y,
|
||||
axis_position.y,
|
||||
),
|
||||
crate::entities::common::edit_prop(
|
||||
t!("Axis position Z").as_ref(),
|
||||
PROP_AXIS_POSITION_Z,
|
||||
axis_position.z,
|
||||
),
|
||||
crate::entities::common::edit_scalar_prop(
|
||||
t!("Axis direction X").as_ref(),
|
||||
PROP_AXIS_DIRECTION_X,
|
||||
axis_direction.x,
|
||||
),
|
||||
crate::entities::common::edit_scalar_prop(
|
||||
t!("Axis direction Y").as_ref(),
|
||||
PROP_AXIS_DIRECTION_Y,
|
||||
axis_direction.y,
|
||||
),
|
||||
crate::entities::common::edit_scalar_prop(
|
||||
t!("Axis direction Z").as_ref(),
|
||||
PROP_AXIS_DIRECTION_Z,
|
||||
axis_direction.z,
|
||||
),
|
||||
],
|
||||
},
|
||||
PropSection {
|
||||
title: t!("Solid History").into_owned(),
|
||||
props: vec![
|
||||
Property {
|
||||
label: t!("History").into_owned(),
|
||||
field: PROP_HISTORY,
|
||||
value: PropValue::Choice {
|
||||
selected: if record_history { "Record" } else { "None" }.to_string(),
|
||||
options: vec!["None".to_string(), "Record".to_string()],
|
||||
},
|
||||
},
|
||||
Property {
|
||||
label: t!("Show History").into_owned(),
|
||||
field: PROP_SHOW_HISTORY,
|
||||
value: if show_history_editable {
|
||||
PropValue::Choice {
|
||||
selected: show_value.to_string(),
|
||||
options: vec!["No".to_string(), "Yes".to_string()],
|
||||
}
|
||||
} else {
|
||||
PropValue::ReadOnly(show_value.to_string())
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn extrusion_properties(
|
||||
document: &acadrust::CadDocument,
|
||||
handle: acadrust::Handle,
|
||||
@@ -1021,6 +1131,7 @@ pub fn primitive_properties(
|
||||
SolidHistoryOperation::Extrusion(value) => {
|
||||
extrusion_properties(document, handle, value)
|
||||
}
|
||||
SolidHistoryOperation::Revolve(value) => revolve_properties(document, handle, value),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -1053,6 +1164,13 @@ pub fn is_primitive_property(field: &str) -> bool {
|
||||
| PROP_SCALE_ALONG_PATH
|
||||
| PROP_EXTRUSION_HEIGHT
|
||||
| PROP_TAPER_ANGLE
|
||||
| PROP_REVOLVE_ANGLE
|
||||
| PROP_AXIS_POSITION_X
|
||||
| PROP_AXIS_POSITION_Y
|
||||
| PROP_AXIS_POSITION_Z
|
||||
| PROP_AXIS_DIRECTION_X
|
||||
| PROP_AXIS_DIRECTION_Y
|
||||
| PROP_AXIS_DIRECTION_Z
|
||||
| PROP_PYRAMID_TYPE
|
||||
)
|
||||
}
|
||||
@@ -1142,6 +1260,93 @@ fn apply_extrusion_geometry_property(
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_revolve_geometry_property(
|
||||
value: &mut SolidHistoryRevolve,
|
||||
field: &str,
|
||||
text: &str,
|
||||
) -> Option<bool> {
|
||||
if field == PROP_REVOLVE_ANGLE {
|
||||
let angle = crate::entities::common::parse_angle(text)?;
|
||||
if !angle.is_finite()
|
||||
|| angle.abs() <= 1e-12
|
||||
|| angle.abs() > std::f64::consts::TAU + 1e-12
|
||||
|| (angle - value.revolve_angle).abs() <= 1e-12
|
||||
{
|
||||
return Some(false);
|
||||
}
|
||||
value.revolve_angle = angle;
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
if matches!(
|
||||
field,
|
||||
PROP_AXIS_POSITION_X | PROP_AXIS_POSITION_Y | PROP_AXIS_POSITION_Z
|
||||
) {
|
||||
let axis = match field {
|
||||
PROP_AXIS_POSITION_X => 0,
|
||||
PROP_AXIS_POSITION_Y => 1,
|
||||
_ => 2,
|
||||
};
|
||||
let target = crate::entities::common::parse_length(text)?;
|
||||
if !target.is_finite() {
|
||||
return Some(false);
|
||||
}
|
||||
let mut world = world_point(
|
||||
value.base.transform,
|
||||
[value.axis_point.x, value.axis_point.y, value.axis_point.z],
|
||||
)?;
|
||||
if (world[axis] - target).abs() <= 1e-12 {
|
||||
return Some(false);
|
||||
}
|
||||
world[axis] = target;
|
||||
let local = local_point(value.base.transform, world)?;
|
||||
if !local.is_finite() {
|
||||
return Some(false);
|
||||
}
|
||||
value.axis_point = acadrust::types::Vector3::new(local.x, local.y, local.z);
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
if matches!(
|
||||
field,
|
||||
PROP_AXIS_DIRECTION_X | PROP_AXIS_DIRECTION_Y | PROP_AXIS_DIRECTION_Z
|
||||
) {
|
||||
let axis = match field {
|
||||
PROP_AXIS_DIRECTION_X => 0,
|
||||
PROP_AXIS_DIRECTION_Y => 1,
|
||||
_ => 2,
|
||||
};
|
||||
let target = text.trim().replace(',', ".").parse::<f64>().ok()?;
|
||||
if !target.is_finite() {
|
||||
return Some(false);
|
||||
}
|
||||
let mut world = world_vector(
|
||||
value.base.transform,
|
||||
[value.direction.x, value.direction.y, value.direction.z],
|
||||
)?;
|
||||
world[axis] = target;
|
||||
let Some(world) = world.try_normalize() else {
|
||||
return Some(false);
|
||||
};
|
||||
let Some(local) = matrix(value.base.transform)?
|
||||
.inverse()
|
||||
.transform_vector3(world)
|
||||
.try_normalize()
|
||||
else {
|
||||
return Some(false);
|
||||
};
|
||||
let current = glam::DVec3::new(value.direction.x, value.direction.y, value.direction.z)
|
||||
.normalize_or_zero();
|
||||
if (local - current).length_squared() <= 1e-24 {
|
||||
return Some(false);
|
||||
}
|
||||
value.direction = acadrust::types::Vector3::new(local.x, local.y, local.z);
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn apply_history_choice(
|
||||
document: &mut acadrust::CadDocument,
|
||||
handle: acadrust::Handle,
|
||||
@@ -1578,6 +1783,11 @@ pub fn apply_primitive_property(
|
||||
return applied;
|
||||
}
|
||||
}
|
||||
if let SolidHistoryOperation::Revolve(revolve_value) = operation {
|
||||
if let Some(applied) = apply_revolve_geometry_property(revolve_value, field, value) {
|
||||
return applied;
|
||||
}
|
||||
}
|
||||
if let SolidHistoryOperation::Torus(torus_value) = operation {
|
||||
if let Some(applied) = apply_torus_position_property(torus_value, field, value) {
|
||||
return applied;
|
||||
|
||||
@@ -386,15 +386,65 @@ pub fn revolved(
|
||||
from: [f64; 3],
|
||||
to: [f64; 3],
|
||||
angle: f64,
|
||||
start_angle: f64,
|
||||
) -> Option<Body> {
|
||||
let profile = profile_of(entity)?;
|
||||
brep::revolve(
|
||||
profile.plane,
|
||||
&profile.pieces,
|
||||
from,
|
||||
[to[0] - from[0], to[1] - from[1], to[2] - from[2]],
|
||||
angle,
|
||||
)
|
||||
let axis = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
|
||||
let body = if let Some((plane, profiles)) =
|
||||
region_profiles(entity).filter(|(_, profiles)| profiles.len() > 1)
|
||||
{
|
||||
brep::revolve_region(plane, &profiles, from, axis, angle)?
|
||||
} else {
|
||||
let profile = profile_of(entity)?;
|
||||
brep::revolve(profile.plane, &profile.pieces, from, axis, angle)?
|
||||
};
|
||||
turn_revolved_body(body, from, axis, start_angle)
|
||||
}
|
||||
|
||||
/// REVOLVE sheet mode for an open or closed planar profile.
|
||||
pub fn revolved_surface(
|
||||
entity: &EntityType,
|
||||
from: [f64; 3],
|
||||
to: [f64; 3],
|
||||
angle: f64,
|
||||
start_angle: f64,
|
||||
) -> Option<Body> {
|
||||
let axis = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
|
||||
let body = if let Some((plane, profiles)) =
|
||||
region_profiles(entity).filter(|(_, profiles)| profiles.len() > 1)
|
||||
{
|
||||
brep::revolve_surface_region(plane, &profiles, from, axis, angle)?
|
||||
} else {
|
||||
let (profile, _) = extrusion_profile_of(entity)?;
|
||||
brep::revolve_surface(profile.plane, &profile.pieces, from, axis, angle)?
|
||||
};
|
||||
turn_revolved_body(body, from, axis, start_angle)
|
||||
}
|
||||
|
||||
fn turn_revolved_body(
|
||||
body: Body,
|
||||
pivot: [f64; 3],
|
||||
axis: [f64; 3],
|
||||
angle: f64,
|
||||
) -> Option<Body> {
|
||||
if !angle.is_finite() {
|
||||
return None;
|
||||
}
|
||||
if angle.abs() <= 1e-12 {
|
||||
return Some(body);
|
||||
}
|
||||
let axis = Vec3::from(axis).normalize()?;
|
||||
let rotate = |vector: Vec3| {
|
||||
let (sin, cos) = angle.sin_cos();
|
||||
vector * cos + axis.cross(vector) * sin + axis * axis.dot(vector) * (1.0 - cos)
|
||||
};
|
||||
let pivot = Vec3::from(pivot);
|
||||
let placement = brep::Placement {
|
||||
x_axis: rotate(Vec3::X).to_array(),
|
||||
y_axis: rotate(Vec3::Y).to_array(),
|
||||
z_axis: rotate(Vec3::Z).to_array(),
|
||||
origin: (pivot - rotate(pivot)).to_array(),
|
||||
};
|
||||
brep::transform(&body, &placement)
|
||||
}
|
||||
|
||||
fn profile_center(profile: &Profile) -> Option<Vec3> {
|
||||
@@ -413,8 +463,13 @@ pub fn revolve_history(
|
||||
from: [f64; 3],
|
||||
to: [f64; 3],
|
||||
angle: f64,
|
||||
start_angle: f64,
|
||||
) -> Option<SolidHistoryOperation> {
|
||||
if !angle.is_finite() || angle.abs() <= 1e-12 {
|
||||
if !angle.is_finite()
|
||||
|| angle.abs() <= 1e-12
|
||||
|| !start_angle.is_finite()
|
||||
|| matches!(entity, EntityType::Region(region) if region.wires.len() > 1)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let profile = profile_of(entity)?;
|
||||
@@ -422,16 +477,27 @@ pub fn revolve_history(
|
||||
let direction = (Vec3::from(to) - from).normalize()?;
|
||||
let center = profile_center(&profile)?;
|
||||
let axis_point = from + direction * (center - from).dot(direction);
|
||||
let (sweep_entity, transform) = embedded_planar_entity(entity)?;
|
||||
let transform = glam::DMat4::from_cols_array(&transform);
|
||||
let inverse = transform.inverse();
|
||||
if !transform.is_finite() || !inverse.is_finite() || transform.determinant().abs() <= 1e-12 {
|
||||
return None;
|
||||
}
|
||||
let axis_point = inverse.transform_point3(glam::DVec3::from_array(axis_point.to_array()));
|
||||
let direction = inverse
|
||||
.transform_vector3(glam::DVec3::from_array(direction.to_array()))
|
||||
.try_normalize()?;
|
||||
let mut base = SolidHistoryNodeBase::new(1);
|
||||
base.transform = glam::DMat4::IDENTITY.to_cols_array();
|
||||
base.transform = transform.to_cols_array();
|
||||
Some(SolidHistoryOperation::Revolve(SolidHistoryRevolve {
|
||||
base,
|
||||
operation_major: 1,
|
||||
axis_point: Vector3::new(axis_point.x, axis_point.y, axis_point.z),
|
||||
direction: Vector3::new(direction.x, direction.y, direction.z),
|
||||
revolve_angle: angle,
|
||||
start_angle,
|
||||
flag_290: true,
|
||||
sweep_entity: Some(embedded_path(entity)?),
|
||||
sweep_entity: Some(sweep_entity),
|
||||
..SolidHistoryRevolve::default()
|
||||
}))
|
||||
}
|
||||
@@ -597,6 +663,10 @@ fn embedded_planar_entity(entity: &EntityType) -> Option<(EmbeddedEntity, [f64;
|
||||
Some((EmbeddedEntity::LwPolyline(polyline), transform))
|
||||
}
|
||||
|
||||
pub fn embedded_revolve_profile(entity: &EntityType) -> Option<(EmbeddedEntity, [f64; 16])> {
|
||||
embedded_planar_entity(entity)
|
||||
}
|
||||
|
||||
pub fn extrusion_history(
|
||||
profile: &EntityType,
|
||||
path: Option<&EntityType>,
|
||||
@@ -850,6 +920,7 @@ mod tests {
|
||||
[0.0, 0.0, 0.0],
|
||||
[0.0, 10.0, 0.0],
|
||||
std::f64::consts::TAU,
|
||||
0.0,
|
||||
);
|
||||
// The profile is in the XY plane and the axis lies in it, so this is
|
||||
// a revolution about the y axis: radius ten, height ten.
|
||||
@@ -875,7 +946,8 @@ mod tests {
|
||||
&square(10.0),
|
||||
[0.0, 0.0, 0.0],
|
||||
[0.0, 1.0, 1.0],
|
||||
std::f64::consts::TAU
|
||||
std::f64::consts::TAU,
|
||||
0.0,
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user