/src/s2geometry/src/s2/s2shape_index.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2012 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 | | // S2ShapeIndex is an abstract base class for indexing polygonal geometry in |
19 | | // memory. The main documentation is with the class definition below. |
20 | | // (Some helper classes are defined first.) |
21 | | // |
22 | | // S2ShapeIndex has two major subtypes: |
23 | | // |
24 | | // - MutableS2ShapeIndex is for building new S2ShapeIndexes. Indexes may |
25 | | // also be updated dynamically by inserting or deleting shapes. Once an |
26 | | // index has been built it can be encoded compactly and later decoded as |
27 | | // either a MutableS2ShapeIndex or an EncodedS2ShapeIndex. |
28 | | // |
29 | | // - EncodedS2ShapeIndex is an S2ShapeIndex implementation that works |
30 | | // directly with encoded data. Rather than decoding everything in advance, |
31 | | // geometry is decoded incrementally (down to individual edges) as needed. |
32 | | // It can be initialized from a single block of data in nearly constant |
33 | | // time. This saves large amounts of memory and is also much faster in the |
34 | | // common situation where geometric data is loaded from somewhere, decoded, |
35 | | // and then only a single operation is performed on it. (Speedups for |
36 | | // large geometric objects can be over 1000x.) It supports all |
37 | | // S2ShapeIndex operations including boolean operations, measuring |
38 | | // distances, etc. |
39 | | |
40 | | #ifndef S2_S2SHAPE_INDEX_H_ |
41 | | #define S2_S2SHAPE_INDEX_H_ |
42 | | |
43 | | #include <array> |
44 | | #include <cstddef> |
45 | | #include <cstdint> |
46 | | #include <iterator> |
47 | | #include <memory> |
48 | | #include <type_traits> |
49 | | #include <utility> |
50 | | |
51 | | #include "absl/log/absl_check.h" |
52 | | #include "absl/types/span.h" |
53 | | |
54 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
55 | | #include "s2/s2cell_id.h" |
56 | | #include "s2/s2cell_iterator.h" |
57 | | #include "s2/s2point.h" |
58 | | #include "s2/s2shape.h" |
59 | | #include "s2/util/coding/coder.h" |
60 | | #include "s2/util/gtl/compact_array.h" |
61 | | |
62 | | class R1Interval; |
63 | | class S2PaddedCell; |
64 | | |
65 | | // S2ClippedShape represents the part of a shape that intersects an S2Cell. |
66 | | // It consists of the set of edge ids that intersect that cell, and a boolean |
67 | | // indicating whether the center of the cell is inside the shape (for shapes |
68 | | // that have an interior). |
69 | | // |
70 | | // Note that the edges themselves are not clipped; we always use the original |
71 | | // edges for intersection tests so that the results will be the same as the |
72 | | // original shape. |
73 | | class S2ClippedShape { |
74 | | public: |
75 | 0 | S2ClippedShape() : num_edges_(0) {} |
76 | | |
77 | | // The shape id of the clipped shape. |
78 | | int shape_id() const; |
79 | | |
80 | | // Returns true if the center of the S2CellId is inside the shape. Returns |
81 | | // false for shapes that do not have an interior. |
82 | | bool contains_center() const; |
83 | | |
84 | | // The number of edges that intersect the S2CellId. |
85 | | int num_edges() const; |
86 | | |
87 | | // Returns the edge id of the given edge in this clipped shape. Edges are |
88 | | // sorted in increasing order of edge id. |
89 | | // |
90 | | // REQUIRES: 0 <= i < num_edges() |
91 | | int edge(int i) const; |
92 | | |
93 | | // Returns true if the clipped shape contains the given edge id. |
94 | | bool ContainsEdge(int id) const; |
95 | | |
96 | | private: |
97 | | // This class may be copied by value, but note that it does *not* own its |
98 | | // underlying data. (It is owned by the containing S2ShapeIndexCell.) |
99 | | |
100 | | friend class MutableS2ShapeIndex; |
101 | | friend class S2ShapeIndexCell; |
102 | | friend class S2Stats; |
103 | | |
104 | | // Internal methods are documented with their definition. |
105 | | void Init(int32_t shape_id, int32_t num_edges); |
106 | | void Destruct(); |
107 | | bool is_inline() const; |
108 | | void set_contains_center(bool contains_center); |
109 | | void set_edge(int i, int edge); |
110 | | |
111 | | // All fields are packed into 16 bytes (assuming 64-bit pointers). Up to |
112 | | // two edge ids are stored inline; this is an important optimization for |
113 | | // clients that use S2Shapes consisting of a single edge. |
114 | | int32_t shape_id_; |
115 | | uint32_t contains_center_ : 1; // shape contains the cell center |
116 | | // TODO(user): Use in-class initializer when C++20 is allowed in |
117 | | // opensource version. |
118 | | uint32_t num_edges_ : 31; |
119 | | |
120 | | // The maximum number of edges that we can store inline in the union. |
121 | | static constexpr int kMaxInlineEdges = 2; |
122 | | |
123 | | // If there are more than two edges, this field holds a pointer. |
124 | | // Otherwise it holds an array of edge ids. |
125 | | union { |
126 | | int32_t* edges_; // Owned by the containing S2ShapeIndexCell. |
127 | | std::array<int32_t, kMaxInlineEdges> inline_edges_; |
128 | | }; |
129 | | }; |
130 | | |
131 | | // S2ShapeIndexCell stores the index contents for a particular S2CellId. |
132 | | // It consists of a set of clipped shapes. |
133 | | class S2ShapeIndexCell { |
134 | | public: |
135 | 0 | S2ShapeIndexCell() = default; |
136 | | ~S2ShapeIndexCell(); |
137 | | |
138 | | // Returns the number of clipped shapes in this cell. |
139 | 0 | int num_clipped() const { return shapes_.size(); } |
140 | | |
141 | | // Returns the clipped shape at the given index. Shapes are kept sorted in |
142 | | // increasing order of shape id. |
143 | | // |
144 | | // REQUIRES: 0 <= i < num_clipped() |
145 | 0 | const S2ClippedShape& clipped(int i) const { return shapes_[i]; } |
146 | | |
147 | | // Returns a pointer to the clipped shape corresponding to the given shape, |
148 | | // or nullptr if the shape does not intersect this cell. |
149 | | const S2ClippedShape* find_clipped(int shape_id) const; |
150 | | |
151 | | // Returns a read-only span over the clipped shapes in the cell. |
152 | 0 | absl::Span<const S2ClippedShape> clipped_shapes() const { |
153 | 0 | if (!shapes_.empty()) { |
154 | 0 | return {shapes_.begin(), shapes_.size()}; |
155 | 0 | } |
156 | 0 | return {}; |
157 | 0 | } |
158 | | |
159 | | // Convenience method that returns the total number of edges in all clipped |
160 | | // shapes. |
161 | | int num_edges() const; |
162 | | |
163 | | // Appends an encoded representation of the S2ShapeIndexCell to "encoder". |
164 | | // "num_shape_ids" should be set to index.num_shape_ids(); this information |
165 | | // allows the encoding to be more compact in some cases. |
166 | | // |
167 | | // REQUIRES: "encoder" uses the default constructor, so that its buffer |
168 | | // can be enlarged as necessary by calling Ensure(int). |
169 | | void Encode(int num_shape_ids, Encoder* encoder) const; |
170 | | |
171 | | // Decodes an S2ShapeIndexCell, returning true on success. |
172 | | // "num_shape_ids" should be set to index.num_shape_ids(). |
173 | | bool Decode(int num_shape_ids, Decoder* decoder); |
174 | | |
175 | | private: |
176 | | friend class MutableS2ShapeIndex; |
177 | | friend class EncodedS2ShapeIndex; |
178 | | friend class S2Stats; |
179 | | |
180 | | // Internal methods are documented with their definitions. |
181 | | S2ClippedShape* add_shapes(int n); |
182 | | static void EncodeEdges(const S2ClippedShape& clipped, Encoder* encoder); |
183 | | static bool DecodeEdges(int num_edges, S2ClippedShape* clipped, |
184 | | Decoder* decoder); |
185 | | |
186 | | using S2ClippedShapeSet = gtl::compact_array<S2ClippedShape>; |
187 | | S2ClippedShapeSet shapes_; |
188 | | |
189 | | S2ShapeIndexCell(const S2ShapeIndexCell&) = delete; |
190 | | void operator=(const S2ShapeIndexCell&) = delete; |
191 | | }; |
192 | | |
193 | | // S2ShapeIndex is an abstract base class for indexing polygonal geometry in |
194 | | // memory. The objects in the index are known as "shapes", and may consist of |
195 | | // points, polylines, and/or polygons, possibly overlapping. The index makes |
196 | | // it very fast to answer queries such as finding nearby shapes, measuring |
197 | | // distances, testing for intersection and containment, etc. |
198 | | // |
199 | | // Each object in the index implements the S2Shape interface. An S2Shape is a |
200 | | // collection of edges that optionally defines an interior. The edges do not |
201 | | // need to be connected, so for example an S2Shape can represent a polygon |
202 | | // with multiple shells and/or holes, or a set of polylines, or a set of |
203 | | // points. All geometry within a single S2Shape must have the same dimension, |
204 | | // so for example if you want to create an S2ShapeIndex containing a polyline |
205 | | // and 10 points, then you will need at least two different S2Shape objects. |
206 | | // |
207 | | // There are two important types of S2ShapeIndex. MutableS2ShapeIndex allows |
208 | | // you to build an index incrementally by adding or removing shapes, whereas |
209 | | // EncodedS2ShapeIndex works very efficiently with existing indexes by keeping |
210 | | // the index data in encoded form (see introduction at the top of this file). |
211 | | // |
212 | | // Code that only needs read-only ("const") access to an index should use the |
213 | | // S2ShapeIndex base class as the parameter type, so that it will work with |
214 | | // any S2ShapeIndex subtype. For example: |
215 | | // |
216 | | // void DoSomething(const S2ShapeIndex& index) { |
217 | | // ... works with MutableS2ShapeIndex or EncodedS2ShapeIndex ... |
218 | | // } |
219 | | // |
220 | | // There are a number of built-in classes that work with S2ShapeIndex objects. |
221 | | // Generally these classes accept any collection of geometry that can be |
222 | | // represented by an S2ShapeIndex, i.e. any combination of points, polylines, |
223 | | // and polygons. Such classes include: |
224 | | // |
225 | | // - S2ContainsPointQuery: returns the shape(s) that contain a given point. |
226 | | // |
227 | | // - S2ClosestEdgeQuery: returns the closest edge(s) to a given point, edge, |
228 | | // S2CellId, or S2ShapeIndex. |
229 | | // |
230 | | // - S2CrossingEdgeQuery: returns the edge(s) that cross a given edge. |
231 | | // |
232 | | // - S2BooleanOperation: computes boolean operations such as union, |
233 | | // and boolean predicates such as containment. |
234 | | // |
235 | | // - S2ShapeIndexRegion: can be used together with S2RegionCoverer to |
236 | | // approximate geometry as a set of S2CellIds. |
237 | | // |
238 | | // - S2ShapeIndexBufferedRegion: computes approximations that have been |
239 | | // expanded by a given radius. |
240 | | // |
241 | | // Here is an example showing how to index a set of polygons and then |
242 | | // determine which polygon(s) contain each of a set of query points: |
243 | | // |
244 | | // void TestContainment(const vector<S2Point>& points, |
245 | | // const vector<S2Polygon*>& polygons) { |
246 | | // MutableS2ShapeIndex index; |
247 | | // for (auto polygon : polygons) { |
248 | | // index.Add(std::make_unique<S2Polygon::Shape>(polygon)); |
249 | | // } |
250 | | |
251 | | // auto query = MakeS2ContainsPointQuery(&index); |
252 | | // for (const auto& point : points) { |
253 | | // for (int shape_id : query.GetContainingShapeIds(point)) { |
254 | | // S2Polygon* polygon = polygons[shape_id]; |
255 | | // ... do something with (point, polygon) ... |
256 | | // } |
257 | | // } |
258 | | // } |
259 | | // |
260 | | // This example uses S2Polygon::Shape, which is one example of an S2Shape |
261 | | // object. S2Polyline and S2Loop also have nested Shape classes, and there are |
262 | | // additional S2Shape types defined in *_shape.h. |
263 | | // |
264 | | // Internally, an S2ShapeIndex is essentially a map from S2CellIds to the set |
265 | | // of shapes that intersect each S2CellId. It is adaptively refined to ensure |
266 | | // that no cell contains more than a small number of edges. |
267 | | // |
268 | | // In addition to implementing a shared set of virtual methods, all |
269 | | // S2ShapeIndex subtypes define an Iterator type with the same API. This |
270 | | // makes it easy to convert code that uses a particular S2ShapeIndex subtype |
271 | | // to instead use the abstract base class (or vice versa). You can also |
272 | | // choose to avoid the overhead of virtual method calls by making the |
273 | | // S2ShapeIndex type a template argument, like this: |
274 | | // |
275 | | // template <class IndexType> |
276 | | // void DoSomething(const IndexType& index) { |
277 | | // for (typename IndexType::Iterator it(&index, S2ShapeIndex::BEGIN); |
278 | | // !it.done(); it.Next()) { |
279 | | // ... |
280 | | // } |
281 | | // } |
282 | | // |
283 | | // The S2ShapeIndex subtypes provided by the S2 library are thread-compatible, |
284 | | // meaning that const methods may be called concurrently from multiple threads, |
285 | | // while non-const methods require exclusive access to the S2ShapeIndex. |
286 | | class S2ShapeIndex { |
287 | | public: |
288 | | // Each subtype of S2ShapeIndex should define an Iterator type derived |
289 | | // from the following base class. |
290 | | class IteratorBase : public S2CellIterator { |
291 | | public: |
292 | | // Returns a reference to the contents of the current index cell. |
293 | | // REQUIRES: !done() |
294 | | virtual const S2ShapeIndexCell& cell() const = 0; |
295 | | |
296 | | // Returns a newly allocated copy of this iterator. |
297 | | virtual std::unique_ptr<IteratorBase> Clone() const = 0; |
298 | | |
299 | | protected: |
300 | | // Protect the default constructor and move/copy constructors and operators. |
301 | | // This allows sub-classes to still be default/copy/move-constructible but |
302 | | // prevents accidental slicing through a base class pointer. |
303 | 7.21k | IteratorBase() = default; |
304 | 0 | IteratorBase(const IteratorBase&) = default; |
305 | | IteratorBase& operator=(const IteratorBase&) = default; |
306 | 0 | IteratorBase(IteratorBase&&) = default; |
307 | | IteratorBase& operator=(IteratorBase&&) = default; |
308 | | }; |
309 | | |
310 | | // A type function to check if a type is derived from S2ShapeIndex. This is |
311 | | // useful for writing static checks on template parameters when we want to |
312 | | // inline a particular iterator call, but we need to make sure it implements |
313 | | // the interface that we want. We don't have access to c++ concepts, so this |
314 | | // is the next best thing: |
315 | | // |
316 | | // template <typename Index> |
317 | | // void Process(Index& iter) { |
318 | | // static_assert(S2ShapeIndex::ImplementedBy<Index>{}, |
319 | | // "We require an S2ShapeIndex."); |
320 | | // } |
321 | | template <typename T> |
322 | | using ImplementedBy = std::is_convertible<std::decay_t<T>*, S2ShapeIndex*>; |
323 | | |
324 | 7.21k | virtual ~S2ShapeIndex() = default; |
325 | | |
326 | | // Returns the number of distinct shape ids in the index. This is the same |
327 | | // as the number of shapes provided that no shapes have ever been removed. |
328 | | // (Shape ids are never reused.) |
329 | | virtual int num_shape_ids() const = 0; |
330 | | |
331 | | // Returns a pointer to the shape with the given id, or nullptr if the shape |
332 | | // has been removed from the index. |
333 | | virtual const S2Shape* shape(int id) const = 0; |
334 | | |
335 | | // Stores an encoded representation of the index into the given encoder. |
336 | | virtual void Encode(Encoder* encoder) const = 0; |
337 | | |
338 | | // Allows iterating over the indexed shapes using range-based for loops: |
339 | | // |
340 | | // for (S2Shape* shape : index) { ... } |
341 | | // |
342 | | // CAVEAT: Returns nullptr for shapes that have been removed from the index. |
343 | | class ShapeIterator { |
344 | | public: |
345 | | using iterator_category = std::forward_iterator_tag; |
346 | | using value_type = const S2Shape*; |
347 | | using difference_type = std::ptrdiff_t; |
348 | | using pointer = const S2Shape**; |
349 | | using reference = const S2Shape*&; |
350 | | |
351 | | ShapeIterator() = default; |
352 | | const S2Shape* operator*() const; |
353 | | ShapeIterator& operator++(); |
354 | | ShapeIterator operator++(int); |
355 | | |
356 | | // REQUIRES: "it" and *this must reference the same S2ShapeIndex. |
357 | | bool operator==(ShapeIterator it) const; |
358 | | |
359 | | // REQUIRES: "it" and *this must reference the same S2ShapeIndex. |
360 | | bool operator!=(ShapeIterator it) const; |
361 | | |
362 | | private: |
363 | | friend class S2ShapeIndex; |
364 | | ShapeIterator(const S2ShapeIndex* index, int shape_id) |
365 | 0 | : index_(index), shape_id_(shape_id) {} |
366 | | |
367 | | const S2ShapeIndex* index_ = nullptr; |
368 | | int shape_id_ = 0; |
369 | | }; |
370 | | ShapeIterator begin() const; |
371 | | ShapeIterator end() const; |
372 | | |
373 | | // Returns the number of bytes currently occupied by the index (including any |
374 | | // unused space at the end of vectors, etc). |
375 | | virtual size_t SpaceUsed() const = 0; |
376 | | |
377 | | // Minimizes memory usage by requesting that any data structures that can be |
378 | | // rebuilt should be discarded. This method invalidates all iterators. |
379 | | // |
380 | | // Like all non-const methods, this method is not thread-safe. |
381 | | virtual void Minimize() = 0; |
382 | | |
383 | | // When passed to an Iterator constructor, specifies whether the iterator |
384 | | // should be positioned at the beginning of the index (BEGIN), the end of |
385 | | // the index (END), or arbitrarily (UNPOSITIONED). By default iterators are |
386 | | // unpositioned, since this avoids an extra seek in this situation where one |
387 | | // of the seek methods (such as Locate) is immediately called. |
388 | | enum InitialPosition { BEGIN, END, UNPOSITIONED }; |
389 | | |
390 | | // A random access iterator that provides low-level access to the cells of |
391 | | // the index. Cells are sorted in increasing order of S2CellId. |
392 | | class Iterator final : public IteratorBase { |
393 | | public: |
394 | | // Default constructor; must be followed by a call to Init(). |
395 | 0 | Iterator() = default; |
396 | | |
397 | | // Constructs an iterator positioned as specified. By default iterators |
398 | | // are unpositioned, since this avoids an extra seek in this situation |
399 | | // where one of the seek methods (such as Locate) is immediately called. |
400 | | // |
401 | | // If you want to position the iterator at the beginning, e.g. in order to |
402 | | // loop through the entire index, do this instead: |
403 | | // |
404 | | // for (S2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN); |
405 | | // !it.done(); it.Next()) { ... } |
406 | | explicit Iterator(const S2ShapeIndex* index, |
407 | 0 | InitialPosition pos = UNPOSITIONED) { |
408 | 0 | Init(index, pos); |
409 | 0 | } |
410 | | |
411 | | // Initializes an iterator for the given S2ShapeIndex. This method may |
412 | | // also be called in order to restore an iterator to a valid state after |
413 | | // the underlying index has been updated (although it is usually easier |
414 | | // just to declare a new iterator whenever required, since iterator |
415 | | // construction is cheap). |
416 | | void Init(const S2ShapeIndex* index, |
417 | 0 | InitialPosition pos = UNPOSITIONED) { |
418 | 0 | iter_ = index->NewIterator(pos); |
419 | 0 | } |
420 | | |
421 | | // Iterators are copyable and movable. |
422 | | Iterator(const Iterator&); |
423 | | Iterator& operator=(const Iterator&); |
424 | 0 | Iterator(Iterator&&) = default; |
425 | | Iterator& operator=(Iterator&&) = default; |
426 | | |
427 | | // Returns the S2CellId of the current index cell. If done() is true, |
428 | | // returns a value larger than any valid S2CellId (S2CellId::Sentinel()). |
429 | 0 | S2CellId id() const override { return iter_->id(); } |
430 | | |
431 | | // Returns the center point of the cell. |
432 | | // REQUIRES: !done() |
433 | 0 | S2Point center() const { return id().ToPoint(); } |
434 | | |
435 | | // Returns a reference to the contents of the current index cell. |
436 | | // REQUIRES: !done() |
437 | 0 | const S2ShapeIndexCell& cell() const override { return iter_->cell(); } |
438 | | |
439 | | // Returns true if the iterator is positioned past the last index cell. |
440 | 0 | bool done() const override { return iter_->done(); } |
441 | | |
442 | | // Positions the iterator at the first index cell (if any). |
443 | 0 | void Begin() override { iter_->Begin(); } |
444 | | |
445 | | // Positions the iterator past the last index cell. |
446 | 0 | void Finish() override { iter_->Finish(); } |
447 | | |
448 | | // Positions the iterator at the next index cell. |
449 | | // REQUIRES: !done() |
450 | 0 | void Next() override { iter_->Next(); } |
451 | | |
452 | | // If the iterator is already positioned at the beginning, returns false. |
453 | | // Otherwise positions the iterator at the previous entry and returns true. |
454 | 0 | bool Prev() override { return iter_->Prev(); } |
455 | | |
456 | | // Positions the iterator at the first cell with id() >= target, or at the |
457 | | // end of the index if no such cell exists. |
458 | 0 | void Seek(S2CellId target) override { iter_->Seek(target); } |
459 | | |
460 | | // Positions the iterator at the cell containing target and returns true. If |
461 | | // no such cell exists, return false and leave the iterator in an undefined |
462 | | // (but valid) state. |
463 | 0 | bool Locate(const S2Point& target) override { |
464 | 0 | return LocateImpl(*this, target); |
465 | 0 | } |
466 | | |
467 | | // Let T be the target S2CellId. If T is contained by some index cell I |
468 | | // (including equality), this method positions the iterator at I and |
469 | | // returns INDEXED. Otherwise if T contains one or more (smaller) index |
470 | | // cells, it positions the iterator at the first such cell I and returns |
471 | | // SUBDIVIDED. Otherwise it returns DISJOINT and leaves the iterator |
472 | | // positioned arbitrarily. |
473 | 0 | S2CellRelation Locate(S2CellId target) override { |
474 | 0 | return LocateImpl(*this, target); |
475 | 0 | } |
476 | | |
477 | | // Clone our underlying iterator to clone this iterator. |
478 | 0 | std::unique_ptr<IteratorBase> Clone() const override { |
479 | 0 | return std::make_unique<Iterator>(Iterator(iter_->Clone())); |
480 | 0 | }; |
481 | | |
482 | | private: |
483 | | // Although S2ShapeIndex::Iterator can be used to iterate over any |
484 | | // index subtype, it is more efficient to use the subtype's iterator when |
485 | | // the subtype is known at compile time. For example, MutableS2ShapeIndex |
486 | | // should use a MutableS2ShapeIndex::Iterator. |
487 | | // |
488 | | // The following declarations prevent accidental use of |
489 | | // S2ShapeIndex::Iterator when the actual subtype is known. (If you |
490 | | // really want to do this, you can down_cast the index argument to |
491 | | // S2ShapeIndex.) |
492 | | template <class T> |
493 | | explicit Iterator(const T* index, InitialPosition pos = UNPOSITIONED) {} |
494 | | |
495 | | explicit Iterator(std::unique_ptr<IteratorBase> iter) |
496 | 0 | : iter_(std::move(iter)) {} |
497 | | |
498 | | std::unique_ptr<IteratorBase> iter_; |
499 | | }; |
500 | | |
501 | | // ShapeFactory is an interface for decoding vectors of S2Shapes. It allows |
502 | | // random access to the shapes in order to support lazy decoding. See |
503 | | // s2shapeutil_coding.h for useful subtypes. |
504 | | class ShapeFactory { |
505 | | public: |
506 | | virtual ~ShapeFactory() = default; |
507 | | |
508 | | // Returns the number of S2Shapes in the vector. |
509 | | virtual int size() const = 0; |
510 | | |
511 | | // Returns the S2Shape object corresponding to the given "shape_id". |
512 | | // Returns nullptr if a shape cannot be decoded or a shape is missing |
513 | | // (e.g., because MutableS2ShapeIndex::Release() was called). |
514 | | virtual std::unique_ptr<S2Shape> operator[](int shape_id) const = 0; |
515 | | |
516 | | // Returns a deep copy of this ShapeFactory. |
517 | | virtual std::unique_ptr<ShapeFactory> Clone() const = 0; |
518 | | }; |
519 | | |
520 | | protected: |
521 | | // Returns a new iterator positioned as specified. |
522 | | virtual std::unique_ptr<IteratorBase> NewIterator(InitialPosition pos) |
523 | | const = 0; |
524 | | |
525 | 7.21k | S2ShapeIndex() = default; |
526 | | S2ShapeIndex(const S2ShapeIndex&) = delete; |
527 | | S2ShapeIndex(S2ShapeIndex&&) = delete; |
528 | | S2ShapeIndex& operator=(const S2ShapeIndex&) = delete; |
529 | | S2ShapeIndex& operator=(S2ShapeIndex&&) = delete; |
530 | | }; |
531 | | |
532 | | ////////////////// Implementation details follow //////////////////// |
533 | | |
534 | | |
535 | 0 | inline int S2ClippedShape::shape_id() const { |
536 | 0 | return shape_id_; |
537 | 0 | } |
538 | | |
539 | 0 | inline bool S2ClippedShape::contains_center() const { |
540 | 0 | return contains_center_; |
541 | 0 | } |
542 | | |
543 | 0 | inline int S2ClippedShape::num_edges() const { |
544 | 0 | return num_edges_; |
545 | 0 | } |
546 | | |
547 | 0 | inline int S2ClippedShape::edge(int i) const { |
548 | 0 | return is_inline() ? inline_edges_[i] : edges_[i]; |
549 | 0 | } |
550 | | |
551 | | // Initialize an S2ClippedShape to hold the given number of edges. |
552 | 0 | inline void S2ClippedShape::Init(int32_t shape_id, int32_t num_edges) { |
553 | 0 | shape_id_ = shape_id; |
554 | 0 | num_edges_ = num_edges; |
555 | 0 | contains_center_ = false; |
556 | 0 | if (!is_inline()) { |
557 | 0 | edges_ = new int32_t[num_edges]; |
558 | 0 | } |
559 | 0 | } |
560 | | |
561 | | // Free any memory allocated by this S2ClippedShape. We don't do this in |
562 | | // the destructor because S2ClippedShapes are copied by STL code, and we |
563 | | // don't want to repeatedly copy and free the edge data. Instead the data |
564 | | // is owned by the containing S2ShapeIndexCell. |
565 | 0 | inline void S2ClippedShape::Destruct() { |
566 | 0 | if (!is_inline()) delete[] edges_; |
567 | 0 | } |
568 | | |
569 | 0 | inline bool S2ClippedShape::is_inline() const { |
570 | 0 | return num_edges_ <= kMaxInlineEdges; |
571 | 0 | } |
572 | | |
573 | | // Set "contains_center_" to indicate whether this clipped shape contains the |
574 | | // center of the cell to which it belongs. |
575 | 0 | inline void S2ClippedShape::set_contains_center(bool contains_center) { |
576 | 0 | contains_center_ = contains_center; |
577 | 0 | } |
578 | | |
579 | | // Set the i-th edge of this clipped shape to be the given edge of the |
580 | | // original shape. |
581 | 0 | inline void S2ClippedShape::set_edge(int i, int edge) { |
582 | 0 | if (is_inline()) { |
583 | 0 | inline_edges_[i] = edge; |
584 | 0 | } else { |
585 | 0 | edges_[i] = edge; |
586 | 0 | } |
587 | 0 | } |
588 | | |
589 | | // Inline because an index cell frequently contains just one shape. |
590 | 0 | inline int S2ShapeIndexCell::num_edges() const { |
591 | 0 | int n = 0; |
592 | 0 | for (int i = 0; i < num_clipped(); ++i) n += clipped(i).num_edges(); |
593 | 0 | return n; |
594 | 0 | } |
595 | | |
596 | 0 | inline const S2Shape* S2ShapeIndex::ShapeIterator::operator*() const { |
597 | 0 | return index_->shape(shape_id_); |
598 | 0 | } |
599 | | |
600 | 0 | inline S2ShapeIndex::ShapeIterator& S2ShapeIndex::ShapeIterator::operator++() { |
601 | 0 | ++shape_id_; |
602 | 0 | return *this; |
603 | 0 | } |
604 | | |
605 | | inline S2ShapeIndex::ShapeIterator S2ShapeIndex::ShapeIterator::operator++( |
606 | 0 | int) { |
607 | 0 | return ShapeIterator(index_, shape_id_++); |
608 | 0 | } |
609 | | |
610 | 0 | inline bool S2ShapeIndex::ShapeIterator::operator==(ShapeIterator it) const { |
611 | 0 | ABSL_DCHECK_EQ(index_, it.index_); |
612 | 0 | return shape_id_ == it.shape_id_; |
613 | 0 | } |
614 | | |
615 | 0 | inline bool S2ShapeIndex::ShapeIterator::operator!=(ShapeIterator it) const { |
616 | 0 | ABSL_DCHECK_EQ(index_, it.index_); |
617 | 0 | return shape_id_ != it.shape_id_; |
618 | 0 | } |
619 | | |
620 | 0 | inline S2ShapeIndex::ShapeIterator S2ShapeIndex::begin() const { |
621 | 0 | return ShapeIterator(this, 0); |
622 | 0 | } |
623 | | |
624 | 0 | inline S2ShapeIndex::ShapeIterator S2ShapeIndex::end() const { |
625 | 0 | return ShapeIterator(this, num_shape_ids()); |
626 | 0 | } |
627 | | |
628 | | inline S2ShapeIndex::Iterator::Iterator(const Iterator& other) |
629 | 0 | : iter_(other.iter_->Clone()) { |
630 | 0 | } |
631 | | |
632 | | inline S2ShapeIndex::Iterator& S2ShapeIndex::Iterator::operator=( |
633 | 0 | const Iterator& other) { |
634 | 0 | iter_ = other.iter_->Clone(); |
635 | 0 | return *this; |
636 | 0 | } |
637 | | |
638 | | #endif // S2_S2SHAPE_INDEX_H_ |