坐标计算改为以对齐点为基准计算,解决多行文本中文位置偏移问题

master
liaoxianglian 8 months ago
parent e0fb0160e5
commit 89acf05ad5

@ -5,6 +5,7 @@ use simple_xml_builder::XMLElement;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use uuid::Uuid; use uuid::Uuid;
use dxf::enums::AttachmentPoint; use dxf::enums::AttachmentPoint;
use dxf::enums::{HorizontalTextJustification, VerticalTextJustification};
/*use parley::{ /*use parley::{
Alignment, FontContext, FontWeight, InlineBox, Layout, LayoutContext, PositionedLayoutItem, Alignment, FontContext, FontWeight, InlineBox, Layout, LayoutContext, PositionedLayoutItem,
@ -60,8 +61,27 @@ impl From<&DynamicText> for XMLElement {
// o.k. ... as long as we do not know the real width: // o.k. ... as long as we do not know the real width:
// "guess" the width by number of characters and font-size: // "guess" the width by number of characters and font-size:
// //
let graphene_count = txt.text.graphemes(true).count(); // let graphene_count = txt.text.graphemes(true).count();
let txt_width = if txt.reference_rectangle_width > 2.0 { let mut cjk_char_count = 0;
let mut graphene_count = 0;
for grapheme in txt.text.graphemes(true) {
graphene_count += 1;
if grapheme.chars().any(|c| {
// 检查是否为中文字符(包括中日韩统一表意文字)
(c >= '\u{4E00}' && c <= '\u{9FFF}') || // CJK统一表意文字
(c >= '\u{3400}' && c <= '\u{4DBF}') || // CJK扩展A
(c >= '\u{20000}' && c <= '\u{2A6DF}') || // CJK扩展B
(c >= '\u{2A700}' && c <= '\u{2B73F}') || // CJK扩展C
(c >= '\u{2B740}' && c <= '\u{2B81F}') || // CJK扩展D
(c >= '\u{2B820}' && c <= '\u{2CEAF}') || // CJK扩展E
(c >= '\u{F900}' && c <= '\u{FAFF}') || // CJK兼容表意文字
(c >= '\u{2F800}' && c <= '\u{2FA1F}') // CJK兼容表意文字补充
}) {
cjk_char_count += 1;
}
}
let txt_width = if txt.reference_rectangle_width > 2.0 {
txt.reference_rectangle_width txt.reference_rectangle_width
} else { } else {
(graphene_count as f64) * pt_size * 0.75 (graphene_count as f64) * pt_size * 0.75
@ -93,22 +113,34 @@ impl From<&DynamicText> for XMLElement {
println!("初始位置: x={}, y={}", txt.x, txt.y); println!("初始位置: x={}, y={}", txt.x, txt.y);
println!("旋转角度: {}", txt.rotation); println!("旋转角度: {}", txt.rotation);
// 计算基础位置(不考虑旋转) // 计算基础位置(不考虑旋转)
// 如果是mtext是没有左下角的位置的只有对齐点的位置 // txt.x和txt.y现在是对齐点坐标需要根据对齐方式计算出左上角位置
// 所以需要根据对齐点和文本宽度来计算最终的位置 // 首先根据水平对齐方式计算左边界的x坐标
let left_x = match txt.h_alignment {
let base_x = txt.x + 0.5 - (pt_size / 8.0) - 4.05; HAlignment::Left => txt.x,
let base_y = { HAlignment::Center => txt.x - txt_width / 2.0,
let base_y_pos = txt.y + 0.5 - (7.0 / 5.0 * pt_size + 26.0 / 5.0) + pt_size; HAlignment::Right => txt.x - txt_width,
match txt.v_alignment { };
VAlignment::Top => base_y_pos + pt_size / 2.0,
VAlignment::Center => base_y_pos - pt_size / 2.0, // 根据垂直对齐方式计算顶部的y坐标
VAlignment::Bottom => base_y_pos - pt_size + pt_size / 2.0, let top_y = txt.y;
// 根据是否包含中文字符调整字体大小相关的偏移量
let cjk_offset:f64 = (cjk_char_count as f64) * pt_size * 0.75;
// 左对齐是不需要偏移的,居中对齐需要偏移,右对齐要偏移
let base_x = left_x + 0.5 - (pt_size / 8.0) - 4.05
- match txt.h_alignment {
HAlignment::Left => 0.0,
HAlignment::Center => cjk_offset / 2.0,
HAlignment::Right => cjk_offset,
};
} let base_y = top_y + 0.5 - (7.0 / 5.0 * pt_size + 26.0 / 5.0)
+ match txt.v_alignment {
VAlignment::Top => pt_size / 2.0,
VAlignment::Center => pt_size,
VAlignment::Bottom => pt_size / 2.0,
}; };
// 如果有旋转角度,应用旋转变换 // 如果有旋转角度,应用旋转变换
@ -117,7 +149,7 @@ impl From<&DynamicText> for XMLElement {
let cos_r = rotation_rad.cos(); let cos_r = rotation_rad.cos();
let sin_r = rotation_rad.sin(); let sin_r = rotation_rad.sin();
// 以文本原点为中心进行旋转变换 // 以对齐点为中心进行旋转变换
let dx = base_x - txt.x; let dx = base_x - txt.x;
let dy = base_y - txt.y; let dy = base_y - txt.y;
@ -246,31 +278,30 @@ impl<'a> DTextBuilder<'a> {
v_alignment, v_alignment,
reference_rectangle_width, reference_rectangle_width,
) = match self.text { ) = match self.text {
TextEntity::Text(txt) => ( TextEntity::Text(txt) => {
txt.location.x, let (x, y) = if txt.horizontal_text_justification == HorizontalTextJustification::Left && (txt.vertical_text_justification == VerticalTextJustification::Bottom || txt.vertical_text_justification == VerticalTextJustification::Baseline) {
-txt.location.y, (txt.location.x, -txt.location.y)
txt.location.z, } else {
txt.rotation, (txt.second_alignment_point.x, -txt.second_alignment_point.y)
&txt.text_style_name, };
txt.text_height, (
txt.value.clone(), x,
HAlignment::from(txt.horizontal_text_justification), y,
VAlignment::from(txt.vertical_text_justification), txt.location.z,
0.0, // as Placeholder: no "reference_rectangle_width" with Text!!! txt.rotation,
), &txt.text_style_name,
txt.text_height,
txt.value.clone(),
HAlignment::from(txt.horizontal_text_justification),
VAlignment::from(txt.vertical_text_justification),
0.0, // as Placeholder: no "reference_rectangle_width" with Text!!!
)},
TextEntity::MText(mtxt) => { TextEntity::MText(mtxt) => {
let (adjusted_x, adjusted_y) = adjust_mtext_coordinates(
mtxt.insertion_point.x,
mtxt.insertion_point.y,
mtxt.attachment_point,
mtxt.initial_text_height,
mtxt.reference_rectangle_width
);
// 计算实际的旋转角度优先使用x_axis_direction向量 // 计算实际的旋转角度优先使用x_axis_direction向量
let actual_rotation = calculate_mtext_rotation(mtxt.rotation_angle, &mtxt.x_axis_direction); let actual_rotation = calculate_mtext_rotation(mtxt.rotation_angle, &mtxt.x_axis_direction);
( (
adjusted_x, mtxt.insertion_point.x,
-adjusted_y, -mtxt.insertion_point.y,
mtxt.insertion_point.z, mtxt.insertion_point.z,
actual_rotation, actual_rotation,
&mtxt.text_style_name, &mtxt.text_style_name,
@ -303,18 +334,28 @@ impl<'a> DTextBuilder<'a> {
VAlignment::from(mtxt.attachment_point), VAlignment::from(mtxt.attachment_point),
mtxt.reference_rectangle_width, mtxt.reference_rectangle_width,
)}, )},
TextEntity::Attrib(attrib) => ( TextEntity::Attrib(attrib) => {
attrib.location.x, // 根据DXF文本对齐规则当水平对齐不是Left时使用second_alignment_point
-attrib.location.y, let (x, y) = if attrib.horizontal_text_justification == HorizontalTextJustification::Left && (attrib.vertical_text_justification == VerticalTextJustification::Bottom || attrib.vertical_text_justification == VerticalTextJustification::Baseline) {
attrib.location.z, println!("{}",111);
attrib.rotation, (attrib.location.x, -attrib.location.y)
&attrib.text_style_name, } else {
attrib.text_height, println!("{}",222);
attrib.text_tag.clone(), (attrib.second_alignment_point.x, -attrib.second_alignment_point.y)
HAlignment::from(attrib.horizontal_text_justification), };
VAlignment::from(attrib.vertical_text_justification), (
0.0, // as Placeholder: not need to check if Attrib has something similar x,
), y,
attrib.location.z,
attrib.rotation,
&attrib.text_style_name,
attrib.text_height,
attrib.text_tag.clone(),
HAlignment::from(attrib.horizontal_text_justification),
VAlignment::from(attrib.vertical_text_justification),
0.0, // as Placeholder: not need to check if Attrib has something similar
)
},
}; };
// Create a FontContext (font database) and LayoutContext (scratch space). // Create a FontContext (font database) and LayoutContext (scratch space).

@ -655,6 +655,9 @@ impl<'a> ObjectsBuilder<'a> {
line.x2 += self.offset.x; line.x2 += self.offset.x;
line.y2 -= self.offset.y; line.y2 -= self.offset.y;
println!("Line: x1: {}, y1: {}, x2: {}, y2: {}", line.x1, line.y1, line.x2, line.y2);
Ok(Objects::Line(line)) Ok(Objects::Line(line))
} }
EntityType::Arc(arc) => { EntityType::Arc(arc) => {
@ -1693,7 +1696,7 @@ fn aci_to_rgb(aci: u8) -> (u8, u8, u8) {
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), // 深绿色

Loading…
Cancel
Save