Summary
Add a new measurement mode that reverses the current container detection: the user draws a rough rectangle, and the tool contracts each edge inward until it encounters a shape boundary.
Use case
"I roughly know where the element is — show me its exact bounds." Useful when the inside-out container detection picks the wrong region, or when you want to measure a specific element that is not fully enclosed.
Interaction
- User selects shrink-to-fit mode (keyboard shortcut, e.g.
4).
- Click & drag to draw a rough bounding rectangle (reuses the
modeRectDrag interaction).
- On mouse release, the rectangle contracts to fit the content.
- The final rectangle + its dimensions are displayed.
Algorithm
For each side of the user-drawn rectangle, scan inward (row-by-row or column-by-column) through the edge map:
- Top edge: scan rows top→down; stop at the first row where edge-pixel density ≥ threshold.
- Bottom edge: scan rows bottom→up; same.
- Left edge: scan columns left→right; same.
- Right edge: scan columns right→left; same.
The density threshold determines what counts as "encountering a shape" — a single edge pixel is noise. Something like ≥ 30% of pixels in that row/column are edge pixels could work. The existing sensitivity slider could control this, or a separate threshold could be exposed.
This is essentially bounding box refinement using the already-computed Canny edge map.
Implementation notes
- Add
shrink_rect_to_content(edge_map, rect, threshold) to core.py — a pure function that returns the contracted rect.
- Expose via a new
@pyqtSlot on RulerBackend.
- QML: new mode constant, reuse
SelectionOutline for the result display.
- Consider an animation showing the contraction (nice-to-have).
Edge cases
- If no edges are found inside the rectangle on a given side, that side stays at its original position.
- Very small rectangles (< 5px on a side) should be rejected or left as-is.
Summary
Add a new measurement mode that reverses the current container detection: the user draws a rough rectangle, and the tool contracts each edge inward until it encounters a shape boundary.
Use case
"I roughly know where the element is — show me its exact bounds." Useful when the inside-out container detection picks the wrong region, or when you want to measure a specific element that is not fully enclosed.
Interaction
4).modeRectDraginteraction).Algorithm
For each side of the user-drawn rectangle, scan inward (row-by-row or column-by-column) through the edge map:
The density threshold determines what counts as "encountering a shape" — a single edge pixel is noise. Something like ≥ 30% of pixels in that row/column are edge pixels could work. The existing sensitivity slider could control this, or a separate threshold could be exposed.
This is essentially bounding box refinement using the already-computed Canny edge map.
Implementation notes
shrink_rect_to_content(edge_map, rect, threshold)tocore.py— a pure function that returns the contracted rect.@pyqtSlotonRulerBackend.SelectionOutlinefor the result display.Edge cases