use crate::xml_element::{XmlElement, XmlElementError, XmlNode};
#[derive(Debug, Clone, PartialEq)]
pub struct QuadraticBezier {
pub point1: (f64, f64),
pub point2: (f64, f64),
}
impl QuadraticBezier {
#[must_use]
pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
Self {
point1: (x1, y1),
point2: (x2, y2),
}
}
#[must_use]
pub fn to_abbreviated_string(&self) -> String {
format!(
"Q {} {} {} {}",
self.point1.0, self.point1.1, self.point2.0, self.point2.1
)
}
}
impl std::fmt::Display for QuadraticBezier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_abbreviated_string())
}
}
impl XmlElement for QuadraticBezier {
fn element_name(&self) -> &'static str {
"QuadraticBezier"
}
fn attributes(&self) -> Vec<(String, String)> {
Vec::new()
}
fn write_xml(&self, out: &mut String) {
out.push_str("<QuadraticBezier>");
out.push_str(&crate::xml_element::xml_escape(
&self.to_abbreviated_string(),
));
out.push_str("</QuadraticBezier>");
}
fn from_xml(node: &XmlNode) -> Result<Self, XmlElementError> {
let text = node
.text
.as_deref()
.ok_or_else(|| XmlElementError("QuadraticBezier 缺少文本内容".to_string()))?;
let parts: Vec<&str> = text.split_whitespace().collect();
if parts.len() < 5 || parts[0] != "Q" {
return Err(XmlElementError(format!("QuadraticBezier 格式错误: {text}")));
}
let x1: f64 = parts[1]
.parse()
.map_err(|e| XmlElementError(format!("解析 QuadraticBezier.x1 失败: {e}")))?;
let y1: f64 = parts[2]
.parse()
.map_err(|e| XmlElementError(format!("解析 QuadraticBezier.y1 失败: {e}")))?;
let x2: f64 = parts[3]
.parse()
.map_err(|e| XmlElementError(format!("解析 QuadraticBezier.x2 失败: {e}")))?;
let y2: f64 = parts[4]
.parse()
.map_err(|e| XmlElementError(format!("解析 QuadraticBezier.y2 失败: {e}")))?;
Ok(Self::new(x1, y1, x2, y2))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::xml_parse::parse_xml_to_nodes;
#[test]
fn quadratic_bezier_new() {
let qb = QuadraticBezier::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(qb.point1, (1.0, 2.0));
assert_eq!(qb.point2, (3.0, 4.0));
}
#[test]
fn quadratic_bezier_to_string() {
let qb = QuadraticBezier::new(5.0, 5.0, 10.0, 0.0);
assert_eq!(qb.to_abbreviated_string(), "Q 5 5 10 0");
}
#[test]
fn quadratic_bezier_display() {
let qb = QuadraticBezier::new(0.0, 0.0, 1.0, 1.0);
assert_eq!(format!("{qb}"), "Q 0 0 1 1");
}
#[test]
fn quadratic_bezier_clone_eq() {
let qb = QuadraticBezier::new(1.0, 2.0, 3.0, 4.0);
let qb2 = qb.clone();
assert_eq!(qb, qb2);
}
#[test]
fn test_xml_element_name() {
let qb = QuadraticBezier::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(qb.element_name(), "QuadraticBezier");
}
#[test]
fn test_xml_element_roundtrip() {
let qb = QuadraticBezier::new(5.0, 5.0, 10.0, 0.0);
let xml = qb.to_xml();
assert!(xml.contains("<QuadraticBezier>"));
assert!(xml.contains("Q 5 5 10 0"));
let node = parse_xml_to_nodes(&xml).unwrap();
let qb2 = QuadraticBezier::from_xml(&node).unwrap();
assert_eq!(qb, qb2);
}
}