|
|
|
|
@ -219,6 +219,8 @@ impl Definition {
|
|
|
|
|
let description = {
|
|
|
|
|
let mut description: Description = (drw, spline_step).into();
|
|
|
|
|
description.scale(scale_factor, scale_factor);
|
|
|
|
|
// DXF 实体可能位于整张 CAD 图纸的任意绝对坐标,导出元件时需要转换为局部坐标。
|
|
|
|
|
description.center_on_origin();
|
|
|
|
|
description
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@ -382,6 +384,42 @@ impl Objects {
|
|
|
|
|
_ => Children { slice: [].iter() },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 对所有图元递归应用同一平移量,保持块内部图形的相对位置不变。
|
|
|
|
|
fn translate(&mut self, offset_x: f64, offset_y: f64) {
|
|
|
|
|
match self {
|
|
|
|
|
Objects::Arc(arc) => {
|
|
|
|
|
arc.x += offset_x;
|
|
|
|
|
arc.y += offset_y;
|
|
|
|
|
}
|
|
|
|
|
Objects::Ellipse(ellipse) => {
|
|
|
|
|
ellipse.x += offset_x;
|
|
|
|
|
ellipse.y += offset_y;
|
|
|
|
|
}
|
|
|
|
|
Objects::Polygon(polygon) => {
|
|
|
|
|
for coordinate in &mut polygon.coordinates {
|
|
|
|
|
coordinate.x += offset_x;
|
|
|
|
|
coordinate.y += offset_y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Objects::DynamicText(dynamic_text) => dynamic_text.translate(offset_x, offset_y),
|
|
|
|
|
Objects::Text(text) => {
|
|
|
|
|
text.x += offset_x;
|
|
|
|
|
text.y += offset_y;
|
|
|
|
|
}
|
|
|
|
|
Objects::Line(line) => {
|
|
|
|
|
line.x1 += offset_x;
|
|
|
|
|
line.y1 += offset_y;
|
|
|
|
|
line.x2 += offset_x;
|
|
|
|
|
line.y2 += offset_y;
|
|
|
|
|
}
|
|
|
|
|
Objects::Group(objects) => {
|
|
|
|
|
for object in objects {
|
|
|
|
|
object.translate(offset_x, offset_y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 结构体,包含一个 stack 字段,存储 Children 迭代器的栈,使用生命周期参数 'a 确保引用的有效性
|
|
|
|
|
@ -771,8 +809,7 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
|
|
|
|
|
dtext.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
dtext.x += self.offset.x;
|
|
|
|
|
dtext.y -= self.offset.y;
|
|
|
|
|
dtext.translate(self.offset.x, -self.offset.y);
|
|
|
|
|
|
|
|
|
|
Objects::DynamicText(dtext)
|
|
|
|
|
},
|
|
|
|
|
@ -813,8 +850,7 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
|
|
|
|
|
dtext.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
dtext.x += self.offset.x;
|
|
|
|
|
dtext.y -= self.offset.y;
|
|
|
|
|
dtext.translate(self.offset.x, -self.offset.y);
|
|
|
|
|
|
|
|
|
|
Objects::DynamicText(dtext)
|
|
|
|
|
},
|
|
|
|
|
@ -1057,8 +1093,7 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
|
|
|
|
|
dtext.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
dtext.x += self.offset.x;
|
|
|
|
|
dtext.y -= self.offset.y;
|
|
|
|
|
dtext.translate(self.offset.x, -self.offset.y);
|
|
|
|
|
|
|
|
|
|
Objects::DynamicText(dtext)
|
|
|
|
|
}),
|
|
|
|
|
@ -1117,6 +1152,18 @@ pub struct Description {
|
|
|
|
|
objects: Vec<Objects>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Description {
|
|
|
|
|
// 将包围盒中心移动到局部原点,避免 CAD 中的插入位置泄漏到 QET 元件坐标。
|
|
|
|
|
fn center_on_origin(&mut self) {
|
|
|
|
|
let offset_x = -((self.left_bound() + self.right_bound()) / 2.0);
|
|
|
|
|
let offset_y = -((self.top_bound() + self.bot_bound()) / 2.0);
|
|
|
|
|
|
|
|
|
|
for object in &mut self.objects {
|
|
|
|
|
object.translate(offset_x, offset_y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 实现Description的ScaleEntity特征
|
|
|
|
|
impl ScaleEntity for Description {
|
|
|
|
|
fn scale(&mut self, fact_x: f64, fact_y: f64) {
|
|
|
|
|
@ -1149,7 +1196,7 @@ impl ScaleEntity for Description {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if let Some(rb) = rb {
|
|
|
|
|
rb.left_bound()
|
|
|
|
|
rb.right_bound()
|
|
|
|
|
} else {
|
|
|
|
|
0.0
|
|
|
|
|
}
|
|
|
|
|
@ -1177,7 +1224,7 @@ impl ScaleEntity for Description {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if let Some(bb) = bb {
|
|
|
|
|
bb.top_bound()
|
|
|
|
|
bb.bot_bound()
|
|
|
|
|
} else {
|
|
|
|
|
0.0
|
|
|
|
|
}
|
|
|
|
|
@ -1989,3 +2036,46 @@ pub(crate) fn strip_mtext_control_sequences(input: &str) -> String {
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::{Description, Line, Objects, ScaleEntity};
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn description_bounds_use_outer_edges_for_single_group() {
|
|
|
|
|
let description = Description {
|
|
|
|
|
objects: vec![Objects::Group(vec![Objects::Line(Line::new(
|
|
|
|
|
12.0,
|
|
|
|
|
-8.0,
|
|
|
|
|
42.0,
|
|
|
|
|
16.0,
|
|
|
|
|
"line-style:normal;line-weight:thin;filling:none;color:black".into(),
|
|
|
|
|
))])],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
assert_eq!(12.0, description.left_bound());
|
|
|
|
|
assert_eq!(42.0, description.right_bound());
|
|
|
|
|
assert_eq!(-8.0, description.top_bound());
|
|
|
|
|
assert_eq!(16.0, description.bot_bound());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn centering_description_removes_source_drawing_offset() {
|
|
|
|
|
let mut description = Description {
|
|
|
|
|
objects: vec![Objects::Group(vec![Objects::Line(Line::new(
|
|
|
|
|
1_290.0,
|
|
|
|
|
-2_070.0,
|
|
|
|
|
1_330.0,
|
|
|
|
|
-2_050.0,
|
|
|
|
|
"line-style:normal;line-weight:thin;filling:none;color:black".into(),
|
|
|
|
|
))])],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
description.center_on_origin();
|
|
|
|
|
|
|
|
|
|
assert_eq!(-20.0, description.left_bound());
|
|
|
|
|
assert_eq!(20.0, description.right_bound());
|
|
|
|
|
assert_eq!(-10.0, description.top_bound());
|
|
|
|
|
assert_eq!(10.0, description.bot_bound());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|