feat(shape): render SHAPE entities from their compiled SHX shape file

SHAPE entities only drew a diamond placeholder — .SHX files were never
parsed. A new reader (scene/text/shx.rs) decodes the classic
`AutoCAD-86 shapes 1.0/1.1` container and interprets the full shape
bytecode — pen up/down, scale divide/multiply, position push/pop,
subshapes, signed XY runs, octant/fractional/bulge arcs, the 16
direction vectors and the vertical-only skip — into unit-space
polylines, cached per file and per shape number.

The entity resolves its STYLE by handle (name fallback), the style's
shape file with the shared path fallbacks (as stored → relative to the
drawing → basename next to it; traded files carry foreign absolute
paths), then places the glyph with size × relative X scale, oblique
shear and rotation through the OCS mapping. load_file now records
doc.source_path so render-time resolution knows the drawing's folder.
A missing or unreadable shape file keeps the diamond placeholder.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Fable 5 committed 2026-07-23 03:53:41 +03:00
1 parent f4f8c0687c
commit 1de4344280
4 files changed
+517 -1

No files matched your search

+3 -1
View File
@@ -190,6 +190,7 @@ pub fn load_file(path: &Path) -> Result<CadDocument, String> {
fix_viewport_status_flags(&mut doc);
fix_current_style_names(&mut doc);
resolve_raster_image_paths(&mut doc, path.parent());
doc.source_path = Some(path.to_string_lossy().into_owned());
Ok(doc)
}
"dxf" => {
@@ -201,6 +202,7 @@ pub fn load_file(path: &Path) -> Result<CadDocument, String> {
fix_viewport_status_flags(&mut doc);
fix_current_style_names(&mut doc);
resolve_raster_image_paths(&mut doc, path.parent());
doc.source_path = Some(path.to_string_lossy().into_owned());
Ok(doc)
}
_ => Err(format!("Unsupported file format: .{ext}")),
@@ -265,7 +267,7 @@ fn resolve_raster_image_paths(doc: &mut CadDocument, base_dir: Option<&Path>) {
/// Resolve a (possibly foreign / absolute) image path to an existing file:
/// as stored, then relative to the drawing folder, then just the file name
/// next to the drawing.
fn resolve_image_file(raw: &str, base_dir: Option<&Path>) -> Option<String> {
pub(crate) fn resolve_image_file(raw: &str, base_dir: Option<&Path>) -> Option<String> {
if Path::new(raw).is_file() {
return Some(raw.to_string());
}