Skip to content

Add outer_approximation_by_rectangles - #149

Merged
fontanf merged 1 commit into
mainfrom
outer-approximation-by-rectangles
Oct 19, 2026
Merged

fontanf merged 1 commit into
mainfrom
outer-approximation-by-rectangles

Conversation

@fontanf

@fontanf fontanf commented Oct 19, 2026

Copy link
Copy Markdown
Owner

Adds outer_approximation_by_rectangles (shape/rectangular_approximation.hpp): approximate shapes by axis-aligned rectangles whose union contains them, within a maximum waste shared by all the shapes, the way simplify shares its maximum approximation area.

It is meant for algorithms which handle obstacles as rectangles: fontanf/packingsolver's periodic packing approximated the defects, borders and fixed items by their bounding boxes, so a fixed part with a hole covered its hole (fontanf/packingsolver#720).

Interface

struct OuterApproximationByRectanglesInputShape
{
    ShapeWithHoles shape;
    ShapePos copies = 1;
};

std::vector<std::vector<AxisAlignedBoundingBox>> outer_approximation_by_rectangles(
        const std::vector<OuterApproximationByRectanglesInputShape>& shapes,
        AreaDbl maximum_waste,
        ElementPos maximum_number_of_rectangles = 256);

The waste of a shape is the area of its rectangles minus its area, counted once per copy. Where rectangles of a shape overlap, the overlap counts several times, so this is an upper bound on the waste of their union.

Algorithm

  1. The circular arcs are replaced by line segments outside of them (approximate_by_line_segments), the shape is decomposed into trapezoids (trapezoidation), and each trapezoid is covered by its bounding box. Shapes whose edges are horizontal or vertical are covered exactly: a rectangular frame gives 4 rectangles and leaves its hole free.
  2. While the waste is larger than maximum_waste, split the rectangle whose split into two halves of a trapezoid removes the most waste, up to maximum_number_of_rectangles per shape (a budget of 0 can't be met with an oblique edge).
  3. While the waste stays at most maximum_waste, merge the two rectangles of a same shape whose bounding box adds the least waste.

Both steps choose across all the shapes, weighted by their copies.

outer_approximation_by_rectangles_export_inputs writes the inputs for test fixtures, like the other algorithms.

Tests

test/rectangular_approximation_test.cpp checks that the rectangles contain each shape (boolean difference), that the waste is within the budget, and the number of rectangles where it is known: rectangle, frame with a hole (4 rectangles, no waste), L shape merged or not depending on the budget, triangles, the maximum number of rectangles with a zero budget, a V notch (overlapping rectangles), a circle, a square with a circular hole, and shapes with copies sharing the budget. All the tests pass (707).

Approximate shapes by axis-aligned rectangles whose union contains them,
within a maximum waste shared by all the shapes, as simplify does with
its maximum approximation area: the shapes are decomposed into
trapezoids, each covered by its bounding box, then the rectangles are
split while the waste is too large, and merged while it stays within the
maximum waste.
@fontanf
fontanf merged commit a4efbe9 into main Oct 19, 2026
3 checks passed
@fontanf
fontanf deleted the outer-approximation-by-rectangles branch October 19, 2026 22:15
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.

1 participant