Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
pgl::BitMatrix< TPointType > Class Template Reference

A bit per cell of a rectangular window of the integer grid. More...

#include <bitmatrix.hpp>

Classes

class  Iterator
 Forward iterator over the set cells, in row-major order. More...

Public Types

using PointType = TPointType
 Point type naming a cell by its lower-left corner.
using NumberType = typename PointType::NumberType
 Coordinate type of a cell.
using RectangleType = Rectangle<PointType>
 Rectangle over PointType, the type of a window.
using RegionType = PolygonWithHoles<PointType>
 Region type asPolygonWithHoles produces.
using PolygonSetType = PolygonSet<PointType>
 Region-set type asPolygonSet produces.
using ConvexType = Convex<PointType>
 Convex type convexHull produces.
using value_type = PointType
 Cell type the iterators yield.
using iterator = Iterator
 Iteration is read-only, so both iterator types are Iterator.
using const_iterator = Iterator
 Iteration is read-only, so both iterator types are Iterator.

Public Member Functions

 BitMatrix ()=default
 Creates a matrix whose window is empty, so no cell can be set.
 BitMatrix (PointType origin, int width, int height)
 Creates an empty matrix covering a window of the grid.
 BitMatrix (const RectangleType &box)
 Creates an empty matrix over the cells a rectangle covers.
template<class TLabel>
 BitMatrix (const PolygonWithHoles< PointType, TLabel > &region)
 Rasterizes a rectilinear region, one bit per covered cell.
template<class OtherPointType, class TLabel>
 BitMatrix (const PolygonWithHoles< OtherPointType, TLabel > &region)
 Rasterizes a rectilinear region given over another coordinate type.
template<class TLabel>
 BitMatrix (const Polygon< PointType, TLabel > &polygon)
 Rasterizes a rectilinear polygon, one bit per covered cell.
template<class OtherPointType, class TLabel>
 BitMatrix (const Polygon< OtherPointType, TLabel > &polygon)
 Rasterizes a rectilinear polygon given over another coordinate type.
template<class TLabel>
 BitMatrix (const PolygonSet< PointType, TLabel > &set)
 Rasterizes a rectilinear set of regions, one bit per covered cell.
template<class OtherPointType, class TLabel>
 BitMatrix (const PolygonSet< OtherPointType, TLabel > &set)
 Rasterizes a rectilinear set given over another coordinate type.
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
 BitMatrix (Range &&points)
 Sets one cell per point of a range, over the smallest window holding them.
const PointTypeorigin () const
 Lower-left cell of the window.
int width () const
 Number of cells per row of the window.
int height () const
 Number of rows of the window.
RectangleType window () const
 The window, as the rectangle its cells cover.
bool emptyWindow () const
 Whether the window itself is degenerate, so no cell can be set.
bool inWindow (NumberType x, NumberType y) const
 Whether a cell is inside the window, and so can be set.
bool inWindow (const PointType &cell) const
 Whether a cell is inside the window, and so can be set.
bool sameWindow (const BitMatrix &other) const
 Whether two matrices cover the same window.
BitMatrix resized (const RectangleType &box) const
 Returns the same cells over another window, dropping those outside.
BitMatrix trimmed () const
 Returns the same cells over the smallest window holding them.
bool get (NumberType x, NumberType y) const
 Whether the cell is set; cells outside the window are not.
bool get (const PointType &cell) const
 Whether the cell is set; cells outside the window are not.
void set (NumberType x, NumberType y)
 Sets the cell; a cell outside the window is silently dropped.
void set (const PointType &cell)
 Sets the cell; a cell outside the window is silently dropped.
void set (NumberType x, NumberType y, bool value)
 Sets or clears the cell; a cell outside the window is dropped.
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
void set (Range &&points)
 Sets one cell per point of a range; cells outside the window are dropped.
void reset (NumberType x, NumberType y)
 Clears the cell; a cell outside the window is silently dropped.
void reset (const PointType &cell)
 Clears the cell; a cell outside the window is silently dropped.
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
void reset (Range &&points)
 Clears one cell per point of a range; cells outside the window are dropped.
void flip (NumberType x, NumberType y)
 Flips the cell; a cell outside the window is silently dropped.
void flip (const PointType &cell)
 Flips the cell; a cell outside the window is silently dropped.
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
void flip (Range &&points)
 Flips one cell per point of a range; cells outside the window are dropped.
void setAll ()
 Sets every cell of the window.
void clear ()
 Clears every cell, keeping the window.
bool empty () const
 Whether no cell is set, which an empty window always is.
std::size_t count () const
 Number of set cells.
template<class ResultNumber = NumberType>
ResultNumber area () const
 Area the set cells cover, which is their number since each is a unit square.
template<class ResultNumber = NumberType>
ResultNumber perimeter () const
 Length of the boundary of the covered region.
template<class ResultNumber = division_result_t<NumberType>>
Point< ResultNumber > centroid () const
 Centroid of the covered region.
Iterator begin () const
 Iterator over the set lattice points, in row-major order.
Iterator end () const
 End of the iteration over the set lattice points.
auto latticeView () const
 Returns a lazy view of the set cells as lattice points.
auto cellsView () const
 Returns a lazy view of the set cells as the unit squares they cover.
std::vector< PointTypelattice () const
 The set cells as lattice points, in row-major order.
std::vector< RectangleTypecells () const
 The set cells as the unit squares they cover, in row-major order.
std::vector< RectangleTyperectangles () const
 The covered region as maximal horizontal runs of cells.
RectangleType bbox () const
 The rectangle the set cells cover, empty when no cell is set.
template<class ResultNumber = double>
Rectangle< Point< ResultNumber > > fbox () const
 A floating-point bounding box of the covered region.
template<class ResultNumber = division_result_t<NumberType>>
Point< ResultNumber > pointInside () const
 A point in the interior of the covered region.
RegionType asPolygonWithHoles () const
 The covered region, as one region with holes.
PolygonSetType asPolygonSet () const
 The covered region, as a set of regions with holes.
ConvexType convexHull () const
 Convex hull of the covered region.
BitMatrix operator~ () const
 Returns the complement within the same window.
BitMatrixoperator&= (const BitMatrix &other)
 Drops every cell the other matrix does not have.
BitMatrixoperator|= (const BitMatrix &other)
 Adds every cell of the other matrix that this window holds.
BitMatrixoperator^= (const BitMatrix &other)
 Flips every cell the other matrix has and this window holds.
BitMatrix operator& (const BitMatrix &other) const
 The cells both matrices have, over the overlap of the windows.
BitMatrix operator| (const BitMatrix &other) const
 The cells either matrix has, over the hull of the windows.
BitMatrix operator^ (const BitMatrix &other) const
 The cells exactly one matrix has, over the hull of the windows.
BitMatrix difference (const BitMatrix &other) const
 The cells this matrix has and the other does not, over this window.
BitMatrix symmetricDifference (const BitMatrix &other) const
 The cells exactly one matrix has; the same as operator^.
bool operator== (const BitMatrix &other) const
 Whether the two matrices have the same window and the same cells.
std::strong_ordering operator<=> (const BitMatrix &other) const
 Orders matrices lexicographically by (origin, width, height, bits).
bool samePointSet (const BitMatrix &other) const
 Whether the two matrices cover the same region.
bool contains (const BitMatrix &other) const
 Whether the covered region contains the other one.
bool interiorContains (const BitMatrix &other) const
 Whether the interior of the covered region contains the other one.
bool boundaryContains (const BitMatrix &other) const
 Whether the boundary of the covered region contains the other one.
bool intersects (const BitMatrix &other) const
 Whether the two covered regions share a point.
bool interiorsIntersect (const BitMatrix &other) const
 Whether the interiors of the two covered regions share a point.
std::size_t andCount (const BitMatrix &other) const
 Number of cells set in both matrices.
std::size_t orCount (const BitMatrix &other) const
 Number of cells set in either matrix.
std::size_t xorCount (const BitMatrix &other) const
 Number of cells set in exactly one matrix.
BitMatrix translated (const PointType &vector) const
 Returns the same cells translated by a vector.
BitMatrix operator+ (const PointType &vector) const
 Returns the same cells translated by a vector.
BitMatrix operator- (const PointType &vector) const
 Returns the same cells translated by the opposite of a vector.
BitMatrixoperator+= (const PointType &vector)
 Translates the cells by a vector.
BitMatrixoperator-= (const PointType &vector)
 Translates the cells by the opposite of a vector.
BitMatrix reflected () const
 Returns the reflection of the covered region through the origin.
BitMatrix operator- () const
 Returns the reflection of the covered region through the origin.
BitMatrix reflectedX () const
 Returns the reflection of the covered region across the x-axis.
BitMatrix reflectedY () const
 Returns the reflection of the covered region across the y-axis.
BitMatrix transposed () const
 Returns the reflection of the covered region across the diagonal.
BitMatrix rotated90 (int k=1) const
 Returns the rotation of the covered region about the origin.
BitMatrixrotate90 (int k=1)
 Rotates the covered region about the origin.
BitMatrix latticeReflected () const
 Returns the reflection of the cells as lattice points, {-c}.
BitMatrix latticeReflectedX () const
 Returns the reflection of the cells as lattice points, {(x, -y)}.
BitMatrix latticeReflectedY () const
 Returns the reflection of the cells as lattice points, {(-x, y)}.
BitMatrix latticeTransposed () const
 Returns {(y, x)}; the same as transposed, which the two readings agree on.
BitMatrix latticeRotated90 (int k=1) const
 Returns the rotation of the cells as lattice points.
BitMatrixlatticeRotate90 (int k=1)
 Rotates the cells as lattice points.
BitMatrix latticeMinkowskiSum (const BitMatrix &other) const
 Returns the Minkowski sum {a + b : a in *this, b in other}.
BitMatrix minkowskiSum (const BitMatrix &other) const
 Returns the Minkowski sum of the two covered regions.
BitMatrix operator+ (const BitMatrix &other) const
 Returns the Minkowski sum of the regions; the same as minkowskiSum.
BitMatrix minkowskiErosion (const BitMatrix &other) const
 Returns the regularized Minkowski erosion of the covered regions.
BitMatrix latticeMinkowskiErosion (const BitMatrix &other) const
 Returns the Minkowski erosion {p : p + other is inside *this}.
BitMatrix latticeOpening (const BitMatrix &other) const
 Returns the opening, a lattice erosion by other followed by a lattice sum.
BitMatrix latticeClosing (const BitMatrix &other) const
 Returns the closing, a lattice sum with other followed by a lattice erosion.
BitMatrix interior (GridAdjacency adjacency=GridAdjacency::edge) const
 Returns the set cells all of whose neighbors are set.
BitMatrix boundary (GridAdjacency adjacency=GridAdjacency::edge) const
 Returns the set cells with at least one neighbor that is not set.
std::vector< BitMatrixconnectedComponents (GridAdjacency adjacency=GridAdjacency::edge) const
 Returns one matrix per connected group of cells, each trimmed.
std::size_t componentCount (GridAdjacency adjacency=GridAdjacency::edge) const
 Number of connected groups of cells.
bool isConnected (GridAdjacency adjacency=GridAdjacency::edge) const
 Whether the set cells form exactly one connected group.
BitMatrix fillHoles (GridAdjacency adjacency=GridAdjacency::edge) const
 Returns the cells together with every hole they enclose.
std::size_t holeCount (GridAdjacency adjacency=GridAdjacency::edge) const
 Number of holes the set cells enclose.
std::int64_t eulerNumber (GridAdjacency adjacency=GridAdjacency::edge) const
 Euler characteristic of the covered region: components minus holes.
bool fillRows ()
 Fills the gaps of every row.
bool fillColumns ()
 Fills the gaps of every column.
std::size_t makeHvConvex ()
 Fills every cell that has set cells on both sides in its row and in its column, until nothing changes.
bool isRowConvex () const
 Whether every row meets the set cells in a single interval.
bool isColumnConvex () const
 Whether every column meets the set cells in a single interval.
bool isHvConvex () const
 Whether every row and every column meets the cells in one interval.

Friends

Canvasoperator<< (Canvas &canvas, const BitMatrix &matrix)
 Draws the covered region to a canvas.

Detailed Description

template<class TPointType = Point<int>>
requires std::signed_integral<typename TPointType::NumberType>
class pgl::BitMatrix< TPointType >

A bit per cell of a rectangular window of the integer grid.

Cell (x, y) is the unit square [x, x+1] x [y, y+1], named by the integer coordinates of its lower-left corner. The bits cover the window [origin, origin + (width, height)), which is fixed at construction and never grows: writing outside it is a no-op and reading outside it gives false. Sizing the window is the caller's job, and resized and trimmed move a matrix to another one.

Rows are packed into 64-bit words, which is what makes the bulk operations cheap: the whole set algebra, count, andCount, perimeter and eulerNumber run a word at a time, latticeMinkowskiSum costs one shifted or-assignment of a whole matrix per cell of the smaller operand, and the connectivity and boundary walks behind componentCount and asPolygonSet move a run of cells at a time rather than a cell at a time.

A matrix wears two hats, and which one an operation wears is stated in its documentation:

  • As a region of the plane – the union of its cells as unit squares – for area, perimeter, centroid, boundingBox, convexHull, asPolygonWithHoles, asPolygonSet, and the symmetries and Minkowski operations whose names carry no prefix.
  • As a set of lattice points – each cell standing for its lower-left corner – for every lattice-prefixed operation, which is the convention that makes a structuring element behave: the sum of cells a and b is the single cell a + b, not the two-by-two square that adding the unit squares would give. It is what makes a one-cell matrix the identity of latticeMinkowskiSum, and latticeMinkowskiErosion its exact dual. Every such operation has an unprefixed counterpart that wears the region hat instead, and the pair differs by a cell: reflected maps cell c to -c - (1,1) where latticeReflected maps it to -c.

minkowskiSum and minkowskiErosion, without the prefix, are the region sum and the regularized region erosion the shapes compute, and both commute with asPolygonSet.

Two operations compute from the window rather than only from the cells, since a complement has to be taken relative to something bounded: operator~ and, through it, latticeMinkowskiErosion. Every other construction and every geometric predicate depends only on the cells.

The window is part of a matrix's value all the same. operator==, operator<=> and std::hash compare the window along with the cells, as they do for a shape's stored representation, so a != a.trimmed() whenever trimming moves anything. samePointSet is the geometric question of whether two matrices cover the same region, and ignores the window. A window covering no cell has one canonical form, so all such matrices compare equal whatever origin they were built with.

Template Parameters
TPointTypePoint type naming a cell; its coordinates must be a signed integral type, since a cell of the grid is an integer position.

Member Typedef Documentation

◆ const_iterator

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::const_iterator = Iterator

Iteration is read-only, so both iterator types are Iterator.

◆ ConvexType

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::ConvexType = Convex<PointType>

Convex type convexHull produces.

◆ iterator

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::iterator = Iterator

Iteration is read-only, so both iterator types are Iterator.

◆ NumberType

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::NumberType = typename PointType::NumberType

Coordinate type of a cell.

◆ PointType

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::PointType = TPointType

Point type naming a cell by its lower-left corner.

◆ PolygonSetType

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::PolygonSetType = PolygonSet<PointType>

Region-set type asPolygonSet produces.

◆ RectangleType

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::RectangleType = Rectangle<PointType>

Rectangle over PointType, the type of a window.

◆ RegionType

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::RegionType = PolygonWithHoles<PointType>

Region type asPolygonWithHoles produces.

◆ value_type

template<class TPointType = Point<int>>
using pgl::BitMatrix< TPointType >::value_type = PointType

Cell type the iterators yield.

Constructor & Destructor Documentation

◆ BitMatrix() [1/10]

template<class TPointType = Point<int>>
pgl::BitMatrix< TPointType >::BitMatrix ( )
default

Creates a matrix whose window is empty, so no cell can be set.

◆ BitMatrix() [2/10]

template<class TPointType = Point<int>>
pgl::BitMatrix< TPointType >::BitMatrix ( PointType origin,
int width,
int height )
inline

Creates an empty matrix covering a window of the grid.

Parameters
originLower-left cell of the window.
widthNumber of cells per row; a non-positive value empties the window.
heightNumber of rows; a non-positive value empties the window.

◆ BitMatrix() [3/10]

template<class TPointType = Point<int>>
pgl::BitMatrix< TPointType >::BitMatrix ( const RectangleType & box)
inlineexplicit

Creates an empty matrix over the cells a rectangle covers.

The window runs from box.min() to box.max(), so a rectangle of width w and height h gives w * h cells, the last of them named by box.max() - (1, 1). This is the inverse of window.

Parameters
boxRectangle covering the window; it must have integer corners, which its point type guarantees.

◆ BitMatrix() [4/10]

template<class TPointType = Point<int>>
template<class TLabel>
pgl::BitMatrix< TPointType >::BitMatrix ( const PolygonWithHoles< PointType, TLabel > & region)
inlineexplicit

Rasterizes a rectilinear region, one bit per covered cell.

Fills the cells whose interior lies inside the region, over a window that is exactly the region's bounding box. Crossing parity along each row does it: every ring contributes its vertical edges, and the cells between the first and second crossing, the third and fourth, and so on, are inside. The integer coordinates make it exact, since they keep every horizontal cross-section constant within a row of cells.

This is the fast path for the rectilinear case. innerRaster gives the same answer for such a region and also accepts every other shape, at the cost of one exact predicate per cell of the bounding box.

Parameters
regionRegion to rasterize; every edge of it must be axis-parallel.
Exceptions
std::logic_errorIf an edge of the region is not axis-parallel.

◆ BitMatrix() [5/10]

template<class TPointType = Point<int>>
template<class OtherPointType, class TLabel>
pgl::BitMatrix< TPointType >::BitMatrix ( const PolygonWithHoles< OtherPointType, TLabel > & region)
inlineexplicit

Rasterizes a rectilinear region given over another coordinate type.

A cell is an integer position, so a region whose coordinates are not integers – a Rational or a floating-point one – covers a set of cells only when every coordinate of it happens to be whole. That is checked rather than rounded: a coordinate that is not a whole number, or is one NumberType cannot hold, throws instead of moving a vertex.

Parameters
regionRegion to rasterize; every edge of it must be axis-parallel and every coordinate a whole number this grid can hold.
Exceptions
std::logic_errorIf an edge is not axis-parallel, or a coordinate is not a whole number of the grid.

◆ BitMatrix() [6/10]

template<class TPointType = Point<int>>
template<class TLabel>
pgl::BitMatrix< TPointType >::BitMatrix ( const Polygon< PointType, TLabel > & polygon)
inlineexplicit

Rasterizes a rectilinear polygon, one bit per covered cell.

The single-ring case of BitMatrix(const PolygonWithHoles<PointType, TLabel>&), with the same crossing parity over the same window, the polygon's bounding box. A self-intersecting polygon is filled by that parity rather than rejected.

Parameters
polygonPolygon to rasterize; every edge of it must be axis-parallel.
Exceptions
std::logic_errorIf an edge of the polygon is not axis-parallel.

◆ BitMatrix() [7/10]

template<class TPointType = Point<int>>
template<class OtherPointType, class TLabel>
pgl::BitMatrix< TPointType >::BitMatrix ( const Polygon< OtherPointType, TLabel > & polygon)
inlineexplicit

Rasterizes a rectilinear polygon given over another coordinate type.

The single-ring case of BitMatrix(const PolygonWithHoles<OtherPointType, TLabel>&), with the same whole-number requirement on every coordinate.

Parameters
polygonPolygon to rasterize; every edge of it must be axis-parallel and every coordinate a whole number this grid can hold.
Exceptions
std::logic_errorIf an edge is not axis-parallel, or a coordinate is not a whole number of the grid.

◆ BitMatrix() [8/10]

template<class TPointType = Point<int>>
template<class TLabel>
pgl::BitMatrix< TPointType >::BitMatrix ( const PolygonSet< PointType, TLabel > & set)
inlineexplicit

Rasterizes a rectilinear set of regions, one bit per covered cell.

The many-component case of BitMatrix(const PolygonWithHoles<PointType, TLabel>&), over a window that is the bounding box of the whole set. Every ring of every component feeds the same parity pass, which the disjoint interiors keep exact: a row leaves one component before it enters the next, so the crossings pair up within a component.

Parameters
setSet to rasterize; every edge of it must be axis-parallel.
Exceptions
std::logic_errorIf an edge of the set is not axis-parallel.

◆ BitMatrix() [9/10]

template<class TPointType = Point<int>>
template<class OtherPointType, class TLabel>
pgl::BitMatrix< TPointType >::BitMatrix ( const PolygonSet< OtherPointType, TLabel > & set)
inlineexplicit

Rasterizes a rectilinear set given over another coordinate type.

The many-component case of BitMatrix(const PolygonWithHoles<OtherPointType, TLabel>&), with the same whole-number requirement on every coordinate.

Parameters
setSet to rasterize; every edge of it must be axis-parallel and every coordinate a whole number this grid can hold.
Exceptions
std::logic_errorIf an edge is not axis-parallel, or a coordinate is not a whole number of the grid.

◆ BitMatrix() [10/10]

template<class TPointType = Point<int>>
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
pgl::BitMatrix< TPointType >::BitMatrix ( Range && points)
inlineexplicit

Sets one cell per point of a range, over the smallest window holding them.

This is the lattice-point reading of a matrix: every point names the cell it is, rather than a corner of a region to fill. The window is the smallest one holding every point, so the result has window() == bbox() and equals its own trimmed; an empty range gives an empty window. Repeated points set the same cell again, which changes nothing.

Any range of points does, except a shape or another matrix. A shape that happens to iterate over its vertices – a Polygon, a Convex, a Polyline – is a boundary and not a point cloud, and the shapes that rasterize have their own constructor above; a matrix carries a window that this would silently trim. Feed either one's points through lattice or a view to ask for this reading of it anyway.

The points may carry any coordinate type, checked rather than rounded exactly as the shape constructors check theirs.

Template Parameters
RangeInput range of points, defaulting to an initializer list so that a braced list of cells works.
Parameters
pointsCells to set.
Exceptions
std::logic_errorIf a coordinate is not a whole number this grid can hold, or the points span more cells than a window holds.

Member Function Documentation

◆ andCount()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::andCount ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Number of cells set in both matrices.

The two windows need not agree; only the cells they share can be set in both, so the count runs over the rows and words of the overlap, reading the other matrix a word at a time, shifted into this one's alignment.

◆ area()

template<class TPointType = Point<int>>
template<class ResultNumber = NumberType>
ResultNumber pgl::BitMatrix< TPointType >::area ( ) const
inlinenodiscard

Area the set cells cover, which is their number since each is a unit square.

Template Parameters
ResultNumberResult type (default: NumberType).
Returns
count as a measure, so 0 when no cell is set.

◆ asPolygonSet()

template<class TPointType = Point<int>>
PolygonSetType pgl::BitMatrix< TPointType >::asPolygonSet ( ) const
inlinenodiscard

The covered region, as a set of regions with holes.

One component per edge-connected group of cells, so this has no precondition; two components touching only at a corner stay apart, and bbox() is exactly the bounding box of the result.

The cost is one pass over the words plus one over the boundary edges, not a union of unit squares: the loops are read straight off the words, which gives the outer ring and one ring per hole directly, with the vertices in the middle of a straight stretch dropped along the way. A window of w cells whose components carry b boundary edges and split into r runs of cells therefore costs O(w / 64 + b + r log r), against the arrangement a regularized union of unit squares would have to build.

◆ asPolygonWithHoles()

template<class TPointType = Point<int>>
RegionType pgl::BitMatrix< TPointType >::asPolygonWithHoles ( ) const
inlinenodiscard

The covered region, as one region with holes.

A matrix with no cell gives an empty region.

Exceptions
std::logic_errorIf the set cells do not form a single edge-connected polyomino, which is what a rasterized region and its Minkowski sums are. Use asPolygonSet when they need not.

◆ bbox()

template<class TPointType = Point<int>>
RectangleType pgl::BitMatrix< TPointType >::bbox ( ) const
inlinenodiscard

The rectangle the set cells cover, empty when no cell is set.

Exactly the box asPolygonSet would report, read off the first and last set word of every row rather than built from the regions.

◆ begin()

template<class TPointType = Point<int>>
Iterator pgl::BitMatrix< TPointType >::begin ( ) const
inlinenodiscard

Iterator over the set lattice points, in row-major order.

◆ boundary()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::boundary ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Returns the set cells with at least one neighbor that is not set.

Parameters
adjacencyWhich cells count as neighbors.

◆ boundaryContains()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::boundaryContains ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether the boundary of the covered region contains the other one.

The boundary is a curve and a nonempty matrix covers area, so this holds only for an empty other. It is here to answer the question rather than to leave it to a wrong guess.

◆ cells()

template<class TPointType = Point<int>>
std::vector< RectangleType > pgl::BitMatrix< TPointType >::cells ( ) const
inlinenodiscard

The set cells as the unit squares they cover, in row-major order.

One rectangle per cell. rectangles instead merges each row's runs into as few rectangles as a row-major pass can, which is the cheaper covering to draw or to measure.

◆ cellsView()

template<class TPointType = Point<int>>
auto pgl::BitMatrix< TPointType >::cellsView ( ) const
inlinenodiscard

Returns a lazy view of the set cells as the unit squares they cover.

Builds each rectangle as it is reached, so nothing is allocated. Like latticeView it refers to this matrix; cells materializes the same squares into a vector.

Returns
A forward view of the count() set cells.

◆ centroid()

template<class TPointType = Point<int>>
template<class ResultNumber = division_result_t<NumberType>>
Point< ResultNumber > pgl::BitMatrix< TPointType >::centroid ( ) const
inlinenodiscard

Centroid of the covered region.

Template Parameters
ResultNumberCoordinate type of the result; the default divides exactly, as every other pgl construction that divides does.
Exceptions
std::logic_errorIf no cell is set, since there is no centroid.
Warning
Divides coordinates by 2, and by the cell count on top of that. Inexact for integer coordinates.

◆ clear()

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::clear ( )
inline

Clears every cell, keeping the window.

◆ componentCount()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::componentCount ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Number of connected groups of cells.

A scanline flood fill, so this costs one pass over the words and a constant per run of cells, and never materializes a group.

◆ connectedComponents()

template<class TPointType = Point<int>>
std::vector< BitMatrix > pgl::BitMatrix< TPointType >::connectedComponents ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Returns one matrix per connected group of cells, each trimmed.

The groups come out ordered by their lowest, then leftmost cell.

Parameters
adjacencyWhich cells count as neighbors.

◆ contains()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::contains ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether the covered region contains the other one.

A cell the other matrix has and this one does not sticks out of this region, so this is exactly "every cell of @p other is a cell of this".

◆ convexHull()

template<class TPointType = Point<int>>
ConvexType pgl::BitMatrix< TPointType >::convexHull ( ) const
inlinenodiscard

Convex hull of the covered region.

◆ count()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::count ( ) const
inlinenodiscard

Number of set cells.

◆ difference()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::difference ( const BitMatrix< TPointType > & other) const
inlinenodiscard

The cells this matrix has and the other does not, over this window.

◆ empty()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::empty ( ) const
inlinenodiscard

Whether no cell is set, which an empty window always is.

◆ emptyWindow()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::emptyWindow ( ) const
inlinenodiscard

Whether the window itself is degenerate, so no cell can be set.

◆ end()

template<class TPointType = Point<int>>
Iterator pgl::BitMatrix< TPointType >::end ( ) const
inlinenodiscard

End of the iteration over the set lattice points.

◆ eulerNumber()

template<class TPointType = Point<int>>
std::int64_t pgl::BitMatrix< TPointType >::eulerNumber ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Euler characteristic of the covered region: components minus holes.

Counted from the sixteen patterns a two-by-two block of cells can show, so it costs one pass over the words and needs no flood fill.

Parameters
adjacencyWhich cells count as neighbors of the foreground.

◆ fbox()

template<class TPointType = Point<int>>
template<class ResultNumber = double>
Rectangle< Point< ResultNumber > > pgl::BitMatrix< TPointType >::fbox ( ) const
inlinenodiscard

A floating-point bounding box of the covered region.

Template Parameters
ResultNumberCoordinate type of the result.

◆ fillColumns()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::fillColumns ( )
inline

Fills the gaps of every column.

Returns
Whether any cell was filled in.

◆ fillHoles()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::fillHoles ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Returns the cells together with every hole they enclose.

A hole is a group of unset cells that cannot reach outside the bounding box. The background is walked with the adjacency complementary to adjacency – 8 for a 4-connected foreground and the other way round – which is what keeps a diagonal chain of cells from both being connected and letting the background leak through it.

Parameters
adjacencyWhich cells count as neighbors of the foreground.

◆ fillRows()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::fillRows ( )
inline

Fills the gaps of every row.

Returns
Whether any cell was filled in.

◆ flip() [1/3]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::flip ( const PointType & cell)
inline

Flips the cell; a cell outside the window is silently dropped.

◆ flip() [2/3]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::flip ( NumberType x,
NumberType y )
inline

Flips the cell; a cell outside the window is silently dropped.

◆ flip() [3/3]

template<class TPointType = Point<int>>
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
void pgl::BitMatrix< TPointType >::flip ( Range && points)
inline

Flips one cell per point of a range; cells outside the window are dropped.

The plural of flip(const PointType&), taking the same ranges the range set does and reading their points the same way: every point names the cell it is, over the window the matrix already has. A repeated point flips the same cell twice and so leaves it as it was, unlike the range set and reset, which repetition does not affect.

Template Parameters
RangeInput range of points, defaulting to an initializer list so that a braced list of cells works.
Parameters
pointsCells to flip.
Exceptions
std::logic_errorIf a coordinate is not a whole number this grid can hold.

◆ get() [1/2]

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::get ( const PointType & cell) const
inlinenodiscard

Whether the cell is set; cells outside the window are not.

◆ get() [2/2]

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::get ( NumberType x,
NumberType y ) const
inlinenodiscard

Whether the cell is set; cells outside the window are not.

◆ height()

template<class TPointType = Point<int>>
int pgl::BitMatrix< TPointType >::height ( ) const
inlinenodiscard

Number of rows of the window.

◆ holeCount()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::holeCount ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Number of holes the set cells enclose.

Parameters
adjacencyWhich cells count as neighbors of the foreground.

◆ interior()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::interior ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Returns the set cells all of whose neighbors are set.

A cell on the border of the window has neighbors outside it, which count as unset, so it never belongs to the interior.

Parameters
adjacencyWhich cells count as neighbors.

◆ interiorContains()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::interiorContains ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether the interior of the covered region contains the other one.

A cell of other whose closure touches the boundary of this region is not inside its interior, and touching includes meeting at a corner, so this asks whether interior(GridAdjacency::vertex) contains other.

◆ interiorsIntersect()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::interiorsIntersect ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether the interiors of the two covered regions share a point.

Two distinct cells have disjoint interiors, so this holds exactly when the matrices share a cell.

◆ intersects()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::intersects ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether the two covered regions share a point.

The cells are closed unit squares, so two of them meeting along an edge or at a single corner already intersect: this holds as soon as a cell of one matrix is within Chebyshev distance one of a cell of the other. Use interiorsIntersect for the stricter question of a shared cell.

◆ inWindow() [1/2]

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::inWindow ( const PointType & cell) const
inlinenodiscard

Whether a cell is inside the window, and so can be set.

◆ inWindow() [2/2]

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::inWindow ( NumberType x,
NumberType y ) const
inlinenodiscard

Whether a cell is inside the window, and so can be set.

◆ isColumnConvex()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::isColumnConvex ( ) const
inlinenodiscard

Whether every column meets the set cells in a single interval.

Read off the words rather than by filling a copy: sweeping the rows upwards, a column closes once a gap opens over a cell it has shown, and the answer is no as soon as a closed column shows another cell.

◆ isConnected()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::isConnected ( GridAdjacency adjacency = GridAdjacency::edge) const
inlinenodiscard

Whether the set cells form exactly one connected group.

◆ isHvConvex()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::isHvConvex ( ) const
inlinenodiscard

Whether every row and every column meets the cells in one interval.

◆ isRowConvex()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::isRowConvex ( ) const
inlinenodiscard

Whether every row meets the set cells in a single interval.

Read off the words rather than by filling a copy: a row is an interval exactly when it holds as many cells as lie between its first and its last.

◆ lattice()

template<class TPointType = Point<int>>
std::vector< PointType > pgl::BitMatrix< TPointType >::lattice ( ) const
inlinenodiscard

The set cells as lattice points, in row-major order.

The reading every lattice-prefixed operation works in: a cell stands for the point at its lower-left corner, which is also the name get and set address it by, and what the iterators yield. cells is the same list read as the squares the cells cover.

◆ latticeClosing()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeClosing ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the closing, a lattice sum with other followed by a lattice erosion.

◆ latticeMinkowskiErosion()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeMinkowskiErosion ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the Minkowski erosion {p : p + other is inside *this}.

Like operator~, this reads the window: a cell outside it counts as unset, so the erosion is taken against this matrix as a bounded set. The window of the result is this window shrunk by the bounding box of other, which is the largest window a translate of other can land in. Eroding by a matrix with no cell is vacuously true everywhere, and fills the whole window.

◆ latticeMinkowskiSum()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeMinkowskiSum ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the Minkowski sum {a + b : a in *this, b in other}.

The window of the result is exactly the bounding box of the sum. The cost is one shifted or-assignment of the larger operand per cell of the smaller one, so summing a large region with a small structuring element is cheap.

◆ latticeOpening()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeOpening ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the opening, a lattice erosion by other followed by a lattice sum.

◆ latticeReflected()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeReflected ( ) const
inlinenodiscard

Returns the reflection of the cells as lattice points, {-c}.

The reflection latticeMinkowskiErosion is dual to: it is what makes ~(~a).latticeMinkowskiSum(b.latticeReflected()) and a.latticeMinkowskiErosion(b) the same question over a common window. It sits one cell from reflected, which reflects the squares instead.

◆ latticeReflectedX()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeReflectedX ( ) const
inlinenodiscard

Returns the reflection of the cells as lattice points, {(x, -y)}.

◆ latticeReflectedY()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeReflectedY ( ) const
inlinenodiscard

Returns the reflection of the cells as lattice points, {(-x, y)}.

◆ latticeRotate90()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::latticeRotate90 ( int k = 1)
inline

Rotates the cells as lattice points.

Parameters
kNumber of counterclockwise quarter turns; may be negative.

◆ latticeRotated90()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeRotated90 ( int k = 1) const
inlinenodiscard

Returns the rotation of the cells as lattice points.

Parameters
kNumber of counterclockwise quarter turns; may be negative.

◆ latticeTransposed()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::latticeTransposed ( ) const
inlinenodiscard

Returns {(y, x)}; the same as transposed, which the two readings agree on.

◆ latticeView()

template<class TPointType = Point<int>>
auto pgl::BitMatrix< TPointType >::latticeView ( ) const
inlinenodiscard

Returns a lazy view of the set cells as lattice points.

The iteration range itself: it yields every set cell as a const reference to its lower-left corner, in row-major order, copying and allocating nothing. It refers to this matrix and is invalidated by anything that modifies it; lattice materializes the same cells into a vector.

Returns
A forward view of the count() set cells.

◆ makeHvConvex()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::makeHvConvex ( )
inline

Fills every cell that has set cells on both sides in its row and in its column, until nothing changes.

The result is the smallest hv-convex superset: every row and every column of it meets it in a single interval. Only cells strictly between set cells are added, so the window is never outgrown and the loop terminates.

Returns
The number of cells that were filled in.

◆ minkowskiErosion()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::minkowskiErosion ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the regularized Minkowski erosion of the covered regions.

The erosion the shapes compute, regularized as PolygonSet regularizes its own, so this commutes with the conversion: a.minkowskiErosion(b).asPolygonSet() and a.asPolygonSet().minkowskiErosion(b.asPolygonSet()) agree.

Regularizing is what keeps the answer on the grid. Writing the operand as B = latB (+) U, the erosion splits into (A (-) latB) (-) U, and the first step is the lattice erosion, which is a cell region. For the second, a non-integer p has p + U inside a cell region exactly when the two-by-two block of cells it straddles is, so the interior of the result is a union of open cells and its closure is the lattice erosion by that block. What regularizing drops is the lower-dimensional part: eroding a single cell by a single cell leaves the one point p = 0, which the shapes report as a degenerate HalfplaneIntersection and this reports as empty.

The two steps compose into one, so the cost is a single lattice erosion by other dilated with the two-by-two block. Eroding by a matrix with no cell is the whole plane, which no window holds; this fills the window, as latticeMinkowskiErosion does.

◆ minkowskiSum()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::minkowskiSum ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the Minkowski sum of the two covered regions.

The sum the shapes compute, so this commutes with the conversion: (a + b).asPolygonSet() and a.asPolygonSet() + b.asPolygonSet() agree. The unit square is not the identity of that sum – U (+) U is the two-by-two square [0,2]^2 – so this is latticeMinkowskiSum followed by a dilation with the two-by-two block of cells that the extra square covers, leaving the result one cell wider and one cell taller than the lattice sum. Reach for latticeMinkowskiSum in morphology, where a single cell has to be the identity.

◆ operator&()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator& ( const BitMatrix< TPointType > & other) const
inline

The cells both matrices have, over the overlap of the windows.

◆ operator&=()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::operator&= ( const BitMatrix< TPointType > & other)
inline

Drops every cell the other matrix does not have.

◆ operator+() [1/2]

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator+ ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Returns the Minkowski sum of the regions; the same as minkowskiSum.

◆ operator+() [2/2]

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator+ ( const PointType & vector) const
inline

Returns the same cells translated by a vector.

◆ operator+=()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::operator+= ( const PointType & vector)
inline

Translates the cells by a vector.

◆ operator-() [1/2]

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator- ( ) const
inlinenodiscard

Returns the reflection of the covered region through the origin.

◆ operator-() [2/2]

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator- ( const PointType & vector) const
inline

Returns the same cells translated by the opposite of a vector.

◆ operator-=()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::operator-= ( const PointType & vector)
inline

Translates the cells by the opposite of a vector.

◆ operator<=>()

template<class TPointType = Point<int>>
std::strong_ordering pgl::BitMatrix< TPointType >::operator<=> ( const BitMatrix< TPointType > & other) const
inline

Orders matrices lexicographically by (origin, width, height, bits).

A total order consistent with operator==, so a matrix can key a std::set or a std::map. It is an order on the representation and carries no geometric meaning: two matrices covering the same region over different windows are ordered by their windows.

◆ operator==()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::operator== ( const BitMatrix< TPointType > & other) const
inline

Whether the two matrices have the same window and the same cells.

Compares the stored representation, as a shape's operator== does. Use samePointSet to ask whether they cover the same region regardless of the window.

◆ operator^()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator^ ( const BitMatrix< TPointType > & other) const
inline

The cells exactly one matrix has, over the hull of the windows.

◆ operator^=()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::operator^= ( const BitMatrix< TPointType > & other)
inline

Flips every cell the other matrix has and this window holds.

◆ operator|()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator| ( const BitMatrix< TPointType > & other) const
inline

The cells either matrix has, over the hull of the windows.

◆ operator|=()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::operator|= ( const BitMatrix< TPointType > & other)
inline

Adds every cell of the other matrix that this window holds.

◆ operator~()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::operator~ ( ) const
inline

Returns the complement within the same window.

The window is unchanged, so this is the complement of the set cells inside it, not of the whole plane. Together with latticeMinkowskiErosion, which is built on it, this is the only operation that reads the window rather than only the cells.

◆ orCount()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::orCount ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Number of cells set in either matrix.

◆ origin()

template<class TPointType = Point<int>>
const PointType & pgl::BitMatrix< TPointType >::origin ( ) const
inlinenodiscard

Lower-left cell of the window.

◆ perimeter()

template<class TPointType = Point<int>>
template<class ResultNumber = NumberType>
ResultNumber pgl::BitMatrix< TPointType >::perimeter ( ) const
inlinenodiscard

Length of the boundary of the covered region.

Counts the unit edges with a set cell on exactly one side, so a cell on the border of the window contributes the edges facing out of it. Runs a word at a time.

Template Parameters
ResultNumberResult type (default: NumberType).

◆ pointInside()

template<class TPointType = Point<int>>
template<class ResultNumber = division_result_t<NumberType>>
Point< ResultNumber > pgl::BitMatrix< TPointType >::pointInside ( ) const
inlinenodiscard

A point in the interior of the covered region.

The center of the first set cell in row-major order.

Template Parameters
ResultNumberCoordinate type of the result.
Exceptions
std::logic_errorIf no cell is set, since there is no such point.
Warning
Divides coordinates by 2.

◆ rectangles()

template<class TPointType = Point<int>>
std::vector< RectangleType > pgl::BitMatrix< TPointType >::rectangles ( ) const
inlinenodiscard

The covered region as maximal horizontal runs of cells.

The rectangles are disjoint and cover exactly the set cells, one per maximal run, in row-major order. Streaming them into a Canvas draws the matrix: canvas << matrix.rectangles().

◆ reflected()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::reflected ( ) const
inlinenodiscard

Returns the reflection of the covered region through the origin.

A symmetry of the plane, so it acts on the cells as the squares they are: the square of cell c reflects onto the square of cell -c - (1,1), and the result is what reflecting asPolygonSet() gives. latticeReflected is the reflection of the lattice points, which lands one cell away.

◆ reflectedX()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::reflectedX ( ) const
inlinenodiscard

Returns the reflection of the covered region across the x-axis.

◆ reflectedY()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::reflectedY ( ) const
inlinenodiscard

Returns the reflection of the covered region across the y-axis.

◆ reset() [1/3]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::reset ( const PointType & cell)
inline

Clears the cell; a cell outside the window is silently dropped.

◆ reset() [2/3]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::reset ( NumberType x,
NumberType y )
inline

Clears the cell; a cell outside the window is silently dropped.

◆ reset() [3/3]

template<class TPointType = Point<int>>
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
void pgl::BitMatrix< TPointType >::reset ( Range && points)
inline

Clears one cell per point of a range; cells outside the window are dropped.

The plural of reset(const PointType&), taking the same ranges the range set does and reading their points the same way: every point names the cell it is, over the window the matrix already has. Repeated points clear the same cell again, which changes nothing.

Template Parameters
RangeInput range of points, defaulting to an initializer list so that a braced list of cells works.
Parameters
pointsCells to clear.
Exceptions
std::logic_errorIf a coordinate is not a whole number this grid can hold.

◆ resized()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::resized ( const RectangleType & box) const
inlinenodiscard

Returns the same cells over another window, dropping those outside.

Parameters
boxWindow of the result, read as BitMatrix(const RectangleType&) reads it.

◆ rotate90()

template<class TPointType = Point<int>>
BitMatrix & pgl::BitMatrix< TPointType >::rotate90 ( int k = 1)
inline

Rotates the covered region about the origin.

Parameters
kNumber of counterclockwise quarter turns; may be negative.

◆ rotated90()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::rotated90 ( int k = 1) const
inlinenodiscard

Returns the rotation of the covered region about the origin.

Parameters
kNumber of counterclockwise quarter turns; may be negative.

◆ samePointSet()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::samePointSet ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether the two matrices cover the same region.

Reads only the cells, so a matrix and its trimmed copy agree, unlike operator==, which compares the window too.

◆ sameWindow()

template<class TPointType = Point<int>>
bool pgl::BitMatrix< TPointType >::sameWindow ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Whether two matrices cover the same window.

◆ set() [1/4]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::set ( const PointType & cell)
inline

Sets the cell; a cell outside the window is silently dropped.

◆ set() [2/4]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::set ( NumberType x,
NumberType y )
inline

Sets the cell; a cell outside the window is silently dropped.

◆ set() [3/4]

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::set ( NumberType x,
NumberType y,
bool value )
inline

Sets or clears the cell; a cell outside the window is dropped.

◆ set() [4/4]

template<class TPointType = Point<int>>
template<std::ranges::input_range Range = std::initializer_list<PointType>>
requires (detail::is_point_v<std::remove_cvref_t<std::ranges::range_value_t<Range>>> && !AnyShapeConcept<std::remove_cvref_t
<Range>> && !detail::is_bit_matrix_v<std::remove_cvref_t<Range>>)
void pgl::BitMatrix< TPointType >::set ( Range && points)
inline

Sets one cell per point of a range; cells outside the window are dropped.

Every point names the cell it is, the lattice-point reading the range constructor takes, except that the window here is the one the matrix already has. Repeated points set the same cell again, which changes nothing.

Any range of points does, except a shape or another matrix, exactly as for that constructor: a shape that iterates over its vertices is a boundary and not a point cloud. The points may carry any coordinate type, checked rather than rounded.

Template Parameters
RangeInput range of points, defaulting to an initializer list so that a braced list of cells works.
Parameters
pointsCells to set.
Exceptions
std::logic_errorIf a coordinate is not a whole number this grid can hold.

◆ setAll()

template<class TPointType = Point<int>>
void pgl::BitMatrix< TPointType >::setAll ( )
inline

Sets every cell of the window.

◆ symmetricDifference()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::symmetricDifference ( const BitMatrix< TPointType > & other) const
inlinenodiscard

The cells exactly one matrix has; the same as operator^.

◆ translated()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::translated ( const PointType & vector) const
inlinenodiscard

Returns the same cells translated by a vector.

◆ transposed()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::transposed ( ) const
inlinenodiscard

Returns the reflection of the covered region across the diagonal.

Swapping the coordinates carries the square of cell (x, y) onto the square of cell (y, x), so this is the one symmetry the two readings agree on; latticeTransposed is the same operation under its lattice name.

◆ trimmed()

template<class TPointType = Point<int>>
BitMatrix pgl::BitMatrix< TPointType >::trimmed ( ) const
inlinenodiscard

Returns the same cells over the smallest window holding them.

The result has window() == bbox(), so its origin is the lower-left corner of its own bounding box.

◆ width()

template<class TPointType = Point<int>>
int pgl::BitMatrix< TPointType >::width ( ) const
inlinenodiscard

Number of cells per row of the window.

◆ window()

template<class TPointType = Point<int>>
RectangleType pgl::BitMatrix< TPointType >::window ( ) const
inlinenodiscard

The window, as the rectangle its cells cover.

◆ xorCount()

template<class TPointType = Point<int>>
std::size_t pgl::BitMatrix< TPointType >::xorCount ( const BitMatrix< TPointType > & other) const
inlinenodiscard

Number of cells set in exactly one matrix.

◆ operator<<

template<class TPointType = Point<int>>
Canvas & operator<< ( Canvas & canvas,
const BitMatrix< TPointType > & matrix )
friend

Draws the covered region to a canvas.

Sends asPolygonSet with the current style, so the whole matrix is a single element however many components it has, with its holes as holes. Stream rectangles instead to draw the cells as separate elements.

Parameters
canvasDestination canvas.
matrixMatrix whose covered region is drawn.
Returns
The canvas.