forked from 1b-agent/opencadstudio-upstream
refactor(fillet): take the corner arc from cadkernel
`compute_fillet` keeps the entity work — resolving which side of each line the pick kept, and trimming the lines back — and hands the geometry out. The kernel takes the corner as an apex plus the two keep directions, which is what the side resolution here already produces, and returns the tangent points, centre and the endpoints in fill-the-corner order. `line_circle_ts` and `circle_circle_pts` were further copies of maths the kernel already had; the second now calls `circle_circle_points`, added for callers that want the crossings as points rather than as angles to cut at. `arc_span` and `clamp_angle_to_arc` stay put on purpose. This file's `arc_span` treats any span under 1e-6 as a full turn, where the kernel's only does so at zero or below. That difference is real for a degenerate arc, and picking a winner is a separate question from moving the code. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
397fb38292
commit
95e61f3e8d
2 files changed
+12
-84
No files matched your search
Generated
+1
-1
@@ -945,7 +945,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
[[package]]
|
||||
name = "cadkernel"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git#9c7b2b75ab76806d086f2e7eca17750771150dba"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git#feed535a0f72f9479d618a4999dba9bafcea250f"
|
||||
dependencies = [
|
||||
"cavalier_contours",
|
||||
]
|
||||
|
||||
@@ -14,6 +14,9 @@ use acadrust::entities::{Arc as ArcEnt, Line as LineEnt, LwPolyline};
|
||||
// Shared plane geometry, from cadkernel via the local adapters.
|
||||
use super::geom;
|
||||
use super::geom::{arc_points as arc_pts, line_line as ll, normalize_angle as norm_angle};
|
||||
use acadrust::kernel::geom2d::{
|
||||
circle_circle_points as circle_circle_pts, fillet_between_rays, line_circle,
|
||||
};
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::{EntityType, Handle};
|
||||
use glam::DVec3;
|
||||
@@ -121,7 +124,6 @@ fn compute_fillet(
|
||||
return None;
|
||||
}
|
||||
|
||||
let half = angle / 2.0;
|
||||
let z = l1.start.z;
|
||||
|
||||
if radius < 1e-9 {
|
||||
@@ -135,47 +137,19 @@ fn compute_fillet(
|
||||
return Some((EntityType::Line(new_l1), EntityType::Line(new_l2), None));
|
||||
}
|
||||
|
||||
// Distance from P to tangent points
|
||||
let d = radius / half.tan();
|
||||
let rounded = fillet_between_rays([px, py], dir1, dir2, radius)?;
|
||||
|
||||
// Tangent points
|
||||
let t1 = [px + d * dir1[0], py + d * dir1[1]];
|
||||
let t2 = [px + d * dir2[0], py + d * dir2[1]];
|
||||
// Trim each line back to where the arc meets it.
|
||||
let new_l1 = trim_to_xy(l1, rounded.tangent1, dir1, u1)?;
|
||||
let new_l2 = trim_to_xy(l2, rounded.tangent2, dir2, u2)?;
|
||||
|
||||
// Arc center: along bisector of dir1+dir2, distance = r / sin(half)
|
||||
let bx = dir1[0] + dir2[0];
|
||||
let by = dir1[1] + dir2[1];
|
||||
let blen = (bx * bx + by * by).sqrt();
|
||||
if blen < 1e-10 {
|
||||
return None;
|
||||
}
|
||||
let arc_dist = radius / half.sin();
|
||||
let arc_cx = px + arc_dist * bx / blen;
|
||||
let arc_cy = py + arc_dist * by / blen;
|
||||
|
||||
let a_start = (t1[1] - arc_cy).atan2(t1[0] - arc_cx);
|
||||
let a_end = (t2[1] - arc_cy).atan2(t2[0] - arc_cx);
|
||||
|
||||
// Pick CCW direction that fills the concave corner
|
||||
let cross = dir1[0] * dir2[1] - dir1[1] * dir2[0];
|
||||
let (start_angle, end_angle) = if cross <= 0.0 {
|
||||
(a_start, a_end)
|
||||
} else {
|
||||
(a_end, a_start)
|
||||
};
|
||||
|
||||
// Trim l1 to T1 and l2 to T2
|
||||
let new_l1 = trim_to_xy(l1, t1, dir1, u1)?;
|
||||
let new_l2 = trim_to_xy(l2, t2, dir2, u2)?;
|
||||
|
||||
// Build arc entity
|
||||
let mut arc = ArcEnt::new();
|
||||
arc.common = l1.common.clone();
|
||||
arc.common.handle = Handle::NULL;
|
||||
arc.center = Vector3::new(arc_cx, arc_cy, z);
|
||||
arc.center = Vector3::new(rounded.centre[0], rounded.centre[1], z);
|
||||
arc.radius = radius;
|
||||
arc.start_angle = norm_angle(start_angle);
|
||||
arc.end_angle = norm_angle(end_angle);
|
||||
arc.start_angle = rounded.start_angle;
|
||||
arc.end_angle = rounded.end_angle;
|
||||
|
||||
Some((
|
||||
EntityType::Line(new_l1),
|
||||
@@ -286,52 +260,6 @@ fn trim_arc(orig: &ArcEnt, new_start: f64, new_end: f64) -> ArcEnt {
|
||||
a
|
||||
}
|
||||
|
||||
/// Intersect a line (point p + direction d) with a circle (center c, radius r).
|
||||
/// Returns up to 2 parameter values t on the line.
|
||||
fn line_circle_ts(px: f64, py: f64, dx: f64, dy: f64, cx: f64, cy: f64, r: f64) -> Vec<f64> {
|
||||
let fx = px - cx;
|
||||
let fy = py - cy;
|
||||
let a = dx * dx + dy * dy;
|
||||
let b = 2.0 * (fx * dx + fy * dy);
|
||||
let c = fx * fx + fy * fy - r * r;
|
||||
let disc = b * b - 4.0 * a * c;
|
||||
if disc < 0.0 {
|
||||
return vec![];
|
||||
}
|
||||
let sq = disc.sqrt();
|
||||
if disc < 1e-14 {
|
||||
vec![(-b) / (2.0 * a)]
|
||||
} else {
|
||||
vec![(-b - sq) / (2.0 * a), (-b + sq) / (2.0 * a)]
|
||||
}
|
||||
}
|
||||
|
||||
/// Intersect two circles. Returns intersection points.
|
||||
fn circle_circle_pts(c1: [f64; 2], r1: f64, c2: [f64; 2], r2: f64) -> Vec<[f64; 2]> {
|
||||
let dx = c2[0] - c1[0];
|
||||
let dy = c2[1] - c1[1];
|
||||
let d = (dx * dx + dy * dy).sqrt();
|
||||
if d < 1e-12 || d > r1 + r2 + 1e-9 || d < (r1 - r2).abs() - 1e-9 {
|
||||
return vec![];
|
||||
}
|
||||
let a = (r1 * r1 - r2 * r2 + d * d) / (2.0 * d);
|
||||
let h2 = r1 * r1 - a * a;
|
||||
if h2 < 0.0 {
|
||||
return vec![];
|
||||
}
|
||||
let h = h2.sqrt();
|
||||
let mx = c1[0] + a * dx / d;
|
||||
let my = c1[1] + a * dy / d;
|
||||
if h < 1e-9 {
|
||||
vec![[mx, my]]
|
||||
} else {
|
||||
vec![
|
||||
[mx + h * dy / d, my - h * dx / d],
|
||||
[mx - h * dy / d, my + h * dx / d],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// ── LwPolyline helpers ────────────────────────────────────────────────────
|
||||
|
||||
/// Find the index of the LwPolyline segment nearest to `click` (DXF XY).
|
||||
@@ -761,7 +689,7 @@ fn fillet_line_arc(
|
||||
let (ac, ar, a_start, a_end, _) = arc_geom(arc);
|
||||
|
||||
// Intersection of infinite line with the arc's circle
|
||||
let ts = line_circle_ts(p1[0], p1[1], u[0], u[1], ac[0], ac[1], ar);
|
||||
let ts = line_circle(p1, u, ac, ar);
|
||||
|
||||
if radius < 1e-9 {
|
||||
// r=0: trim to intersection (nearest to each click)
|
||||
|
||||
Reference in new issue
Block a user