first commit

This commit is contained in:
Hakan Seven committed 2026-03-22 14:56:27 +03:00
1 parent d52c6440ff
commit d2fdac7f1e
274 files changed
+89330

No files matched your search

+192
View File
@@ -0,0 +1,192 @@
use acadrust::CadDocument;
use crate::scene::cxf;
pub struct ResolvedTextStyle {
pub font_name: String,
pub width_factor: f32,
pub oblique_angle: f32,
}
pub fn resolve_text_style(style_name: &str, document: &CadDocument) -> ResolvedTextStyle {
let style = document.text_styles.iter().find(|entry| {
entry.name.eq_ignore_ascii_case(style_name)
|| (style_name.trim().is_empty() && entry.name.eq_ignore_ascii_case("Standard"))
});
let font_name = if let Some(style) = style {
if !style.font_file.trim().is_empty() {
let file = style.font_file.trim();
let basename = file.rsplit(['/', '\\']).next().unwrap_or(file);
let stem = basename.split('.').next().unwrap_or(basename).trim();
if !stem.is_empty() {
stem.to_string()
} else if !style.true_type_font.trim().is_empty() {
style.true_type_font.trim().to_string()
} else if !style.name.trim().is_empty() {
style.name.trim().to_string()
} else {
"Standard".to_string()
}
} else if !style.true_type_font.trim().is_empty() {
style.true_type_font.trim().to_string()
} else if !style.name.trim().is_empty() {
style.name.trim().to_string()
} else {
"Standard".to_string()
}
} else if style_name.trim().is_empty() {
"Standard".to_string()
} else {
style_name.trim().to_string()
};
ResolvedTextStyle {
font_name,
width_factor: style.map(|s| s.width_factor as f32).unwrap_or(1.0),
oblique_angle: style.map(|s| s.oblique_angle as f32).unwrap_or(0.0),
}
}
pub fn text_local_bounds(
font_name: &str,
text: &str,
height: f32,
width_factor: f32,
oblique_angle: f32,
) -> Option<([f32; 2], [f32; 2])> {
if text.is_empty() || height <= 0.0 {
return None;
}
let font = cxf::get_font(font_name);
let scale = height / 9.0;
let wf = width_factor.clamp(0.01, 100.0);
let ob = oblique_angle.tan();
let mut cursor_x = 0.0_f32;
let mut min_x = f32::INFINITY;
let mut max_x = f32::NEG_INFINITY;
let mut min_y = f32::INFINITY;
let mut max_y = f32::NEG_INFINITY;
for ch in text.chars() {
if ch == ' ' {
cursor_x += font.word_spacing;
continue;
}
match font.glyph(ch) {
Some(glyph) => {
for stroke in &glyph.strokes {
for &[gx, gy] in stroke {
let sx = (cursor_x + gx) * scale * wf + gy * scale * ob;
let sy = gy * scale;
min_x = min_x.min(sx);
max_x = max_x.max(sx);
min_y = min_y.min(sy);
max_y = max_y.max(sy);
}
}
cursor_x += glyph.advance + font.letter_spacing;
}
None => {
cursor_x += 6.0 + font.letter_spacing;
}
}
}
if min_x.is_finite() && min_y.is_finite() && max_x.is_finite() && max_y.is_finite() {
Some(([min_x, min_y], [max_x, max_y]))
} else {
None
}
}
pub fn strip_mtext_codes(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut chars = s.chars().peekable();
while let Some(ch) = chars.next() {
match ch {
'\\' => match chars.peek().copied() {
Some('P') | Some('n') | Some('N') => {
chars.next();
out.push('\n');
}
Some('~') => {
chars.next();
out.push(' ');
}
Some(c) if "pHWQTACcLOKlfFUu".contains(c) => {
chars.next();
for c in chars.by_ref() {
if c == ';' {
break;
}
}
}
Some('\\') => {
chars.next();
out.push('\\');
}
Some('{') | Some('}') => {
out.push(chars.next().unwrap());
}
_ => {}
},
'{' | '}' => {}
'\r' => {}
other => out.push(other),
}
}
out
}
pub fn split_mtext_lines(s: &str) -> Vec<String> {
s.split('\n')
.map(|l| l.trim().to_string())
.filter(|l| !l.is_empty())
.collect()
}
pub fn word_wrap(text: &str, max_w: f32, scale: f32, font: &'static cxf::CxfFile) -> Vec<String> {
if max_w <= 0.0 || text.is_empty() {
return vec![text.to_string()];
}
let glyph_w = |c: char| -> f32 {
if c == ' ' {
return font.word_spacing * scale;
}
font.glyph(c)
.map(|g| (g.advance + font.letter_spacing) * scale)
.unwrap_or(scale * 6.0)
};
let mut lines = Vec::new();
let mut current = String::new();
let mut current_w = 0.0_f32;
for word in text.split(' ') {
let word_w: f32 = word.chars().map(glyph_w).sum();
let space_w = if current.is_empty() {
0.0
} else {
glyph_w(' ')
};
if !current.is_empty() && current_w + space_w + word_w > max_w {
lines.push(std::mem::take(&mut current));
current_w = 0.0;
}
if !current.is_empty() {
current.push(' ');
current_w += space_w;
}
current.push_str(word);
current_w += word_w;
}
if !current.is_empty() {
lines.push(current);
}
lines
}