Skip to content

Commit f716b8b

Browse files
committed
fix bevel algo for curves
1 parent 8001050 commit f716b8b

File tree

1 file changed

+16
-37
lines changed

1 file changed

+16
-37
lines changed

node-graph/gcore/src/vector/vector_nodes.rs

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ async fn morph<F: 'n + Send + Copy>(
10911091
VectorDataTable::new(result)
10921092
}
10931093

1094-
fn bevel_algorithm(mut vector_data: VectorData, distance: f64, roundness: f64) -> VectorData {
1094+
fn bevel_algorithm(mut vector_data: VectorData, distance: f64) -> VectorData {
10951095
// Splits a bézier curve based on a distance measurement
10961096
fn split_distance(bezier: bezier_rs::Bezier, distance: f64, length: f64) -> bezier_rs::Bezier {
10971097
const EUCLIDEAN_ERROR: f64 = 0.001;
@@ -1150,23 +1150,19 @@ fn bevel_algorithm(mut vector_data: VectorData, distance: f64, roundness: f64) -
11501150
let length2 = bezier2.length(None);
11511151

11521152
let max_split = length1.min(length2);
1153-
const EUCLIDEAN_ERROR: f64 = 0.001;
11541153

1155-
// Adaptive sampling approach
11561154
let mut split_distance = 0.0;
11571155
let mut best_diff = f64::MAX;
11581156
let mut current_best_distance = 0.0;
11591157

1160-
// Start with coarse sampling to find promising regions
1158+
let clamp_and_round = |value: f64| ((value * 1000.0).round() / 1000.0).clamp(0.0, 1.0);
1159+
11611160
const INITIAL_SAMPLES: usize = 50;
11621161
for i in 0..=INITIAL_SAMPLES {
11631162
let distance_sample = max_split * (i as f64 / INITIAL_SAMPLES as f64);
11641163

1165-
let parametric1 = bezier1.euclidean_to_parametric_with_total_length((distance_sample / length1).clamp(0.0, 1.0), EUCLIDEAN_ERROR, length1);
1166-
let parametric2 = bezier2.euclidean_to_parametric_with_total_length((distance_sample / length2).clamp(0.0, 1.0), EUCLIDEAN_ERROR, length2);
1167-
1168-
let x_point = bezier1.evaluate(TValue::Parametric(1.0 - parametric1));
1169-
let y_point = bezier2.evaluate(TValue::Parametric(parametric2));
1164+
let x_point = bezier1.evaluate(TValue::Euclidean(1.0 - clamp_and_round(distance_sample / length1)));
1165+
let y_point = bezier2.evaluate(TValue::Euclidean(clamp_and_round(distance_sample / length2)));
11701166

11711167
let distance = x_point.distance(y_point);
11721168
let diff = (bevel_length - distance).abs();
@@ -1186,11 +1182,8 @@ fn bevel_algorithm(mut vector_data: VectorData, distance: f64, roundness: f64) -
11861182
for j in 1..=REFINE_STEPS {
11871183
let refined_sample = prev_sample + (distance_sample - prev_sample) * (j as f64 / REFINE_STEPS as f64);
11881184

1189-
let parametric1 = bezier1.euclidean_to_parametric_with_total_length((refined_sample / length1).clamp(0.0, 1.0), EUCLIDEAN_ERROR, length1);
1190-
let parametric2 = bezier2.euclidean_to_parametric_with_total_length((refined_sample / length2).clamp(0.0, 1.0), EUCLIDEAN_ERROR, length2);
1191-
1192-
let x_point = bezier1.evaluate(TValue::Parametric(1.0 - parametric1));
1193-
let y_point = bezier2.evaluate(TValue::Parametric(parametric2));
1185+
let x_point = bezier1.evaluate(TValue::Euclidean(1.0 - (refined_sample / length1).clamp(0.0, 1.0)));
1186+
let y_point = bezier2.evaluate(TValue::Euclidean((refined_sample / length2).clamp(0.0, 1.0)));
11941187

11951188
let distance = x_point.distance(y_point);
11961189

@@ -1365,30 +1358,19 @@ fn bevel_algorithm(mut vector_data: VectorData, distance: f64, roundness: f64) -
13651358
new_segments
13661359
}
13671360

1368-
fn insert_new_segments(vector_data: &mut VectorData, new_segments: &[[usize; 2]], roundness: f64) {
1361+
fn insert_new_segments(vector_data: &mut VectorData, new_segments: &[[usize; 2]]) {
13691362
let mut next_id = vector_data.segment_domain.next_id();
13701363

13711364
for &[start, end] in new_segments {
1372-
let start_pos = vector_data.point_domain.positions()[start];
1373-
let end_pos = vector_data.point_domain.positions()[end];
1374-
1375-
let direction = start_pos - end_pos;
1376-
let perpendicular = DVec2::new(-direction.y, direction.x).normalize();
1377-
1378-
let curve_amount = direction.length() * roundness; // 50% of line length
1379-
let midpoint = (start_pos + end_pos) / 2.0;
1380-
let control_point = midpoint + perpendicular * curve_amount;
1381-
1382-
let handles = bezier_rs::BezierHandles::Quadratic { handle: control_point };
1383-
1365+
let handles = bezier_rs::BezierHandles::Linear;
13841366
vector_data.segment_domain.push(next_id.next_id(), start, end, handles, StrokeId::ZERO);
13851367
}
13861368
}
13871369

13881370
if distance > 1.0 {
13891371
let mut segments_connected = segments_connected_count(&vector_data);
13901372
let new_segments = update_existing_segments(&mut vector_data, distance, &mut segments_connected);
1391-
insert_new_segments(&mut vector_data, &new_segments, roundness);
1373+
insert_new_segments(&mut vector_data, &new_segments);
13921374
}
13931375

13941376
vector_data
@@ -1407,14 +1389,11 @@ async fn bevel<F: 'n + Send + Copy>(
14071389
)]
14081390
source: impl Node<F, Output = VectorDataTable>,
14091391
#[default(10.)] distance: Length,
1410-
#[default(0.)]
1411-
#[range((-1.0, 1.0))]
1412-
roundness: f64,
14131392
) -> VectorDataTable {
14141393
let source = source.eval(footprint).await;
14151394
let source = source.one_item();
14161395

1417-
let result = bevel_algorithm(source.clone(), distance, roundness);
1396+
let result = bevel_algorithm(source.clone(), distance);
14181397

14191398
VectorDataTable::new(result)
14201399
}
@@ -1657,7 +1636,7 @@ mod test {
16571636
#[tokio::test]
16581637
async fn bevel_rect() {
16591638
let source = Subpath::new_rect(DVec2::ZERO, DVec2::ONE * 100.);
1660-
let beveled = super::bevel(Footprint::default(), &vector_node(source), 5., 0.).await;
1639+
let beveled = super::bevel(Footprint::default(), &vector_node(source), 5.).await;
16611640
let beveled = beveled.one_item();
16621641

16631642
assert_eq!(beveled.point_domain.positions().len(), 8);
@@ -1680,7 +1659,7 @@ mod test {
16801659
async fn bevel_open_curve() {
16811660
let curve = Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::new(10., 0.), DVec2::new(10., 100.), DVec2::X * 100.);
16821661
let source = Subpath::from_beziers(&[Bezier::from_linear_dvec2(DVec2::X * -100., DVec2::ZERO), curve], false);
1683-
let beveled = super::bevel(Footprint::default(), &vector_node(source), 5., 0.).await;
1662+
let beveled = super::bevel(Footprint::default(), &vector_node(source), 5.).await;
16841663
let beveled = beveled.one_item();
16851664

16861665
assert_eq!(beveled.point_domain.positions().len(), 4);
@@ -1702,7 +1681,7 @@ mod test {
17021681
let mut vector_data = VectorData::from_subpath(source);
17031682
let transform = DAffine2::from_scale_angle_translation(DVec2::splat(10.), 1., DVec2::new(99., 77.));
17041683
vector_data.transform = transform;
1705-
let beveled = super::bevel(Footprint::default(), &FutureWrapperNode(VectorDataTable::new(vector_data)), 5., 0.).await;
1684+
let beveled = super::bevel(Footprint::default(), &FutureWrapperNode(VectorDataTable::new(vector_data)), 5.).await;
17061685
let beveled = beveled.one_item();
17071686

17081687
assert_eq!(beveled.point_domain.positions().len(), 4);
@@ -1721,7 +1700,7 @@ mod test {
17211700
#[tokio::test]
17221701
async fn bevel_too_high() {
17231702
let source = Subpath::from_anchors([DVec2::ZERO, DVec2::new(100., 0.), DVec2::new(100., 100.), DVec2::new(0., 100.)], false);
1724-
let beveled = super::bevel(Footprint::default(), &vector_node(source), 999., 0.).await;
1703+
let beveled = super::bevel(Footprint::default(), &vector_node(source), 999.).await;
17251704
let beveled = beveled.one_item();
17261705

17271706
assert_eq!(beveled.point_domain.positions().len(), 6);
@@ -1742,7 +1721,7 @@ mod test {
17421721
let curve = Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::new(10., 0.), DVec2::new(10., 100.), DVec2::X * 100.);
17431722
let point = Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::ZERO, DVec2::ZERO, DVec2::ZERO);
17441723
let source = Subpath::from_beziers(&[Bezier::from_linear_dvec2(DVec2::X * -100., DVec2::ZERO), point, curve], false);
1745-
let beveled = super::bevel(Footprint::default(), &vector_node(source), 5., 0.).await;
1724+
let beveled = super::bevel(Footprint::default(), &vector_node(source), 5.).await;
17461725
let beveled = beveled.one_item();
17471726

17481727
assert_eq!(beveled.point_domain.positions().len(), 6);

0 commit comments

Comments
 (0)