21#include <geos/geom/Envelope.h>
23namespace geos::operation::grid {
26 static constexpr size_t padding = 1;
31 static constexpr size_t padding = 0;
41template<
typename extent_tag>
52 , m_xOrig { extent.getMinX() }
53 , m_yOrig { extent.getMaxY() }
54 , m_num_rows{ 2 * extent_tag::padding + (extent.getMaxY() > extent.getMinY() ? static_cast<size_t>(std::round(extent.getHeight() / dy)) : 0) }
55 , m_num_cols{ 2 * extent_tag::padding + (extent.getMaxX() > extent.getMinX() ? static_cast<size_t>(std::round(extent.getWidth() / dx)) : 0) } {
56 static_assert(std::is_same_v<extent_tag, bounded_extent>);
66 , m_xOrig { extent.getMinX() }
67 , m_yOrig { extent.getMaxY() }
68 , m_num_rows{ 2 * extent_tag::padding + (extent.getMaxY() > extent.getMinY() ? static_cast<size_t>(std::round(extent.getHeight() / dy)) : 0) }
69 , m_num_cols{ 2 * extent_tag::padding + (extent.getMaxX() > extent.getMinX() ? static_cast<size_t>(std::round(extent.getWidth() / dx)) : 0) }
71 static_assert(std::is_same_v<extent_tag, infinite_extent>);
75 static Grid makeEmpty()
77 if constexpr (std::is_same_v<extent_tag, bounded_extent>) {
78 return Grid({ 0, 0, 0, 0 }, 0, 0);
80 return Grid({ 0, 0, 0, 0 }, 0, 0, geom::Envelope());
87 if (extent_tag::padding) {
88 if (x < m_extent.getMinX())
90 if (x > m_extent.getMaxX())
91 return m_num_cols - 1;
92 if (x == m_extent.getMaxX())
93 return m_num_cols - 2;
95 if (x < m_extent.getMinX() || x > m_extent.getMaxX())
96 throw std::out_of_range(
"x");
98 if (x == m_extent.getMaxX())
99 return m_num_cols - 1;
106 extent_tag::padding +
static_cast<size_t>(std::floor((x - m_extent.getMinX()) / m_dx)),
107 getColumn(m_extent.getMaxX()));
113 if (extent_tag::padding) {
114 if (y > m_extent.getMaxY())
116 if (y < m_extent.getMinY())
117 return m_num_rows - 1;
118 if (y == m_extent.getMinY())
119 return m_num_rows - 2;
121 if (y < m_extent.getMinY() || y > m_extent.getMaxY())
122 throw std::out_of_range(
"y");
124 if (y == m_extent.getMinY())
125 return m_num_rows - 1;
132 extent_tag::padding +
static_cast<size_t>(std::floor((m_extent.getMaxY() - y) / m_dy)),
133 getRow(m_extent.getMinY()));
140 return getRow(y) * getNumCols() + getColumn(x);
143 bool isEmpty()
const {
return m_num_rows <= 2 * extent_tag::padding && m_num_cols <= 2 * extent_tag::padding; }
145 size_t getNumRows()
const {
return m_num_rows; }
147 size_t getNumCols()
const {
return m_num_cols; }
149 size_t getSize()
const {
return getNumRows() * getNumCols(); }
151 double xmin()
const {
return m_extent.getMinX(); }
153 double xmax()
const {
return m_extent.getMaxX(); }
155 double ymin()
const {
return m_extent.getMinY(); }
157 double ymax()
const {
return m_extent.getMaxY(); }
159 double dx()
const {
return m_dx; }
161 double dy()
const {
return m_dy; }
163 const geom::Envelope& getExtent()
const {
return m_extent; }
168 size_t getRowOffset(
const Grid& other)
const {
return static_cast<size_t>(std::round(std::abs(other.m_extent.
getMaxY() - m_extent.getMaxY()) / m_dy)); }
173 size_t getColOffset(
const Grid& other)
const {
return static_cast<size_t>(std::round(std::abs(m_extent.getMinX() - other.m_extent.
getMinX()) / m_dx)); }
176 double getColX(
size_t col)
const {
return m_extent.getMinX() + (
static_cast<double>(col - extent_tag::padding) + 0.5) * m_dx; }
179 double getRowY(
size_t row)
const {
return m_extent.getMaxY() - (
static_cast<double>(row - extent_tag::padding) + 0.5) * m_dy; }
183 if (m_extent.intersects(e)) {
200 if (b.
getMinX() < m_extent.getMinX() || b.
getMinY() < m_extent.getMinY() || b.
getMaxX() > m_extent.getMaxX() || b.
getMaxY() > m_extent.getMaxY()) {
201 throw std::range_error(
"Cannot shrink extent to bounds larger than original.");
204 size_t col0 = getColumn(b.
getMinX());
205 size_t row1 = getRow(b.
getMaxY());
208 double snapped_xmin = m_extent.getMinX() +
static_cast<double>(col0 - extent_tag::padding) * m_dx;
209 double snapped_ymax = m_extent.getMaxY() -
static_cast<double>(row1 - extent_tag::padding) * m_dy;
213 if (b.
getMinX() < snapped_xmin) {
214 snapped_xmin -= m_dx;
218 if (b.
getMaxY() > snapped_ymax) {
219 snapped_ymax += m_dy;
223 size_t col1 = getColumn(b.
getMaxX());
224 size_t row0 = getRow(b.
getMinY());
226 size_t num_rows = 1 + (row0 - row1);
227 size_t num_cols = 1 + (col1 - col0);
234 if (num_rows > 2 && (snapped_ymax -
static_cast<double>(num_rows - 1) * m_dy <= b.
getMinY())) {
237 if (num_cols > 2 && (snapped_xmin +
static_cast<double>(num_cols - 1) * m_dx >= b.
getMaxX())) {
241 const double snapped_xmax = m_extent.getMinX() +
static_cast<double>(col0 + num_cols - extent_tag::padding) * m_dx;
242 const double snapped_ymin = m_extent.getMaxY() -
static_cast<double>(row1 + num_rows - extent_tag::padding) * m_dy;
250 calcExtentFromNewGrid ? std::max(snapped_xmin +
static_cast<double>(num_cols) * m_dx, b.
getMaxX()) : snapped_xmax,
251 calcExtentFromNewGrid ? std::min(snapped_ymax -
static_cast<double>(num_rows) * m_dy, b.
getMinY()) : snapped_ymin,
257 if (reduced_box.
getMaxX() > m_extent.getMaxX()) {
258 if (std::round(reduced_box.
getWidth() / m_dx) ==
259 std::round((m_extent.getMaxX() - reduced_box.
getMinX()) / m_dx)) {
262 throw std::runtime_error(
"Shrink operation failed.");
265 if (reduced_box.
getMinY() < m_extent.getMinY()) {
266 if (std::round(reduced_box.
getHeight() / m_dy) ==
267 std::round((reduced_box.
getMaxY() - m_extent.getMinY()) / m_dy)) {
270 throw std::runtime_error(
"Shrink operation failed.");
274 if constexpr (std::is_same_v<extent_tag, bounded_extent>) {
277 if (!calcExtentFromNewGrid) {
278 reduced.m_xOrig = m_xOrig;
279 reduced.m_yOrig = m_yOrig;
280 reduced.m_skipRows = reduced.getRowOffset(*
this);
281 reduced.m_skipCols = reduced.getColOffset(*
this);
282 }
else if (!reduced.getExtent().contains(b)) {
283 throw std::runtime_error(
"Shrink operation failed.");
289 if (!calcExtentFromNewGrid) {
290 reduced.m_xOrig = m_xOrig;
291 reduced.m_yOrig = m_yOrig;
292 reduced.m_skipRows = reduced.getRowOffset(*
this);
293 reduced.m_skipCols = reduced.getColOffset(*
this);
294 }
else if (!reduced.getExtent().contains(b)) {
295 throw std::runtime_error(
"Shrink operation failed.");
303 return m_extent == b.m_extent &&
308 bool operator!=(
const Grid<extent_tag>& b)
const
310 return !(*
this == b);
326 size_t m_skipRows{0};
327 size_t m_skipCols{0};
332 friend Grid<infinite_extent> make_infinite(
const Grid<bounded_extent>&,
const geom::Envelope&);
333 friend Grid<bounded_extent> make_finite(
const Grid<infinite_extent>&);
337make_infinite(
const Grid<bounded_extent>& grid,
const geom::Envelope& domain);
339make_finite(
const Grid<infinite_extent>& grid);
An Envelope defines a rectangulare region of the 2D coordinate plane.
Definition: Envelope.h:59
double getMinX() const
Returns the Envelope minimum x-value. Null envelopes do not have maximum values.
Definition: Envelope.h:350
bool intersection(const Envelope &env, Envelope &result) const
Computes the intersection of two Envelopes.
double getArea() const
Gets the area of this envelope.
Definition: Envelope.h:290
double getHeight() const
Returns the difference between the maximum and minimum y values.
Definition: Envelope.h:275
double getWidth() const
Returns the difference between the maximum and minimum x values.
Definition: Envelope.h:262
double getMaxX() const
Returns the Envelope maximum x-value. Null envelopes do not have maximum values.
Definition: Envelope.h:330
double getMaxY() const
Returns the Envelope maximum y-value. Null envelopes do not have maximum values.
Definition: Envelope.h:320
double getMinY() const
Returns the Envelope minimum y-value. Null envelopes do not have maximum values.
Definition: Envelope.h:340
The Grid class represents a grid of constant-size rectangular cells that covers a specified envelope....
Definition: Grid.h:43
Grid< extent_tag > shrinkToFit(const geom::Envelope &b, bool calcExtentFromNewGrid=true) const
Definition: Grid.h:194
double getColX(size_t col) const
Get the x coordinate at the center of the specified column.
Definition: Grid.h:176
Grid(const geom::Envelope &extent, double dx, double dy, const geom::Envelope &domain)
Definition: Grid.h:61
Grid(const geom::Envelope &extent, double dx, double dy)
Construct a bounded grid covering a specified extent.
Definition: Grid.h:47
size_t getColumn(double x) const
Get the column in which the specified x coordinate would fall.
Definition: Grid.h:85
size_t getColOffset(const Grid &other) const
Definition: Grid.h:173
size_t getRow(double y) const
Get the row in which the specified y coordinate would fall.
Definition: Grid.h:111
double getRowY(size_t row) const
Get the y coordinate at the center of the specified row.
Definition: Grid.h:179
size_t getRowOffset(const Grid &other) const
Definition: Grid.h:168
std::size_t getCell(double x, double y) const
Definition: Grid.h:138