From 34b7d9481bb26b135a71c7e5e45f34c99a924824 Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Tue, 15 Sep 2026 15:04:14 +0300 Subject: [PATCH] Keep point-on-arc constraints within their sweep --- Cargo.lock | 4 +-- Cargo.toml | 4 +-- src/scene/parametric_solve.rs | 56 ++++++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96ae7c765..75ece6af5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -919,7 +919,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=eb3cfe7#eb3cfe7b478230897bfb9094e7bc70aa4d00411b" +source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=0699490#069949099e08c51807681ee3f525bb525b42e006" dependencies = [ "acadrust", "cavalier_contours", @@ -930,7 +930,7 @@ dependencies = [ [[package]] name = "cadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=eb3cfe7#eb3cfe7b478230897bfb9094e7bc70aa4d00411b" +source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=0699490#069949099e08c51807681ee3f525bb525b42e006" dependencies = [ "nalgebra", ] diff --git a/Cargo.toml b/Cargo.toml index 8441fc21f..1752c0b4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,8 +33,8 @@ rfd = "0.17" clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "568a12c", features = ["serde"] } -cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "eb3cfe7", features = ["acis", "offset"] } -cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "eb3cfe7" } +cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "0699490", features = ["acis", "offset"] } +cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "0699490" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } flate2 = "1" image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] } diff --git a/src/scene/parametric_solve.rs b/src/scene/parametric_solve.rs index af5a32af8..5424028f2 100644 --- a/src/scene/parametric_solve.rs +++ b/src/scene/parametric_solve.rs @@ -13,7 +13,7 @@ use cadkernel_constraints::constraints::circle_arc::{C2LDistance, P2CDistance, T use cadkernel_constraints::constraints::conic::{ EqualMajorAxesConic, PointOnEllipse, TangentEllipseLine, }; -use cadkernel_constraints::constraints::curve_generic::CurveValue; +use cadkernel_constraints::constraints::curve_generic::{BoundedArcValue, CurveValue}; use cadkernel_constraints::constraints::point_line::{ CenterOfGravity, Difference, Equal, EqualLineLength, MidpointOnLine, P2PDistance, Parallel as ParallelConstraint, Perpendicular as PerpendicularConstraint, PointOnLine, @@ -364,7 +364,11 @@ fn register_entity( ); let rad = sys.add_param(a.radius, false); let start_angle = sys.add_param(a.start_angle, false); - let end_angle = sys.add_param(a.end_angle, false); + let end_angle = sys.add_param( + a.start_angle + + (a.end_angle - a.start_angle).rem_euclid(std::f64::consts::TAU), + false, + ); let start_seed = a.start_point(); let end_seed = a.end_point(); let start = GPoint::new( @@ -855,6 +859,35 @@ fn build_constraint( resolve_constraint_point(document, sys, cache, r) }; + let point_on_bounded_arc = |sys: &mut System, point: GPoint, arc: GArc| { + let normalized = { + let store = sys.store(); + let point_angle = + (store.get(point.y) - store.get(arc.circle.center.y)).atan2( + store.get(point.x) - store.get(arc.circle.center.x), + ); + let start = store.get(arc.start_angle); + let end = store.get(arc.end_angle); + let sweep = end - start; + if sweep.abs() <= 1e-12 { + 0.0 + } else { + let midpoint = (start + end) * 0.5; + let unwrapped = point_angle + + ((midpoint - point_angle) / std::f64::consts::TAU).round() + * std::f64::consts::TAU; + ((unwrapped - start) / sweep).clamp(0.0, 1.0) + } + }; + let parameter = sys.add_param(normalized.sqrt().asin(), false); + vec![ + Rc::new(BoundedArcValue::new(point, point.x, arc, parameter)) + as Rc, + Rc::new(BoundedArcValue::new(point, point.y, arc, parameter)) + as Rc, + ] + }; + // `Coincident`/`Concentric`/`CenterPoint` all solve identically — two // points (an endpoint, a circle's center via the existing `-3` marker, // or a plain point) held equal on both axes. Only the DWG-native class @@ -1025,14 +1058,7 @@ fn build_constraint( let zero = sys.add_param(0.0, true); vec![Rc::new(P2CDistance::new(circ, p, zero))] } - // Same "distance to the underlying circle is zero" relation - // as the `Circle` arm — doesn't restrict the point to - // within the arc's own sweep, matching that same - // pre-existing simplification for `Circle`. - EntityGeom::Arc(a) => { - let zero = sys.add_param(0.0, true); - vec![Rc::new(P2CDistance::new(a.circle, p, zero))] - } + EntityGeom::Arc(a) => point_on_bounded_arc(sys, p, a), EntityGeom::Ellipse(ellipse) => { vec![Rc::new(PointOnEllipse::new(p, ellipse))] } @@ -1070,14 +1096,8 @@ fn build_constraint( vec![Rc::new(PointOnLine::new(p, line)) as Rc] }) .or_else(|| { - geom.arc_segment(index).map(|segment| { - let zero = sys.add_param(0.0, true); - vec![Rc::new(P2CDistance::new( - segment.arc.circle, - p, - zero, - )) as Rc] - }) + geom.arc_segment(index) + .map(|segment| point_on_bounded_arc(sys, p, segment.arc)) }) }) .unwrap_or_default(),