![]() |
Pangolin
Header-only C++20 plane computational geometry library
|
Minkowski erosions: the set of translations of one shape that keep it inside another. More...
#include "implementation/minkowskisum.hpp"#include <algorithm>#include <cstddef>#include <optional>#include <stdexcept>#include <type_traits>#include <utility>#include <vector>Go to the source code of this file.
Namespaces | |
| namespace | pgl |
Macros | |
| #define | PGL_DEFINE_MINKOWSKI_EROSION(SHAPE) |
| #define | PGL_DEFINE_CONVEX_MINKOWSKI_EROSION(SHAPE) |
| #define | PGL_DEFINE_REGION_MINKOWSKI_EROSION(RECEIVER) |
Minkowski erosions: the set of translations of one shape that keep it inside another.
The erosion of A by B is the set
, the operation implementation/minkowski.hpp's sum is the morphological dual of. It is defined for exactly the pairs whose sum is (pgl::MinkowskiSummableConcept, plus the region-valued overload sets of implementation/minkowskisum.hpp), and it is not commutative: A ⊖ B reads its two operands quite differently, so every pair the sum answers by forwarding to the higher-ranked operand is answered here on the receiver itself.
Write a closed half-plane as H = {p : cross(d, p) >= c}. Then
H ⊖ B = {x : cross(d, x) >= c - inf_{b in B} cross(d, b)},
which is H translated by -b*, where b* is the point of B attaining that infimum — the very support point pgl::detail::minkowskiHalfplaneSum translates the other way to make the sum. And because erosion distributes over an intersection of constraints,
A ⊖ B = ⋂ᵢ (Hᵢ ⊖ B) whenever A = ⋂ᵢ Hᵢ,
a convex receiver needs nothing but its own half-planes and the operand's support function: one clamp per constraint, O(a·b) in the two operands' sizes, and no arithmetic beyond a cross product and a subtraction. Three consequences are worth stating, because they are what the contract below is made of:
That identity is all about A being an intersection of half-planes, so it says nothing about a Polygon with a notch, and the erosion of one is genuinely harder than its sum: it can disconnect a connected shape, which is why every region-valued erosion returns a pgl::PolygonSet where the corresponding sum returns one pgl::PolygonWithHoles.
What always works is the complement, taken inside a window big enough to hide that the plane is not one. With W a box containing A and every a + b, and U = closure(W° ∖ A) the material just outside A,
A ⊖ B = A ∖ (U ⊕ (-B)),
since for x ∈ A some x + b leaves A exactly when some x + b lands in U, and U is where every such point is. So one difference, one Minkowski sum — pgl::detail::regularizedMinkowskiSum, whole — and one more difference answer it. That A ∖ … at the front is also what makes it read A ⊖ B ⊆ A, which is true only of an operand covering the origin, so the operand is first moved onto one of its own vertices and the answer moved back. See pgl::detail::regularizedMinkowskiErosion.
A convex receiver that merely arrived as a Polygon or a hole-free region skips all of that for the linear clamp above, exactly as the sum's first construction skips the arrangement for the linear merge.
A ⊖ ∅ is the whole plane: every x satisfies x ⊕ ∅ ⊆ A vacuously. That is the one answer a shrinking operation gives that is bigger than its receiver, and what happens to it turns on when the operand is known to be empty. An EmptyShape operand is empty by its type, so the dispatcher answers before any result type is chosen and every receiver gets the plane as a HalfplaneIntersection. An operand that merely turns out to cover no point — an empty Convex, Rectangle, Polygon, PolygonSet or HalfplaneIntersection — arrives at whatever result type its pair fixed, and the three tighter ones cannot hold the plane: Rectangle ⊖ Rectangle, Halfplane ⊖ bounded and every region-valued pair throw std::logic_error rather than answer something else, where a HalfplaneIntersection result simply returns it.
There is deliberately no operator for the erosion. operator+ spells the sum because A ⊕ {p} is the translation A + p it already spelled, but A - B is read at least as often as A ⊕ (-B), which is a different set; the operator- this library has stays what it was, a translation by a point.
| #define PGL_DEFINE_CONVEX_MINKOWSKI_EROSION | ( | SHAPE | ) |
| #define PGL_DEFINE_MINKOWSKI_EROSION | ( | SHAPE | ) |
| #define PGL_DEFINE_REGION_MINKOWSKI_EROSION | ( | RECEIVER | ) |