forked from 1b-agent/opencadstudio-upstream
feat(xref+block): bind xref tables, fade rendered geometry, per-defn precision offset
Xref work:
- merge_xref_into_block now copies the xref's layer / linetype / nested
block_record tables into the host under `{xref}|{name}` prefixes and
remaps entity references, so ByLayer/ByBlock resolution lands on the
right entry instead of falling back to WHITE + 1 px.
- expand_insert (and the explode fallback) detect xref BlockRecords by
flag and apply `fade_toward_bg(color, bg, 0.5)` to every emitted final
color (selection bypasses the fade). ExpandCtx propagates `is_xref` +
`bg_color` through nested expansions.
Block precision groundwork:
- BlockDefn gains `local_offset: [f64; 3]` set in build_defn from the
AABB centre of the defn's direct entities. tessellate_sub_local now
passes that offset to tessellate(), so LocalWire.points / fill_tris /
aabb_local / text_obb_local are stored in offset-frame f32 and don't
lose precision for distant content.
- emit_wire / emit_greeked_text / transform_tangent take the defn offset
and re-add it in f64 before composing with accum_xform. defn_aabb_
recursive transforms nested children from their offset frame into the
parent's. transform_offset_aabb_xy replaces transform_aabb_xy.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
ea87b3db76
commit
2f0220b1a0
3 files changed
+395
-69
No files matched your search
+38
-23
@@ -79,24 +79,6 @@ pub struct DerivedCaches {
|
||||
/// Build hatch / image / mesh caches from a document without needing `&mut Scene`.
|
||||
/// Intended to run on a background thread during file load.
|
||||
pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||
// world_offset
|
||||
let h = &doc.header;
|
||||
let (min, max) = (h.model_space_extents_min, h.model_space_extents_max);
|
||||
let valid = min.x < max.x && min.y < max.y;
|
||||
let (world_offset, local_extent_max) = if valid {
|
||||
let offset = [
|
||||
(min.x + max.x) * 0.5,
|
||||
(min.y + max.y) * 0.5,
|
||||
(min.z + max.z) * 0.5,
|
||||
];
|
||||
let hw = ((max.x - min.x) * 0.5) as f32;
|
||||
let hh = ((max.y - min.y) * 0.5) as f32;
|
||||
let hz = ((max.z - min.z) * 0.5).max(1.0) as f32;
|
||||
(offset, hw.max(hh).max(hz) * 10.0)
|
||||
} else {
|
||||
([0.0; 3], 1e9_f32)
|
||||
};
|
||||
|
||||
// model-space block handle (same logic as Scene::model_space_block_handle)
|
||||
let model_block = doc
|
||||
.objects
|
||||
@@ -119,6 +101,25 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||
.unwrap_or(Handle::NULL)
|
||||
});
|
||||
|
||||
// world_offset (from DXF header extents — fast and works when the
|
||||
// writer correctly folded Insert→Block expansion into $EXTMIN/$EXTMAX).
|
||||
let h = &doc.header;
|
||||
let (min, max) = (h.model_space_extents_min, h.model_space_extents_max);
|
||||
let valid = min.x < max.x && min.y < max.y;
|
||||
let (world_offset, local_extent_max) = if valid {
|
||||
let offset = [
|
||||
(min.x + max.x) * 0.5,
|
||||
(min.y + max.y) * 0.5,
|
||||
(min.z + max.z) * 0.5,
|
||||
];
|
||||
let hw = ((max.x - min.x) * 0.5) as f32;
|
||||
let hh = ((max.y - min.y) * 0.5) as f32;
|
||||
let hz = ((max.z - min.z) * 0.5).max(1.0) as f32;
|
||||
(offset, hw.max(hh).max(hz) * 10.0)
|
||||
} else {
|
||||
([0.0; 3], 1e9_f32)
|
||||
};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
// Single pass over entities — collect only handles per kind. No clones.
|
||||
@@ -4030,6 +4031,13 @@ fn tessellate_entity(
|
||||
};
|
||||
|
||||
if let Some(cache) = block_cache {
|
||||
// Xrefs render with the same hue but faded toward `bg_color` so
|
||||
// the user can recognise external-reference geometry at a glance.
|
||||
let is_xref = document
|
||||
.block_records
|
||||
.get(&ins.block_name)
|
||||
.map(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.unwrap_or(false);
|
||||
if let Some(mut wires) = block_cache::expand_insert(
|
||||
cache,
|
||||
ins,
|
||||
@@ -4043,6 +4051,8 @@ fn tessellate_entity(
|
||||
pslt_factor,
|
||||
view_aabb,
|
||||
world_per_pixel,
|
||||
is_xref,
|
||||
bg_color,
|
||||
) {
|
||||
wires.push(marker);
|
||||
return wires;
|
||||
@@ -4053,11 +4063,11 @@ fn tessellate_entity(
|
||||
// but keep the safety bail-out for pathologically large blocks so
|
||||
// the UI doesn't hang on broken or unbounded sub-entity counts.
|
||||
const INSERT_SUB_LIMIT: usize = 5_000;
|
||||
let sub_count = document
|
||||
.block_records
|
||||
.get(&ins.block_name)
|
||||
.map(|br| br.entity_handles.len())
|
||||
.unwrap_or(0);
|
||||
let br = document.block_records.get(&ins.block_name);
|
||||
let sub_count = br.map(|br| br.entity_handles.len()).unwrap_or(0);
|
||||
let is_xref = br
|
||||
.map(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.unwrap_or(false);
|
||||
if sub_count > INSERT_SUB_LIMIT {
|
||||
return vec![marker];
|
||||
}
|
||||
@@ -4077,6 +4087,11 @@ fn tessellate_entity(
|
||||
ins_lw_px,
|
||||
);
|
||||
let sub_color = render::adapt_to_bg(sub_color, bg_color);
|
||||
let sub_color = if is_xref && !sel {
|
||||
block_cache::fade_toward_bg(sub_color, bg_color)
|
||||
} else {
|
||||
sub_color
|
||||
};
|
||||
let sub_aabb = entity_aabb(&sub, world_offset);
|
||||
let sub_pattern_length = sub_pattern_length * pslt_factor;
|
||||
let sub_pattern = sub_pattern.map(|v| v * pslt_factor);
|
||||
|
||||
Reference in new issue
Block a user