forked from 1b-agent/opencadstudio-upstream
feat(shx): real SHX glyphs for text fonts and linetype shapes
The SHX reader now serves all three consumers instead of just SHAPE
entities:
- Complex-linetype shape elements stopped being skipped: a document
linetype's Shape{number} resolves its style's shape file (shared path
fallbacks) and draws the real glyph; `.lin` catalog references keep
the file token and look the shape up by name. The converted-LFF
substitute set remains the fallback for anything unresolved.
- Face::Shx renders resolvable on-disk .SHX text FONTS with their real
stroke glyphs: character code → shape lookup, cap height normalised
to the 9-unit space every stroke-font consumer expects, advance from
the interpreter's final pen position, line spacing from the shape #0
above/below header, TTF fallback per missing glyph.
resolve_text_style resolves a style's .shx next to the drawing and
passes the absolute path through; unresolvable names keep their LFF
substitutes. Shapes-only files (no #0 header) are refused as fonts.
Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
1de4344280
commit
bcd1fc15ea
5 files changed
+241
-23
No files matched your search
+45
-6
@@ -22,11 +22,15 @@ pub enum LtSegment {
|
||||
Space(f32),
|
||||
/// Draw a dot (zero-length element, rendered as a tiny mark).
|
||||
Dot,
|
||||
/// Draw a shape at the current pen position. Embedded SHAPE elements are
|
||||
/// no longer rendered (the LFF font set ships no shape file).
|
||||
/// Draw a shape at the current pen position.
|
||||
Shape {
|
||||
/// Shape name (retained for round-tripping; not drawn).
|
||||
/// Shape name (`.lin` catalog reference; empty for document shapes).
|
||||
name: String,
|
||||
/// Resolved .SHX shape-file path ("" when none resolved — the LFF
|
||||
/// substitute set is the fallback for catalog names).
|
||||
shx_file: String,
|
||||
/// Shape number inside the file (0 = look up by name).
|
||||
number: u16,
|
||||
/// X offset along the linetype direction (can be negative).
|
||||
x: f32,
|
||||
/// Y offset perpendicular to the linetype direction.
|
||||
@@ -130,9 +134,38 @@ pub fn document_lt_segments(document: &CadDocument, name: &str) -> Option<Comple
|
||||
rot_deg: c.rotation as f32,
|
||||
});
|
||||
}
|
||||
// Embedded SHAPE glyphs need a .shp set we don't ship; skip the
|
||||
// draw (matches the bundled-catalog behaviour).
|
||||
LineTypeComplexContent::Shape { .. } => {}
|
||||
LineTypeComplexContent::Shape { shape_number } => {
|
||||
// Resolve the style's shape file with the shared path
|
||||
// fallbacks (as stored / next to the drawing) so the real
|
||||
// SHX glyph draws; unresolved files simply skip.
|
||||
let font = document
|
||||
.text_styles
|
||||
.iter()
|
||||
.find(|s| s.handle == c.style_handle)
|
||||
.map(|s| s.font_file.trim().to_string())
|
||||
.unwrap_or_default();
|
||||
if font.is_empty() || *shape_number <= 0 {
|
||||
continue;
|
||||
}
|
||||
let base = document
|
||||
.source_path
|
||||
.as_deref()
|
||||
.map(std::path::Path::new)
|
||||
.and_then(|p| p.parent());
|
||||
let Some(resolved) = crate::io::resolve_image_file(&font, base) else {
|
||||
continue;
|
||||
};
|
||||
let scale = c.scale as f32;
|
||||
segments.push(LtSegment::Shape {
|
||||
name: String::new(),
|
||||
shx_file: resolved,
|
||||
number: *shape_number as u16,
|
||||
x: c.offset[0] as f32,
|
||||
y: c.offset[1] as f32,
|
||||
scale: if scale.abs() < 1e-6 { 1.0 } else { scale },
|
||||
rot_deg: c.rotation as f32,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,6 +480,7 @@ fn parse_shape_element(inner: &str) -> Option<LtSegment> {
|
||||
let mut y = 0.0f32;
|
||||
let mut scale = 1.0f32;
|
||||
let mut rot_deg = 0.0f32;
|
||||
let mut shx_file = String::new();
|
||||
|
||||
for part in parts {
|
||||
let p = part.trim();
|
||||
@@ -463,11 +497,16 @@ fn parse_shape_element(inner: &str) -> Option<LtSegment> {
|
||||
.or_else(|| p.strip_prefix("U="))
|
||||
{
|
||||
rot_deg = v.parse().unwrap_or(0.0);
|
||||
} else if p.to_ascii_lowercase().ends_with(".shx") {
|
||||
// `[NAME,ltypeshp.shx,…]` — the shape file reference.
|
||||
shx_file = p.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
Some(LtSegment::Shape {
|
||||
name,
|
||||
shx_file,
|
||||
number: 0,
|
||||
x,
|
||||
y,
|
||||
scale,
|
||||
|
||||
Reference in new issue
Block a user