/src/s2geometry/src/s2/s2crossing_edge_query.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2013 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_S2CROSSING_EDGE_QUERY_H_ |
19 | | #define S2_S2CROSSING_EDGE_QUERY_H_ |
20 | | |
21 | | #include <functional> |
22 | | #include <memory> |
23 | | #include <type_traits> |
24 | | #include <vector> |
25 | | |
26 | | #include "absl/base/macros.h" |
27 | | #include "absl/container/inlined_vector.h" |
28 | | #include "absl/log/absl_check.h" |
29 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
30 | | #include "s2/r2.h" |
31 | | #include "s2/r2rect.h" |
32 | | #include "s2/s2padded_cell.h" |
33 | | #include "s2/s2point.h" |
34 | | #include "s2/s2shape.h" |
35 | | #include "s2/s2shape_index.h" |
36 | | #include "s2/s2shapeutil_shape_edge.h" |
37 | | #include "s2/s2shapeutil_shape_edge_id.h" |
38 | | |
39 | | // A parameter that controls the reporting of edge intersections. |
40 | | // |
41 | | // - CrossingType::INTERIOR reports intersections that occur at a point |
42 | | // interior to both edges (i.e., not at a vertex). |
43 | | // |
44 | | // - CrossingType::ALL reports all intersections, even those where two edges |
45 | | // intersect only because they share a common vertex. |
46 | | namespace s2shapeutil { |
47 | | enum class CrossingType { INTERIOR, ALL }; |
48 | | } // namespace s2shapeutil |
49 | | |
50 | | // S2CrossingEdgeQuery is used to find edges or shapes that are crossed by |
51 | | // an edge. Here is an example showing how to index a set of polylines, |
52 | | // and then find the polylines that are crossed by a given edge AB: |
53 | | // |
54 | | // void Test(const vector<S2Polyline*>& polylines,` |
55 | | // const S2Point& a0, const S2Point &a1) { |
56 | | // MutableS2ShapeIndex index; |
57 | | // for (S2Polyline* polyline : polylines) { |
58 | | // index.Add(std::make_unique<S2Polyline::Shape>(polyline)); |
59 | | // } |
60 | | // S2CrossingEdgeQuery query(&index); |
61 | | // for (const auto& edge : query.GetCrossingEdges(a, b, CrossingType::ALL)) { |
62 | | // ABSL_CHECK_GE(S2::CrossingSign(a0, a1, edge.v0(), edge.v1()), 0); |
63 | | // } |
64 | | // } |
65 | | // |
66 | | // Note that if you need to query many edges, it is more efficient to declare |
67 | | // a single S2CrossingEdgeQuery object and reuse it so that temporary storage |
68 | | // does not need to be reallocated each time. |
69 | | // |
70 | | // If you want to find *all* pairs of crossing edges, use |
71 | | // s2shapeutil::VisitCrossingEdgePairs() instead. |
72 | | class S2CrossingEdgeQuery { |
73 | | public: |
74 | | using CrossingType = s2shapeutil::CrossingType; // Defined above. |
75 | | |
76 | | // Convenience constructor that calls Init(). |
77 | | explicit S2CrossingEdgeQuery(const S2ShapeIndex* index); |
78 | | |
79 | | // Default constructor; requires Init() to be called. |
80 | | S2CrossingEdgeQuery(); |
81 | | ~S2CrossingEdgeQuery(); |
82 | | |
83 | | S2CrossingEdgeQuery(const S2CrossingEdgeQuery&) = delete; |
84 | | void operator=(const S2CrossingEdgeQuery&) = delete; |
85 | | |
86 | 0 | const S2ShapeIndex& index() const { return *index_; } |
87 | | |
88 | | // REQUIRES: "index" is not modified after this method is called. |
89 | | void Init(const S2ShapeIndex* index); |
90 | | |
91 | | // Returns all edges that intersect the given query edge (a0,a1) and that |
92 | | // have the given CrossingType (ALL or INTERIOR). Edges are sorted and |
93 | | // unique. |
94 | | std::vector<s2shapeutil::ShapeEdge> GetCrossingEdges( |
95 | | const S2Point& a0, const S2Point& a1, CrossingType type); |
96 | | |
97 | | // A specialized version of GetCrossingEdges() that only returns the edges |
98 | | // that belong to a particular S2Shape. |
99 | | std::vector<s2shapeutil::ShapeEdge> GetCrossingEdges(const S2Point& a0, |
100 | | const S2Point& a1, |
101 | | int shape_id, |
102 | | const S2Shape& shape, |
103 | | CrossingType type); |
104 | | |
105 | | // These versions can be more efficient when they are called many times, |
106 | | // since they do not require allocating a new vector on each call. |
107 | | void GetCrossingEdges(const S2Point& a0, const S2Point& a1, CrossingType type, |
108 | | std::vector<s2shapeutil::ShapeEdge>* edges); |
109 | | |
110 | | void GetCrossingEdges(const S2Point& a0, const S2Point& a1, int shape_id, |
111 | | const S2Shape& shape, CrossingType type, |
112 | | std::vector<s2shapeutil::ShapeEdge>* edges); |
113 | | |
114 | | /////////////////////////// Low-Level Methods //////////////////////////// |
115 | | // |
116 | | // Most clients will not need the following methods. They can be slightly |
117 | | // more efficient but are harder to use, since they require the client to do |
118 | | // all the actual crossing tests. |
119 | | |
120 | | // Returns a superset of the edges that intersect a query edge (a0, a1). |
121 | | // This method is useful for clients that want to test intersections in some |
122 | | // other way, e.g. using S2::EdgeOrVertexCrossing(). |
123 | | std::vector<s2shapeutil::ShapeEdgeId> GetCandidates(const S2Point& a0, |
124 | | const S2Point& a1); |
125 | | |
126 | | // A specialized version of GetCandidates() that only returns the edges that |
127 | | // belong to a particular S2Shape. |
128 | | std::vector<s2shapeutil::ShapeEdgeId> GetCandidates(const S2Point& a0, |
129 | | const S2Point& a1, |
130 | | int shape_id, |
131 | | const S2Shape& shape); |
132 | | |
133 | | // These versions can be more efficient when they are called many times, |
134 | | // since they do not require allocating a new vector on each call. |
135 | | void GetCandidates(const S2Point& a0, const S2Point& a1, |
136 | | std::vector<s2shapeutil::ShapeEdgeId>* edges); |
137 | | |
138 | | void GetCandidates(const S2Point& a0, const S2Point& a1, int shape_id, |
139 | | const S2Shape& shape, |
140 | | std::vector<s2shapeutil::ShapeEdgeId>* edges); |
141 | | |
142 | | // A function that is called with each candidate intersecting edge. The |
143 | | // function may return false in order to request that the algorithm should |
144 | | // be terminated, i.e. no further crossings are needed. |
145 | | using ShapeEdgeIdVisitor = |
146 | | std::function<bool (const s2shapeutil::ShapeEdgeId& id)>; |
147 | | |
148 | | // Visits a superset of the edges that intersect the query edge (a0, a1), |
149 | | // terminating early if the given ShapeEdgeIdVisitor returns false (in which |
150 | | // case this function returns false as well). |
151 | | // |
152 | | // CAVEAT: Edges may be visited more than once. |
153 | | bool VisitRawCandidates(const S2Point& a0, const S2Point& a1, |
154 | | const ShapeEdgeIdVisitor& visitor); |
155 | | |
156 | | bool VisitRawCandidates(const S2Point& a0, const S2Point& a1, int shape_id, |
157 | | const S2Shape& shape, |
158 | | const ShapeEdgeIdVisitor& visitor); |
159 | | |
160 | | // A function that is called with each S2ShapeIndexCell that might contain |
161 | | // edges intersecting the given query edge. The function may return false |
162 | | // in order to request that the algorithm should be terminated, i.e. no |
163 | | // further crossings are needed. |
164 | | using CellVisitor = std::function<bool (const S2ShapeIndexCell& cell)>; |
165 | | |
166 | | // Visits all S2ShapeIndexCells that might contain edges intersecting the |
167 | | // given query edge (a0, a1), terminating early if the given CellVisitor |
168 | | // returns false (in which case this function returns false as well). |
169 | | // |
170 | | // NOTE: Each candidate cell is visited exactly once. |
171 | | bool VisitCells(const S2Point& a0, const S2Point& a1, |
172 | | const CellVisitor& visitor); |
173 | | |
174 | | // Visits all S2ShapeIndexCells within "root" that might contain edges |
175 | | // intersecting the given query edge (a0, a1), terminating early if the |
176 | | // given CellVisitor returns false (in which case this function returns |
177 | | // false as well). |
178 | | // |
179 | | // NOTE: Each candidate cell is visited exactly once. |
180 | | // |
181 | | // REQUIRES: root.padding() == 0 |
182 | | // [This low-level method does not support padding; the argument is supplied |
183 | | // as an S2PaddedCell in order to avoid constructing it repeatedly when |
184 | | // this method is called using different query edges with the same root.] |
185 | | bool VisitCells(const S2Point& a0, const S2Point& a1, |
186 | | const S2PaddedCell& root, const CellVisitor& visitor); |
187 | | |
188 | | |
189 | | // Given a query edge AB and a cell "root", returns all S2ShapeIndex cells |
190 | | // within "root" that might contain edges intersecting AB. |
191 | | // |
192 | | // REQUIRES: root.padding() == 0 (see above) |
193 | | void GetCells(const S2Point& a0, const S2Point& a1, const S2PaddedCell& root, |
194 | | std::vector<const S2ShapeIndexCell*>* cells); |
195 | | |
196 | | private: |
197 | | // Internal methods are documented with their definitions. |
198 | | bool VisitCells(const S2PaddedCell& pcell, const R2Rect& edge_bound); |
199 | | bool ClipVAxis(const R2Rect& edge_bound, double center, int i, |
200 | | const S2PaddedCell& pcell); |
201 | | void SplitUBound(const R2Rect& edge_bound, double u, |
202 | | R2Rect child_bounds[2]) const; |
203 | | void SplitVBound(const R2Rect& edge_bound, double v, |
204 | | R2Rect child_bounds[2]) const; |
205 | | static void SplitBound(const R2Rect& edge_bound, int u_end, double u, |
206 | | int v_end, double v, R2Rect child_bounds[2]); |
207 | | |
208 | | const S2ShapeIndex* index_ = nullptr; |
209 | | |
210 | | //////////// Temporary storage used while processing a query /////////// |
211 | | |
212 | | R2Point a0_, a1_; |
213 | | S2ShapeIndex::Iterator iter_; |
214 | | const CellVisitor* visitor_; |
215 | | |
216 | | // Avoids repeated allocation when methods are called many times. |
217 | | std::vector<s2shapeutil::ShapeEdgeId> tmp_candidates_; |
218 | | }; |
219 | | |
220 | | |
221 | | ////////////////// Implementation details follow //////////////////// |
222 | | |
223 | | |
224 | 0 | inline S2CrossingEdgeQuery::S2CrossingEdgeQuery(const S2ShapeIndex* index) { |
225 | 0 | Init(index); |
226 | 0 | } |
227 | | |
228 | | #endif // S2_S2CROSSING_EDGE_QUERY_H_ |