Fix extruded solid grip preview and taper range

This commit is contained in:
ramox81 committed 2026-09-03 10:35:02 +03:00
1 parent 3ad0423393
commit ea6eb58c53
8 files changed
+87 -10

No files matched your search

+28 -5
View File
@@ -2314,7 +2314,7 @@ fn apply_extrusion_draft_grip(value: &mut SolidHistorySweep, apply: GripApply) -
let GripApply::Absolute(world) = apply else {
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;
};
let top_offset = (world - base_top).dot(radial);
@@ -2322,10 +2322,27 @@ fn apply_extrusion_draft_grip(value: &mut SolidHistorySweep, apply: GripApply) -
return false;
}
let limit = 89.0_f64.to_radians();
let inward_limit = ((profile_radius - 1e-6).max(1e-6) / height)
.atan()
.min(limit);
let angle = (-top_offset).atan2(height).clamp(-limit, inward_limit);
let desired = (-top_offset).atan2(height).clamp(-limit, limit);
let angle = if desired > 0.0 && !extrusion_draft_rebuilds(value, desired) {
// The maximum inset is profile-dependent. A corner radius is too
// 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 {
return false;
}
@@ -2333,6 +2350,12 @@ fn apply_extrusion_draft_grip(value: &mut SolidHistorySweep, apply: GripApply) -
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(
id: usize,
world: glam::DVec3,
+22
View File
@@ -3,6 +3,7 @@
use cadkernel::brep::{self, Body, Curve3, EdgeKey, FaceKey, Surface};
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.
const TOL: f64 = 1e-9;
@@ -243,6 +244,27 @@ pub fn edge_wires(body: &Body) -> Vec<acadrust::entities::Wire> {
.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.
pub fn nearest_edge(body: &Body, pick: [f64; 3]) -> Option<EdgeKey> {
let pick = cadkernel::space::Vec3::from(pick);