easyofd_core/graph/tight/method/
arc.rs1use crate::xml_element::{XmlElement, XmlElementError, XmlNode};
6
7#[derive(Debug, Clone, PartialEq)]
13pub struct Arc {
14 pub rx: f64,
16 pub ry: f64,
18 pub rotation_angle: f64,
20 pub large_arc: bool,
22 pub sweep_direction: bool,
24 pub end_point: (f64, f64),
26}
27
28impl Arc {
29 #[must_use]
31 pub fn new(
32 rx: f64,
33 ry: f64,
34 rotation_angle: f64,
35 large_arc: bool,
36 sweep_direction: bool,
37 end_x: f64,
38 end_y: f64,
39 ) -> Self {
40 Self {
41 rx,
42 ry,
43 rotation_angle: rotation_angle % 360.0,
44 large_arc,
45 sweep_direction,
46 end_point: (end_x, end_y),
47 }
48 }
49
50 #[must_use]
52 pub fn to_abbreviated_string(&self) -> String {
53 let large = i32::from(self.large_arc);
54 let sweep = i32::from(self.sweep_direction);
55 format!(
56 "A {} {} {} {} {} {} {}",
57 self.rx, self.ry, self.rotation_angle, large, sweep, self.end_point.0, self.end_point.1
58 )
59 }
60}
61
62impl std::fmt::Display for Arc {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.write_str(&self.to_abbreviated_string())
65 }
66}
67
68impl XmlElement for Arc {
69 fn element_name(&self) -> &'static str {
71 "Arc"
72 }
73
74 fn attributes(&self) -> Vec<(String, String)> {
75 Vec::new()
76 }
77
78 fn write_xml(&self, out: &mut String) {
80 out.push_str("<Arc>");
81 out.push_str(&crate::xml_element::xml_escape(
82 &self.to_abbreviated_string(),
83 ));
84 out.push_str("</Arc>");
85 }
86
87 fn from_xml(node: &XmlNode) -> Result<Self, XmlElementError> {
88 let text = node
89 .text
90 .as_deref()
91 .ok_or_else(|| XmlElementError("Arc 缺少文本内容".to_string()))?;
92 let parts: Vec<&str> = text.split_whitespace().collect();
94 if parts.len() < 8 || parts[0] != "A" {
95 return Err(XmlElementError(format!("Arc 格式错误: {text}")));
96 }
97 let rx: f64 = parts[1]
98 .parse()
99 .map_err(|e| XmlElementError(format!("解析 Arc.rx 失败: {e}")))?;
100 let ry: f64 = parts[2]
101 .parse()
102 .map_err(|e| XmlElementError(format!("解析 Arc.ry 失败: {e}")))?;
103 let rotation_angle: f64 = parts[3]
104 .parse()
105 .map_err(|e| XmlElementError(format!("解析 Arc.rotation_angle 失败: {e}")))?;
106 let large_arc: i32 = parts[4]
107 .parse()
108 .map_err(|e| XmlElementError(format!("解析 Arc.large_arc 失败: {e}")))?;
109 let sweep: i32 = parts[5]
110 .parse()
111 .map_err(|e| XmlElementError(format!("解析 Arc.sweep 失败: {e}")))?;
112 let end_x: f64 = parts[6]
113 .parse()
114 .map_err(|e| XmlElementError(format!("解析 Arc.end_x 失败: {e}")))?;
115 let end_y: f64 = parts[7]
116 .parse()
117 .map_err(|e| XmlElementError(format!("解析 Arc.end_y 失败: {e}")))?;
118 Ok(Self::new(
119 rx,
120 ry,
121 rotation_angle,
122 large_arc != 0,
123 sweep != 0,
124 end_x,
125 end_y,
126 ))
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::xml_parse::parse_xml_to_nodes;
134
135 #[test]
136 fn arc_new() {
137 let a = Arc::new(5.0, 5.0, 0.0, true, false, 10.0, 10.0);
138 assert!((a.rx - 5.0).abs() < f64::EPSILON);
139 assert!((a.ry - 5.0).abs() < f64::EPSILON);
140 assert!(a.large_arc);
141 assert!(!a.sweep_direction);
142 assert!((a.end_point.0 - 10.0).abs() < f64::EPSILON);
143 }
144
145 #[test]
146 fn arc_rotation_modulo() {
147 let a = Arc::new(1.0, 1.0, 720.0, false, false, 0.0, 0.0);
148 assert!((a.rotation_angle - 0.0).abs() < f64::EPSILON);
149 }
150
151 #[test]
152 fn arc_to_string() {
153 let a = Arc::new(5.0, 5.0, 0.0, true, false, 10.0, 10.0);
154 let s = a.to_abbreviated_string();
155 assert!(s.starts_with("A 5 5 0 1 0 10 10"));
156 }
157
158 #[test]
159 fn arc_display() {
160 let a = Arc::new(1.0, 2.0, 45.0, false, true, 3.0, 4.0);
161 let s = format!("{a}");
162 assert!(s.contains("A 1 2 45 0 1 3 4"));
163 }
164
165 #[test]
166 fn arc_clone_eq() {
167 let a = Arc::new(1.0, 2.0, 30.0, true, true, 5.0, 6.0);
168 let b = a.clone();
169 assert!((a.rx - b.rx).abs() < f64::EPSILON);
170 }
171
172 #[test]
173 fn test_xml_element_name() {
174 let a = Arc::new(1.0, 2.0, 0.0, false, false, 3.0, 4.0);
175 assert_eq!(a.element_name(), "Arc");
176 }
177
178 #[test]
179 fn test_xml_element_roundtrip() {
180 let a = Arc::new(5.0, 5.0, 45.0, true, false, 10.0, 10.0);
181 let xml = a.to_xml();
182 assert!(xml.contains("<Arc>"));
183 assert!(xml.contains("A 5 5 45 1 0 10 10"));
184 let node = parse_xml_to_nodes(&xml).unwrap();
185 let a2 = Arc::from_xml(&node).unwrap();
186 assert!((a.rx - a2.rx).abs() < f64::EPSILON);
187 assert!((a.ry - a2.ry).abs() < f64::EPSILON);
188 assert_eq!(a.large_arc, a2.large_arc);
189 assert_eq!(a.sweep_direction, a2.sweep_direction);
190 }
191}