forked from 1b-agent/opencadstudio-upstream
Restore revolve profile and axis grips (#976)
Restore revolve profile and axis grips
This commit is contained in:
5 files changed
+182
-19
No files matched your search
Generated
+3
-3
@@ -71,8 +71,8 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "acadrust"
|
name = "acadrust"
|
||||||
version = "0.4.1"
|
version = "0.5.1"
|
||||||
source = "git+https://git@github.com/HakanSeven12/cadcodec.git?rev=a0f7d444f1607bc4b2c881060cbe7ea1014253cb#a0f7d444f1607bc4b2c881060cbe7ea1014253cb"
|
source = "git+https://git@github.com/HakanSeven12/cadcodec.git?rev=393d6c0857447f9ca678bed97a612707f0a842c6#393d6c0857447f9ca678bed97a612707f0a842c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash 0.8.12",
|
"ahash 0.8.12",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -878,7 +878,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "cadkernel"
|
name = "cadkernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=92578f0cc8e4eec0678b72c9bd1c701ff21b57b7#92578f0cc8e4eec0678b72c9bd1c701ff21b57b7"
|
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=fb5a5c18f794df30e97c712fb5d4fe7c6629d1d5#fb5a5c18f794df30e97c712fb5d4fe7c6629d1d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"acadrust",
|
"acadrust",
|
||||||
"cavalier_contours",
|
"cavalier_contours",
|
||||||
|
|||||||
+3
-3
@@ -27,8 +27,8 @@ glam = { version = "0.33", features = ["bytemuck"] }
|
|||||||
rfd = "0.17"
|
rfd = "0.17"
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "a0f7d444f1607bc4b2c881060cbe7ea1014253cb", features = ["serde"] }
|
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "393d6c0857447f9ca678bed97a612707f0a842c6", features = ["serde"] }
|
||||||
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "92578f0cc8e4eec0678b72c9bd1c701ff21b57b7", features = ["acis", "offset"] }
|
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "fb5a5c18f794df30e97c712fb5d4fe7c6629d1d5", features = ["acis", "offset"] }
|
||||||
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
||||||
@@ -61,7 +61,7 @@ iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aa
|
|||||||
iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||||
|
|
||||||
[patch."https://github.com/HakanSeven12/cadcodec.git"]
|
[patch."https://github.com/HakanSeven12/cadcodec.git"]
|
||||||
acadrust = { git = "https://git@github.com/HakanSeven12/cadcodec.git", rev = "a0f7d444f1607bc4b2c881060cbe7ea1014253cb" }
|
acadrust = { git = "https://git@github.com/HakanSeven12/cadcodec.git", rev = "393d6c0857447f9ca678bed97a612707f0a842c6" }
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
|||||||
+21
-12
@@ -3837,18 +3837,27 @@ impl OpenCADStudio {
|
|||||||
|
|
||||||
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
|
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
|
||||||
if let Some(entity) = entity_opt {
|
if let Some(entity) = entity_opt {
|
||||||
let result = sweep_model::revolved(
|
let from = [
|
||||||
&entity,
|
axis_start.x as f64,
|
||||||
[
|
axis_start.y as f64,
|
||||||
axis_start.x as f64,
|
axis_start.z as f64,
|
||||||
axis_start.y as f64,
|
];
|
||||||
axis_start.z as f64,
|
let to = [axis_end.x as f64, axis_end.y as f64, axis_end.z as f64];
|
||||||
],
|
let angle = (angle_deg as f64).to_radians();
|
||||||
[axis_end.x as f64, axis_end.y as f64, axis_end.z as f64],
|
let result = sweep_model::revolve_history(&entity, from, to, angle)
|
||||||
(angle_deg as f64).to_radians(),
|
.and_then(|history| {
|
||||||
);
|
cadkernel::acis::rebuild_body(&history)
|
||||||
if let Some(solid) = result {
|
.ok()
|
||||||
let history = crate::scene::model::solid_history::brep_op(&solid);
|
.map(|solid| (solid, history))
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
sweep_model::revolved(&entity, from, to, angle).map(|solid| {
|
||||||
|
let history =
|
||||||
|
crate::scene::model::solid_history::brep_op(&solid);
|
||||||
|
(solid, history)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if let Some((solid, history)) = result {
|
||||||
let pending = self.begin_undo(i, "REVOLVE", 1, true);
|
let pending = self.begin_undo(i, "REVOLVE", 1, true);
|
||||||
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() {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use acadrust::entities::{EmbeddedEntity, Solid3D};
|
|||||||
use acadrust::objects::{
|
use acadrust::objects::{
|
||||||
DynamicBlockData, ObjectType, SolidHistoryBox, SolidHistoryBrep, SolidHistoryCone,
|
DynamicBlockData, ObjectType, SolidHistoryBox, SolidHistoryBrep, SolidHistoryCone,
|
||||||
SolidHistoryCylinder, SolidHistoryLoft, SolidHistoryNodeBase, SolidHistoryOperation,
|
SolidHistoryCylinder, SolidHistoryLoft, SolidHistoryNodeBase, SolidHistoryOperation,
|
||||||
SolidHistoryPyramid, SolidHistorySphere, SolidHistorySweep, SolidHistoryTorus,
|
SolidHistoryPyramid, SolidHistoryRevolve, SolidHistorySphere, SolidHistorySweep,
|
||||||
|
SolidHistoryTorus,
|
||||||
};
|
};
|
||||||
use acadrust::EntityType;
|
use acadrust::EntityType;
|
||||||
use cadkernel::brep::Body;
|
use cadkernel::brep::Body;
|
||||||
@@ -29,6 +30,8 @@ pub const GRIP_PROFILE_FIRST: usize = 10_200;
|
|||||||
pub const GRIP_SWEEP_PROFILE_FIRST: usize = 20_000;
|
pub const GRIP_SWEEP_PROFILE_FIRST: usize = 20_000;
|
||||||
pub const GRIP_SWEEP_PATH_FIRST: usize = 30_000;
|
pub const GRIP_SWEEP_PATH_FIRST: usize = 30_000;
|
||||||
pub const GRIP_LOFT_SECTION_FIRST: usize = 40_000;
|
pub const GRIP_LOFT_SECTION_FIRST: usize = 40_000;
|
||||||
|
pub const GRIP_REVOLVE_PROFILE_FIRST: usize = 50_000;
|
||||||
|
pub const GRIP_REVOLVE_AXIS: usize = 10_013;
|
||||||
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;
|
||||||
@@ -2146,6 +2149,100 @@ fn apply_loft_section_grip(
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn revolve_profile_matrix(value: &SolidHistoryRevolve) -> Option<glam::DMat4> {
|
||||||
|
let base = matrix(value.base.transform)?;
|
||||||
|
let axis_point = glam::DVec3::new(
|
||||||
|
value.axis_point.x,
|
||||||
|
value.axis_point.y,
|
||||||
|
value.axis_point.z,
|
||||||
|
);
|
||||||
|
let axis = glam::DVec3::new(value.direction.x, value.direction.y, value.direction.z)
|
||||||
|
.try_normalize()?;
|
||||||
|
if !axis_point.is_finite() || !value.start_angle.is_finite() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(
|
||||||
|
base
|
||||||
|
* glam::DMat4::from_translation(axis_point)
|
||||||
|
* glam::DMat4::from_axis_angle(axis, value.start_angle)
|
||||||
|
* glam::DMat4::from_translation(-axis_point),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn revolve_profile_grips(value: &SolidHistoryRevolve) -> Vec<GripDef> {
|
||||||
|
let Some(profile) = value.sweep_entity.as_ref().and_then(embedded_entity) else {
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let Some(transform) = revolve_profile_matrix(value) else {
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
profile
|
||||||
|
.grips()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(index, source)| {
|
||||||
|
let world = transform.transform_point3(source.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: GRIP_REVOLVE_PROFILE_FIRST + index,
|
||||||
|
world,
|
||||||
|
is_midpoint: source.is_midpoint,
|
||||||
|
shape: source.shape,
|
||||||
|
dir: source.dir.and_then(transform_vector),
|
||||||
|
axis: source.axis.and_then(transform_vector),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_revolve_profile_grip(
|
||||||
|
value: &mut SolidHistoryRevolve,
|
||||||
|
index: usize,
|
||||||
|
apply: GripApply,
|
||||||
|
) -> bool {
|
||||||
|
let Some(mut profile) = value.sweep_entity.as_ref().and_then(embedded_entity) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(source) = profile.grips().get(index).cloned() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(transform) = revolve_profile_matrix(value) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let inverse = transform.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(delta) => {
|
||||||
|
let local = inverse.transform_vector3(delta);
|
||||||
|
if !local.is_finite() || local.length_squared() <= 1e-24 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GripApply::Translate(local)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
profile.apply_grip(source.id, apply);
|
||||||
|
let Some(profile) = into_embedded_entity(profile) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
value.sweep_entity = Some(profile);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn extrusion_draft_grip(
|
fn extrusion_draft_grip(
|
||||||
value: &SolidHistorySweep,
|
value: &SolidHistorySweep,
|
||||||
) -> Option<(glam::DVec3, glam::DVec3, glam::DVec3, f64, f64)> {
|
) -> Option<(glam::DVec3, glam::DVec3, glam::DVec3, f64, f64)> {
|
||||||
@@ -2472,6 +2569,16 @@ pub fn primitive_grips(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
SolidHistoryOperation::Loft(value) => grips.extend(loft_section_grips(value)),
|
SolidHistoryOperation::Loft(value) => grips.extend(loft_section_grips(value)),
|
||||||
|
SolidHistoryOperation::Revolve(value) => {
|
||||||
|
add(
|
||||||
|
GRIP_REVOLVE_AXIS,
|
||||||
|
value.base.transform,
|
||||||
|
[value.axis_point.x, value.axis_point.y, value.axis_point.z],
|
||||||
|
GripShape::Square,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
grips.extend(revolve_profile_grips(value));
|
||||||
|
}
|
||||||
SolidHistoryOperation::Extrusion(value) => {
|
SolidHistoryOperation::Extrusion(value) => {
|
||||||
let (profile_grips, profile_center) = extrusion_profile_grips(value);
|
let (profile_grips, profile_center) = extrusion_profile_grips(value);
|
||||||
grips.extend(profile_grips);
|
grips.extend(profile_grips);
|
||||||
@@ -2508,6 +2615,11 @@ pub fn apply_primitive_grip(
|
|||||||
grip_id: usize,
|
grip_id: usize,
|
||||||
apply: GripApply,
|
apply: GripApply,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if let SolidHistoryOperation::Revolve(value) = operation {
|
||||||
|
if let Some(index) = grip_id.checked_sub(GRIP_REVOLVE_PROFILE_FIRST) {
|
||||||
|
return apply_revolve_profile_grip(value, index, apply);
|
||||||
|
}
|
||||||
|
}
|
||||||
if let SolidHistoryOperation::Loft(value) = operation {
|
if let SolidHistoryOperation::Loft(value) = operation {
|
||||||
if let Some(index) = grip_id.checked_sub(GRIP_LOFT_SECTION_FIRST) {
|
if let Some(index) = grip_id.checked_sub(GRIP_LOFT_SECTION_FIRST) {
|
||||||
return apply_loft_section_grip(value, index, apply);
|
return apply_loft_section_grip(value, index, apply);
|
||||||
@@ -2677,6 +2789,9 @@ pub fn apply_primitive_grip(
|
|||||||
}
|
}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
},
|
},
|
||||||
|
SolidHistoryOperation::Revolve(value) if grip_id == GRIP_REVOLVE_AXIS => {
|
||||||
|
value.axis_point = acadrust::types::Vector3::new(local.x, local.y, local.z);
|
||||||
|
}
|
||||||
SolidHistoryOperation::Extrusion(value) => match grip_id {
|
SolidHistoryOperation::Extrusion(value) => match grip_id {
|
||||||
GRIP_HEIGHT => {
|
GRIP_HEIGHT => {
|
||||||
if value.path_entity.is_some() {
|
if value.path_entity.is_some() {
|
||||||
|
|||||||
@@ -396,6 +396,45 @@ pub fn revolved(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn profile_center(profile: &Profile) -> Option<Vec3> {
|
||||||
|
let count = profile.pieces.len();
|
||||||
|
let sum = profile.pieces.iter().try_fold(Vec3::ZERO, |sum, piece| {
|
||||||
|
let point = Vec3::from(profile.plane.point_at(piece.point_at(0.0)));
|
||||||
|
point.is_finite().then_some(sum + point)
|
||||||
|
})?;
|
||||||
|
(count > 0).then_some(sum / count as f64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the source profile and canonical axis required to rebuild and edit
|
||||||
|
/// a revolved solid.
|
||||||
|
pub fn revolve_history(
|
||||||
|
entity: &EntityType,
|
||||||
|
from: [f64; 3],
|
||||||
|
to: [f64; 3],
|
||||||
|
angle: f64,
|
||||||
|
) -> Option<SolidHistoryOperation> {
|
||||||
|
if !angle.is_finite() || angle.abs() <= 1e-12 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let profile = profile_of(entity)?;
|
||||||
|
let from = Vec3::from(from);
|
||||||
|
let direction = (Vec3::from(to) - from).normalize()?;
|
||||||
|
let center = profile_center(&profile)?;
|
||||||
|
let axis_point = from + direction * (center - from).dot(direction);
|
||||||
|
let mut base = SolidHistoryNodeBase::new(1);
|
||||||
|
base.transform = glam::DMat4::IDENTITY.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,
|
||||||
|
flag_290: true,
|
||||||
|
sweep_entity: Some(embedded_path(entity)?),
|
||||||
|
..SolidHistoryRevolve::default()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// SWEEP as an exact B-rep along straight and circular path pieces.
|
/// SWEEP as an exact B-rep along straight and circular path pieces.
|
||||||
pub fn swept(profile: &EntityType, path: &EntityType) -> Option<Body> {
|
pub fn swept(profile: &EntityType, path: &EntityType) -> Option<Body> {
|
||||||
let profile = profile_of(profile)?;
|
let profile = profile_of(profile)?;
|
||||||
|
|||||||
Reference in new issue
Block a user