diff --git a/src/qelmt/arc.rs b/src/qelmt/arc.rs index 84912a2..4ca0b32 100644 --- a/src/qelmt/arc.rs +++ b/src/qelmt/arc.rs @@ -1,5 +1,6 @@ use super::{two_dec, ScaleEntity}; use dxf::entities; +use dxf::entities::LwPolyline; use simple_xml_builder::XMLElement; #[derive(Debug)] @@ -130,3 +131,100 @@ impl ScaleEntity for Arc { self.y + self.height } } + +// 在 mod.rs 中添加从 LwPolyline 转换为 Arc 的方法 +impl TryFrom<&LwPolyline> for Arc { + type Error = String; + + fn try_from(lwpolyline: &LwPolyline) -> Result { + // 检查顶点数量,必须是2个顶点才能形成圆弧 + if lwpolyline.vertices.len() != 2 { + return Err(format!("Arc conversion requires exactly 2 vertices, got {}", lwpolyline.vertices.len())); + } + + let v1 = &lwpolyline.vertices[0]; + let v2 = &lwpolyline.vertices[1]; + + // 检查第一个顶点是否有bulge值 + if v1.bulge == 0.0 { + return Err("No bulge value found for arc conversion".to_string()); + } + + // 计算弦长和中点 + let chord_length = ((v2.x - v1.x).powi(2) + (v2.y - v1.y).powi(2)).sqrt(); + let mid_x = (v1.x + v2.x) / 2.0; + let mid_y = (v1.y + v2.y) / 2.0; + + // 根据bulge值计算圆弧参数 + // bulge = tan(angle/4),其中angle是圆弧的包含角 + let bulge = v1.bulge; + let included_angle = 4.0 * bulge.atan(); // 圆弧包含角(弧度) + + // 计算半径 + let radius = chord_length / (2.0 * (included_angle / 2.0).sin()); + + // 计算圆心位置 + // 弦的方向向量 + let chord_dx = v2.x - v1.x; + let chord_dy = v2.y - v1.y; + + // 弦的垂直方向(向左旋转90度) + let perp_dx = -chord_dy; + let perp_dy = chord_dx; + let perp_length = (perp_dx * perp_dx + perp_dy * perp_dy).sqrt(); + + // 标准化垂直向量 + let unit_perp_x = perp_dx / perp_length; + let unit_perp_y = perp_dy / perp_length; + + // 计算圆心到弦中点的距离 + let center_distance = radius * (included_angle / 2.0).cos(); + + // 根据bulge的符号确定圆心位置 + let center_x = if bulge > 0.0 { + mid_x + center_distance * unit_perp_x + } else { + mid_x - center_distance * unit_perp_x + }; + let center_y = if bulge > 0.0 { + mid_y + center_distance * unit_perp_y + } else { + mid_y - center_distance * unit_perp_y + }; + + // 计算起始角度和结束角度 + let start_angle = (v1.y - center_y).atan2(v1.x - center_x); + let end_angle = (v2.y - center_y).atan2(v2.x - center_x); + + // 将弧度转换为度数 + let mut start_angle_deg = start_angle.to_degrees(); + let mut end_angle_deg = end_angle.to_degrees(); + + // 标准化角度到0-360度范围 + if start_angle_deg < 0.0 { + start_angle_deg += 360.0; + } + if end_angle_deg < 0.0 { + end_angle_deg += 360.0; + } + + // 计算角度跨度 + let arc_angle = included_angle.to_degrees().abs(); + + // 创建Arc对象 + Ok(Arc { + x: center_x - radius, // 边界框左上角x坐标 + y: -center_y - radius, // 边界框左上角y坐标(y轴翻转) + width: radius * 2.0, // 边界框宽度 + height: radius * 2.0, // 边界框高度 + start: start_angle_deg, // 起始角度(度) + angle: arc_angle, // 圆弧角度跨度(度) + style: if lwpolyline.thickness > 0.1 { + "line-style:normal;line-weight:normal;filling:none;color:black" + } else { + "line-style:normal;line-weight:thin;filling:none;color:black" + }.into(), + antialias: false, + }) + } +} \ No newline at end of file diff --git a/src/qelmt/mod.rs b/src/qelmt/mod.rs index 6dd8292..8f710e6 100644 --- a/src/qelmt/mod.rs +++ b/src/qelmt/mod.rs @@ -819,6 +819,21 @@ impl<'a> ObjectsBuilder<'a> { EntityType::LwPolyline(lwpolyline) => match lwpolyline.vertices.len() { 0 | 1 => Err("Error empty LwPolyline"), 2 => { + if lwpolyline.vertices[0].bulge != 0.0 { + match Arc::try_from(lwpolyline) { + Ok(mut arc) => { + arc.update_line_style(&update_line_style); + arc.scale(self.scale_fact.x, self.scale_fact.y); + arc.x += self.offset.x; + arc.y -= self.offset.y; + return Ok(Objects::Arc(arc)); + } + Err(_) => { + // Arc转换失败,继续执行下面的Line转换 + } + } + } + let mut line = Line::try_from(lwpolyline)?; // 根据line_type_name更新线型样式