Sketch Intersect: a round beside another arc keeps its refit while their joint stays within a profile's join distance

The guard on a joint between two arcs now asks whether the refitted end stays within
ENDPOINT_JOIN_TOL (1e-4 mm, the distance a profile joins ends across, now public in
solidcraft-sketch) of where the other arc ends now, which may itself be refitted. Before, it asked
whether the end moved more than the fit's join distance (1e-7 of the size), which kept back refits
the profile would have closed across.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Markus Reichart
2026-11-07 13:38:31 +01:00
parent 7db4da654b
commit bd7db2626a
3 changed files with 18 additions and 10 deletions
+14 -7
View File
@@ -1786,11 +1786,13 @@ fn section_segments(plane: &Plane, m: &Mesh, face: Option<u32>) -> (Vec<(Vec2, V
/// Re-fit each circle and arc of a fitted section through the exact section points near it.
/// The outline stays closed: a line meeting an arc's end moves with it. Where the arc meets
/// another curve, the refit stands only if that end stays put; else the arc keeps its fit,
/// since moving the other curve's end would take it off its circle.
/// another curve, the refit stands only if that end moves less than a profile joins ends
/// across; else the arc keeps its fit, since moving the other curve's end would take it off
/// its circle.
fn refine_rounds(mut v: Vec<LinkGeom>, exact: &[Vec2], size: f64) -> Vec<LinkGeom> {
// Ends this close meet: the fit joins crossings this close into one point.
let meet = size * 1e-7;
let fitted = v.clone();
for i in 0..v.len() {
let Some(g) = v.get(i).cloned() else { continue };
let LinkGeom::Arc { a: a0, b: b0, .. } = g else {
@@ -1799,14 +1801,19 @@ fn refine_rounds(mut v: Vec<LinkGeom>, exact: &[Vec2], size: f64) -> Vec<LinkGeo
}
continue;
};
let touches = |h: &LinkGeom, e: Vec2| match *h {
LinkGeom::Line(s, t) | LinkGeom::Arc { a: s, b: t, .. } => s.dist(e) <= meet || t.dist(e) <= meet,
_ => false,
};
let refined = refine_round(g, exact, size * 2e-3);
let LinkGeom::Arc { a: a1, b: b1, .. } = refined else { continue };
// Another curve's end that met this end as fitted, where that curve ends now (it may
// have been refitted already).
let ends = |h: &LinkGeom| match *h {
LinkGeom::Line(s, t) | LinkGeom::Arc { a: s, b: t, .. } => Some([s, t]),
_ => None,
};
let tears = |e0: Vec2, e1: Vec2| {
e1.dist(e0) > meet && v.iter().enumerate().any(|(j, h)| j != i && !matches!(h, LinkGeom::Line(..)) && touches(h, e0))
fitted.iter().zip(&v).enumerate().filter(|(j, (h, _))| *j != i && !matches!(h, LinkGeom::Line(..))).any(|(_, (h, now))| {
let (Some(was), Some(now)) = (ends(h), ends(now)) else { return false };
was.iter().zip(now).any(|(w, n)| w.dist(e0) <= meet && n.dist(e1) > solidcraft_sketch::ENDPOINT_JOIN_TOL)
})
};
if tears(a0, a1) || tears(b0, b1) {
continue;
+2 -2
View File
@@ -68,8 +68,8 @@ pub use offset_topology::{OffsetCreated, OffsetRole, OffsetRoleFlags, OffsetRole
pub use pattern::{PatternAlignment, PatternInstance, SketchPattern, SketchPatternKind};
pub use periodic::periodic_beziers;
pub use profiles::{
CurvePick, MAX_PROFILE_EDGES, Profile, ProfileSearch, distinct_curves, find_drawn_profiles, find_profiles, find_profiles_checked, merge_regions,
profile_at_point, profile_by_curves, without_text_counters,
CurvePick, ENDPOINT_JOIN_TOL, MAX_PROFILE_EDGES, Profile, ProfileSearch, distinct_curves, find_drawn_profiles, find_profiles,
find_profiles_checked, merge_regions, profile_at_point, profile_by_curves, without_text_counters,
};
pub use shape::{Shape, intersections, intersections_within, nearest_crossing, nearest_curve_intersection};
pub use solver::solve_after_edit_with_analysis;
+2 -1
View File
@@ -20,7 +20,8 @@ use crate::shape::{Shape, intersections_within};
use crate::union_find::{find, union};
const MERGE_TOL: f64 = 1e-6;
const ENDPOINT_JOIN_TOL: f64 = MERGE_TOL * 100.0;
/// Curve ends this close (mm) join into one corner of a profile.
pub const ENDPOINT_JOIN_TOL: f64 = MERGE_TOL * 100.0;
const MAX_EDGES: usize = 50_000;
/// A closed region usable by features, with the ids of the curves bounding it.