diff --git a/src/qelmt/arc.rs b/src/qelmt/arc.rs index 4ca0b32..b1fe576 100644 --- a/src/qelmt/arc.rs +++ b/src/qelmt/arc.rs @@ -99,6 +99,19 @@ impl From<&Arc> for XMLElement { } impl Arc { + pub fn new(x: f64, y: f64, width: f64, height: f64, start: f64, angle: f64, style: String) -> Self { + Arc { + x, + y, + width, + height, + start, + angle, + style, + antialias: false, + } + } + pub fn update_line_style(&mut self, update_fn: F) where F: FnOnce(&mut String), diff --git a/src/qelmt/line.rs b/src/qelmt/line.rs index 23b6713..da8e51e 100644 --- a/src/qelmt/line.rs +++ b/src/qelmt/line.rs @@ -174,6 +174,21 @@ impl From<&Line> for XMLElement { } impl Line { + pub fn new(x1: f64, y1: f64, x2: f64, y2: f64, style: String) -> Self { + Line { + length2: 1.5, + end2: LineEnd::None, + length1: 1.5, + x1, + y1, + x2, + y2, + style, + end1: LineEnd::None, + antialias: false, + } + } + pub fn update_line_style(&mut self, update_fn: F) where F: FnOnce(&mut String), diff --git a/src/qelmt/mod.rs b/src/qelmt/mod.rs index 8f710e6..14ea42c 100644 --- a/src/qelmt/mod.rs +++ b/src/qelmt/mod.rs @@ -860,20 +860,43 @@ impl<'a> ObjectsBuilder<'a> { ellipse.y -= self.offset.y; Ok(Objects::Ellipse(ellipse)) + } else if polygon::is_rounded_rectangle(lwpolyline) { + // 拆分圆角四边形为圆弧和直线段 + let mut decomposed_objects = polygon::decompose_rounded_rectangle(lwpolyline); + + // 对每个对象应用缩放和偏移 + for obj in &mut decomposed_objects { + obj.scale(self.scale_fact.x, self.scale_fact.y); + match obj { + Objects::Arc(ref mut arc) => { + arc.x += self.offset.x; + arc.y -= self.offset.y; + } + Objects::Line(ref mut line) => { + line.x1 += self.offset.x; + line.y1 -= self.offset.y; + line.x2 += self.offset.x; + line.y2 -= self.offset.y; + } + _ => {} + } + } + + Ok(Objects::Group(decomposed_objects)) } else { - let mut poly: Polygon = lwpolyline.into(); + let mut poly: Polygon = lwpolyline.into(); - // 根据line_type_name更新线型样式 - poly.update_line_style(&update_line_style); + // 根据line_type_name更新线型样式 + poly.update_line_style(&update_line_style); - poly.scale(self.scale_fact.x, self.scale_fact.y); + poly.scale(self.scale_fact.x, self.scale_fact.y); - for cord in &mut poly.coordinates { - cord.x += self.offset.x; - cord.y -= self.offset.y; - } + for cord in &mut poly.coordinates { + cord.x += self.offset.x; + cord.y -= self.offset.y; + } - Ok(Objects::Polygon(poly)) + Ok(Objects::Polygon(poly)) } } }, @@ -1638,3 +1661,4 @@ enum TextEntity<'a> { MText(&'a dxf::entities::MText), Attrib(&'a AttributeDefinition), } + diff --git a/src/qelmt/polygon.rs b/src/qelmt/polygon.rs index 1d5e827..989e174 100644 --- a/src/qelmt/polygon.rs +++ b/src/qelmt/polygon.rs @@ -289,3 +289,168 @@ impl ScaleEntity for Polygon { } } } + + +/// 判断LwPolyline是否为带圆角的四边形 +/// 条件:恰好8个顶点,闭合,每个顶点的bulge值要么为0(直线段)要么非0(圆弧段) +pub fn is_rounded_rectangle(lwpolyline: &LwPolyline) -> bool { + // 检查顶点数量 + if lwpolyline.vertices.len() != 8 { + return false; + } + + // 检查每个顶点的bulge值,确保形成合理的圆角四边形 + // 圆角四边形应该有交替的直线段和圆弧段,或者4个圆角 + let bulge_count = lwpolyline.vertices.iter() + .filter(|v| v.bulge.abs() > 0.0) + .count(); + + // 4个圆角 + bulge_count == 4 +} + +/// 将带圆角的四边形拆分为圆弧和直线段 +pub fn decompose_rounded_rectangle(lwpolyline: &LwPolyline) -> Vec { + let mut objects = Vec::new(); + let vertices = &lwpolyline.vertices; + + for i in 0..vertices.len() { + let current = &vertices[i]; + let next = &vertices[(i + 1) % vertices.len()]; + + if current.bulge.abs() > 1e-10 { + // 创建圆弧段 + if let Some(arc) = create_arc_from_bulge(current.x, current.y, next.x, next.y, current.bulge) { + objects.push(super::Objects::Arc(arc)); + } + } else { + // 创建直线段 + let style = if lwpolyline.thickness > 0.5 { + "line-style:normal;line-weight:normal;filling:none;color:black" + } else { + "line-style:normal;line-weight:thin;filling:none;color:black" + }.to_string(); + + let line = super::Line::new( + current.x, + -current.y, // Y轴翻转 + next.x, + -next.y, // Y轴翻转 + style, + ); + objects.push(super::Objects::Line(line)); + } + } + objects +} + +/// 根据bulge值创建圆弧 +fn create_arc_from_bulge(start_x: f64, start_y: f64, end_x: f64, end_y: f64, bulge: f64) -> Option { + if bulge.abs() <= 1e-10 { + return None; + } + + // 计算弦长和中点 + let chord_length = ((end_x - start_x).powi(2) + (end_y - start_y).powi(2)).sqrt(); + let mid_x = (start_x + end_x) / 2.0; + let mid_y = (start_y + end_y) / 2.0; + + // 根据bulge值计算圆弧参数 + // bulge = tan(angle/4),其中angle是圆弧的包含角 + let included_angle = 4.0 * bulge.atan(); // 圆弧包含角(弧度) + + // 计算半径 + let radius: f64 = chord_length / (2.0 * (included_angle / 2.0).sin()); + + // 计算圆心位置 + // 弦的方向向量 + let chord_dx = end_x - start_x; + let chord_dy = end_y - start_y; + + // 弦的垂直方向(向左旋转90度) + let perp_dx = -chord_dy; + let perp_dy = chord_dx; + let perp_length: f64 = (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: f64 = 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 = (start_y - center_y).atan2(start_x - center_x); + let end_angle = (end_y - center_y).atan2(end_x - center_x); + + // 将弧度转换为度数 + let mut start_angle_deg: f64 = start_angle.to_degrees(); + let mut end_angle_deg: f64 = 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: f64 = included_angle.to_degrees().abs(); + + // // 计算圆弧参数 + // let start_x = start_vertex.x; + // let start_y = -start_vertex.y; // Y轴翻转 + // let end_x = end_vertex.x; + // let end_y = -end_vertex.y; // Y轴翻转 + + // // 弦长 + // let chord_length = ((end_x - start_x).powi(2) + (end_y - start_y).powi(2)).sqrt(); + // if chord_length < 1e-10 { + // return None; + // } + + // // 根据bulge计算圆弧的角度 + // let angle = 4.0 * bulge.atan(); + // // 计算圆弧的半径 + // let radius = chord_length / (2.0 * (angle / 2.0).sin()); + + // // 计算中点 + // let mid_x = (start_x + end_x) / 2.0; + // let mid_y = (start_y + end_y) / 2.0; + + // // 计算弦角 + // let chord_angle = (end_y - start_y).atan2(end_x - start_x); + // let center_offset = radius * (angle / 2.0).cos(); + + // let center_x = mid_x - center_offset * (chord_angle + std::f64::consts::PI / 2.0).sin(); + // let center_y = mid_y + center_offset * (chord_angle + std::f64::consts::PI / 2.0).cos(); + + // // 计算起始角度和角度跨度 + // let start_angle = (start_y - center_y).atan2(start_x - center_x).to_degrees(); + // let angle_span = angle.to_degrees().abs(); + + let style = "line-style:normal;line-weight:thin;filling:none;color:black".to_string(); + + Some(super::Arc::new( + center_x-radius, + -center_y-radius, + radius.abs() * 2.0, + radius.abs() * 2.0, + start_angle_deg, + arc_angle, + style, + )) +} \ No newline at end of file