forked from 1b-agent/opencadstudio-upstream
refactor(blend): evaluate the Bézier with de Casteljau from the kernel
BLEND summed Bernstein terms using a binomial-coefficient table with entries for degrees three and five — the two it builds — and a fallback of one for everything else. Correct today, and quietly wrong the moment a third continuity mode is added. De Casteljau needs no coefficients at all, works at any degree, and is steadier: the Bernstein terms are large coefficients times small powers and they cancel, while repeated interpolation only ever averages neighbours. Curvature through three points moves with it, since both are the 3D arithmetic a blend needs and neither has a planar counterpart to delegate to. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
77a9167e34
commit
0677dd146c
2 files changed
+21
-40
No files matched your search
Generated
+1
-1
@@ -935,7 +935,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
[[package]]
|
||||
name = "cadkernel"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git#e4c9fe626a60fd1500e8f2264e5a712e939c4027"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git#69a8bf2b747c8b0a4abe6a571859c4c3a4f610d2"
|
||||
dependencies = [
|
||||
"cavalier_contours",
|
||||
]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//! geometric curvature (G2).
|
||||
|
||||
use acadrust::entities::{EntityCommon, Spline};
|
||||
use acadrust::kernel::space::curve as space_curve;
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::{EntityType, Handle};
|
||||
use glam::DVec3;
|
||||
@@ -628,49 +629,29 @@ fn curve_frame(
|
||||
})
|
||||
}
|
||||
|
||||
/// The curvature vector at `point` of the circle through the three points.
|
||||
fn circumcircle_curvature(point: DVec3, next: DVec3, third: DVec3) -> DVec3 {
|
||||
let u = next - point;
|
||||
let v = third - point;
|
||||
let cross = u.cross(v);
|
||||
let denominator = 2.0 * cross.length_squared();
|
||||
if denominator <= EPS {
|
||||
return DVec3::ZERO;
|
||||
}
|
||||
let center_offset =
|
||||
(u.length_squared() * v.cross(cross) + v.length_squared() * cross.cross(u)) / denominator;
|
||||
let radius_squared = center_offset.length_squared();
|
||||
if radius_squared <= EPS {
|
||||
DVec3::ZERO
|
||||
} else {
|
||||
center_offset / radius_squared
|
||||
}
|
||||
let curvature = space_curve::curvature_through(
|
||||
[point.x, point.y, point.z],
|
||||
[next.x, next.y, next.z],
|
||||
[third.x, third.y, third.z],
|
||||
);
|
||||
DVec3::new(curvature[0], curvature[1], curvature[2])
|
||||
}
|
||||
|
||||
/// A Bézier control polygon sampled into a polyline.
|
||||
///
|
||||
/// De Casteljau, from the kernel. What was here summed Bernstein terms with
|
||||
/// binomial coefficients out of a lookup table that had entries for degrees
|
||||
/// three and five and returned one for everything else — correct only for
|
||||
/// the two the blend happens to build today, and quietly wrong the moment a
|
||||
/// third was added.
|
||||
fn sample_bezier(control_points: &[Vector3], segments: usize) -> Vec<[f64; 3]> {
|
||||
let degree = control_points.len().saturating_sub(1);
|
||||
(0..=segments)
|
||||
.map(|step| {
|
||||
let t = step as f64 / segments as f64;
|
||||
let mut point = DVec3::ZERO;
|
||||
for (index, control) in control_points.iter().enumerate() {
|
||||
let coefficient = binomial(degree, index) as f64
|
||||
* t.powi(index as i32)
|
||||
* (1.0 - t).powi((degree - index) as i32);
|
||||
point += coefficient * to_dvec(*control);
|
||||
}
|
||||
[point.x, point.y, point.z]
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn binomial(n: usize, k: usize) -> usize {
|
||||
match (n, k) {
|
||||
(3, 0 | 3) | (5, 0 | 5) => 1,
|
||||
(3, 1 | 2) => 3,
|
||||
(5, 1 | 4) => 5,
|
||||
(5, 2 | 3) => 10,
|
||||
_ => 1,
|
||||
}
|
||||
let control: Vec<[f64; 3]> = control_points
|
||||
.iter()
|
||||
.map(|p| [p.x, p.y, p.z])
|
||||
.collect();
|
||||
space_curve::bezier_points(&control, segments)
|
||||
}
|
||||
|
||||
fn ocs_to_dvec(x: f64, y: f64, z: f64, normal: DVec3) -> DVec3 {
|
||||
|
||||
Reference in new issue
Block a user