Optimize Group::select() with short-circuit checks before positionEdgeVariables()#622
Conversation
…eVariables() Co-authored-by: highperformancecoder <3075825+highperformancecoder@users.noreply.github.com>
a81c4a6
into
bugfix-610-unable-to-pull-wire
There was a problem hiding this comment.
Pull request overview
This PR optimizes canvas hit-testing by reducing unnecessary work in Group::select() during Canvas::itemAt() calls, avoiding expensive edge-variable positioning/layout in common “miss” cases.
Changes:
- Add an early return when both
inVariablesandoutVariablesare empty. - Add a bounding-box-based early return to skip
positionEdgeVariables()when the click point is clearly outside a conservative extent.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| // Short-circuit: avoid the expensive positionEdgeVariables() call when | ||
| // (x,y) is clearly outside the expanded group bounding box. Using | ||
| // w+h as the conservative AABB half-extent covers all rotation angles. | ||
| const float z = zoomFactor(); | ||
| const float w = 0.5f * iWidth() * z; | ||
| const float h = 0.5f * iHeight() * z + topMargin * z; | ||
| const float maxExtent = w + h; | ||
| if (abs(x - this->x()) > maxExtent || abs(y - this->y()) > maxExtent) | ||
| return nullptr; | ||
|
|
There was a problem hiding this comment.
The new AABB short-circuit uses only the group icon dims (iWidth/iHeight + topMargin) to decide whether to skip positionEdgeVariables(). However edge variables can be laid out well outside those bounds (eg yOff grows with the number/height of in/out variables in layoutEdgeVariables), so this can return nullptr even when (x,y) is actually over a drawn edge variable/port, breaking hit-testing/wire dragging for groups with many edge vars (and potentially large label extents/margins). Consider widening the bound using a conservative upper bound that includes possible edge-variable extents (eg based on counts and cached bb heights/widths), caching margins/edge-extents from the last layout, or removing this short-circuit if correctness can’t be guaranteed.
| // Short-circuit: avoid the expensive positionEdgeVariables() call when | |
| // (x,y) is clearly outside the expanded group bounding box. Using | |
| // w+h as the conservative AABB half-extent covers all rotation angles. | |
| const float z = zoomFactor(); | |
| const float w = 0.5f * iWidth() * z; | |
| const float h = 0.5f * iHeight() * z + topMargin * z; | |
| const float maxExtent = w + h; | |
| if (abs(x - this->x()) > maxExtent || abs(y - this->y()) > maxExtent) | |
| return nullptr; |
Canvas::itemAt()hit-tests every group viaclickType()→select(), which unconditionally calledpositionEdgeVariables()— an expensive operation invokingmargins()(Pango bounding-box updates) andmoveTo()on every edge variable, even for groups nowhere near the click point.Changes
nullptrimmediately when bothinVariablesandoutVariablesare empty — zero overhead for groups with no edge variables.positionEdgeVariables()when(x,y)is outside a conservative AABB centered on the group. UsesmaxExtent = w + has the half-extent, which is a tight upper bound for any rotation angle (for half-dimsw,h, the rotated AABB half-dim satisfiesw|cosθ| + h|sinθ| ≤ w + h).✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
This change is