1 // Copyright 2017 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 // Original Author: ericv@google.com (Eric Veach)
17 // Converted to D:  madric@gmail.com (Vijay Nayar)
18 
19 module s2.s2contains_vertex_query;
20 
21 import s2.s2point;
22 import s2.s2pointutil : ortho;
23 import s2.s2predicates : orderedCCW;
24 
25 import std.exception : enforce;
26 import std.math : abs;
27 import std.typecons : tuple;
28 
29 // This class determines whether a polygon contains one of its vertices given
30 // the edges incident to that vertex.  The result is +1 if the vertex is
31 // contained, -1 if it is not contained, and 0 if the incident edges consist
32 // of matched sibling pairs (in which case the result cannot be determined
33 // locally).
34 //
35 // Point containment is defined according to the "semi-open" boundary model
36 // (see S2VertexModel), which means that if several polygons tile the region
37 // around a vertex, then exactly one of those polygons contains that vertex.
38 //
39 // This class is not thread-safe.  To use it in parallel, each thread should
40 // construct its own instance (this is not expensive).
41 class S2ContainsVertexQuery {
42 public:
43   // "target" is the vertex whose containment will be determined.
44   this(in S2Point target) {
45     _target = target;
46   }
47 
48   // Indicates that the polygon has an edge between "target" and "v" in the
49   // given direction (+1 = outgoing, -1 = incoming, 0 = degenerate).
50   void addEdge(in S2Point v, int direction) {
51     _edgeMap[v] += direction;
52   }
53 
54   // Returns +1 if the vertex is contained, -1 if it is not contained, and 0
55   // if the incident edges consisted of matched sibling pairs.
56   int containsSign() {
57     // Find the unmatched edge that is immediately clockwise from S2::Ortho(P).
58     S2Point reference_dir = ortho(_target);
59     auto best = tuple(reference_dir, 0);
60     foreach (S2Point point, int dir; _edgeMap) {
61       enforce(abs(dir) <= 1);
62       if (dir == 0) continue;  // This is a "matched" edge.
63       if (orderedCCW(reference_dir, best[0], point, _target)) {
64         best = tuple(point, dir);
65       }
66     }
67     return best[1];
68   }
69 
70 private:
71   S2Point _target;
72   int[S2Point] _edgeMap;
73 }