/src/s2geometry/src/s2/s2region_coverer.h
Line | Count | Source |
1 | | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // Author: ericv@google.com (Eric Veach) |
17 | | |
18 | | #ifndef S2_S2REGION_COVERER_H_ |
19 | | #define S2_S2REGION_COVERER_H_ |
20 | | |
21 | | #include <algorithm> |
22 | | #include <cstddef> |
23 | | #include <new> |
24 | | #include <queue> |
25 | | #include <utility> |
26 | | #include <vector> |
27 | | |
28 | | #include "absl/base/casts.h" |
29 | | #include "absl/base/macros.h" |
30 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
31 | | #include "s2/s2cell.h" |
32 | | #include "s2/s2cell_id.h" |
33 | | #include "s2/s2cell_union.h" |
34 | | #include "s2/s2point.h" |
35 | | #include "s2/s2region.h" |
36 | | |
37 | | class S2Region; |
38 | | |
39 | | // An S2RegionCoverer is a class that allows arbitrary regions to be |
40 | | // approximated as unions of cells (S2CellUnion). This is useful for |
41 | | // implementing various sorts of search and precomputation operations. |
42 | | // |
43 | | // Typical usage: |
44 | | // |
45 | | // S2RegionCoverer::Options options; |
46 | | // options.set_max_cells(5); |
47 | | // S2RegionCoverer coverer(options); |
48 | | // S2Cap cap(center, radius); |
49 | | // S2CellUnion covering = coverer.GetCovering(cap); |
50 | | // |
51 | | // This yields a vector of at most 5 cells that is guaranteed to cover the |
52 | | // given cap (a disc-shaped region on the sphere). |
53 | | // |
54 | | // The approximation algorithm is not optimal but does a pretty good job in |
55 | | // practice. The output does not always use the maximum number of cells |
56 | | // allowed, both because this would not always yield a better approximation, |
57 | | // and because max_cells() is a limit on how much work is done exploring the |
58 | | // possible covering as well as a limit on the final output size. |
59 | | // |
60 | | // Because it is an approximation algorithm, one should not rely on the |
61 | | // stability of the output. In particular, the output of the covering algorithm |
62 | | // may change across different versions of the library. |
63 | | // |
64 | | // One can also generate interior coverings, which are sets of cells which |
65 | | // are entirely contained within a region. Interior coverings can be |
66 | | // empty, even for non-empty regions, if there are no cells that satisfy |
67 | | // the provided constraints and are contained by the region. Note that for |
68 | | // performance reasons, it is wise to specify a max_level when computing |
69 | | // interior coverings - otherwise for regions with small or zero area, the |
70 | | // algorithm may spend a lot of time subdividing cells all the way to leaf |
71 | | // level to try to find contained cells. |
72 | | class S2RegionCoverer { |
73 | | public: |
74 | | class Options { |
75 | | public: |
76 | | // Sets the desired maximum number of cells in the approximation. Note |
77 | | // the following: |
78 | | // |
79 | | // - For any setting of max_cells(), up to 6 cells may be returned if |
80 | | // that is the minimum number required (e.g. if the region intersects |
81 | | // all six cube faces). Even for very tiny regions, up to 3 cells may |
82 | | // be returned if they happen to be located at the intersection of |
83 | | // three cube faces. |
84 | | // |
85 | | // - min_level() takes priority over max_cells(), i.e. cells below the |
86 | | // given level will never be used even if this causes a large number of |
87 | | // cells to be returned. |
88 | | // |
89 | | // - If max_cells() is less than 4, the area of the covering may be |
90 | | // arbitrarily large compared to the area of the original region even |
91 | | // if the region is convex (e.g. an S2Cap or S2LatLngRect). |
92 | | // |
93 | | // Accuracy is measured by dividing the area of the covering by the area |
94 | | // of the original region. The following table shows the median and worst |
95 | | // case values for this area ratio on a test case consisting of 100,000 |
96 | | // spherical caps of random size (generated using s2region_coverer_test): |
97 | | // |
98 | | // max_cells: 3 4 5 6 8 12 20 100 1000 |
99 | | // median ratio: 5.33 3.32 2.73 2.34 1.98 1.66 1.42 1.11 1.01 |
100 | | // worst case: 215518 14.41 9.72 5.26 3.91 2.75 1.92 1.20 1.02 |
101 | | // |
102 | | // The default value of 8 gives a reasonable tradeoff between the number |
103 | | // of cells used and the accuracy of the approximation. |
104 | | // |
105 | | // DEFAULT: kDefaultMaxCells |
106 | | static constexpr int kDefaultMaxCells = 8; |
107 | 0 | int max_cells() const { return max_cells_; } |
108 | | void set_max_cells(int max_cells); |
109 | | |
110 | | // Sets the minimum and maximum cell levels to be used. The default is to |
111 | | // use all cell levels. |
112 | | // |
113 | | // To find the cell level corresponding to a given physical distance, use |
114 | | // the S2Cell metrics defined in s2metrics.h. For example, to find the |
115 | | // cell level that corresponds to an average edge length of 10km, use: |
116 | | // |
117 | | // int level = |
118 | | // S2::kAvgEdge.GetClosestLevel(S2Earth::KmToRadians(length_km)); |
119 | | // |
120 | | // Note that min_level() takes priority over max_cells(), i.e. cells below |
121 | | // the given level will never be used even if this causes a large number |
122 | | // of cells to be returned. (This doesn't apply to interior coverings, |
123 | | // since interior coverings make no completeness guarantees -- the result |
124 | | // is simply a set of cells that covers as much of the interior as |
125 | | // possible while satisfying the given restrictions.) |
126 | | // |
127 | | // REQUIRES: min_level() <= max_level() |
128 | | // DEFAULT: 0 |
129 | 0 | int min_level() const { return min_level_; } |
130 | | void set_min_level(int min_level); |
131 | | |
132 | | // REQUIRES: min_level() <= max_level() |
133 | | // DEFAULT: S2CellId::kMaxLevel |
134 | 0 | int max_level() const { return max_level_; } |
135 | | void set_max_level(int max_level); |
136 | | |
137 | | // Convenience function that sets both the maximum and minimum cell levels. |
138 | | void set_fixed_level(int level); |
139 | | |
140 | | // If specified, then only cells where (level - min_level) is a multiple |
141 | | // of "level_mod" will be used (default 1). This effectively allows the |
142 | | // branching factor of the S2CellId hierarchy to be increased. Currently |
143 | | // the only parameter values allowed are 1, 2, or 3, corresponding to |
144 | | // branching factors of 4, 16, and 64 respectively. |
145 | | // |
146 | | // DEFAULT: 1 |
147 | 0 | int level_mod() const { return level_mod_; } |
148 | | void set_level_mod(int level_mod); |
149 | | |
150 | | // Convenience function that returns the maximum level such that |
151 | | // |
152 | | // (level <= max_level()) && (level - min_level()) % level_mod() == 0. |
153 | | // |
154 | | // This is the maximum level that will actually be used in coverings. |
155 | | int true_max_level() const; |
156 | | |
157 | | protected: |
158 | | int max_cells_ = kDefaultMaxCells; |
159 | | int min_level_ = 0; |
160 | | int max_level_ = S2CellId::kMaxLevel; |
161 | | int level_mod_ = 1; |
162 | | }; |
163 | | |
164 | | // Constructs an S2RegionCoverer with the given options. |
165 | | explicit S2RegionCoverer(const Options& options); |
166 | | |
167 | | // S2RegionCoverer is movable but not copyable. |
168 | | S2RegionCoverer(const S2RegionCoverer&) = delete; |
169 | | S2RegionCoverer& operator=(const S2RegionCoverer&) = delete; |
170 | | S2RegionCoverer(S2RegionCoverer&&) noexcept; |
171 | | S2RegionCoverer& operator=(S2RegionCoverer&&) noexcept; |
172 | | |
173 | | // Default constructor. Options can be set using mutable_options(). |
174 | | S2RegionCoverer(); |
175 | | ~S2RegionCoverer(); |
176 | | |
177 | | // Returns the current options. Options can be modified between calls. |
178 | 0 | const Options& options() const { return options_; } |
179 | 0 | Options* mutable_options() { return &options_; } |
180 | | |
181 | | // Returns an S2CellUnion that covers (GetCovering) or is contained within |
182 | | // (GetInteriorCovering) the given region and satisfies the current options. |
183 | | // |
184 | | // Note that if options().min_level() > 0 or options().level_mod() > 1, then |
185 | | // by definition the S2CellUnion may not be normalized, i.e. there may be |
186 | | // groups of four child cells that can be replaced by their parent cell. |
187 | | S2CellUnion GetCovering(const S2Region& region); |
188 | | S2CellUnion GetInteriorCovering(const S2Region& region); |
189 | | |
190 | | // Like the methods above, but works directly with a vector of S2CellIds. |
191 | | // This version can be more efficient when this method is called many times, |
192 | | // since it does not require allocating a new vector on each call. |
193 | | void GetCovering(const S2Region& region, std::vector<S2CellId>* covering); |
194 | | void GetInteriorCovering(const S2Region& region, |
195 | | std::vector<S2CellId>* interior); |
196 | | |
197 | | // Like GetCovering(), except that this method is much faster and the |
198 | | // coverings are not as tight. All of the usual parameters are respected |
199 | | // (max_cells, min_level, max_level, and level_mod), except that the |
200 | | // implementation makes no attempt to take advantage of large values of |
201 | | // max_cells(). (A small number of cells will always be returned.) |
202 | | // |
203 | | // This function is useful as a starting point for algorithms that |
204 | | // recursively subdivide cells. |
205 | | void GetFastCovering(const S2Region& region, std::vector<S2CellId>* covering); |
206 | | |
207 | | // Given a connected region and a starting point on the boundary or inside the |
208 | | // region, returns a set of cells at the given level that cover the region. |
209 | | // The output cells are returned in arbitrary order. |
210 | | // |
211 | | // Note that this method is *not* faster than the regular GetCovering() |
212 | | // method for most region types, such as S2Cap or S2Polygon, and in fact it |
213 | | // can be much slower when the output consists of a large number of cells. |
214 | | // Currently it can be faster at generating coverings of long narrow regions |
215 | | // such as polylines, but this may change in the future, in which case this |
216 | | // method will most likely be removed. |
217 | | static void GetSimpleCovering(const S2Region& region, const S2Point& start, |
218 | | int level, std::vector<S2CellId>* output); |
219 | | |
220 | | // Like GetSimpleCovering(), but accepts a starting S2CellId rather than a |
221 | | // starting point and cell level. Returns all edge-connected cells at the |
222 | | // same level as "start" that intersect "region", in arbitrary order. |
223 | | static void FloodFill(const S2Region& region, S2CellId start, |
224 | | std::vector<S2CellId>* output); |
225 | | |
226 | | // Returns true if the given S2CellId vector represents a valid covering |
227 | | // that conforms to the current covering parameters. In particular: |
228 | | // |
229 | | // - All S2CellIds must be valid. |
230 | | // |
231 | | // - S2CellIds must be sorted and non-overlapping. |
232 | | // |
233 | | // - S2CellId levels must satisfy min_level(), max_level(), and level_mod(). |
234 | | // |
235 | | // - If covering.size() > max_cells(), there must be no two cells with |
236 | | // a common ancestor at min_level() or higher. |
237 | | // |
238 | | // - There must be no sequence of cells that could be replaced by an |
239 | | // ancestor (i.e. with level_mod() == 1, the 4 child cells of a parent). |
240 | | bool IsCanonical(const S2CellUnion& covering) const; |
241 | | bool IsCanonical(const std::vector<S2CellId>& covering) const; |
242 | | |
243 | | // Modify "covering" if necessary so that it conforms to the current |
244 | | // covering parameters (max_cells, min_level, max_level, and level_mod). |
245 | | // There are no restrictions on the input S2CellIds (they may be unsorted, |
246 | | // overlapping, etc). |
247 | | S2CellUnion CanonicalizeCovering(const S2CellUnion& covering); |
248 | | void CanonicalizeCovering(std::vector<S2CellId>* covering); |
249 | | |
250 | | private: |
251 | | struct Candidate { |
252 | 0 | void* operator new(std::size_t size, std::size_t max_children) { |
253 | 0 | return ::operator new (size + max_children * sizeof(Candidate *)); |
254 | 0 | } |
255 | | |
256 | 0 | void operator delete(void* p) { |
257 | 0 | ::operator delete (p); |
258 | 0 | } |
259 | | |
260 | | Candidate(const S2Cell& cell, const std::size_t max_children) |
261 | 0 | : cell(cell), is_terminal(max_children == 0) { |
262 | 0 | std::fill_n(&children[0], max_children, |
263 | 0 | absl::implicit_cast<Candidate*>(nullptr)); |
264 | 0 | } |
265 | | |
266 | | // Default destructor is fine; Candidate* is trivially destructible. |
267 | | // children must be deleted by DeleteCandidate. |
268 | 0 | ~Candidate() = default; |
269 | | |
270 | | S2Cell cell; |
271 | | bool is_terminal; // Cell should not be expanded further. |
272 | | int num_children = 0; // Number of children that intersect the region. |
273 | | Candidate* children[0]; // Actual size may be 0, 4, 16, or 64 elements. |
274 | | }; |
275 | | |
276 | | // If the cell intersects the given region, return a new candidate with no |
277 | | // children, otherwise return nullptr. Also marks the candidate as "terminal" |
278 | | // if it should not be expanded further. |
279 | | Candidate* NewCandidate(const S2Cell& cell); |
280 | | |
281 | | // Returns the log base 2 of the maximum number of children of a candidate. |
282 | 0 | int max_children_shift() const { return 2 * options().level_mod(); } |
283 | | |
284 | | // Frees the memory associated with a candidate. |
285 | | static void DeleteCandidate(Candidate* candidate, bool delete_children); |
286 | | |
287 | | // Processes a candidate by either adding it to the result_ vector or |
288 | | // expanding its children and inserting it into the priority queue. |
289 | | // Passing an argument of nullptr does nothing. |
290 | | void AddCandidate(Candidate* candidate); |
291 | | |
292 | | // Populates the children of "candidate" by expanding the given number of |
293 | | // levels from the given cell. Returns the number of children that were |
294 | | // marked "terminal". |
295 | | int ExpandChildren(Candidate* candidate, const S2Cell& cell, int num_levels); |
296 | | |
297 | | // Computes a set of initial candidates that cover the given region. |
298 | | void GetInitialCandidates(); |
299 | | |
300 | | // Generates a covering and stores it in result_. |
301 | | void GetCoveringInternal(const S2Region& region); |
302 | | |
303 | | // If level > min_level(), then reduces "level" if necessary so that it also |
304 | | // satisfies level_mod(). Levels smaller than min_level() are not affected |
305 | | // (since cells at these levels are eventually expanded). |
306 | | int AdjustLevel(int level) const; |
307 | | |
308 | | // Ensures that all cells with level > min_level() also satisfy level_mod(), |
309 | | // by replacing them with an ancestor if necessary. Cell levels smaller |
310 | | // than min_level() are not modified (see AdjustLevel). The output is |
311 | | // then normalized to ensure that no redundant cells are present. |
312 | | void AdjustCellLevels(std::vector<S2CellId>* cells) const; |
313 | | |
314 | | // Returns true if "covering" contains all children of "id" at level |
315 | | // (id.level() + options_.level_mod()). |
316 | | bool ContainsAllChildren(const std::vector<S2CellId>& covering, |
317 | | S2CellId id) const; |
318 | | |
319 | | // Replaces all descendants of "id" in "covering" with "id". |
320 | | // REQUIRES: "covering" contains at least one descendant of "id". |
321 | | void ReplaceCellsWithAncestor(std::vector<S2CellId>* covering, |
322 | | S2CellId id) const; |
323 | | |
324 | | Options options_; |
325 | | |
326 | | // We save a temporary copy of the pointer passed to GetCovering() in order |
327 | | // to avoid passing this parameter around internally. It is only used (and |
328 | | // only valid) for the duration of a single GetCovering() call. |
329 | | const S2Region* region_ = nullptr; |
330 | | |
331 | | // The set of S2CellIds that have been added to the covering so far. |
332 | | std::vector<S2CellId> result_; |
333 | | |
334 | | // We keep the candidates in a priority queue. We specify a vector to hold |
335 | | // the queue entries since for some reason priority_queue<> uses a deque by |
336 | | // default. We define our own own comparison function on QueueEntries in |
337 | | // order to make the results deterministic. (Using the default |
338 | | // less<QueueEntry>, entries of equal priority would be sorted according to |
339 | | // the memory address of the candidate.) |
340 | | |
341 | | typedef std::pair<int, Candidate*> QueueEntry; |
342 | | struct CompareQueueEntries { |
343 | 0 | bool operator()(const QueueEntry& x, const QueueEntry& y) const { |
344 | 0 | return x.first < y.first; |
345 | 0 | } |
346 | | }; |
347 | | typedef std::priority_queue<QueueEntry, std::vector<QueueEntry>, |
348 | | CompareQueueEntries> CandidateQueue; |
349 | | CandidateQueue pq_; |
350 | | |
351 | | // True if we're computing an interior covering. |
352 | | bool interior_covering_; |
353 | | |
354 | | // Counter of number of candidates created, for performance evaluation. |
355 | | int candidates_created_counter_; |
356 | | }; |
357 | | |
358 | | #endif // S2_S2REGION_COVERER_H_ |