Skip to main content

dioxuscut_paths/
transform.rs

1//! SVG path geometric transformations.
2
3use crate::parser::{parse_path, serialize_instructions};
4use crate::types::Instruction;
5
6/// Translates (offsets) an SVG path string by `(dx, dy)`.
7pub fn translate_path(path: &str, dx: f64, dy: f64) -> String {
8    let mut instructions = match parse_path(path) {
9        Ok(insts) => insts,
10        Err(_) => return path.to_string(),
11    };
12
13    for inst in &mut instructions {
14        match inst {
15            Instruction::MoveTo { x, y } => {
16                *x += dx;
17                *y += dy;
18            }
19            Instruction::LineTo { x, y } => {
20                *x += dx;
21                *y += dy;
22            }
23            Instruction::CubicCurveTo {
24                x1,
25                y1,
26                x2,
27                y2,
28                x,
29                y,
30            } => {
31                *x1 += dx;
32                *y1 += dy;
33                *x2 += dx;
34                *y2 += dy;
35                *x += dx;
36                *y += dy;
37            }
38            Instruction::QuadCurveTo { x1, y1, x, y } => {
39                *x1 += dx;
40                *y1 += dy;
41                *x += dx;
42                *y += dy;
43            }
44            Instruction::ClosePath => {}
45        }
46    }
47
48    serialize_instructions(&instructions)
49}
50
51/// Scales an SVG path string by factors `(sx, sy)`.
52pub fn scale_path(path: &str, sx: f64, sy: f64) -> String {
53    let mut instructions = match parse_path(path) {
54        Ok(insts) => insts,
55        Err(_) => return path.to_string(),
56    };
57
58    for inst in &mut instructions {
59        match inst {
60            Instruction::MoveTo { x, y } => {
61                *x *= sx;
62                *y *= sy;
63            }
64            Instruction::LineTo { x, y } => {
65                *x *= sx;
66                *y *= sy;
67            }
68            Instruction::CubicCurveTo {
69                x1,
70                y1,
71                x2,
72                y2,
73                x,
74                y,
75            } => {
76                *x1 *= sx;
77                *y1 *= sy;
78                *x2 *= sx;
79                *y2 *= sy;
80                *x *= sx;
81                *y *= sy;
82            }
83            Instruction::QuadCurveTo { x1, y1, x, y } => {
84                *x1 *= sx;
85                *y1 *= sy;
86                *x *= sx;
87                *y *= sy;
88            }
89            Instruction::ClosePath => {}
90        }
91    }
92
93    serialize_instructions(&instructions)
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_translate_path() {
102        let path = "M 0 0 L 10 10 Z";
103        let res = translate_path(path, 5.0, 15.0);
104        assert_eq!(res, "M 5.0000 15.0000 L 15.0000 25.0000 Z");
105    }
106
107    #[test]
108    fn test_scale_path() {
109        let path = "M 10 20 L 30 40 Z";
110        let res = scale_path(path, 2.0, 0.5);
111        assert_eq!(res, "M 20.0000 10.0000 L 60.0000 20.0000 Z");
112    }
113}