GEOS 3.15.0dev
FloodFill.h
1/**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (C) 2018-2025 ISciences, LLC
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU Lesser General Public Licence as published
10 * by the Free Software Foundation.
11 * See the COPYING file for more information.
12 *
13 **********************************************************************/
14
15#pragma once
16
17#include <geos/operation/grid/Grid.h>
18#include <geos/operation/grid/Matrix.h>
19
20#include <queue>
21
22namespace geos::geom {
23 class Geometry;
24}
25
27 class PointOnGeometryLocator;
28}
29
30namespace geos::operation::grid {
31
32template<typename T>
33struct fill_values
34{
35 static T EXTERIOR;
36};
37
38template<>
39struct fill_values<float>
40{
41 static constexpr float EXTERIOR{ 0.0f }; // Cell is known to be entirely outside the polygon
42 static constexpr float INTERIOR{ 1.0f }; // Cell is known to be entirely within the polygon
43 static constexpr float FILLABLE{ -1.0f }; // Cell location relative to polygon unknown, but
44 // can be determined by fill.
45 static constexpr float UNKNOWN{ -2.0f }; // Cell location relative to polygon unknown
46 // and cannot be determined from a flood fill
47 // (must be explicitly tested)
48};
49
50class FloodFill
51{
52
53 public:
54 FloodFill(const geom::Geometry& g, const Grid<bounded_extent>& extent);
55
56 ~FloodFill();
57
58 template<typename T>
59 void flood(Matrix<T>& arr) const;
60
61 bool cellIsInside(size_t i, size_t j) const;
62
63 private:
64 Grid<bounded_extent> m_extent;
65 const geom::Geometry& m_g;
66 std::unique_ptr<algorithm::locate::PointOnGeometryLocator> m_loc;
67};
68
69template<typename T>
70void
71floodFromPixel(Matrix<T>& arr, size_t i, size_t j, T fill_value)
72{
73 std::queue<std::pair<size_t, size_t>> locations;
74
75 locations.emplace(i, j);
76
77 while (!locations.empty()) {
78 i = locations.front().first;
79 j = locations.front().second;
80 locations.pop();
81
82 if (arr(i, j) == fill_value) {
83 continue;
84 }
85
86 // Left
87 if (j > 0 && arr(i, j - 1) == fill_values<T>::FILLABLE) {
88 locations.emplace(i, j - 1);
89 }
90
91 auto j0 = j;
92
93 // Fill along this row until we hit something
94 for (; j < arr.getNumCols() && arr(i, j) == fill_values<T>::FILLABLE; j++) {
95 arr(i, j) = fill_value;
96 }
97
98 auto j1 = j;
99
100 // Initiate scanlines above our current row
101 if (i > 0) {
102 for (j = j0; j < j1; j++) {
103 // Up
104 if (arr(i - 1, j) == fill_values<T>::FILLABLE) {
105 locations.emplace(i - 1, j);
106 }
107 }
108 }
109
110 // Initiate scanlines below our current row
111 if (i < arr.getNumRows() - 1) {
112 for (j = j0; j < j1; j++) {
113 // Down
114 if (arr(i + 1, j) == fill_values<T>::FILLABLE) {
115 locations.emplace(i + 1, j);
116 }
117 }
118 }
119 }
120}
121
122template<typename T>
123void
124FloodFill::flood(Matrix<T>& arr) const
125{
126
127 for (size_t i = 0; i < arr.getNumRows(); i++) {
128 for (size_t j = 0; j < arr.getNumCols(); j++) {
129 if (arr(i, j) == fill_values<T>::UNKNOWN) {
130 throw std::runtime_error("Cell with unknown position encountered.");
131 } else if (arr(i, j) == fill_values<T>::FILLABLE) {
132 // Cell position relative to polygon is unknown but can
133 // be determined from adjacent cells.
134 if (cellIsInside(i, j)) {
135 floodFromPixel(arr, i, j, fill_values<T>::INTERIOR);
136 } else {
137 floodFromPixel(arr, i, j, fill_values<T>::EXTERIOR);
138 }
139 }
140 }
141 }
142}
143
144}
Classes which determine the Location of points in geometries.
Definition IndexedPointInAreaLocator.h:40
Definition Angle.h:26