|
|
|
|
@ -100,6 +100,9 @@ trait Circularity {
|
|
|
|
|
//for a specific type
|
|
|
|
|
0.98..=1.02
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 考虑bugle圆形判断
|
|
|
|
|
fn is_circular_with_bulge(&self) -> bool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为 Polyline 类型实现圆形检测,有点类似函数定义
|
|
|
|
|
@ -137,6 +140,10 @@ impl Circularity for Polyline {
|
|
|
|
|
|
|
|
|
|
Self::match_range().contains(&t_ratio)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_circular_with_bulge(&self) -> bool{
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为 LwPolyline 类型实现相同的圆形检测逻辑
|
|
|
|
|
@ -165,22 +172,45 @@ impl Circularity for LwPolyline {
|
|
|
|
|
poly_area /= 2.0;
|
|
|
|
|
poly_area.abs()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let t_ratio = 4.0 * PI * poly_area / poly_perim.powf(2.0);
|
|
|
|
|
|
|
|
|
|
Self::match_range().contains(&t_ratio)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_circular_with_bulge(&self) -> bool {
|
|
|
|
|
// 检查是否有显著的bulge值
|
|
|
|
|
let has_bulge = self.vertices.iter().any(|v| v.bulge.abs() > 0.5);
|
|
|
|
|
if !has_bulge {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let all_quarter_arcs = self.vertices.iter()
|
|
|
|
|
.all(|v| (v.bulge.abs() - 1.0).abs() < 0.05);
|
|
|
|
|
|
|
|
|
|
if all_quarter_arcs {
|
|
|
|
|
// 检查是否闭合
|
|
|
|
|
if self.vertices.len() >= 3 {
|
|
|
|
|
let first = &self.vertices[0];
|
|
|
|
|
let last = &self.vertices[self.vertices.len() - 1];
|
|
|
|
|
let distance = ((last.x - first.x).powf(2.0) + (last.y - first.y).powf(2.0)).sqrt();
|
|
|
|
|
return distance < 0.1; // 起点终点接近
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 实现Definition的方法
|
|
|
|
|
// 最后返回文本的definition标签了
|
|
|
|
|
impl Definition {
|
|
|
|
|
// 创建新的 Definition 实例
|
|
|
|
|
// 创建新的 Definition 实例,对应elmt的<definition>标签 传入参数:文件名, 步长, dxf图纸
|
|
|
|
|
pub fn new(name: impl Into<String>, spline_step: u32, drw: &Drawing) -> Self {
|
|
|
|
|
/*for st in drw.styles() {
|
|
|
|
|
dbg!(st);
|
|
|
|
|
}*/
|
|
|
|
|
// 缩放处理
|
|
|
|
|
// 根据制图系统的类型缩放处理
|
|
|
|
|
let scale_factor = Self::scale_factor(drw.header.default_drawing_units);
|
|
|
|
|
// 创建description
|
|
|
|
|
// 创建description,对应elmt的<description>标签,里面就是实际的画图元素标签
|
|
|
|
|
let description = {
|
|
|
|
|
let mut description: Description = (drw, spline_step).into();
|
|
|
|
|
description.scale(scale_factor, scale_factor);
|
|
|
|
|
@ -530,7 +560,7 @@ pub struct ObjectsBuilder<'a> {
|
|
|
|
|
spline_step: u32,
|
|
|
|
|
blocks: &'a [&'a Block],
|
|
|
|
|
offset: Offset,
|
|
|
|
|
scale_fact: ScaleFactor,
|
|
|
|
|
scale_fact: ScaleFactor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
@ -575,6 +605,28 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
if !self.ent.common.is_visible {
|
|
|
|
|
return Err("Entity is not visible");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取线型名称
|
|
|
|
|
let line_type_name: String = self.ent.common.line_type_name.clone();
|
|
|
|
|
|
|
|
|
|
// 通用样式修改函数:根据line_type_name修改现有style中的line-style
|
|
|
|
|
let update_line_style = |style: &mut String| {
|
|
|
|
|
// 只有当line_type_name需要虚线样式时才进行修改,提高性能
|
|
|
|
|
if line_type_name.contains("DASH") || line_type_name == "BORDURE" {
|
|
|
|
|
// 使用正则表达式替换line-style部分
|
|
|
|
|
if style.contains("line-style:") {
|
|
|
|
|
*style = style.replace(
|
|
|
|
|
&format!("line-style:{}",
|
|
|
|
|
if style.contains("line-style:normal") { "normal" }
|
|
|
|
|
else if style.contains("line-style:dashed") { "dashed" }
|
|
|
|
|
else { "normal" }
|
|
|
|
|
),
|
|
|
|
|
"line-style:dashed"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 如果不是特殊线型,保持原有样式不变,避免不必要的操作
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 实体类型转换处理
|
|
|
|
|
match &self.ent.specific {
|
|
|
|
|
@ -582,13 +634,26 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
EntityType::Circle(circle) => {
|
|
|
|
|
let mut ellipse: Ellipse = circle.into();
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
ellipse.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
ellipse.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
ellipse.x += self.offset.x;
|
|
|
|
|
ellipse.y -= self.offset.y;
|
|
|
|
|
Ok(Objects::Ellipse(ellipse))
|
|
|
|
|
}
|
|
|
|
|
EntityType::Line(line) => {
|
|
|
|
|
let mut line: Line = line.into();
|
|
|
|
|
// 获取颜色
|
|
|
|
|
let color = if let Some(aci_index) = self.ent.common.color.index() {
|
|
|
|
|
aci_to_hex_color(aci_index)
|
|
|
|
|
} else {
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut line: Line = Line::from_line_with_color(line, color);
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
line.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
line.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
@ -598,10 +663,23 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
line.x2 += self.offset.x;
|
|
|
|
|
line.y2 -= self.offset.y;
|
|
|
|
|
|
|
|
|
|
println!("Line: x1: {}, y1: {}, x2: {}, y2: {}", line.x1, line.y1, line.x2, line.y2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Objects::Line(line))
|
|
|
|
|
}
|
|
|
|
|
EntityType::Arc(arc) => {
|
|
|
|
|
let mut arc: Arc = arc.into();
|
|
|
|
|
// 获取颜色
|
|
|
|
|
let color = if let Some(aci_index) = self.ent.common.color.index() {
|
|
|
|
|
aci_to_hex_color(aci_index)
|
|
|
|
|
} else {
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut arc: Arc = Arc::from_arc_with_color(arc, color);
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
arc.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
arc.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
@ -613,6 +691,9 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
EntityType::Spline(spline) => {
|
|
|
|
|
let mut poly: Polygon = (spline, self.spline_step).into();
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
poly.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
match poly.coordinates.len() {
|
|
|
|
|
0 | 1 => Err("Error removing empty Spline"),
|
|
|
|
|
//I'll need to improve my understanding of splines and the math here
|
|
|
|
|
@ -641,7 +722,13 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
//how best to pass in the flag for dynamic text or not....should the flag also default to true?
|
|
|
|
|
let mut text: Text = (
|
|
|
|
|
text,
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32),
|
|
|
|
|
{
|
|
|
|
|
if let Some(aci_index) = self.ent.common.color.index() {
|
|
|
|
|
aci_to_hex_color(aci_index)
|
|
|
|
|
} else {
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.into();
|
|
|
|
|
|
|
|
|
|
@ -653,7 +740,15 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
Objects::Text(text)
|
|
|
|
|
} else {
|
|
|
|
|
let mut dtext = DTextBuilder::from_text(text)
|
|
|
|
|
.color(HexColor::from_u32(self.ent.common.color_24_bit as u32))
|
|
|
|
|
.color({
|
|
|
|
|
// 优先使用 ACI 颜色索引
|
|
|
|
|
if let Some(aci_index) = self.ent.common.color.index() {
|
|
|
|
|
aci_to_hex_color(aci_index)
|
|
|
|
|
} else {
|
|
|
|
|
// 回退到24位颜色
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
dtext.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
@ -668,6 +763,9 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
EntityType::Ellipse(ellipse) => {
|
|
|
|
|
let mut ellipse: Ellipse = ellipse.into();
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
ellipse.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
ellipse.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
ellipse.x += self.offset.x;
|
|
|
|
|
ellipse.y -= self.offset.y;
|
|
|
|
|
@ -709,6 +807,9 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
2 => {
|
|
|
|
|
let mut line = Line::try_from(polyline)?;
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
line.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
line.scale(self.scale_fact.x, self.scale_fact.x);
|
|
|
|
|
|
|
|
|
|
line.x1 += self.offset.x;
|
|
|
|
|
@ -721,6 +822,9 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
if let Ok(mut ellipse) = Ellipse::try_from(polyline) {
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
ellipse.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
ellipse.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
ellipse.x += self.offset.x;
|
|
|
|
|
@ -730,6 +834,9 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
} else {
|
|
|
|
|
let mut poly: Polygon = polyline.into();
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
poly.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
poly.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
for cord in &mut poly.coordinates {
|
|
|
|
|
@ -741,40 +848,96 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
EntityType::LwPolyline(lwpolyline) => match lwpolyline.vertices.len() {
|
|
|
|
|
0 | 1 => Err("Error empty LwPolyline"),
|
|
|
|
|
2 => {
|
|
|
|
|
let mut line = Line::try_from(lwpolyline)?;
|
|
|
|
|
|
|
|
|
|
line.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
EntityType::LwPolyline(lwpolyline) => {
|
|
|
|
|
// 获取颜色
|
|
|
|
|
let color = if let Some(aci_index) = self.ent.common.color.index() {
|
|
|
|
|
aci_to_hex_color(aci_index)
|
|
|
|
|
} else {
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match lwpolyline.vertices.len() {
|
|
|
|
|
0 | 1 => Err("Error empty LwPolyline"),
|
|
|
|
|
2 => {
|
|
|
|
|
if lwpolyline.vertices[0].bulge != 0.0 {
|
|
|
|
|
match Arc::try_from_lwpolyline_with_color(lwpolyline, color) {
|
|
|
|
|
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转换
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line.x1 += self.offset.x;
|
|
|
|
|
line.y1 -= self.offset.y;
|
|
|
|
|
let mut line = Line::try_from_lwpolyline_with_color(lwpolyline, color)?;
|
|
|
|
|
|
|
|
|
|
line.x2 += self.offset.x;
|
|
|
|
|
line.y2 -= self.offset.y;
|
|
|
|
|
|
|
|
|
|
Ok(Objects::Line(line))
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
if let Ok(mut ellipse) = Ellipse::try_from(lwpolyline) {
|
|
|
|
|
ellipse.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
line.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
ellipse.x += self.offset.x;
|
|
|
|
|
ellipse.y -= self.offset.y;
|
|
|
|
|
line.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
Ok(Objects::Ellipse(ellipse))
|
|
|
|
|
} else {
|
|
|
|
|
let mut poly: Polygon = lwpolyline.into();
|
|
|
|
|
line.x1 += self.offset.x;
|
|
|
|
|
line.y1 -= self.offset.y;
|
|
|
|
|
|
|
|
|
|
poly.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
line.x2 += self.offset.x;
|
|
|
|
|
line.y2 -= self.offset.y;
|
|
|
|
|
|
|
|
|
|
for cord in &mut poly.coordinates {
|
|
|
|
|
cord.x += self.offset.x;
|
|
|
|
|
cord.y -= self.offset.y;
|
|
|
|
|
Ok(Objects::Line(line))
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
if let Ok(mut ellipse) = Ellipse::try_from_lwpolyline_with_color(lwpolyline, color) {
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
ellipse.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
ellipse.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
|
|
|
|
|
ellipse.x += self.offset.x;
|
|
|
|
|
ellipse.y -= self.offset.y;
|
|
|
|
|
|
|
|
|
|
Ok(Objects::Ellipse(ellipse))
|
|
|
|
|
} else if polygon::is_rounded_rectangle(lwpolyline) {
|
|
|
|
|
// 拆分圆角四边形为圆弧和直线段
|
|
|
|
|
let mut decomposed_objects = polygon::decompose_rounded_rectangle_with_color(lwpolyline, color);
|
|
|
|
|
|
|
|
|
|
// 对每个对象应用缩放和偏移
|
|
|
|
|
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 = Polygon::from_lwpolyline_with_color(lwpolyline, color);
|
|
|
|
|
|
|
|
|
|
// 根据line_type_name更新线型样式
|
|
|
|
|
poly.update_line_style(&update_line_style);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Objects::Polygon(poly))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Objects::Polygon(poly))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
@ -849,7 +1012,15 @@ impl<'a> ObjectsBuilder<'a> {
|
|
|
|
|
EntityType::AttributeDefinition(attrib) => Ok({
|
|
|
|
|
//need to look up the proper way to get the color for the Attrib
|
|
|
|
|
let mut dtext = DTextBuilder::from_attrib(attrib)
|
|
|
|
|
.color(HexColor::from_u32(self.ent.common.color_24_bit as u32))
|
|
|
|
|
.color({
|
|
|
|
|
// 优先使用 ACI 颜色索引
|
|
|
|
|
if let Some(aci_index) = self.ent.common.color.index() {
|
|
|
|
|
aci_to_hex_color(aci_index)
|
|
|
|
|
} else {
|
|
|
|
|
// 回退到24位颜色
|
|
|
|
|
HexColor::from_u32(self.ent.common.color_24_bit as u32)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
dtext.scale(self.scale_fact.x, self.scale_fact.y);
|
|
|
|
|
@ -1205,6 +1376,7 @@ impl From<HorizontalTextJustification> for HAlignment {
|
|
|
|
|
match value {
|
|
|
|
|
HorizontalTextJustification::Left => HAlignment::Left,
|
|
|
|
|
HorizontalTextJustification::Center => HAlignment::Center,
|
|
|
|
|
HorizontalTextJustification::Middle => HAlignment::Center,
|
|
|
|
|
HorizontalTextJustification::Right => HAlignment::Right,
|
|
|
|
|
|
|
|
|
|
//TODO: Handling the Aligned Middle and Fit alignments are a bit more complicated
|
|
|
|
|
@ -1539,3 +1711,153 @@ enum TextEntity<'a> {
|
|
|
|
|
MText(&'a dxf::entities::MText),
|
|
|
|
|
Attrib(&'a AttributeDefinition),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AutoCAD Color Index (ACI) 到 RGB 转换函数
|
|
|
|
|
fn aci_to_rgb(aci: u8) -> (u8, u8, u8) {
|
|
|
|
|
match aci {
|
|
|
|
|
1 => (255, 0, 0), // 红色
|
|
|
|
|
2 => (255, 255, 0), // 黄色
|
|
|
|
|
3 => (0, 255, 0), // 绿色
|
|
|
|
|
4 => (0, 255, 255), // 青色
|
|
|
|
|
5 => (0, 0, 255), // 蓝色
|
|
|
|
|
6 => (255, 0, 255), // 洋红色
|
|
|
|
|
// 7 => (255, 255, 255), // 白色
|
|
|
|
|
8 => (128, 128, 128), // 深灰色
|
|
|
|
|
9 => (192, 192, 192), // 浅灰色
|
|
|
|
|
94 => (0, 129, 0), // 深绿色
|
|
|
|
|
15 => (129, 86, 86), // 深棕色
|
|
|
|
|
|
|
|
|
|
// 更多标准颜色可以根据需要添加
|
|
|
|
|
_ => (0, 0, 0), // 默认黑色
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ACI 转换为 HexColor
|
|
|
|
|
fn aci_to_hex_color(aci: u8) -> HexColor {
|
|
|
|
|
let (r, g, b) = aci_to_rgb(aci);
|
|
|
|
|
HexColor::rgb(r, g, b)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 从PCL格式字符串中提取文本内容
|
|
|
|
|
///
|
|
|
|
|
/// 解析Printer Command Language (PCL)格式的字符串,提取其中的文本内容。
|
|
|
|
|
/// 支持格式如:"\pxt1;{\T1.001;传感器S1}" -> "传感器S1"
|
|
|
|
|
/// 以及Unicode转义格式:"{\T1.00100;\U+4F20\U+611F\U+5668S2}" -> "传感器S2"
|
|
|
|
|
///
|
|
|
|
|
/// # 参数
|
|
|
|
|
/// * `pcl_string` - PCL格式的字符串
|
|
|
|
|
///
|
|
|
|
|
/// # 返回值
|
|
|
|
|
/// 提取出的文本内容,如果解析失败则返回原字符串
|
|
|
|
|
pub fn extract_text_from_pcl(pcl_string: &str) -> String {
|
|
|
|
|
// 移除开头和结尾的空白字符
|
|
|
|
|
let trimmed = pcl_string.trim();
|
|
|
|
|
|
|
|
|
|
// 处理直接以大括号开始的格式:{\T1.00100;\U+4F20\U+611F\U+5668S2}
|
|
|
|
|
if trimmed.starts_with('{') && trimmed.ends_with('}') {
|
|
|
|
|
let content = &trimmed[1..trimmed.len() - 1];
|
|
|
|
|
|
|
|
|
|
// 查找\T命令
|
|
|
|
|
if let Some(t_pos) = content.find("\\T") {
|
|
|
|
|
// 查找\T命令后的分号
|
|
|
|
|
let t_content = &content[t_pos..];
|
|
|
|
|
if let Some(t_semicolon_pos) = t_content.find(';') {
|
|
|
|
|
let text_content = &t_content[t_semicolon_pos + 1..];
|
|
|
|
|
return decode_unicode_escapes(text_content);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果没有找到\T命令,返回大括号内的全部内容并解码Unicode
|
|
|
|
|
return decode_unicode_escapes(content);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否以\pxt开头
|
|
|
|
|
if !trimmed.starts_with("\\pxt") {
|
|
|
|
|
return pcl_string.to_string();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查找第一个分号,这标志着\pxt命令的结束
|
|
|
|
|
if let Some(semicolon_pos) = trimmed.find(';') {
|
|
|
|
|
let remaining = &trimmed[semicolon_pos + 1..];
|
|
|
|
|
|
|
|
|
|
// 检查是否有大括号包围的内容
|
|
|
|
|
if remaining.starts_with('{') && remaining.ends_with('}') {
|
|
|
|
|
let content = &remaining[1..remaining.len() - 1];
|
|
|
|
|
|
|
|
|
|
// 查找\T命令
|
|
|
|
|
if let Some(t_pos) = content.find("\\T") {
|
|
|
|
|
// 查找\T命令后的分号
|
|
|
|
|
let t_content = &content[t_pos..];
|
|
|
|
|
if let Some(t_semicolon_pos) = t_content.find(';') {
|
|
|
|
|
let text_content = &t_content[t_semicolon_pos + 1..];
|
|
|
|
|
return decode_unicode_escapes(text_content);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果没有找到\T命令,返回大括号内的全部内容并解码Unicode
|
|
|
|
|
return decode_unicode_escapes(content);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果解析失败,返回原字符串
|
|
|
|
|
pcl_string.to_string()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 解码Unicode转义序列,如\U+4F20转换为对应的Unicode字符
|
|
|
|
|
///
|
|
|
|
|
/// # 参数
|
|
|
|
|
/// * `text` - 包含Unicode转义序列的文本
|
|
|
|
|
///
|
|
|
|
|
/// # 返回值
|
|
|
|
|
/// 解码后的文本
|
|
|
|
|
fn decode_unicode_escapes(text: &str) -> String {
|
|
|
|
|
let mut result = String::new();
|
|
|
|
|
let mut chars = text.chars().peekable();
|
|
|
|
|
|
|
|
|
|
while let Some(ch) = chars.next() {
|
|
|
|
|
if ch == '\\' {
|
|
|
|
|
// 检查是否是Unicode转义序列 \U+XXXX
|
|
|
|
|
if chars.peek() == Some(&'U') {
|
|
|
|
|
chars.next(); // 消费 'U'
|
|
|
|
|
if chars.peek() == Some(&'+') {
|
|
|
|
|
chars.next(); // 消费 '+'
|
|
|
|
|
|
|
|
|
|
// 收集十六进制数字
|
|
|
|
|
let mut hex_digits = String::new();
|
|
|
|
|
while let Some(&next_ch) = chars.peek() {
|
|
|
|
|
if next_ch.is_ascii_hexdigit() {
|
|
|
|
|
hex_digits.push(chars.next().unwrap());
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 尝试解析十六进制数字为Unicode码点
|
|
|
|
|
if let Ok(code_point) = u32::from_str_radix(&hex_digits, 16) {
|
|
|
|
|
if let Some(unicode_char) = char::from_u32(code_point) {
|
|
|
|
|
result.push(unicode_char);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果解析失败,保留原始字符
|
|
|
|
|
result.push('\\');
|
|
|
|
|
result.push('U');
|
|
|
|
|
result.push('+');
|
|
|
|
|
result.push_str(&hex_digits);
|
|
|
|
|
} else {
|
|
|
|
|
// 不是 \U+ 格式,保留原始字符
|
|
|
|
|
result.push('\\');
|
|
|
|
|
result.push('U');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 不是Unicode转义,保留反斜杠
|
|
|
|
|
result.push('\\');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.push(ch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
}
|