forked from 1b-agent/opencadstudio-upstream
fix(hatch): refresh associative hatch during geometry edits
This commit is contained in:
1 parent
67163de15d
commit
b7c2ce2e13
2 files changed
+93
-10
No files matched your search
+84
-10
@@ -84,6 +84,38 @@ fn entity_curves_on_plane(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn entity_boundary_source_on_plane(
|
||||||
|
entity: &EntityType,
|
||||||
|
plane: WorkingPlane,
|
||||||
|
tolerance: f64,
|
||||||
|
) -> Option<BoundarySource> {
|
||||||
|
let curves = entity_curves_on_plane(entity, plane, tolerance);
|
||||||
|
|
||||||
|
if curves.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let segments: Vec<Line> = curves
|
||||||
|
.iter()
|
||||||
|
.flat_map(|curve| {
|
||||||
|
curve
|
||||||
|
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
||||||
|
.windows(2)
|
||||||
|
.filter_map(|pair| {
|
||||||
|
let start = pair[0];
|
||||||
|
let end = pair[1];
|
||||||
|
|
||||||
|
(start.iter().chain(&end).all(|value| value.is_finite())
|
||||||
|
&& start != end)
|
||||||
|
.then_some(Line { start, end })
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(!segments.is_empty()).then_some(BoundarySource { segments, curves })
|
||||||
|
}
|
||||||
|
|
||||||
fn hatch_path_seed(path: &acadrust::entities::BoundaryPath) -> Option<[f64; 2]> {
|
fn hatch_path_seed(path: &acadrust::entities::BoundaryPath) -> Option<[f64; 2]> {
|
||||||
let mut ring = Vec::new();
|
let mut ring = Vec::new();
|
||||||
for edge in &path.edges {
|
for edge in &path.edges {
|
||||||
@@ -731,10 +763,22 @@ impl Scene {
|
|||||||
.boundary_handles
|
.boundary_handles
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|source| {
|
.filter_map(|source| {
|
||||||
all_sources
|
// Associative boundaries are explicit document references.
|
||||||
.get(source)
|
// During a grip drag their display wire can be preview-hidden,
|
||||||
.cloned()
|
// so prefer the live entity geometry over the resident wire cache.
|
||||||
.map(|geometry| (*source, geometry))
|
let geometry = self
|
||||||
|
.document
|
||||||
|
.get_entity(*source)
|
||||||
|
.and_then(|entity| {
|
||||||
|
entity_boundary_source_on_plane(
|
||||||
|
entity,
|
||||||
|
plane,
|
||||||
|
WELD_TOLERANCE,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.or_else(|| all_sources.get(source).cloned());
|
||||||
|
|
||||||
|
geometry.map(|geometry| (*source, geometry))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let segments: Vec<_> = sources
|
let segments: Vec<_> = sources
|
||||||
@@ -817,17 +861,47 @@ impl Scene {
|
|||||||
.extend(segments);
|
.extend(segments);
|
||||||
}
|
}
|
||||||
for (&handle, source) in &mut sources {
|
for (&handle, source) in &mut sources {
|
||||||
source.curves = self
|
let curves = self
|
||||||
.document
|
.document
|
||||||
.get_entity(handle)
|
.get_entity(handle)
|
||||||
.map(|entity| entity_curves_on_plane(entity, plane, tolerance))
|
.map(|entity| entity_curves_on_plane(entity, plane, tolerance))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
source.curves.retain(|curve| {
|
|
||||||
source.segments.iter().any(|segment| {
|
// Associative hatch regeneration must use the entity's live geometry,
|
||||||
distance_to(curve, segment.start).max(distance_to(curve, segment.end))
|
// not a potentially one-frame-old display wire. Grip edits and STRETCH
|
||||||
<= tolerance * 4.0
|
// mutate the document before the resident wire cache catches up.
|
||||||
|
let live_segments: Vec<Line> = curves
|
||||||
|
.iter()
|
||||||
|
.flat_map(|curve| {
|
||||||
|
curve
|
||||||
|
.tessellate_angle(cadkernel::tessellation::DEFAULT_ANGLE)
|
||||||
|
.windows(2)
|
||||||
|
.filter_map(|pair| {
|
||||||
|
let start = pair[0];
|
||||||
|
let end = pair[1];
|
||||||
|
|
||||||
|
(start.iter().chain(&end).all(|value| value.is_finite())
|
||||||
|
&& start != end)
|
||||||
|
.then_some(Line { start, end })
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
})
|
})
|
||||||
});
|
.collect();
|
||||||
|
|
||||||
|
if !live_segments.is_empty() {
|
||||||
|
source.segments = live_segments;
|
||||||
|
source.curves = curves;
|
||||||
|
} else {
|
||||||
|
// Fallback for entity types that do not expose usable native curves:
|
||||||
|
// retain the existing display-wire geometry.
|
||||||
|
source.curves = curves;
|
||||||
|
source.curves.retain(|curve| {
|
||||||
|
source.segments.iter().any(|segment| {
|
||||||
|
distance_to(curve, segment.start).max(distance_to(curve, segment.end))
|
||||||
|
<= tolerance * 4.0
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sources
|
sources
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1387,5 +1387,14 @@ impl Scene {
|
|||||||
self.images.insert(handle, model);
|
self.images.insert(handle, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// A grip edit can move geometry used as the boundary of an associative hatch.
|
||||||
|
// The source entity has already been mutated above, so rebuild any dependent
|
||||||
|
// hatch from the live document geometry immediately.
|
||||||
|
let source_change = [(handle, ChangeKind::Modified)];
|
||||||
|
let hatch_changes = self.refresh_associative_hatches(&source_change);
|
||||||
|
|
||||||
|
if !hatch_changes.is_empty() {
|
||||||
|
self.bump_entities(&hatch_changes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user