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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy