forked from 1b-agent/opencadstudio-upstream
fix(xclip): clip hatch fills and render nested-block hatches
Hatch fills render through the separate HatchModel pipeline, so the block wire clip never touched them: hatches outside an XCLIP boundary were still drawn. Clip each hatch boundary loop to the clip polygon (Sutherland-Hodgman, even-odd islands preserved) when the insert carries a spatial filter. Also fix hatches inside the boundary that were never drawn: the hatch collector exploded each insert only one level, so hatches nested in sub-blocks were dropped entirely. Walk the full block tree (depth guarded) so nested hatches render and clip like the rest. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
dd1ec3ad40
commit
540d5f7b78
2 files changed
+191
-14
No files matched your search
+48
-14
@@ -3703,23 +3703,57 @@ impl Scene {
|
||||
continue;
|
||||
}
|
||||
let selected = self.selected.contains(&ins.common.handle);
|
||||
for sub in ins
|
||||
// XCLIP: clip this insert's exploded hatch fills to the boundary,
|
||||
// matching how the line geometry is clipped in expand_insert.
|
||||
let clip_poly = xclip::insert_spatial_filter(&self.document, ins)
|
||||
.map(|sf| xclip::world_clip_polygon(sf, ins, hatch_offset));
|
||||
// Walk the full block tree: `explode_from_document` only descends
|
||||
// one level, so nested INSERTs are re-exploded here. Each level
|
||||
// bakes its transform into the children it returns, so nested
|
||||
// hatches land in the correct world position. A depth guard keeps
|
||||
// a malformed cyclic block reference from looping forever.
|
||||
let normalize = crate::modules::home::modify::explode::normalize_insert_entity;
|
||||
let mut stack: Vec<(EntityType, usize)> = ins
|
||||
.explode_from_document(&self.document)
|
||||
.into_iter()
|
||||
.map(crate::modules::home::modify::explode::normalize_insert_entity)
|
||||
{
|
||||
let EntityType::Hatch(dxf) = sub else {
|
||||
continue;
|
||||
};
|
||||
if dxf.common.invisible || layer_hidden(&dxf.common.layer) {
|
||||
continue;
|
||||
}
|
||||
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
||||
if let Some(mut model) = Self::hatch_model_from_dxf(&dxf, color, hatch_offset) {
|
||||
if selected {
|
||||
model.color = [0.15, 0.55, 1.00, model.color[3]];
|
||||
.map(|e| (normalize(e), 0usize))
|
||||
.collect();
|
||||
while let Some((sub, depth)) = stack.pop() {
|
||||
match sub {
|
||||
EntityType::Insert(nins) => {
|
||||
if depth >= 32 {
|
||||
continue;
|
||||
}
|
||||
for e in nins.explode_from_document(&self.document) {
|
||||
stack.push((normalize(e), depth + 1));
|
||||
}
|
||||
}
|
||||
models.push(model);
|
||||
EntityType::Hatch(dxf) => {
|
||||
if dxf.common.invisible || layer_hidden(&dxf.common.layer) {
|
||||
continue;
|
||||
}
|
||||
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
||||
if let Some(mut model) =
|
||||
Self::hatch_model_from_dxf(&dxf, color, hatch_offset)
|
||||
{
|
||||
if let Some(poly) = &clip_poly {
|
||||
let clipped = xclip::clip_hatch_boundary(
|
||||
&model.boundary,
|
||||
model.world_origin,
|
||||
poly,
|
||||
);
|
||||
if clipped.is_empty() {
|
||||
continue;
|
||||
}
|
||||
model.boundary = std::sync::Arc::new(clipped);
|
||||
}
|
||||
if selected {
|
||||
model.color = [0.15, 0.55, 1.00, model.color[3]];
|
||||
}
|
||||
models.push(model);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user