forked from 1b-agent/opencadstudio-upstream
Fix extruded solid grip preview and taper range
This commit is contained in:
1 parent
3ad0423393
commit
ea6eb58c53
8 files changed
+87
-10
No files matched your search
Generated
+1
-1
@@ -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=fb5a5c18f794df30e97c712fb5d4fe7c6629d1d5#fb5a5c18f794df30e97c712fb5d4fe7c6629d1d5"
|
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=7d1fc67ec179ce9eac726efaedaa7c59d60e2416#7d1fc67ec179ce9eac726efaedaa7c59d60e2416"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"acadrust",
|
"acadrust",
|
||||||
"cavalier_contours",
|
"cavalier_contours",
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ 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 = "393d6c0857447f9ca678bed97a612707f0a842c6", features = ["serde"] }
|
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "393d6c0857447f9ca678bed97a612707f0a842c6", features = ["serde"] }
|
||||||
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "fb5a5c18f794df30e97c712fb5d4fe7c6629d1d5", features = ["acis", "offset"] }
|
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "7d1fc67ec179ce9eac726efaedaa7c59d60e2416", 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"] }
|
||||||
|
|||||||
@@ -1685,14 +1685,21 @@ impl OpenCADStudio {
|
|||||||
} else {
|
} else {
|
||||||
// Current deformed geometry.
|
// Current deformed geometry.
|
||||||
let mut preview =
|
let mut preview =
|
||||||
self.tabs[i].scene.wire_models_for(&edited_handles);
|
self.tabs[i].scene.grip_wire_models_for(&edited_handles);
|
||||||
|
|
||||||
// Also show the drag-start geometry as a faint ghost.
|
// Also show the drag-start geometry as a faint ghost.
|
||||||
//
|
//
|
||||||
// This is display-only. Preview wires never participate in the resident
|
// This is display-only. Preview wires never participate in the resident
|
||||||
// hit-test/snap set, so keeping the original shape visible does not
|
// hit-test/snap set, so keeping the original shape visible does not
|
||||||
// reintroduce self-snapping.
|
// reintroduce self-snapping.
|
||||||
let mut reference = self.grip_reference_wires.clone();
|
let keep_reference_overlay = edited_handles
|
||||||
|
.iter()
|
||||||
|
.any(|handle| self.tabs[i].scene.preview_hidden.contains(handle));
|
||||||
|
let mut reference = if keep_reference_overlay {
|
||||||
|
self.grip_reference_wires.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
for wire in &mut reference {
|
for wire in &mut reference {
|
||||||
wire.selected = false;
|
wire.selected = false;
|
||||||
|
|||||||
@@ -1476,6 +1476,9 @@ pub struct Scene {
|
|||||||
pub selection_filter: HashSet<String>,
|
pub selection_filter: HashSet<String>,
|
||||||
/// In-progress preview wires while a command is active (rubber-band + object ghosts).
|
/// In-progress preview wires while a command is active (rubber-band + object ghosts).
|
||||||
pub preview_wires: Vec<WireModel>,
|
pub preview_wires: Vec<WireModel>,
|
||||||
|
/// Candidate wireframes produced by editable solid-history grips. The
|
||||||
|
/// resident body remains untouched until the grip is committed.
|
||||||
|
solid_history_preview_wires: HashMap<Handle, Vec<WireModel>>,
|
||||||
/// Live hatch fill used by interactive edits such as dragging the pattern
|
/// Live hatch fill used by interactive edits such as dragging the pattern
|
||||||
/// origin grip. Kept separate from the resident hatch set so moving one
|
/// origin grip. Kept separate from the resident hatch set so moving one
|
||||||
/// pattern never re-uploads every hatch in a large drawing.
|
/// pattern never re-uploads every hatch in a large drawing.
|
||||||
@@ -1883,6 +1886,7 @@ impl Scene {
|
|||||||
model_lineweight_scale: 1.0,
|
model_lineweight_scale: 1.0,
|
||||||
selection_filter: HashSet::default(),
|
selection_filter: HashSet::default(),
|
||||||
preview_wires: vec![],
|
preview_wires: vec![],
|
||||||
|
solid_history_preview_wires: HashMap::default(),
|
||||||
preview_hatches: Arc::new(Vec::new()),
|
preview_hatches: Arc::new(Vec::new()),
|
||||||
preview_text: vec![],
|
preview_text: vec![],
|
||||||
interim_wire: None,
|
interim_wire: None,
|
||||||
|
|||||||
@@ -2314,7 +2314,7 @@ fn apply_extrusion_draft_grip(value: &mut SolidHistorySweep, apply: GripApply) -
|
|||||||
let GripApply::Absolute(world) = apply else {
|
let GripApply::Absolute(world) = apply else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let Some((_, base_top, radial, profile_radius, height)) = extrusion_draft_grip(value) else {
|
let Some((_, base_top, radial, _, height)) = extrusion_draft_grip(value) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let top_offset = (world - base_top).dot(radial);
|
let top_offset = (world - base_top).dot(radial);
|
||||||
@@ -2322,10 +2322,27 @@ fn apply_extrusion_draft_grip(value: &mut SolidHistorySweep, apply: GripApply) -
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let limit = 89.0_f64.to_radians();
|
let limit = 89.0_f64.to_radians();
|
||||||
let inward_limit = ((profile_radius - 1e-6).max(1e-6) / height)
|
let desired = (-top_offset).atan2(height).clamp(-limit, limit);
|
||||||
.atan()
|
let angle = if desired > 0.0 && !extrusion_draft_rebuilds(value, desired) {
|
||||||
.min(limit);
|
// The maximum inset is profile-dependent. A corner radius is too
|
||||||
let angle = (-top_offset).atan2(height).clamp(-limit, inward_limit);
|
// restrictive for many outlines, while allowing the pointer through
|
||||||
|
// a collapsed outline makes the top grow again. Search the actual
|
||||||
|
// rebuild boundary so every supported profile reaches its smallest
|
||||||
|
// valid top without crossing into an inverted result.
|
||||||
|
let mut valid = 0.0;
|
||||||
|
let mut invalid = limit;
|
||||||
|
for _ in 0..16 {
|
||||||
|
let candidate = (valid + invalid) * 0.5;
|
||||||
|
if extrusion_draft_rebuilds(value, candidate) {
|
||||||
|
valid = candidate;
|
||||||
|
} else {
|
||||||
|
invalid = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valid
|
||||||
|
} else {
|
||||||
|
desired
|
||||||
|
};
|
||||||
if !angle.is_finite() || (angle - value.draft_angle).abs() <= 1e-12 {
|
if !angle.is_finite() || (angle - value.draft_angle).abs() <= 1e-12 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2333,6 +2350,12 @@ fn apply_extrusion_draft_grip(value: &mut SolidHistorySweep, apply: GripApply) -
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extrusion_draft_rebuilds(value: &SolidHistorySweep, angle: f64) -> bool {
|
||||||
|
let mut candidate = value.clone();
|
||||||
|
candidate.draft_angle = angle;
|
||||||
|
cadkernel::acis::rebuild_body(&SolidHistoryOperation::Extrusion(candidate)).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
fn grip(
|
fn grip(
|
||||||
id: usize,
|
id: usize,
|
||||||
world: glam::DVec3,
|
world: glam::DVec3,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
use cadkernel::brep::{self, Body, Curve3, EdgeKey, FaceKey, Surface};
|
use cadkernel::brep::{self, Body, Curve3, EdgeKey, FaceKey, Surface};
|
||||||
|
|
||||||
use crate::scene::model::mesh_model::{MeshLodSet, MeshModel};
|
use crate::scene::model::mesh_model::{MeshLodSet, MeshModel};
|
||||||
|
use crate::scene::model::wire_model::WireModel;
|
||||||
|
|
||||||
/// What counts as the same point when the kernel checks a body over.
|
/// What counts as the same point when the kernel checks a body over.
|
||||||
const TOL: f64 = 1e-9;
|
const TOL: f64 = 1e-9;
|
||||||
@@ -243,6 +244,27 @@ pub fn edge_wires(body: &Body) -> Vec<acadrust::entities::Wire> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// White wireframe used while a solid-history grip is hot.
|
||||||
|
///
|
||||||
|
/// This deliberately does not touch the resident solid mesh or its entity
|
||||||
|
/// wires: the selected source stays visible in blue while the candidate body
|
||||||
|
/// is presented as a separate, non-pickable outline until placement.
|
||||||
|
pub fn grip_preview_wires(body: &Body, handle: acadrust::Handle) -> Vec<WireModel> {
|
||||||
|
tessellation(body)
|
||||||
|
.edges
|
||||||
|
.into_iter()
|
||||||
|
.filter(|edge| edge.positions.len() >= 2)
|
||||||
|
.map(|edge| {
|
||||||
|
WireModel::solid_f64(
|
||||||
|
format!("{}-GRIP-PREVIEW", handle.value()),
|
||||||
|
edge.positions,
|
||||||
|
WireModel::WHITE,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// B-rep edge nearest a world-space surface pick.
|
/// B-rep edge nearest a world-space surface pick.
|
||||||
pub fn nearest_edge(body: &Body, pick: [f64; 3]) -> Option<EdgeKey> {
|
pub fn nearest_edge(body: &Body, pick: [f64; 3]) -> Option<EdgeKey> {
|
||||||
let pick = cadkernel::space::Vec3::from(pick);
|
let pick = cadkernel::space::Vec3::from(pick);
|
||||||
|
|||||||
+6
-1
@@ -841,6 +841,7 @@ impl Scene {
|
|||||||
handle: Handle,
|
handle: Handle,
|
||||||
operation: acadrust::objects::SolidHistoryOperation,
|
operation: acadrust::objects::SolidHistoryOperation,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
self.solid_history_preview_wires.remove(&handle);
|
||||||
let Ok(body) = cadkernel::acis::rebuild_body(&operation) else {
|
let Ok(body) = cadkernel::acis::rebuild_body(&operation) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -879,6 +880,7 @@ impl Scene {
|
|||||||
};
|
};
|
||||||
entity.set_sat_document(&document);
|
entity.set_sat_document(&document);
|
||||||
self.sync_solid_reference_point(handle);
|
self.sync_solid_reference_point(handle);
|
||||||
|
self.solid_history_preview_wires.remove(&handle);
|
||||||
self.register_solid_model(handle, body);
|
self.register_solid_model(handle, body);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -901,7 +903,10 @@ impl Scene {
|
|||||||
let Some(EntityType::Solid3D(_)) = self.document.get_entity(handle) else {
|
let Some(EntityType::Solid3D(_)) = self.document.get_entity(handle) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
self.register_solid_model(handle, body);
|
self.solid_history_preview_wires.insert(
|
||||||
|
handle,
|
||||||
|
crate::scene::model::solid_model::grip_preview_wires(&body, handle),
|
||||||
|
);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ impl Scene {
|
|||||||
// flips the wire content id back to the base tessellation id, which
|
// flips the wire content id back to the base tessellation id, which
|
||||||
// re-uploads the base wires (without the preview) on the next frame.
|
// re-uploads the base wires (without the preview) on the next frame.
|
||||||
self.preview_wires = vec![];
|
self.preview_wires = vec![];
|
||||||
|
self.solid_history_preview_wires.clear();
|
||||||
if !self.preview_hatches.is_empty() {
|
if !self.preview_hatches.is_empty() {
|
||||||
self.preview_hatches = std::sync::Arc::new(Vec::new());
|
self.preview_hatches = std::sync::Arc::new(Vec::new());
|
||||||
}
|
}
|
||||||
@@ -302,6 +303,21 @@ impl Scene {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Current candidate geometry for a hot grip. Solid-history candidates
|
||||||
|
/// live outside the document until placement; ordinary entities continue
|
||||||
|
/// to use their current tessellation.
|
||||||
|
pub fn grip_wire_models_for(&self, handles: &[acadrust::Handle]) -> Vec<WireModel> {
|
||||||
|
handles
|
||||||
|
.iter()
|
||||||
|
.flat_map(|handle| {
|
||||||
|
self.solid_history_preview_wires
|
||||||
|
.get(handle)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| self.wire_models_for(std::slice::from_ref(handle)))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Split a MIRROR selection into plain ghost wires (reflected wholesale) and
|
/// Split a MIRROR selection into plain ghost wires (reflected wholesale) and
|
||||||
/// text ghosts paired with their bounding-box centre. Lets the preview match
|
/// text ghosts paired with their bounding-box centre. Lets the preview match
|
||||||
/// the commit for TEXT: MIRRTEXT on → true glyph mirror (full reflection, same
|
/// the commit for TEXT: MIRRTEXT on → true glyph mirror (full reflection, same
|
||||||
|
|||||||
Reference in new issue
Block a user