forked from 1b-agent/opencadstudio-upstream
Cut the cost of finding what a selection box contains
A window over a whole drawing spent 407 ms gathering candidates and 259 ms testing them, of 825 ms total, at 186 468 entities. **Gathering** ran eight spatial queries because that is what hover and snapping need between them. An area selection reads five: the wires and their segments, plus the fill triangles, pick triangles and glyphs that `indexed_box_crossing_hits` uses to catch hatches and text inside the box. The three that exist only for snapping are skipped. That was worth 148 ms. The rest came from the queries themselves. `SpatialGrid::query` sorts its result twice — once over the entry indices, to remove the repeats an entry collects for spanning several cells, and once over the values. Over a box covering the drawing that is two O(n log n) passes across 4.4 M elements to remove a handful of duplicates. `query_unordered` returns the same set in cell order with the duplicates left in, and reserves the space it needs instead of growing a 17 MB vector in steps. Gathering went from 515 ms to 69 ms on a synthetic set at that size, and from 407 ms to 27-40 ms in the application. Everything an area selection does with the result already dedups and does not read the order. Click picking keeps the sorted `query`, where scan order decides which of two overlapping entities a click lands on. **Testing** projected both endpoints of every segment in the box, then threw the result away for any wire already selected. A circle or a polyline contributes one segment per tessellated span, so at 24 spans per wire that is 23 projection pairs out of 24 doing nothing. Skipping a wire once it is in took a 4.4 M-segment scan from roughly a second to 42 ms. The overlay path — active after any edit, so most of a working session — needed the same treatment, including its own merge: `extend_indexed` sorts and dedups every category, which would have put back the sorts this removes. `extend_indexed_area` keeps the dedup on `wire_indices`, and must: the window branch of `box_hit` walks it directly, so a wire left in twice would be selected twice. Tests cover the equivalence in both directions: the area query matches the full one as a set in every category an area selection reads, and the merge dedups `wire_indices` and nothing else.
This commit is contained in:
1 parent
d02ce08349
commit
d5bf919414
4 files changed
+547
-20
No files matched your search
@@ -4186,8 +4186,9 @@ impl OpenCADStudio {
|
||||
self.refresh_properties();
|
||||
if crate::perf::enabled() {
|
||||
crate::perf_record!(
|
||||
"[perf] select-commit kind=drag-box candidates={cand_ms:.1}ms \
|
||||
hit={hit_ms:.1}ms apply={apply_ms:.1}ms properties={:.1}ms picked={}",
|
||||
"[perf] select-commit kind=drag-box crossing={crossing} \
|
||||
candidates={cand_ms:.1}ms hit={hit_ms:.1}ms apply={apply_ms:.1}ms \
|
||||
properties={:.1}ms picked={}",
|
||||
t_props.map_or(0.0, |t| t.elapsed().as_secs_f64() * 1000.0),
|
||||
handles.len(),
|
||||
);
|
||||
@@ -4564,8 +4565,9 @@ hit={hit_ms:.1}ms apply={apply_ms:.1}ms properties={:.1}ms picked={}",
|
||||
self.refresh_properties();
|
||||
if crate::perf::enabled() {
|
||||
crate::perf_record!(
|
||||
"[perf] select-commit kind=window candidates={cand_ms:.1}ms \
|
||||
hit={hit_ms:.1}ms filter={filter_ms:.1}ms apply={apply_ms:.1}ms properties={:.1}ms picked={}",
|
||||
"[perf] select-commit kind=window crossing={crossing} \
|
||||
candidates={cand_ms:.1}ms hit={hit_ms:.1}ms filter={filter_ms:.1}ms \
|
||||
apply={apply_ms:.1}ms properties={:.1}ms picked={}",
|
||||
t_props.map_or(0.0, |t| t.elapsed().as_secs_f64() * 1000.0),
|
||||
handles.len(),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user