Skip to content

Commit edd0d9f

Browse files
committed
raster-nodes: move CubicSplines to separate mod
1 parent 93b3844 commit edd0d9f

4 files changed

Lines changed: 121 additions & 120 deletions

File tree

node-graph/graster-nodes/src/adjustments.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(clippy::too_many_arguments)]
22

3-
use crate::curve::CubicSplines;
3+
use crate::cubic_spline::CubicSplines;
44
use dyn_any::DynAny;
55
use graphene_core::Node;
66
use graphene_core::blending::BlendMode;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#[derive(Debug)]
2+
pub struct CubicSplines {
3+
pub x: [f32; 4],
4+
pub y: [f32; 4],
5+
}
6+
7+
impl CubicSplines {
8+
pub fn solve(&self) -> [f32; 4] {
9+
let (x, y) = (&self.x, &self.y);
10+
11+
// Build an augmented matrix to solve the system of equations using Gaussian elimination
12+
let mut augmented_matrix = [
13+
[
14+
2. / (x[1] - x[0]),
15+
1. / (x[1] - x[0]),
16+
0.,
17+
0.,
18+
// |
19+
3. * (y[1] - y[0]) / ((x[1] - x[0]) * (x[1] - x[0])),
20+
],
21+
[
22+
1. / (x[1] - x[0]),
23+
2. * (1. / (x[1] - x[0]) + 1. / (x[2] - x[1])),
24+
1. / (x[2] - x[1]),
25+
0.,
26+
// |
27+
3. * ((y[1] - y[0]) / ((x[1] - x[0]) * (x[1] - x[0])) + (y[2] - y[1]) / ((x[2] - x[1]) * (x[2] - x[1]))),
28+
],
29+
[
30+
0.,
31+
1. / (x[2] - x[1]),
32+
2. * (1. / (x[2] - x[1]) + 1. / (x[3] - x[2])),
33+
1. / (x[3] - x[2]),
34+
// |
35+
3. * ((y[2] - y[1]) / ((x[2] - x[1]) * (x[2] - x[1])) + (y[3] - y[2]) / ((x[3] - x[2]) * (x[3] - x[2]))),
36+
],
37+
[
38+
0.,
39+
0.,
40+
1. / (x[3] - x[2]),
41+
2. / (x[3] - x[2]),
42+
// |
43+
3. * (y[3] - y[2]) / ((x[3] - x[2]) * (x[3] - x[2])),
44+
],
45+
];
46+
47+
// Gaussian elimination: forward elimination
48+
for row in 0..4 {
49+
let pivot_row_index = (row..4)
50+
.max_by(|&a_row, &b_row| augmented_matrix[a_row][row].abs().partial_cmp(&augmented_matrix[b_row][row].abs()).unwrap_or(std::cmp::Ordering::Equal))
51+
.unwrap();
52+
53+
// Swap the current row with the row that has the largest pivot element
54+
augmented_matrix.swap(row, pivot_row_index);
55+
56+
// Eliminate the current column in all rows below the current one
57+
for row_below_current in row + 1..4 {
58+
assert!(augmented_matrix[row][row].abs() > f32::EPSILON);
59+
60+
let scale_factor = augmented_matrix[row_below_current][row] / augmented_matrix[row][row];
61+
for col in row..5 {
62+
augmented_matrix[row_below_current][col] -= augmented_matrix[row][col] * scale_factor
63+
}
64+
}
65+
}
66+
67+
// Gaussian elimination: back substitution
68+
let mut solutions = [0.; 4];
69+
for col in (0..4).rev() {
70+
assert!(augmented_matrix[col][col].abs() > f32::EPSILON);
71+
72+
solutions[col] = augmented_matrix[col][4] / augmented_matrix[col][col];
73+
74+
for row in (0..col).rev() {
75+
augmented_matrix[row][4] -= augmented_matrix[row][col] * solutions[col];
76+
augmented_matrix[row][col] = 0.;
77+
}
78+
}
79+
80+
solutions
81+
}
82+
83+
pub fn interpolate(&self, input: f32, solutions: &[f32]) -> f32 {
84+
if input <= self.x[0] {
85+
return self.y[0];
86+
}
87+
if input >= self.x[self.x.len() - 1] {
88+
return self.y[self.x.len() - 1];
89+
}
90+
91+
// Find the segment that the input falls between
92+
let mut segment = 1;
93+
while self.x[segment] < input {
94+
segment += 1;
95+
}
96+
let segment_start = segment - 1;
97+
let segment_end = segment;
98+
99+
// Calculate the output value using quadratic interpolation
100+
let input_value = self.x[segment_start];
101+
let input_value_prev = self.x[segment_end];
102+
let output_value = self.y[segment_start];
103+
let output_value_prev = self.y[segment_end];
104+
let solutions_value = solutions[segment_start];
105+
let solutions_value_prev = solutions[segment_end];
106+
107+
let output_delta = solutions_value_prev * (input_value - input_value_prev) - (output_value - output_value_prev);
108+
let solution_delta = (output_value - output_value_prev) - solutions_value * (input_value - input_value_prev);
109+
110+
let input_ratio = (input - input_value_prev) / (input_value - input_value_prev);
111+
let prev_output_ratio = (1. - input_ratio) * output_value_prev;
112+
let output_ratio = input_ratio * output_value;
113+
let quadratic_ratio = input_ratio * (1. - input_ratio) * (output_delta * (1. - input_ratio) + solution_delta * input_ratio);
114+
115+
let result = prev_output_ratio + output_ratio + quadratic_ratio;
116+
result.clamp(0., 1.)
117+
}
118+
}

node-graph/graster-nodes/src/curve.rs

Lines changed: 0 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -45,125 +45,6 @@ impl Hash for CurveManipulatorGroup {
4545
}
4646
}
4747

48-
#[derive(Debug)]
49-
pub struct CubicSplines {
50-
pub x: [f32; 4],
51-
pub y: [f32; 4],
52-
}
53-
54-
impl CubicSplines {
55-
pub fn solve(&self) -> [f32; 4] {
56-
let (x, y) = (&self.x, &self.y);
57-
58-
// Build an augmented matrix to solve the system of equations using Gaussian elimination
59-
let mut augmented_matrix = [
60-
[
61-
2. / (x[1] - x[0]),
62-
1. / (x[1] - x[0]),
63-
0.,
64-
0.,
65-
// |
66-
3. * (y[1] - y[0]) / ((x[1] - x[0]) * (x[1] - x[0])),
67-
],
68-
[
69-
1. / (x[1] - x[0]),
70-
2. * (1. / (x[1] - x[0]) + 1. / (x[2] - x[1])),
71-
1. / (x[2] - x[1]),
72-
0.,
73-
// |
74-
3. * ((y[1] - y[0]) / ((x[1] - x[0]) * (x[1] - x[0])) + (y[2] - y[1]) / ((x[2] - x[1]) * (x[2] - x[1]))),
75-
],
76-
[
77-
0.,
78-
1. / (x[2] - x[1]),
79-
2. * (1. / (x[2] - x[1]) + 1. / (x[3] - x[2])),
80-
1. / (x[3] - x[2]),
81-
// |
82-
3. * ((y[2] - y[1]) / ((x[2] - x[1]) * (x[2] - x[1])) + (y[3] - y[2]) / ((x[3] - x[2]) * (x[3] - x[2]))),
83-
],
84-
[
85-
0.,
86-
0.,
87-
1. / (x[3] - x[2]),
88-
2. / (x[3] - x[2]),
89-
// |
90-
3. * (y[3] - y[2]) / ((x[3] - x[2]) * (x[3] - x[2])),
91-
],
92-
];
93-
94-
// Gaussian elimination: forward elimination
95-
for row in 0..4 {
96-
let pivot_row_index = (row..4)
97-
.max_by(|&a_row, &b_row| augmented_matrix[a_row][row].abs().partial_cmp(&augmented_matrix[b_row][row].abs()).unwrap_or(std::cmp::Ordering::Equal))
98-
.unwrap();
99-
100-
// Swap the current row with the row that has the largest pivot element
101-
augmented_matrix.swap(row, pivot_row_index);
102-
103-
// Eliminate the current column in all rows below the current one
104-
for row_below_current in row + 1..4 {
105-
assert!(augmented_matrix[row][row].abs() > f32::EPSILON);
106-
107-
let scale_factor = augmented_matrix[row_below_current][row] / augmented_matrix[row][row];
108-
for col in row..5 {
109-
augmented_matrix[row_below_current][col] -= augmented_matrix[row][col] * scale_factor
110-
}
111-
}
112-
}
113-
114-
// Gaussian elimination: back substitution
115-
let mut solutions = [0.; 4];
116-
for col in (0..4).rev() {
117-
assert!(augmented_matrix[col][col].abs() > f32::EPSILON);
118-
119-
solutions[col] = augmented_matrix[col][4] / augmented_matrix[col][col];
120-
121-
for row in (0..col).rev() {
122-
augmented_matrix[row][4] -= augmented_matrix[row][col] * solutions[col];
123-
augmented_matrix[row][col] = 0.;
124-
}
125-
}
126-
127-
solutions
128-
}
129-
130-
pub fn interpolate(&self, input: f32, solutions: &[f32]) -> f32 {
131-
if input <= self.x[0] {
132-
return self.y[0];
133-
}
134-
if input >= self.x[self.x.len() - 1] {
135-
return self.y[self.x.len() - 1];
136-
}
137-
138-
// Find the segment that the input falls between
139-
let mut segment = 1;
140-
while self.x[segment] < input {
141-
segment += 1;
142-
}
143-
let segment_start = segment - 1;
144-
let segment_end = segment;
145-
146-
// Calculate the output value using quadratic interpolation
147-
let input_value = self.x[segment_start];
148-
let input_value_prev = self.x[segment_end];
149-
let output_value = self.y[segment_start];
150-
let output_value_prev = self.y[segment_end];
151-
let solutions_value = solutions[segment_start];
152-
let solutions_value_prev = solutions[segment_end];
153-
154-
let output_delta = solutions_value_prev * (input_value - input_value_prev) - (output_value - output_value_prev);
155-
let solution_delta = (output_value - output_value_prev) - solutions_value * (input_value - input_value_prev);
156-
157-
let input_ratio = (input - input_value_prev) / (input_value - input_value_prev);
158-
let prev_output_ratio = (1. - input_ratio) * output_value_prev;
159-
let output_ratio = input_ratio * output_value;
160-
let quadratic_ratio = input_ratio * (1. - input_ratio) * (output_delta * (1. - input_ratio) + solution_delta * input_ratio);
161-
162-
let result = prev_output_ratio + output_ratio + quadratic_ratio;
163-
result.clamp(0., 1.)
164-
}
165-
}
166-
16748
pub struct ValueMapperNode<C> {
16849
lut: Vec<C>,
16950
}

node-graph/graster-nodes/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
pub mod adjustments;
2+
pub mod cubic_spline;
3+
24
pub mod curve;
35
pub mod dehaze;
46
pub mod filter;

0 commit comments

Comments
 (0)