forked from 1b-agent/opencadstudio-upstream
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:
1 parent
62876b1081
commit
eab72062f9
2 files changed
+95
No files matched your search
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user