Compare commits

...

22 Commits
master ... qdj

Author SHA1 Message Date
liaoxianglian e66820f898 fix/修改符号的缩放比例为1mm=3.78像素,修改的动态文本的高度缩放-lxl-0126 1 week ago
邱德佳 02192f1f22 Revert "修复"
This reverts commit f185acd76c.
3 months ago
邱德佳 394658142d Revert "角度"
This reverts commit acfe44fd2e.
3 months ago
邱德佳 acfe44fd2e 角度 3 months ago
邱德佳 f185acd76c 修复 3 months ago
邱德佳 52f04ed560 修复三角形辅助线显示的问题 4 months ago
邱德佳 cd05c77a88 Revert "调试对齐"
This reverts commit e30474a254.
4 months ago
邱德佳 e30474a254 调试对齐 4 months ago
邱德佳 85b2497f50 取消偏移 4 months ago
邱德佳 b71c47cbdb 修改宽度系数的获取 4 months ago
邱德佳 2bbb51b91d 新增获取动态字体宽度系数 4 months ago
邱德佳 842daed2a3 Revert "修改获取字体宽度"
This reverts commit a5dfaa8f16.
4 months ago
邱德佳 a5dfaa8f16 修改获取字体宽度 4 months ago
邱德佳 1890d084a1 新增获取动态文本高度参数 4 months ago
邱德佳 ed10892e06 修复字体过小无法显示下划线 4 months ago
邱德佳 b0ea237408 字符间距测试 4 months ago
邱德佳 acde03cf70 Merge remote-tracking branch 'origin/master' into qdj 4 months ago
邱德佳 dd0fb97583 修复中文乱码 4 months ago
邱德佳 55740501d0 优化 4 months ago
邱德佳 1735d04ae4 补全256种颜色映射 4 months ago
邱德佳 cc4abf0955 修改了部分图形能显示粗体 4 months ago
邱德佳 578fc5f7a5 修改了部分图形能显示粗体 4 months ago

@ -0,0 +1,264 @@
pub const ACI_COLORS: [(u8,u8,u8); 255] = [
(0,0,0),
(255,0,0),
(255,255,0),
(0,255,0),
(0,255,255),
(0,0,255),
(255,0,255),
// (255,255,255), //白色/黑色。先判空
(128,128,128),
(192,192,192),
(255,0,0),
(230,0,0),
(204,0,0),
(178,0,0),
(153,0,0),
(128,0,0),
(102,0,0),
(76,0,0),
(51,0,0),
(25,0,0),
(255,64,0),
(230,57,0),
(204,51,0),
(178,45,0),
(153,38,0),
(128,32,0),
(102,25,0),
(76,19,0),
(51,13,0),
(25,6,0),
(255,128,0),
(230,115,0),
(204,102,0),
(178,89,0),
(153,76,0),
(128,64,0),
(102,51,0),
(76,38,0),
(51,25,0),
(25,13,0),
(255,191,0),
(230,172,0),
(204,153,0),
(178,134,0),
(153,115,0),
(128,96,0),
(102,76,0),
(76,57,0),
(51,38,0),
(25,19,0),
(255,255,0),
(230,230,0),
(204,204,0),
(178,178,0),
(153,153,0),
(128,128,0),
(102,102,0),
(76,76,0),
(51,51,0),
(25,25,0),
(191,255,0),
(172,230,0),
(153,204,0),
(134,178,0),
(115,153,0),
(96,128,0),
(76,102,0),
(57,76,0),
(38,51,0),
(19,25,0),
(128,255,0),
(115,230,0),
(102,204,0),
(89,178,0),
(76,153,0),
(64,128,0),
(51,102,0),
(38,76,0),
(25,51,0),
(13,25,0),
(64,255,0),
(57,230,0),
(51,204,0),
(45,178,0),
(38,153,0),
(32,128,0),
(25,102,0),
(19,76,0),
(13,51,0),
(6,25,0),
(0,255,0),
(0,230,0),
(0,204,0),
(0,178,0),
(0,153,0),
(0,128,0),
(0,102,0),
(0,76,0),
(0,51,0),
(0,25,0),
(0,255,64),
(0,230,57),
(0,204,51),
(0,178,45),
(0,153,38),
(0,128,32),
(0,102,25),
(0,76,19),
(0,51,13),
(0,25,6),
(0,255,128),
(0,230,115),
(0,204,102),
(0,178,89),
(0,153,76),
(0,128,64),
(0,102,51),
(0,76,38),
(0,51,25),
(0,25,13),
(0,255,191),
(0,230,172),
(0,204,153),
(0,178,134),
(0,153,115),
(0,128,96),
(0,102,76),
(0,76,57),
(0,51,38),
(0,25,19),
(0,255,255),
(0,230,230),
(0,204,204),
(0,178,178),
(0,153,153),
(0,128,128),
(0,102,102),
(0,76,76),
(0,51,51),
(0,25,25),
(0,191,255),
(0,172,230),
(0,153,204),
(0,134,178),
(0,115,153),
(0,96,128),
(0,76,102),
(0,57,76),
(0,38,51),
(0,19,25),
(0,128,255),
(0,115,230),
(0,102,204),
(0,89,178),
(0,76,153),
(0,64,128),
(0,51,102),
(0,38,76),
(0,25,51),
(0,13,25),
(0,64,255),
(0,57,230),
(0,51,204),
(0,45,178),
(0,38,153),
(0,32,128),
(0,25,102),
(0,19,76),
(0,13,51),
(0,6,25),
(0,0,255),
(0,0,230),
(0,0,204),
(0,0,178),
(0,0,153),
(0,0,128),
(0,0,102),
(0,0,76),
(0,0,51),
(0,0,25),
(64,0,255),
(57,0,230),
(51,0,204),
(45,0,178),
(38,0,153),
(32,0,128),
(25,0,102),
(19,0,76),
(13,0,51),
(6,0,25),
(128,0,255),
(115,0,230),
(102,0,204),
(89,0,178),
(76,0,153),
(64,0,128),
(51,0,102),
(38,0,76),
(25,0,51),
(13,0,25),
(191,0,255),
(172,0,230),
(153,0,204),
(134,0,178),
(115,0,153),
(96,0,128),
(76,0,102),
(57,0,76),
(38,0,51),
(19,0,25),
(255,0,255),
(230,0,230),
(204,0,204),
(178,0,178),
(153,0,153),
(128,0,128),
(102,0,102),
(76,0,76),
(51,0,51),
(25,0,25),
(255,0,191),
(230,0,172),
(204,0,153),
(178,0,134),
(153,0,115),
(128,0,96),
(102,0,76),
(76,0,57),
(51,0,38),
(25,0,19),
(255,0,128),
(230,0,115),
(204,0,102),
(178,0,89),
(153,0,76),
(128,0,64),
(102,0,51),
(76,0,38),
(51,0,25),
(25,0,13),
(255,0,64),
(230,0,57),
(204,0,51),
(178,0,45),
(153,0,38),
(128,0,32),
(102,0,25),
(76,0,19),
(51,0,13),
(25,0,6),
(255,255,255),
(192,192,192),
(128,128,128),
(64,64,64),
(32,32,32),
(0,0,0),
];
pub fn aci_to_rgb(aci: u8) -> (u8,u8,u8) {
ACI_COLORS[aci as usize]
}

@ -124,6 +124,22 @@ impl Arc {
{ {
update_fn(&mut self.style); update_fn(&mut self.style);
} }
pub fn update_line_weight(&mut self, lw: i16) {
let weight_str = match lw {
0 | -1 => "thin",
13..=25 => "thin",
26..=70 => "normal",
71..=100 => "thick",
_ => "extra-thick",
};
// 直接追加,不做复杂替换(简单有效)
if !self.style.is_empty() {
self.style.push_str("; ");
}
self.style.push_str(&format!("line-weight: {}", weight_str));
}
} }
impl ScaleEntity for Arc { impl ScaleEntity for Arc {

@ -28,7 +28,9 @@ pub struct DynamicText {
text_from: String, text_from: String,
v_alignment: VAlignment, v_alignment: VAlignment,
frame: bool, frame: bool,
text_width: i32, text_height: f64,
text_width: f64,
pub relative_x_scale_factor: f64,
keep_visual_rotation: bool, keep_visual_rotation: bool,
color: HexColor, color: HexColor,
reference_rectangle_width: f64, reference_rectangle_width: f64,
@ -49,32 +51,16 @@ impl From<&DynamicText> for XMLElement {
// reversed and slightly modified after looking at the result in element-editor: // reversed and slightly modified after looking at the result in element-editor:
// //
let pt_size: f64 = txt.font.point_size; let pt_size: f64 = txt.font.point_size;
// // 使用对象自身保存的 text_widthbuilder 已经计算或直接从 DXF 读取)
// we need the horizontal alignment and the text-width to move to right x-position:
// txt.reference_rectangle_width, // should be text-width (Group code 41)
// txt.attachment_point, // Group code 71
// // 1 = Top left; 2 = Top center; 3 = Top right
// // 4 = Middle left; 5 = Middle center; 6 = Middle right
// // 7 = Bottom left; 8 = Bottom center; 9 = Bottom right // // 7 = Bottom left; 8 = Bottom center; 9 = Bottom right
// //
// //
// it's just annoying if the value for "reference_rectangle_width" in the dxf is “0.0”... // it's just annoying if the value for "reference_rectangle_width" in the dxf is “0.0”...
// //
// o.k. ... as long as we do not know the real width:
// "guess" the width by number of characters and font-size:
//
let graphene_count = txt.text.graphemes(true).count();
let txt_width = if txt.reference_rectangle_width > 2.0 {
txt.reference_rectangle_width
} else {
// 不同的字母宽度与高度的比例并不相同0.75只是一个平均值
(graphene_count as f64) * pt_size * 0.75
};
println!("文本:{}", txt.text); println!("文本:{}", txt.text);
println!("对齐方式:{}, {}", txt.h_alignment, txt.v_alignment); println!("对齐方式:{}, {}", txt.h_alignment, txt.v_alignment);
println!("文本宽度: {}", txt_width); println!("文本宽度: {}", txt.text_width);
println!("relative_x_scale_factor: {}", txt.relative_x_scale_factor);
println!("文本高度:{}", pt_size); println!("文本高度:{}", pt_size);
println!("初始左下角位置: x={}, y={}", txt.x, txt.y); println!("初始左下角位置: x={}, y={}", txt.x, txt.y);
println!("初始对齐位置: x={}, y={}", txt.align_x, txt.align_y); println!("初始对齐位置: x={}, y={}", txt.align_x, txt.align_y);
@ -83,11 +69,11 @@ impl From<&DynamicText> for XMLElement {
// 计算基础位置(不考虑旋转) // 计算基础位置(不考虑旋转)
// txt.x和txt.y现在是左下角位置 // txt.x和txt.y现在是左下角位置
let left_x = txt.x; let left_x = txt.x;
// align_x 是对齐点的x坐标后面加的数字是考虑到QET中boundingRect的没有完全贴合文本内容 // align_x 是对齐点的x坐标
let mut align_x = match txt.h_alignment { let mut align_x = match txt.h_alignment {
HAlignment::Left => txt.align_x - 0.5, HAlignment::Left => txt.align_x,
HAlignment::Center => txt.align_x - 1.0, HAlignment::Center => txt.align_x,
HAlignment::Right => txt.align_x - 2.0 HAlignment::Right => txt.align_x
}; };
// 根据垂直对齐方式计算顶部的y坐标 // 根据垂直对齐方式计算顶部的y坐标
@ -97,16 +83,16 @@ impl From<&DynamicText> for XMLElement {
VAlignment::Bottom => txt.y - pt_size + pt_size / 2.0, VAlignment::Bottom => txt.y - pt_size + pt_size / 2.0,
}; };
// align_y 是对齐点的y坐标后面加的数字是考虑到QET中boundingRect的没有完全贴合文本内容 // align_y 是对齐点的y坐标
let mut align_y = match txt.v_alignment { let mut align_y = match txt.v_alignment {
VAlignment::Top => txt.align_y - 0.5, VAlignment::Top => txt.align_y,
VAlignment::Center => txt.align_y + 0.5, VAlignment::Center => txt.align_y,
VAlignment::Bottom => txt.align_y + 1.0 VAlignment::Bottom => txt.align_y
}; };
if(txt.h_alignment == HAlignment::Left && txt.v_alignment==VAlignment::Bottom) { if txt.h_alignment == HAlignment::Left && txt.v_alignment==VAlignment::Bottom {
align_x = txt.x-0.5; align_x = txt.x;
align_y = txt.y+1.0; align_y = txt.y;
} }
@ -146,7 +132,9 @@ impl From<&DynamicText> for XMLElement {
dtxt_xml.add_attribute("Valignment", &txt.v_alignment); dtxt_xml.add_attribute("Valignment", &txt.v_alignment);
dtxt_xml.add_attribute("text_from", &txt.text_from); dtxt_xml.add_attribute("text_from", &txt.text_from);
dtxt_xml.add_attribute("frame", txt.frame); dtxt_xml.add_attribute("frame", txt.frame);
dtxt_xml.add_attribute("text_height", txt.text_height);
dtxt_xml.add_attribute("text_width", txt.text_width); dtxt_xml.add_attribute("text_width", txt.text_width);
dtxt_xml.add_attribute("relative_x_scale_factor", two_dec(txt.relative_x_scale_factor));
dtxt_xml.add_attribute("color", txt.color.display_rgb()); dtxt_xml.add_attribute("color", txt.color.display_rgb());
dtxt_xml.add_attribute("align_x", two_dec(align_x)); dtxt_xml.add_attribute("align_x", two_dec(align_x));
dtxt_xml.add_attribute("align_y", two_dec(align_y)); dtxt_xml.add_attribute("align_y", two_dec(align_y));
@ -184,8 +172,8 @@ impl ScaleEntity for DynamicText {
self.y *= fact_y; self.y *= fact_y;
self.align_x *= fact_x; self.align_x *= fact_x;
self.align_y *= fact_y; self.align_y *= fact_y;
//self.font.pixel_size *= fact; self.font.scale(fact_y);
self.font.point_size *= fact_x; self.text_height = self.text_height * fact_y;
} }
fn left_bound(&self) -> f64 { fn left_bound(&self) -> f64 {
@ -255,7 +243,7 @@ impl<'a> DTextBuilder<'a> {
reference_rectangle_width, reference_rectangle_width,
align_x, align_x,
align_y, align_y,
relative_x_scale_factor,
) = match self.text { ) = match self.text {
TextEntity::Text(txt) => { TextEntity::Text(txt) => {
// let (x, y) = if txt.horizontal_text_justification == HorizontalTextJustification::Left && (txt.vertical_text_justification == VerticalTextJustification::Bottom || txt.vertical_text_justification == VerticalTextJustification::Baseline) { // let (x, y) = if txt.horizontal_text_justification == HorizontalTextJustification::Left && (txt.vertical_text_justification == VerticalTextJustification::Bottom || txt.vertical_text_justification == VerticalTextJustification::Baseline) {
@ -272,10 +260,11 @@ impl<'a> DTextBuilder<'a> {
txt.text_height, txt.text_height,
txt.value.clone(), txt.value.clone(),
HAlignment::from(txt.horizontal_text_justification), HAlignment::from(txt.horizontal_text_justification),
VAlignment::from_text_entity(txt.vertical_text_justification, false), VAlignment::from_text_entity(txt.vertical_text_justification, true),
0.0, // as Placeholder: no "reference_rectangle_width" with Text!!! 0.0, // as Placeholder: no "reference_rectangle_width" with Text!!!
txt.second_alignment_point.x, txt.second_alignment_point.x,
-txt.second_alignment_point.y -txt.second_alignment_point.y,
txt.relative_x_scale_factor,
)}, )},
TextEntity::MText(mtxt) => { TextEntity::MText(mtxt) => {
// 计算实际的旋转角度优先使用x_axis_direction向量 // 计算实际的旋转角度优先使用x_axis_direction向量
@ -316,6 +305,7 @@ impl<'a> DTextBuilder<'a> {
mtxt.reference_rectangle_width, mtxt.reference_rectangle_width,
mtxt.insertion_point.x, mtxt.insertion_point.x,
-mtxt.insertion_point.y, -mtxt.insertion_point.y,
1.0,
)}, )},
TextEntity::Attrib(attrib) => { TextEntity::Attrib(attrib) => {
// 根据DXF文本对齐规则当水平对齐不是Left时使用second_alignment_point // 根据DXF文本对齐规则当水平对齐不是Left时使用second_alignment_point
@ -338,7 +328,8 @@ impl<'a> DTextBuilder<'a> {
VAlignment::from_text_entity(attrib.vertical_text_justification, true), VAlignment::from_text_entity(attrib.vertical_text_justification, true),
0.0, // as Placeholder: not need to check if Attrib has something similar 0.0, // as Placeholder: not need to check if Attrib has something similar
attrib.second_alignment_point.x, attrib.second_alignment_point.x,
-attrib.second_alignment_point.y -attrib.second_alignment_point.y,
attrib.relative_x_scale_factor,
) )
}, },
}; };
@ -373,6 +364,16 @@ impl<'a> DTextBuilder<'a> {
/*dbg!(&value); /*dbg!(&value);
dbg!(&y); dbg!(&y);
dbg!(&self.text);*/ dbg!(&self.text);*/
let value = super::strip_mtext_control_sequences(&value);
// 将 DXF 中读取到的 text_height 放大 2 倍(用户要求)
// let text_height = text_height * 2.0;
let text_height = text_height;
let text_width = if reference_rectangle_width > 0.0 {
reference_rectangle_width
} else {
estimate_text_width(&value, text_height, relative_x_scale_factor)
};
DynamicText { DynamicText {
//x: x - (calc_width as f64/2.0), //x: x - (calc_width as f64/2.0),
x, x,
@ -384,26 +385,24 @@ impl<'a> DTextBuilder<'a> {
0.0 0.0
}, },
uuid: Uuid::new_v4(), uuid: Uuid::new_v4(),
font: if style_name == "STANDARD" { font: {
FontInfo { let mut font = FontInfo {
point_size: text_height,
..Default::default()
}
} else {
//clearly right now this is exactly the same as the main body of the if block
//I'm jus putting this in for now, to compile while I get the font handling
//working correctly
FontInfo {
point_size: text_height,
..Default::default() ..Default::default()
};
font.apply_height(text_height);
if style_name != "STANDARD" && !style_name.is_empty() {
font.style_name = Some(style_name.to_string());
} }
font
}, },
reference_rectangle_width, //liest aus der dxf-Datei!!! reference_rectangle_width, //liest aus der dxf-Datei!!!
h_alignment, h_alignment,
v_alignment, v_alignment,
text_from: "UserText".into(), text_from: "UserText".into(),
frame: false, frame: false,
text_width: -1, text_height,
text_width: -1.0,
relative_x_scale_factor,//宽度系数
color: self.color.unwrap_or(HexColor::BLACK), color: self.color.unwrap_or(HexColor::BLACK),
text: value, text: value,
@ -498,3 +497,29 @@ pub fn adjust_mtext_coordinates(
(adjusted_x, adjusted_y) (adjusted_x, adjusted_y)
} }
fn estimate_text_width(text: &str, line_height: f64, relative_x_scale_factor: f64) -> f64 {
let effective_height = line_height.abs();
if effective_height == 0.0 {
return 0.0;
}
let base_width = text
.lines()
.map(|line| line.graphemes(true).count() as f64)
.fold(0.0, f64::max);
let base_width = if base_width > 0.0 {
base_width * effective_height * 0.75
} else {
effective_height
};
let scale = if relative_x_scale_factor.abs() <= f64::EPSILON {
1.0
} else {
relative_x_scale_factor
};
base_width * scale
}

@ -98,6 +98,8 @@ impl Line {
}, },
}) })
} }
} }
impl From<&entities::Leader> for Leader { impl From<&entities::Leader> for Leader {

@ -13,6 +13,9 @@ use uuid::Uuid;
use tracing::{error, info, span, trace, Level}; use tracing::{error, info, span, trace, Level};
pub mod aci_colors;
use crate::qelmt::aci_colors::aci_to_rgb;
pub mod arc; pub mod arc;
pub use arc::Arc; pub use arc::Arc;
@ -31,6 +34,8 @@ pub use polygon::Polygon;
pub mod ellipse; pub mod ellipse;
pub use ellipse::Ellipse; pub use ellipse::Ellipse;
// 在 DXF 图纸中根据名称查找特定的块Block // 在 DXF 图纸中根据名称查找特定的块Block
fn find_block<'a>(drw: &'a Drawing, name: &str) -> Option<&'a Block> { fn find_block<'a>(drw: &'a Drawing, name: &str) -> Option<&'a Block> {
//this is ugly there has to be a cleaner way to filter this....but for my first attempt at pulling the //this is ugly there has to be a cleaner way to filter this....but for my first attempt at pulling the
@ -290,7 +295,7 @@ impl Definition {
Units::Inches => 50.8, Units::Inches => 50.8,
Units::Feet => 609.6, Units::Feet => 609.6,
Units::Miles | Units::USSurveyMile => 3_218_694.437_4, Units::Miles | Units::USSurveyMile => 3_218_694.437_4,
Units::Millimeters => 2.0, Units::Millimeters => 3.78,
Units::Centimeters => 20.0, Units::Centimeters => 20.0,
Units::Meters => 2_000.0, Units::Meters => 2_000.0,
Units::Kilometers => 2_000_000.0, Units::Kilometers => 2_000_000.0,
@ -606,13 +611,28 @@ impl<'a> ObjectsBuilder<'a> {
return Err("Entity is not visible"); return Err("Entity is not visible");
} }
// ORIENT 图层在部分 DXF 中仅用于放置定位参考的三角形标记,
// 这些辅助线不应该出现在导出的 QET 元件内。
if self
.ent
.common
.layer
.as_str()
.eq_ignore_ascii_case("orient")
{
return Err("Skip orientation helper layer");
}
// 获取线型名称 // 获取线型名称
let line_type_name: String = self.ent.common.line_type_name.clone(); let line_type_name: String = self.ent.common.line_type_name.clone();
// 通用样式修改函数根据line_type_name修改现有style中的line-style // 通用样式修改函数根据line_type_name修改现有style中的line-style
let update_line_style = |style: &mut String| { let update_line_style = |style: &mut String| {
println!("line_type_name:{line_type_name}");
// 只有当line_type_name需要虚线样式时才进行修改提高性能 // 只有当line_type_name需要虚线样式时才进行修改提高性能
if line_type_name.contains("DASH") || line_type_name == "BORDURE" || line_type_name == "INTERROMPUx2" { if line_type_name.contains("DASH") || line_type_name == "BORDURE" || line_type_name == "INTERROMPU" || line_type_name == "INTERROMPUx2" || line_type_name == "TRACECAD_ISO02W100" {
// 使用正则表达式替换line-style部分 // 使用正则表达式替换line-style部分
if style.contains("line-style:") { if style.contains("line-style:") {
*style = style.replace( *style = style.replace(
@ -807,7 +827,6 @@ impl<'a> ObjectsBuilder<'a> {
// 根据line_type_name更新线型样式 // 根据line_type_name更新线型样式
line.update_line_style(&update_line_style); line.update_line_style(&update_line_style);
line.scale(self.scale_fact.x, self.scale_fact.x); line.scale(self.scale_fact.x, self.scale_fact.x);
line.x1 += self.offset.x; line.x1 += self.offset.x;
@ -822,7 +841,6 @@ impl<'a> ObjectsBuilder<'a> {
if let Ok(mut ellipse) = Ellipse::try_from(polyline) { if let Ok(mut ellipse) = Ellipse::try_from(polyline) {
// 根据line_type_name更新线型样式 // 根据line_type_name更新线型样式
ellipse.update_line_style(&update_line_style); ellipse.update_line_style(&update_line_style);
ellipse.scale(self.scale_fact.x, self.scale_fact.y); ellipse.scale(self.scale_fact.x, self.scale_fact.y);
ellipse.x += self.offset.x; ellipse.x += self.offset.x;
@ -834,7 +852,6 @@ impl<'a> ObjectsBuilder<'a> {
// 根据line_type_name更新线型样式 // 根据line_type_name更新线型样式
poly.update_line_style(&update_line_style); 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 { for cord in &mut poly.coordinates {
@ -853,6 +870,21 @@ impl<'a> ObjectsBuilder<'a> {
} else { } else {
HexColor::from_u32(self.ent.common.color_24_bit as u32) HexColor::from_u32(self.ent.common.color_24_bit as u32)
}; };
// === 获取weight ===
let mut lw: Option<i16> = None;
if lwpolyline.constant_width > 0.0 {
lw = Some((lwpolyline.constant_width * 100.0) as i16);
} else if let Some(v) = lwpolyline.vertices.get(0) {
let w = if v.starting_width > 0.0 {
v.starting_width
} else {
v.ending_width
};
if w > 0.0 {
lw = Some((w * 100.0) as i16);
}
}
// ===============================
match lwpolyline.vertices.len() { match lwpolyline.vertices.len() {
0 | 1 => Err("Error empty LwPolyline"), 0 | 1 => Err("Error empty LwPolyline"),
@ -861,6 +893,10 @@ impl<'a> ObjectsBuilder<'a> {
match Arc::try_from_lwpolyline_with_color(lwpolyline, color) { match Arc::try_from_lwpolyline_with_color(lwpolyline, color) {
Ok(mut arc) => { Ok(mut arc) => {
arc.update_line_style(&update_line_style); arc.update_line_style(&update_line_style);
// 更新线条粗细
if let Some(w) = lw {
arc.update_line_weight(w);
}
arc.scale(self.scale_fact.x, self.scale_fact.y); arc.scale(self.scale_fact.x, self.scale_fact.y);
arc.x += self.offset.x; arc.x += self.offset.x;
arc.y -= self.offset.y; arc.y -= self.offset.y;
@ -876,7 +912,6 @@ impl<'a> ObjectsBuilder<'a> {
// 根据line_type_name更新线型样式 // 根据line_type_name更新线型样式
line.update_line_style(&update_line_style); line.update_line_style(&update_line_style);
line.scale(self.scale_fact.x, self.scale_fact.y); line.scale(self.scale_fact.x, self.scale_fact.y);
line.x1 += self.offset.x; line.x1 += self.offset.x;
@ -891,7 +926,6 @@ impl<'a> ObjectsBuilder<'a> {
if let Ok(mut ellipse) = Ellipse::try_from_lwpolyline_with_color(lwpolyline, color) { if let Ok(mut ellipse) = Ellipse::try_from_lwpolyline_with_color(lwpolyline, color) {
// 根据line_type_name更新线型样式 // 根据line_type_name更新线型样式
ellipse.update_line_style(&update_line_style); ellipse.update_line_style(&update_line_style);
ellipse.scale(self.scale_fact.x, self.scale_fact.y); ellipse.scale(self.scale_fact.x, self.scale_fact.y);
ellipse.x += self.offset.x; ellipse.x += self.offset.x;
@ -926,7 +960,6 @@ impl<'a> ObjectsBuilder<'a> {
// 根据line_type_name更新线型样式 // 根据line_type_name更新线型样式
poly.update_line_style(&update_line_style); 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 { for cord in &mut poly.coordinates {
@ -939,6 +972,7 @@ impl<'a> ObjectsBuilder<'a> {
} }
} }
}, },
EntityType::Solid(solid) => { EntityType::Solid(solid) => {
let mut poly: Polygon = solid.into(); let mut poly: Polygon = solid.into();
@ -1671,7 +1705,7 @@ impl From<&FontStyle> for i32 {
struct FontInfo { struct FontInfo {
family: String, family: String,
point_size: f64, point_size: f64,
pixel_size: i32, pixel_size: f64,
style_hint: FontStyleHint, style_hint: FontStyleHint,
weight: i32, weight: i32,
style: FontStyle, style: FontStyle,
@ -1689,7 +1723,7 @@ impl Default for FontInfo {
family: "宋体".into(), family: "宋体".into(),
// 字号12 // 字号12
point_size: 12.0, point_size: 12.0,
pixel_size: i32::default(), pixel_size: 0.0,
style_hint: FontStyleHint::Helvetica, style_hint: FontStyleHint::Helvetica,
weight: i32::default(), weight: i32::default(),
style: FontStyle::Normal, style: FontStyle::Normal,
@ -1708,7 +1742,7 @@ impl Display for FontInfo {
"{},{},{},{},{},{},{},{},{},0{}", "{},{},{},{},{},{},{},{},{},0{}",
self.family, self.family,
self.point_size.round(), self.point_size.round(),
self.pixel_size, self.pixel_size.round() as i32,
Into::<i32>::into(&self.style_hint), Into::<i32>::into(&self.style_hint),
self.weight, self.weight,
Into::<i32>::into(&self.style), Into::<i32>::into(&self.style),
@ -1724,6 +1758,22 @@ impl Display for FontInfo {
} }
} }
impl FontInfo {
fn apply_height(&mut self, height: f64) {
self.point_size = height;
// Qt ignores point size when pixel size is set; tiny pixel fonts lose glyph details
// so only set pixel size when the height is large enough to render reliably.
self.pixel_size = if height >= 3.0 { height } else { 0.0 };
}
fn scale(&mut self, fact: f64) {
self.point_size *= fact;
if self.pixel_size > 0.0 {
self.pixel_size *= fact;
}
}
}
#[derive(Debug)] #[derive(Debug)]
enum TextEntity<'a> { enum TextEntity<'a> {
Text(&'a dxf::entities::Text), Text(&'a dxf::entities::Text),
@ -1732,24 +1782,24 @@ enum TextEntity<'a> {
} }
// AutoCAD Color Index (ACI) 到 RGB 转换函数 // AutoCAD Color Index (ACI) 到 RGB 转换函数
fn aci_to_rgb(aci: u8) -> (u8, u8, u8) { // fn aci_to_rgb(aci: u8) -> (u8, u8, u8) {
match aci { // match aci {
1 => (255, 0, 0), // 红色 // 1 => (255, 0, 0), // 红色
2 => (255, 255, 0), // 黄色 // 2 => (255, 255, 0), // 黄色
3 => (0, 255, 0), // 绿色 // 3 => (0, 255, 0), // 绿色
4 => (0, 255, 255), // 青色 // 4 => (0, 255, 255), // 青色
5 => (0, 0, 255), // 蓝色 // 5 => (0, 0, 255), // 蓝色
6 => (255, 0, 255), // 洋红色 // 6 => (255, 0, 255), // 洋红色
// 7 => (255, 255, 255), // 白色 // // 7 => (255, 255, 255), // 白色
8 => (128, 128, 128), // 深灰色 // 8 => (128, 128, 128), // 深灰色
9 => (192, 192, 192), // 浅灰色 // 9 => (192, 192, 192), // 浅灰色
94 => (0, 129, 0), // 深绿色 // 94 => (0, 129, 0), // 深绿色
15 => (129, 86, 86), // 深棕色 // 15 => (129, 86, 86), // 深棕色
// 更多标准颜色可以根据需要添加 // // 更多标准颜色可以根据需要添加
_ => (0, 0, 0), // 默认黑色 // _ => (0, 0, 0), // 默认黑色
} // }
} // }
// ACI 转换为 HexColor // ACI 转换为 HexColor
fn aci_to_hex_color(aci: u8) -> HexColor { fn aci_to_hex_color(aci: u8) -> HexColor {
@ -1880,3 +1930,62 @@ fn decode_unicode_escapes(text: &str) -> String {
result result
} }
/// 移除常见的 MTEXT 控制序列(如 `\fSimSun|b0|i0;`)并做基础替换
pub(crate) fn strip_mtext_control_sequences(input: &str) -> String {
let mut result = String::with_capacity(input.len());
let mut chars = input.chars().peekable();
while let Some(ch) = chars.next() {
if ch == '\\' {
let mut handled = false;
if let Some(&cmd) = chars.peek() {
match cmd {
'P' => {
chars.next(); // consume command
result.push('\n');
handled = true;
}
'f' | 'F' | 'H' | 'h' | 'C' | 'c' | 'W' | 'w' | 'A' | 'a' | 'p' | 'q' => {
chars.next(); // consume command
while let Some(next_ch) = chars.next() {
if next_ch == ';' {
break;
}
}
handled = true;
}
'L' | 'l' | 'O' | 'o' | 'K' | 'k' => {
chars.next(); // toggle style command, no payload
handled = true;
}
'~' => {
chars.next();
result.push(' ');
handled = true;
}
'\\' => {
chars.next();
result.push('\\');
handled = true;
}
'{' | '}' => {
chars.next();
result.push(cmd);
handled = true;
}
_ => {}
}
}
if handled {
continue;
}
}
result.push(ch);
}
result
}

@ -15,6 +15,12 @@ pub struct Text {
impl From<(&entities::Text, HexColor)> for Text { impl From<(&entities::Text, HexColor)> for Text {
fn from((txt, color): (&entities::Text, HexColor)) -> Self { fn from((txt, color): (&entities::Text, HexColor)) -> Self {
let mut font = FontInfo::default();
font.apply_height(txt.text_height);
if !txt.text_style_name.is_empty() && txt.text_style_name != "STANDARD" {
font.style_name = Some(txt.text_style_name.clone());
}
Text { Text {
x: txt.location.x, x: txt.location.x,
y: -txt.location.y, y: -txt.location.y,
@ -24,12 +30,7 @@ impl From<(&entities::Text, HexColor)> for Text {
0.0 0.0
}, },
color, color,
font: if &txt.text_style_name == "STANDARD" { font,
FontInfo::default()
} else {
//txt.text_style_name.clone()
FontInfo::default()
},
value: txt.value.clone(), value: txt.value.clone(),
} }
} }
@ -52,8 +53,7 @@ impl ScaleEntity for Text {
fn scale(&mut self, fact_x: f64, fact_y: f64) { fn scale(&mut self, fact_x: f64, fact_y: f64) {
self.x *= fact_x; self.x *= fact_x;
self.y *= fact_y; self.y *= fact_y;
//self.font.pixel_size *= fact; self.font.scale(fact_y);
self.font.point_size *= fact_x;
} }
fn left_bound(&self) -> f64 { fn left_bound(&self) -> f64 {

@ -0,0 +1,70 @@
# generate_aci_colors.py
# 生成 AutoCAD ACI 颜色表 (0-255),输出 Rust 源码文件 aci_colors.rs
import math
def hsv_to_rgb(h, s, v):
c = v * s
x = c * (1 - abs((h / 60) % 2 - 1))
m = v - c
if 0 <= h < 60:
r, g, b = c, x, 0
elif 60 <= h < 120:
r, g, b = x, c, 0
elif 120 <= h < 180:
r, g, b = 0, c, x
elif 180 <= h < 240:
r, g, b = 0, x, c
elif 240 <= h < 300:
r, g, b = x, 0, c
else:
r, g, b = c, 0, x
return (
int(round((r + m) * 255)),
int(round((g + m) * 255)),
int(round((b + m) * 255)),
)
# 固定颜色09 + 250255
fixed_colors = {
0: (0, 0, 0), # BYBLOCK
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), # 浅灰
250: (255, 255, 255),
251: (192, 192, 192),
252: (128, 128, 128),
253: (64, 64, 64),
254: (32, 32, 32),
255: (0, 0, 0),
}
colors = []
for i in range(256):
if i in fixed_colors:
colors.append(fixed_colors[i])
elif 10 <= i <= 249:
idx = i - 10
hue = (idx // 10) * 15.0 # 每 10 个色 → 色相 +15°
val = 1.0 - (idx % 10) * 0.1 # 亮度从 1.0 → 0.1
colors.append(hsv_to_rgb(hue, 1.0, val))
else:
colors.append((0, 0, 0)) # 兜底(不会用到)
# 写 Rust 文件
with open("aci_colors.rs", "w", encoding="utf-8") as f:
f.write("// Auto-generated ACI color table (0255)\n")
f.write("pub const ACI_COLORS: [(u8,u8,u8); 256] = [\n")
for c in colors:
f.write(f" ({c[0]},{c[1]},{c[2]}),\n")
f.write("];\n\n")
f.write("pub fn aci_to_rgb(aci: u8) -> (u8,u8,u8) {\n")
f.write(" ACI_COLORS[aci as usize]\n")
f.write("}\n")
Loading…
Cancel
Save