easyofd_core/graph/tight/method/
quadratic_bezier.rs1use crate::xml_element::{XmlElement, XmlElementError, XmlNode};
6
7#[derive(Debug, Clone, PartialEq)]
14pub struct QuadraticBezier {
15 pub point1: (f64, f64),
17 pub point2: (f64, f64),
19}
20
21impl QuadraticBezier {
22 #[must_use]
24 pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
25 Self {
26 point1: (x1, y1),
27 point2: (x2, y2),
28 }
29 }
30
31 #[must_use]
33 pub fn to_abbreviated_string(&self) -> String {
34 format!(
35 "Q {} {} {} {}",
36 self.point1.0, self.point1.1, self.point2.0, self.point2.1
37 )
38 }
39}
40
41impl std::fmt::Display for QuadraticBezier {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.write_str(&self.to_abbreviated_string())
44 }
45}
46
47impl XmlElement for QuadraticBezier {
48 fn element_name(&self) -> &'static str {
50 "QuadraticBezier"
51 }
52
53 fn attributes(&self) -> Vec<(String, String)> {
54 Vec::new()
55 }
56
57 fn write_xml(&self, out: &mut String) {
59 out.push_str("<QuadraticBezier>");
60 out.push_str(&crate::xml_element::xml_escape(
61 &self.to_abbreviated_string(),
62 ));
63 out.push_str("</QuadraticBezier>");
64 }
65
66 fn from_xml(node: &XmlNode) -> Result<Self, XmlElementError> {
67 let text = node
68 .text
69 .as_deref()
70 .ok_or_else(|| XmlElementError("QuadraticBezier 缺少文本内容".to_string()))?;
71 let parts: Vec<&str> = text.split_whitespace().collect();
72 if parts.len() < 5 || parts[0] != "Q" {
73 return Err(XmlElementError(format!("QuadraticBezier 格式错误: {text}")));
74 }
75 let x1: f64 = parts[1]
76 .parse()
77 .map_err(|e| XmlElementError(format!("解析 QuadraticBezier.x1 失败: {e}")))?;
78 let y1: f64 = parts[2]
79 .parse()
80 .map_err(|e| XmlElementError(format!("解析 QuadraticBezier.y1 失败: {e}")))?;
81 let x2: f64 = parts[3]
82 .parse()
83 .map_err(|e| XmlElementError(format!("解析 QuadraticBezier.x2 失败: {e}")))?;
84 let y2: f64 = parts[4]
85 .parse()
86 .map_err(|e| XmlElementError(format!("解析 QuadraticBezier.y2 失败: {e}")))?;
87 Ok(Self::new(x1, y1, x2, y2))
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use crate::xml_parse::parse_xml_to_nodes;
95
96 #[test]
97 fn quadratic_bezier_new() {
98 let qb = QuadraticBezier::new(1.0, 2.0, 3.0, 4.0);
99 assert_eq!(qb.point1, (1.0, 2.0));
100 assert_eq!(qb.point2, (3.0, 4.0));
101 }
102
103 #[test]
104 fn quadratic_bezier_to_string() {
105 let qb = QuadraticBezier::new(5.0, 5.0, 10.0, 0.0);
106 assert_eq!(qb.to_abbreviated_string(), "Q 5 5 10 0");
107 }
108
109 #[test]
110 fn quadratic_bezier_display() {
111 let qb = QuadraticBezier::new(0.0, 0.0, 1.0, 1.0);
112 assert_eq!(format!("{qb}"), "Q 0 0 1 1");
113 }
114
115 #[test]
116 fn quadratic_bezier_clone_eq() {
117 let qb = QuadraticBezier::new(1.0, 2.0, 3.0, 4.0);
118 let qb2 = qb.clone();
119 assert_eq!(qb, qb2);
120 }
121
122 #[test]
123 fn test_xml_element_name() {
124 let qb = QuadraticBezier::new(1.0, 2.0, 3.0, 4.0);
125 assert_eq!(qb.element_name(), "QuadraticBezier");
126 }
127
128 #[test]
129 fn test_xml_element_roundtrip() {
130 let qb = QuadraticBezier::new(5.0, 5.0, 10.0, 0.0);
131 let xml = qb.to_xml();
132 assert!(xml.contains("<QuadraticBezier>"));
133 assert!(xml.contains("Q 5 5 10 0"));
134 let node = parse_xml_to_nodes(&xml).unwrap();
135 let qb2 = QuadraticBezier::from_xml(&node).unwrap();
136 assert_eq!(qb, qb2);
137 }
138}