fix(scene): render baked block geometry for Dimension and Table

AutoCAD bakes a per-instance block with the final, displayed geometry
into Dimension and Table entities (typically *D### / *T###, but custom
names also occur — sample-file-H uses DIMBLOCK*-4NP). The block's text
already encodes DIMTXT * DIMSCALE (or the table's scale factor), so
synthesising the entity from the dim/table style on top of that
double-applies the scale.

When the referenced block exists with content, render it directly:
- Dimension: dim.base.block_name -> block_record
- Table: block_record_handle -> block_record

The synthesis fallback stays in place for files where the block is
missing or empty.

Fixes sample-file-H.dwg dimensions rendering at 60000 instead of 200
(DIMTXT=199.196 * DIMSCALE=304.8).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
HakanandClaude Opus 4.7 committed 2026-05-21 12:54:49 +03:00
1 parent 62876b1081
commit eab72062f9
2 files changed
+95

No files matched your search

+42
View File
@@ -4814,6 +4814,48 @@ fn tessellate_entity(
return wires;
}
// ── Table baked-block fast path ─────────────────────────────────────────
//
// AutoCAD bakes a Table's final rendered geometry (cell text, gridlines,
// fill) into a per-instance block (usually `*T###`) referenced through
// `table.block_record_handle`. The block's text uses the *displayed*
// height; synthesising cells from `self.rows + TableStyle` instead would
// re-apply the table's scale factor on top of already-baked geometry.
// When the block exists we render it directly. Same pattern as
// Dimension's `block_name`.
if let EntityType::Table(tab) = e {
if let Some(br_h) = tab.block_record_handle {
if let Some(br) = document
.block_records
.iter()
.find(|br| br.handle == br_h)
{
if !br.entity_handles.is_empty() {
let mut wires: Vec<WireModel> =
Vec::with_capacity(br.entity_handles.len());
for &eh in &br.entity_handles {
let Some(sub) = document.get_entity(eh) else { continue };
let sub_wires = tessellate_entity(
document, selected, active_viewport, world_offset, bg_color,
anno_scale, sub, block_cache, view_aabb, world_per_pixel,
);
for mut w in sub_wires {
w.name = h.value().to_string();
wires.push(w);
}
}
if !wires.is_empty() {
let aabb = entity_aabb(e, world_offset);
for w in &mut wires {
w.aabb = aabb;
}
return wires;
}
}
}
}
}
if let EntityType::Insert(ins) = e {
// Resolve the INSERT's own style so ByBlock sub-entities can inherit it.
let (ins_color, ins_pat_len, ins_pat, ins_lw_px, _) = render::render_style_for(document, e);
+53
View File
@@ -464,6 +464,59 @@ pub fn tessellate_dimension(
anno_scale: f32,
) -> Vec<WireModel> {
let name = handle.value().to_string();
// ── Anonymous-block fast path ───────────────────────────────────────────
//
// AutoCAD bakes each dimension's final geometry (extension lines, dim
// line, arrows, text MText) into a per-instance block — usually named
// `*D<n>`, but some authoring tools use a custom name like
// `DIMBLOCK###-4NP`. When that block exists we render its contents
// directly: the text height inside the block is the FINAL displayed
// height (DIMTXT × DIMSCALE already applied at creation), so
// synthesising it from the dim style would double-apply DIMSCALE.
let dim_block_name = &dim.base().block_name;
if !dim_block_name.trim().is_empty() {
if let Some(br) = document
.block_records
.iter()
.find(|br| br.name.eq_ignore_ascii_case(dim_block_name))
{
if !br.entity_handles.is_empty() {
let mut wires: Vec<WireModel> =
Vec::with_capacity(br.entity_handles.len());
for &eh in &br.entity_handles {
let Some(sub) = document.get_entity(eh) else { continue };
// Inherit dim's color + line weight when the sub-entity is
// ByBlock; ByLayer stays on its own layer.
let sub_color = if selected {
WireModel::SELECTED
} else {
entity_color
};
let mut wire = tessellate(
document,
handle,
sub,
selected,
sub_color,
0.0,
[0.0; 8],
line_weight_px,
world_offset,
// Sub-entities are already baked at the final WCS
// size; don't re-apply anno_scale.
1.0,
);
wire.name = name.clone();
wires.push(wire);
}
if !wires.is_empty() {
return wires;
}
}
}
}
let style_name = &dim.base().style_name;
let style = document.dim_styles.iter().find(|s| {
s.name.eq_ignore_ascii_case(style_name)