diff --git a/Cargo.lock b/Cargo.lock index 1f5a6b495..df993e5a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -878,7 +878,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=1e19ad4e4d35cc04384bf72bc9c6d0445876c2d9#1e19ad4e4d35cc04384bf72bc9c6d0445876c2d9" +source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=a809cb32cc6d90fd0e9c4199c3b4977cd56b7fa8#a809cb32cc6d90fd0e9c4199c3b4977cd56b7fa8" dependencies = [ "acadrust", "cavalier_contours", diff --git a/Cargo.toml b/Cargo.toml index fe53217f3..6a5e39342 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ rfd = "0.17" clap = { version = "4", features = ["derive"] } env_logger = "0.11" acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "a0f7d444f1607bc4b2c881060cbe7ea1014253cb", features = ["serde"] } -cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "1e19ad4e4d35cc04384bf72bc9c6d0445876c2d9", features = ["acis", "offset"] } +cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "a809cb32cc6d90fd0e9c4199c3b4977cd56b7fa8", features = ["acis", "offset"] } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } flate2 = "1" image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] } diff --git a/src/app/model_ops.rs b/src/app/model_ops.rs index d99cc66c1..1de87371e 100644 --- a/src/app/model_ops.rs +++ b/src/app/model_ops.rs @@ -23,6 +23,7 @@ impl super::OpenCADStudio { let EntityType::Solid3D(inner) = &mut entity else { return Handle::NULL; }; + inner.common.plotstyle_flags = 2; inner.wires = solid_model::edge_wires(&solid); let Some(document) = crate::scene::convert::acis_export::solid_to_sat(&solid) else { diff --git a/src/app/properties.rs b/src/app/properties.rs index d0038380e..8c95cfa38 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -3066,9 +3066,7 @@ fn retain_specialized_primitive_sections( | "transparency" | "hyperlink" | "material" - | "solid_history_type" - ) || crate::scene::model::solid_history::is_primitive_property(property.field) - || crate::scene::model::solid_history::is_history_choice(property.field) + ) || crate::scene::model::solid_history::is_specialized_property(property.field) }); }); sections.retain(|section| !section.props.is_empty()); diff --git a/src/scene/model/solid_history.rs b/src/scene/model/solid_history.rs index 8c5d838da..3542bf6dd 100644 --- a/src/scene/model/solid_history.rs +++ b/src/scene/model/solid_history.rs @@ -52,6 +52,11 @@ pub const PROP_POSITION_X: &str = "solid_history_position_x"; pub const PROP_POSITION_Y: &str = "solid_history_position_y"; pub const PROP_POSITION_Z: &str = "solid_history_position_z"; pub const PROP_ROTATION: &str = "solid_history_rotation"; +pub const PROP_PROFILE_ROTATION: &str = "solid_history_profile_rotation"; +pub const PROP_BANK: &str = "solid_history_bank"; +pub const PROP_TWIST_ALONG_PATH: &str = "solid_history_twist_along_path"; +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_PYRAMID_TYPE: &str = "solid_history_pyramid_type"; pub const PROP_HISTORY: &str = "solid_history_record"; pub const PROP_SHOW_HISTORY: &str = "solid_history_show"; @@ -139,20 +144,14 @@ fn sweep_properties( handle: acadrust::Handle, value: &SolidHistorySweep, ) -> Vec { - let Some(position) = world_point( - value.base.transform, - [ - value.reference_point.x, - value.reference_point.y, - value.reference_point.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, _) = displayed_history_state(object_show_history, show_history_mode); + let (show_history, show_history_editable) = + displayed_history_state(object_show_history, show_history_mode); let show_value = if show_history { "Yes" } else { "No" }; + let length = sweep_path_length(value) + .map(crate::entities::common::format_length) + .unwrap_or_default(); vec![ PropSection { title: t!("Geometry").into_owned(), @@ -162,21 +161,37 @@ fn sweep_properties( field: "solid_history_type", value: PropValue::ReadOnly(t!("Sweep").into_owned()), }, - crate::entities::common::edit_prop( - t!("Position X").as_ref(), - PROP_POSITION_X, - position.x, - ), - crate::entities::common::edit_prop( - t!("Position Y").as_ref(), - PROP_POSITION_Y, - position.y, - ), - crate::entities::common::edit_prop( - t!("Position Z").as_ref(), - PROP_POSITION_Z, - position.z, - ), + Property { + label: t!("Profile rotation").into_owned(), + field: PROP_PROFILE_ROTATION, + value: PropValue::EditText( + crate::entities::common::format_angle(value.align_angle), + ), + }, + Property { + label: t!("Bank").into_owned(), + field: PROP_BANK, + value: PropValue::ReadOnly( + if value.bank { "Yes" } else { "No" }.to_string(), + ), + }, + Property { + label: t!("Twist along path").into_owned(), + field: PROP_TWIST_ALONG_PATH, + value: PropValue::EditText( + crate::entities::common::format_angle(value.twist_angle), + ), + }, + Property { + label: t!("Scale along path").into_owned(), + field: PROP_SCALE_ALONG_PATH, + value: PropValue::EditText(value.scale_factor.to_string()), + }, + Property { + label: t!("Length").into_owned(), + field: PROP_SWEEP_LENGTH, + value: PropValue::ReadOnly(length), + }, ], }, PropSection { @@ -185,20 +200,61 @@ fn sweep_properties( Property { label: t!("History").into_owned(), field: PROP_HISTORY, - value: PropValue::ReadOnly( - if record_history { "Record" } else { "None" }.to_string(), - ), + 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: PropValue::ReadOnly(show_value.to_string()), + 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 sweep_path_length(value: &SolidHistorySweep) -> Option { + use acadrust::entities::EmbeddedEntity; + use acadrust::EntityType; + + let entity = match value.path_entity.as_ref()? { + 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()), + _ => return None, + }; + let curve = crate::entities::curve::entity_curve(&entity)?; + let transform = value.path_entity_transform; + if transform.iter().any(|value| !value.is_finite()) + || transform[3].abs() > 1e-9 + || transform[7].abs() > 1e-9 + || transform[11].abs() > 1e-9 + || (transform[15] - 1.0).abs() > 1e-9 + { + return None; + } + let placement = cadkernel::brep::Placement { + x_axis: [transform[0], transform[1], transform[2]], + y_axis: [transform[4], transform[5], transform[6]], + z_axis: [transform[8], transform[9], transform[10]], + origin: [transform[12], transform[13], transform[14]], + }; + let length = curve.curve.length() * placement.scale()?; + (length.is_finite() && length >= 0.0).then_some(length) +} + fn torus_properties( document: &acadrust::CadDocument, handle: acadrust::Handle, @@ -860,6 +916,9 @@ pub fn is_primitive_property(field: &str) -> bool { | PROP_POSITION_Y | PROP_POSITION_Z | PROP_ROTATION + | PROP_PROFILE_ROTATION + | PROP_TWIST_ALONG_PATH + | PROP_SCALE_ALONG_PATH | PROP_PYRAMID_TYPE ) } @@ -868,6 +927,12 @@ pub fn is_history_choice(field: &str) -> bool { matches!(field, PROP_HISTORY | PROP_SHOW_HISTORY) } +pub fn is_specialized_property(field: &str) -> bool { + matches!(field, "solid_history_type" | PROP_BANK | PROP_SWEEP_LENGTH) + || is_primitive_property(field) + || is_history_choice(field) +} + pub fn apply_history_choice( document: &mut acadrust::CadDocument, handle: acadrust::Handle, @@ -1067,38 +1132,41 @@ fn apply_cylinder_position_property( Some(true) } -fn apply_sweep_position_property( +fn apply_sweep_geometry_property( value: &mut SolidHistorySweep, field: &str, text: &str, ) -> Option { - let axis = match field { - PROP_POSITION_X => 0, - PROP_POSITION_Y => 1, - PROP_POSITION_Z => 2, - _ => return None, - }; - let target = crate::entities::common::parse_length(text)?; - if !target.is_finite() { - return Some(false); + match field { + PROP_PROFILE_ROTATION => { + let target = crate::entities::common::parse_angle(text)?; + if !target.is_finite() || (target - value.align_angle).abs() <= 1e-12 { + return Some(false); + } + value.align_angle = target; + Some(true) + } + PROP_TWIST_ALONG_PATH => { + let target = crate::entities::common::parse_angle(text)?; + if !target.is_finite() || (target - value.twist_angle).abs() <= 1e-12 { + return Some(false); + } + value.twist_angle = target; + Some(true) + } + PROP_SCALE_ALONG_PATH => { + let target = text.trim().replace(',', ".").parse::().ok()?; + if !target.is_finite() + || target <= 1e-9 + || (target - value.scale_factor).abs() <= 1e-12 + { + return Some(false); + } + value.scale_factor = target; + Some(true) + } + _ => None, } - let current = matrix(value.base.transform)?; - let reference = current.transform_point3(glam::DVec3::new( - value.reference_point.x, - value.reference_point.y, - value.reference_point.z, - )); - if !reference.is_finite() || (target - reference[axis]).abs() <= 1e-12 { - return Some(false); - } - let mut delta = glam::DVec3::ZERO; - delta[axis] = target - reference[axis]; - let updated = glam::DMat4::from_translation(delta) * current; - if !updated.is_finite() || updated.determinant().abs() <= 1e-12 { - return Some(false); - } - value.base.transform = updated.to_cols_array(); - Some(true) } fn apply_torus_position_property( @@ -1290,7 +1358,7 @@ pub fn apply_primitive_property( } } if let SolidHistoryOperation::Sweep(sweep_value) = operation { - if let Some(applied) = apply_sweep_position_property(sweep_value, field, value) { + if let Some(applied) = apply_sweep_geometry_property(sweep_value, field, value) { return applied; } }