Skip to content

New mode: Shrink-to-fit rectangle #7

@pgivel

Description

@pgivel

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

  1. User selects shrink-to-fit mode (keyboard shortcut, e.g. 4).
  2. Click & drag to draw a rough bounding rectangle (reuses the modeRectDrag interaction).
  3. On mouse release, the rectangle contracts to fit the content.
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions