Skip to content

Commit 27e4632

Browse files
committed
Add simple axes plot
1 parent 5fca961 commit 27e4632

1 file changed

Lines changed: 56 additions & 15 deletions

File tree

node-graph/nodes/vector/src/plot_nodes.rs

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ struct CurveBounds {
4848
y_max: f64,
4949
}
5050

51+
#[derive(Debug, Clone, Copy)]
52+
struct PlotTransform {
53+
scale: f64,
54+
x_center: f64,
55+
y_center: f64,
56+
}
57+
5158
struct PlotContext<'a> {
5259
values: &'a HashMap<String, f64>,
5360
}
@@ -145,6 +152,9 @@ fn function_plot(
145152
/// Auto close
146153
#[default(true)]
147154
auto_close: bool,
155+
/// Plot Axes
156+
#[default(true)]
157+
plot_axes: bool,
148158
) -> List<Vector> {
149159
let mut plots = List::new();
150160
let (x_node, y_node, variable_name) = match parse_plot_expressions(&x_expression, &y_expression) {
@@ -157,10 +167,12 @@ fn function_plot(
157167
None => return plots,
158168
};
159169

170+
let plot_transform = calculate_plot_transform(&bounds, width, height);
171+
160172
let segments = detect_curve_segments(sample_points, discontinuity_sensitivity);
161173

162174
for mut segment_anchors in segments {
163-
fit_plot_to_bounds(&mut segment_anchors, &bounds, width, height);
175+
fit_plot_to_bounds(&mut segment_anchors, &plot_transform);
164176

165177
let mut closed = false;
166178

@@ -182,6 +194,19 @@ fn function_plot(
182194
}
183195
}
184196

197+
if plot_axes {
198+
let axes = build_plot_axes(&bounds, &plot_transform);
199+
for axis in axes {
200+
let shape = Vector::from_subpath(subpath::Subpath::from_anchors(axis, false));
201+
202+
if plots.is_empty() {
203+
plots = List::new_from_element(shape);
204+
} else {
205+
plots.push(Item::new_from_element(shape));
206+
}
207+
}
208+
}
209+
185210
plots
186211
}
187212

@@ -228,6 +253,7 @@ fn sample_interval(
228253
max_depth: u32,
229254
) {
230255
if current_depth >= max_depth {
256+
update_bounds(&begin_point, bounds);
231257
sample_points.push(begin_point);
232258
return;
233259
}
@@ -238,9 +264,6 @@ fn sample_interval(
238264
let Some(point_mid) = evaluate_expressions(t_mid, x_node, y_node, variable_name) else {
239265
return;
240266
};
241-
if let SamplePoint::Valid { .. } = point_mid {
242-
update_bounds(&point_mid, bounds);
243-
}
244267

245268
if current_depth > min_depth && begin_point.is_valid() && end_point.is_valid() {
246269
let t_quarter = t_begin + (t_end - t_begin) * 0.25;
@@ -254,14 +277,6 @@ fn sample_interval(
254277
return;
255278
};
256279

257-
if let SamplePoint::Valid { .. } = point_q1 {
258-
update_bounds(&point_q1, bounds);
259-
}
260-
261-
if let SamplePoint::Valid { .. } = point_q3 {
262-
update_bounds(&point_q3, bounds);
263-
}
264-
265280
let Some(begin_coord) = begin_point.coord() else { return };
266281
let Some(end_coord) = end_point.coord() else { return };
267282

@@ -285,6 +300,7 @@ fn sample_interval(
285300
}
286301

287302
if max_error < tolerance {
303+
update_bounds(&begin_point, bounds);
288304
sample_points.push(begin_point);
289305
return;
290306
}
@@ -463,7 +479,7 @@ fn extrapolate_limit(p_coord: DVec2, p1_coord: DVec2, p2_coord: DVec2) -> f64 {
463479
}
464480
}
465481

466-
fn fit_plot_to_bounds(anchor_positions: &mut [DVec2], bounds: &CurveBounds, width: f64, height: f64) {
482+
fn calculate_plot_transform(bounds: &CurveBounds, width: f64, height: f64) -> PlotTransform {
467483
let x_scale = width / (bounds.x_max - bounds.x_min).max(f64::EPSILON);
468484
let y_scale = height / (bounds.y_max - bounds.y_min).max(f64::EPSILON);
469485

@@ -472,12 +488,37 @@ fn fit_plot_to_bounds(anchor_positions: &mut [DVec2], bounds: &CurveBounds, widt
472488
let x_center = (bounds.x_min + bounds.x_max) / 2.;
473489
let y_center = (bounds.y_min + bounds.y_max) / 2.;
474490

491+
PlotTransform { scale, x_center, y_center }
492+
}
493+
494+
fn fit_plot_to_bounds(anchor_positions: &mut [DVec2], plot_transform: &PlotTransform) {
475495
for anchor_position in anchor_positions {
476-
anchor_position.x = (anchor_position.x - x_center) * scale;
477-
anchor_position.y = (y_center - anchor_position.y) * scale;
496+
*anchor_position = fit_point_to_bounds(*anchor_position, plot_transform);
478497
}
479498
}
480499

500+
fn fit_point_to_bounds(point: DVec2, plot_transform: &PlotTransform) -> DVec2 {
501+
DVec2::new((point.x - plot_transform.x_center) * plot_transform.scale, (plot_transform.y_center - point.y) * plot_transform.scale)
502+
}
503+
504+
fn build_plot_axes(bounds: &CurveBounds, plot_transform: &PlotTransform) -> Vec<CurveSegment> {
505+
let axis_x = if bounds.x_min <= 0. && bounds.x_max >= 0. { 0. } else { (bounds.x_min + bounds.x_max) / 2. };
506+
507+
let axis_y = if bounds.y_min <= 0. && bounds.y_max >= 0. { 0. } else { (bounds.y_min + bounds.y_max) / 2. };
508+
509+
let horizontal = vec![
510+
fit_point_to_bounds(DVec2::new(bounds.x_min, axis_y), plot_transform),
511+
fit_point_to_bounds(DVec2::new(bounds.x_max, axis_y), plot_transform),
512+
];
513+
514+
let vertical = vec![
515+
fit_point_to_bounds(DVec2::new(axis_x, bounds.y_min), plot_transform),
516+
fit_point_to_bounds(DVec2::new(axis_x, bounds.y_max), plot_transform),
517+
];
518+
519+
vec![horizontal, vertical]
520+
}
521+
481522
fn parse_plot_expressions(x_expression: &str, y_expression: &str) -> Option<(ast::Node, ast::Node, String)> {
482523
let (x_node, x_vars) = parse_expression(x_expression)?;
483524
let (y_node, y_vars) = parse_expression(y_expression)?;

0 commit comments

Comments
 (0)