1 | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S2CELLUNION_H_ |
4 | #define UTIL_GEOMETRY_S2CELLUNION_H_ |
5 | |
6 | #include <vector> |
7 | using std::vector; |
8 | |
9 | #include "base/integral_types.h" |
10 | #include "base/logging.h" |
11 | #include "base/macros.h" |
12 | #include "s2region.h" |
13 | #include "s2cellid.h" |
14 | |
15 | class S1Angle; |
16 | class S2Cell; |
17 | |
18 | // An S2CellUnion is a region consisting of cells of various sizes. Typically |
19 | // a cell union is used to approximate some other shape. There is a tradeoff |
20 | // between the accuracy of the approximation and how many cells are used. |
21 | // Unlike polygons, cells have a fixed hierarchical structure. This makes |
22 | // them more suitable for optimizations based on preprocessing. |
23 | class S2CellUnion : public S2Region { |
24 | public: |
25 | // The default constructor does nothing. The cell union cannot be used |
26 | // until one of the Init() methods is called. |
27 | S2CellUnion() {} |
28 | |
29 | // Populates a cell union with the given S2CellIds or 64-bit cells ids, and |
30 | // then calls Normalize(). The InitSwap() version takes ownership of the |
31 | // vector data without copying and clears the given vector. These methods |
32 | // may be called multiple times. |
33 | void Init(vector<S2CellId> const& cell_ids); |
34 | void Init(vector<uint64> const& cell_ids); |
35 | void InitSwap(vector<S2CellId>* cell_ids); |
36 | |
37 | // Like Init(), but does not call Normalize(). The cell union *must* be |
38 | // normalized before doing any calculations with it, so it is the caller's |
39 | // responsibility to make sure that the input is normalized. This method is |
40 | // useful when converting cell unions to another representation and back. |
41 | // These methods may be called multiple times. |
42 | void InitRaw(vector<S2CellId> const& cell_ids); |
43 | void InitRaw(vector<uint64> const& cell_ids); |
44 | void InitRawSwap(vector<S2CellId>* cell_ids); |
45 | |
46 | // Gives ownership of the vector data to the client without copying, and |
47 | // clears the content of the cell union. The original data in cell_ids |
48 | // is lost if there was any. This is the opposite of InitRawSwap(). |
49 | void Detach(vector<S2CellId>* cell_ids); |
50 | |
51 | // Convenience methods for accessing the individual cell ids. |
52 | int num_cells() const { return cell_ids_.size(); } |
53 | S2CellId const& cell_id(int i) const { return cell_ids_[i]; } |
54 | |
55 | // Direct access to the underlying vector for STL algorithms. |
56 | vector<S2CellId> const& cell_ids() const { return cell_ids_; } |
57 | |
58 | // Normalizes the cell union by discarding cells that are contained by other |
59 | // cells, replacing groups of 4 child cells by their parent cell whenever |
60 | // possible, and sorting all the cell ids in increasing order. Returns true |
61 | // if the number of cells was reduced. |
62 | // |
63 | // This method *must* be called before doing any calculations on the cell |
64 | // union, such as Intersects() or Contains(). |
65 | bool Normalize(); |
66 | |
67 | // Replaces "output" with an expanded version of the cell union where any |
68 | // cells whose level is less than "min_level" or where (level - min_level) |
69 | // is not a multiple of "level_mod" are replaced by their children, until |
70 | // either both of these conditions are satisfied or the maximum level is |
71 | // reached. |
72 | // |
73 | // This method allows a covering generated by S2RegionCoverer using |
74 | // min_level() or level_mod() constraints to be stored as a normalized cell |
75 | // union (which allows various geometric computations to be done) and then |
76 | // converted back to the original list of cell ids that satisfies the |
77 | // desired constraints. |
78 | void Denormalize(int min_level, int level_mod, |
79 | vector<S2CellId>* output) const; |
80 | |
81 | // If there are more than "excess" elements of the cell_ids() vector that |
82 | // are allocated but unused, reallocate the array to eliminate the excess |
83 | // space. This reduces memory usage when many cell unions need to be held |
84 | // in memory at once. |
85 | void Pack(int excess = 0); |
86 | |
87 | // Return true if the cell union contains the given cell id. Containment is |
88 | // defined with respect to regions, e.g. a cell contains its 4 children. |
89 | // This is a fast operation (logarithmic in the size of the cell union). |
90 | bool Contains(S2CellId const& id) const; |
91 | |
92 | // Return true if the cell union intersects the given cell id. |
93 | // This is a fast operation (logarithmic in the size of the cell union). |
94 | bool Intersects(S2CellId const& id) const; |
95 | |
96 | // Return true if this cell union contain/intersects the given other cell |
97 | // union. |
98 | bool Contains(S2CellUnion const* y) const; |
99 | bool Intersects(S2CellUnion const* y) const; |
100 | |
101 | // Initialize this cell union to the union, intersection, or |
102 | // difference (x - y) of the two given cell unions. |
103 | // Requires: x != this and y != this. |
104 | void GetUnion(S2CellUnion const* x, S2CellUnion const* y); |
105 | void GetIntersection(S2CellUnion const* x, S2CellUnion const* y); |
106 | void GetDifference(S2CellUnion const* x, S2CellUnion const* y); |
107 | |
108 | // Specialized version of GetIntersection() that gets the intersection of a |
109 | // cell union with the given cell id. This can be useful for "splitting" a |
110 | // cell union into chunks. |
111 | void GetIntersection(S2CellUnion const* x, S2CellId const& id); |
112 | |
113 | // Expands the cell union by adding a "rim" of cells on expand_level |
114 | // around the union boundary. |
115 | // |
116 | // For each cell c in the union, we add all cells at level |
117 | // expand_level that abut c. There are typically eight of those |
118 | // (four edge-abutting and four sharing a vertex). However, if c is |
119 | // finer than expand_level, we add all cells abutting |
120 | // c.parent(expand_level) as well as c.parent(expand_level) itself, |
121 | // as an expand_level cell rarely abuts a smaller cell. |
122 | // |
123 | // Note that the size of the output is exponential in |
124 | // "expand_level". For example, if expand_level == 20 and the input |
125 | // has a cell at level 10, there will be on the order of 4000 |
126 | // adjacent cells in the output. For most applications the |
127 | // Expand(min_radius, max_level_diff) method below is easier to use. |
128 | void Expand(int expand_level); |
129 | |
130 | // Expand the cell union such that it contains all points whose distance to |
131 | // the cell union is at most "min_radius", but do not use cells that are |
132 | // more than "max_level_diff" levels higher than the largest cell in the |
133 | // input. The second parameter controls the tradeoff between accuracy and |
134 | // output size when a large region is being expanded by a small amount |
135 | // (e.g. expanding Canada by 1km). For example, if max_level_diff == 4 the |
136 | // region will always be expanded by approximately 1/16 the width of its |
137 | // largest cell. Note that in the worst case, the number of cells in the |
138 | // output can be up to 4 * (1 + 2 ** max_level_diff) times larger than the |
139 | // number of cells in the input. |
140 | void Expand(S1Angle const& min_radius, int max_level_diff); |
141 | |
142 | // Create a cell union that corresponds to a continuous range of cell ids. |
143 | // The output is a normalized collection of cell ids that covers the leaf |
144 | // cells between "min_id" and "max_id" inclusive. |
145 | // Requires: min_id.is_leaf(), max_id.is_leaf(), min_id <= max_id. |
146 | void InitFromRange(S2CellId const& min_id, S2CellId const& max_id); |
147 | |
148 | // The number of leaf cells covered by the union. |
149 | // This will be no more than 6*2^60 for the whole sphere. |
150 | uint64 LeafCellsCovered() const; |
151 | |
152 | // Approximate this cell union's area by summing the average area of |
153 | // each contained cell's average area, using the AverageArea method |
154 | // from the S2Cell class. |
155 | // This is equivalent to the number of leaves covered, multiplied by |
156 | // the average area of a leaf. |
157 | // Note that AverageArea does not take into account distortion of cell, and |
158 | // thus may be off by up to a factor of 1.7. |
159 | // NOTE: Since this is proportional to LeafCellsCovered(), it is |
160 | // always better to use the other function if all you care about is |
161 | // the relative average area between objects. |
162 | double AverageBasedArea() const; |
163 | |
164 | // Calculates this cell union's area by summing the approximate area for each |
165 | // contained cell, using the ApproxArea method from the S2Cell class. |
166 | double ApproxArea() const; |
167 | |
168 | // Calculates this cell union's area by summing the exact area for each |
169 | // contained cell, using the Exact method from the S2Cell class. |
170 | double ExactArea() const; |
171 | |
172 | //////////////////////////////////////////////////////////////////////// |
173 | // S2Region interface (see s2region.h for details): |
174 | |
175 | virtual S2CellUnion* Clone() const; |
176 | virtual S2Cap GetCapBound() const; |
177 | virtual S2LatLngRect GetRectBound() const; |
178 | |
179 | // This is a fast operation (logarithmic in the size of the cell union). |
180 | virtual bool Contains(S2Cell const& cell) const; |
181 | |
182 | // This is a fast operation (logarithmic in the size of the cell union). |
183 | virtual bool MayIntersect(S2Cell const& cell) const; |
184 | |
185 | virtual bool VirtualContainsPoint(S2Point const& p) const { |
186 | return Contains(p); // The same as Contains() below, just virtual. |
187 | } |
188 | |
189 | virtual void Encode(Encoder* const encoder) const { |
190 | LOG(FATAL) << "Unimplemented" ; |
191 | } |
192 | virtual bool Decode(Decoder* const decoder) { return false; } |
193 | |
194 | // The point 'p' does not need to be normalized. |
195 | // This is a fast operation (logarithmic in the size of the cell union). |
196 | bool Contains(S2Point const& p) const; |
197 | |
198 | private: |
199 | vector<S2CellId> cell_ids_; |
200 | |
201 | DISALLOW_EVIL_CONSTRUCTORS(S2CellUnion); |
202 | }; |
203 | |
204 | // Return true if two cell unions are identical. |
205 | bool operator==(S2CellUnion const& x, S2CellUnion const& y); |
206 | |
207 | #endif // UTIL_GEOMETRY_S2CELLUNION_H_ |
208 | |