1 | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S2REGION_COVERER_H_ |
4 | #define UTIL_GEOMETRY_S2REGION_COVERER_H_ |
5 | |
6 | #include <queue> |
7 | using std::priority_queue; |
8 | |
9 | #include <utility> |
10 | using std::pair; |
11 | using std::make_pair; |
12 | |
13 | #include <vector> |
14 | using std::vector; |
15 | |
16 | #include "base/macros.h" |
17 | #include "base/scoped_ptr.h" |
18 | #include "s2cell.h" |
19 | #include "s2cellid.h" |
20 | |
21 | class S2CellUnion; |
22 | |
23 | // An S2RegionCoverer is a class that allows arbitrary regions to be |
24 | // approximated as unions of cells (S2CellUnion). This is useful for |
25 | // implementing various sorts of search and precomputation operations. |
26 | // |
27 | // Typical usage: |
28 | // |
29 | // S2RegionCoverer coverer; |
30 | // coverer.set_max_cells(5); |
31 | // S2Cap cap = S2Cap::FromAxisAngle(...); |
32 | // vector<S2CellId> covering; |
33 | // coverer.GetCovering(cap, &covering); |
34 | // |
35 | // This yields a vector of at most 5 cells that is guaranteed to cover the |
36 | // given cap (a disc-shaped region on the sphere). |
37 | // |
38 | // The approximation algorithm is not optimal but does a pretty good job in |
39 | // practice. The output does not always use the maximum number of cells |
40 | // allowed, both because this would not always yield a better approximation, |
41 | // and because max_cells() is a limit on how much work is done exploring the |
42 | // possible covering as well as a limit on the final output size. |
43 | // |
44 | // One can also generate interior coverings, which are sets of cells which |
45 | // are entirely contained within a region. Interior coverings can be |
46 | // empty, even for non-empty regions, if there are no cells that satisfy |
47 | // the provided constraints and are contained by the region. Note that for |
48 | // performance reasons, it is wise to specify a max_level when computing |
49 | // interior coverings - otherwise for regions with small or zero area, the |
50 | // algorithm may spend a lot of time subdividing cells all the way to leaf |
51 | // level to try to find contained cells. |
52 | class S2RegionCoverer { |
53 | public: |
54 | // By default, the covering uses at most 8 cells at any level. This gives |
55 | // a reasonable tradeoff between the number of cells used and the accuracy |
56 | // of the approximation (see table below). |
57 | static int const kDefaultMaxCells = 8; |
58 | |
59 | S2RegionCoverer(); |
60 | ~S2RegionCoverer(); |
61 | |
62 | // Set the minimum and maximum cell level to be used. The default is to use |
63 | // all cell levels. Requires: max_level() >= min_level(). |
64 | // |
65 | // To find the cell level corresponding to a given physical distance, use |
66 | // the S2Cell metrics defined in s2.h. For example, to find the cell |
67 | // level that corresponds to an average edge length of 10km, use: |
68 | // |
69 | // int level = S2::kAvgEdge.GetClosestLevel( |
70 | // geostore::S2Earth::KmToRadians(length_km)); |
71 | // |
72 | // Note: min_level() takes priority over max_cells(), i.e. cells below the |
73 | // given level will never be used even if this causes a large number of |
74 | // cells to be returned. |
75 | void set_min_level(int min_level); |
76 | void set_max_level(int max_level); |
77 | int min_level() const { return min_level_; } |
78 | int max_level() const { return max_level_; } |
79 | |
80 | // If specified, then only cells where (level - min_level) is a multiple of |
81 | // "level_mod" will be used (default 1). This effectively allows the |
82 | // branching factor of the S2CellId hierarchy to be increased. Currently |
83 | // the only parameter values allowed are 1, 2, or 3, corresponding to |
84 | // branching factors of 4, 16, and 64 respectively. |
85 | void set_level_mod(int level_mod); |
86 | int level_mod() const { return level_mod_; } |
87 | |
88 | // Sets the maximum desired number of cells in the approximation (defaults |
89 | // to kDefaultMaxCells). Note the following: |
90 | // |
91 | // - For any setting of max_cells(), up to 6 cells may be returned if that |
92 | // is the minimum number of cells required (e.g. if the region intersects |
93 | // all six face cells). Up to 3 cells may be returned even for very tiny |
94 | // convex regions if they happen to be located at the intersection of |
95 | // three cube faces. |
96 | // |
97 | // - For any setting of max_cells(), an arbitrary number of cells may be |
98 | // returned if min_level() is too high for the region being approximated. |
99 | // |
100 | // - If max_cells() is less than 4, the area of the covering may be |
101 | // arbitrarily large compared to the area of the original region even if |
102 | // the region is convex (e.g. an S2Cap or S2LatLngRect). |
103 | // |
104 | // Accuracy is measured by dividing the area of the covering by the area of |
105 | // the original region. The following table shows the median and worst case |
106 | // values for this area ratio on a test case consisting of 100,000 spherical |
107 | // caps of random size (generated using s2regioncoverer_unittest): |
108 | // |
109 | // max_cells: 3 4 5 6 8 12 20 100 1000 |
110 | // median ratio: 5.33 3.32 2.73 2.34 1.98 1.66 1.42 1.11 1.01 |
111 | // worst case: 215518 14.41 9.72 5.26 3.91 2.75 1.92 1.20 1.02 |
112 | void set_max_cells(int max_cells); |
113 | int max_cells() const { return max_cells_; } |
114 | |
115 | // Return a vector of cell ids that covers (GetCovering) or is contained |
116 | // within (GetInteriorCovering) the given region and satisfies the various |
117 | // restrictions specified above. |
118 | void GetCovering(S2Region const& region, vector<S2CellId>* covering); |
119 | void GetInteriorCovering(S2Region const& region, vector<S2CellId>* interior); |
120 | |
121 | // Return a normalized cell union that covers (GetCellUnion) or is contained |
122 | // within (GetInteriorCellUnion) the given region and satisfies the |
123 | // restrictions *EXCEPT* for min_level() and level_mod(). These criteria |
124 | // cannot be satisfied using a cell union because cell unions are |
125 | // automatically normalized by replacing four child cells with their parent |
126 | // whenever possible. (Note that the list of cell ids passed to the cell |
127 | // union constructor does in fact satisfy all the given restrictions.) |
128 | void GetCellUnion(S2Region const& region, S2CellUnion* covering); |
129 | void GetInteriorCellUnion(S2Region const& region, S2CellUnion* interior); |
130 | |
131 | // Given a connected region and a starting point, return a set of cells at |
132 | // the given level that cover the region. |
133 | static void GetSimpleCovering(S2Region const& region, S2Point const& start, |
134 | int level, vector<S2CellId>* output); |
135 | |
136 | private: |
137 | struct Candidate { |
138 | S2Cell cell; |
139 | bool is_terminal; // Cell should not be expanded further. |
140 | int num_children; // Number of children that intersect the region. |
141 | Candidate* children[0]; // Actual size may be 0, 4, 16, or 64 elements. |
142 | }; |
143 | |
144 | // If the cell intersects the given region, return a new candidate with no |
145 | // children, otherwise return NULL. Also marks the candidate as "terminal" |
146 | // if it should not be expanded further. |
147 | Candidate* NewCandidate(S2Cell const& cell); |
148 | |
149 | // Return the log base 2 of the maximum number of children of a candidate. |
150 | inline int max_children_shift() const { return 2 * level_mod_; } |
151 | |
152 | // Free the memory associated with a candidate. |
153 | static void DeleteCandidate(Candidate* candidate, bool delete_children); |
154 | |
155 | // Process a candidate by either adding it to the result_ vector or |
156 | // expanding its children and inserting it into the priority queue. |
157 | // Passing an argument of NULL does nothing. |
158 | void AddCandidate(Candidate* candidate); |
159 | |
160 | // Populate the children of "candidate" by expanding the given number of |
161 | // levels from the given cell. Returns the number of children that were |
162 | // marked "terminal". |
163 | int ExpandChildren(Candidate* candidate, S2Cell const& cell, int num_levels); |
164 | |
165 | // Computes a set of initial candidates that cover the given region. |
166 | void GetInitialCandidates(); |
167 | |
168 | // Generates a covering and stores it in result_. |
169 | void GetCoveringInternal(S2Region const& region); |
170 | |
171 | // Given a region and a starting cell, return the set of all the |
172 | // edge-connected cells at the same level that intersect "region". |
173 | // The output cells are returned in arbitrary order. |
174 | static void FloodFill(S2Region const& region, S2CellId const& start, |
175 | vector<S2CellId>* output); |
176 | |
177 | int min_level_; |
178 | int max_level_; |
179 | int level_mod_; |
180 | int max_cells_; |
181 | |
182 | // We save a temporary copy of the pointer passed to GetCovering() in order |
183 | // to avoid passing this parameter around internally. It is only used (and |
184 | // only valid) for the duration of a single GetCovering() call. |
185 | S2Region const* region_; |
186 | |
187 | // A temporary variable used by GetCovering() that holds the cell ids that |
188 | // have been added to the covering so far. |
189 | scoped_ptr<vector<S2CellId> > result_; |
190 | |
191 | // We keep the candidates in a priority queue. We specify a vector to hold |
192 | // the queue entries since for some reason priority_queue<> uses a deque by |
193 | // default. |
194 | struct CompareQueueEntries; |
195 | typedef pair<int, Candidate*> QueueEntry; |
196 | typedef priority_queue<QueueEntry, vector<QueueEntry>, |
197 | CompareQueueEntries> CandidateQueue; |
198 | scoped_ptr<CandidateQueue> pq_; |
199 | |
200 | // True if we're computing an interior covering. |
201 | bool interior_covering_; |
202 | |
203 | // Counter of number of candidates created, for performance evaluation. |
204 | int candidates_created_counter_; |
205 | |
206 | DISALLOW_EVIL_CONSTRUCTORS(S2RegionCoverer); |
207 | }; |
208 | |
209 | #endif // UTIL_GEOMETRY_S2REGION_COVERER_H_ |
210 | |