Skip to content

#13469 - selecting one item does select several - circle only select …#75

Open
Zeljko-Predjeskovic wants to merge 1 commit into
developfrom
fix/13469-hittest-fixes
Open

#13469 - selecting one item does select several - circle only select …#75
Zeljko-Predjeskovic wants to merge 1 commit into
developfrom
fix/13469-hittest-fixes

Conversation

@Zeljko-Predjeskovic

Copy link
Copy Markdown
Collaborator

…bounding box and select highest layer

@Zeljko-Predjeskovic

Copy link
Copy Markdown
Collaborator Author

Session summary

  1. Circle/ellipse border-only hit testing — SvgCircle and SvgEllipse had no IntersectsWith override, so unfilled circles/ellipses were always selectable everywhere in their bounding box, including dead center. Added polygon-approximated border checks to both (SvgCircle.cs, SvgEllipse.cs), matching the existing pattern used by SvgRectangle/SvgPolygon/SvgPath. Root cause of the "why doesn't my fix work" follow-up: the app's EllipseTool draws SvgEllipse, not SvgCircle — two separate classes — so the ellipse needed its own fix.

  2. "Fat finger" stroke tolerance — border-only hit tests for unfilled shapes only counted a hit on the exact mathematical outline, ignoring how wide the stroke actually renders. Added GetStrokeHitTestTolerance() (half the element's StrokeWidth, 0 if no stroke) and threaded it through IsIntersectingWithLine in SvgHitTestingExtensions.cs, wired into SvgRectangle, SvgPolygon, SvgPolyline, SvgPath, SvgLine, SvgCircle, SvgEllipse.

  3. Tap-select vs area-select — SelectionTool was selecting every overlapping element on a single tap, not just the top one (area-drag correctly selected multiple). Changed SelectElementsUnderPoint's default maxItems from unlimited to 1 (SelectionTool.cs), relying on HitTest's existing top-to-bottom z-order.

Tests added across SvgHitTests.cs and SelectionToolTests.cs: circle/ellipse no-fill center-miss/border-hit cases, two-layered-rectangle z-order, thick-vs-thin stroke tolerance, no-stroke gets no bonus tolerance, and end-to-end tap-vs-area selection on overlapping rectangles.

@gentledepp

Copy link
Copy Markdown
Owner

But this should work similar for all tools we provide:

  • stroke/arrow
  • rectangle
  • ellipse
  • ...am I missing some?

@gentledepp gentledepp left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scope — the outline / path hit-testing changes look out of scope for this PR.

The stated goal of #13469 is the select-topmost fix, and that part (the maxItems = 1 change in SelectionTool) is correct and well covered by the new tests.

However this PR also introduces a second, independent feature: border/outline hit-testing for unfilled shapes — the new IntersectsWith overrides on SvgCircle/SvgEllipse, the GetStrokeHitTestTolerance / ScaleTolerance plumbing, and the stroke-tolerance wiring across SvgLine / SvgPolygon / SvgPolyline / SvgRectangle / SvgPath.

Please pull the outline/path hit-testing work into its own PR and keep this one limited to the select-topmost fix. See the inline note on SvgCircle.IntersectsWith for the consistency requirement if any of it does stay.

(Verified locally: checked the branch out into a worktree and ran the new suites — Svg.Editor.Core.Tests 4/4 and the new Svg.Tests.Win hit-test cases 18/18 pass.)

/// </summary>
private const int IntersectsWithSegmentCount = 36;

protected internal override bool IntersectsWith(RectangleF rectangle, Matrix transform, int maxRecursion)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important — path hit-testing has to be all-or-nothing across shapes.

The intended model is: every shape (rectangle, ellipse, line — with or without arrows — and free-draw) first does a bounding-box check; if that hits and the shape has no background (null fill), it then falls through to hit-testing the shape's actual path.

Right now this PR only adds real outline geometry for circle and ellipse. Rectangle/line/polygon/polyline/path merely get an added stroke tolerance on their existing edge logic, and arrow / free-draw shapes aren't addressed at all. That is a partial rollout, so selection ends up behaving differently per shape type.

Either add the path-based hit-testing consistently for all shapes, or none of it. Combined with the scope comment on the PR, my suggestion is to remove it here and do it uniformly in a dedicated PR.

Comment thread Svg/Basic Shapes/SvgEllipse.cs
Comment thread Svg/SvgHitTestingExtensions.cs

var lineSegments = new List<(PointF from, PointF to)>();
PointF previous = null;
for (var i = 0; i <= IntersectsWithSegmentCount; i++)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question on the approach: why approximate the outline with a fixed 36-segment polygon rather than hit-testing the real shape path? A fixed segment count makes the chord-vs-arc error grow with radius/zoom (≈0.0038·r), so for a large radius a tap exactly on the true outline between two vertices can miss. If we're doing path hit-testing at all (see the all-or-nothing note), using the actual geometric path sidesteps this approximation.

Comment thread Svg/SvgHitTestingExtensions.cs
Comment thread Svg/Basic Shapes/SvgLine.cs
Comment thread Svg.Editor.Core/Tools/SelectionTool.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants