/
SearchStructure.java
224 lines (186 loc) · 6.32 KB
/
SearchStructure.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package myLibraries.util.graph;
/*
* SearchStructure.java
*
* JDK: 16
*
* Version:
* $1.0$
*
* Revisions:
* $1.0 basic operations on 10/19/2021$
*/
import myLibraries.lang.MyMath;
import myLibraries.util.geometry.DCEL.Face;
import myLibraries.util.geometry.elements.Trapezoid;
import myLibraries.util.geometry.elements.line.Line;
import myLibraries.util.geometry.elements.point.Vector;
import myLibraries.util.geometry.tools.Lines;
import myLibraries.util.geometry.tools.Polygons;
import myLibraries.util.geometry.tools.Triangles;
import myLibraries.util.geometry.tools.Vectors;
import myLibraries.util.graph.elements.SearchVertex;
import java.util.ArrayList;
import java.util.List;
/**
* Data structure of Search Structure, SS, tree-like DGA, for point location.
*
* @author Xiaoyu Tongyang, or call me sora for short
*/
public class SearchStructure extends DAG<SearchVertex> {
private SearchVertex root = null;
public Trapezoid boundingBox;
private final Face face;
private final List<SearchVertex> searchPath = new ArrayList<>();
private final List<SearchVertex> xNodePs = new ArrayList<>();
private final List<SearchVertex> xNodeQs = new ArrayList<>();
private final List<SearchVertex> yNodes = new ArrayList<>();
private final List<SearchVertex> leaves = new ArrayList<>();
public SearchStructure( SearchVertex R ) {
root = R;
try {
boundingBox = ( Trapezoid ) R.trapezoid.clone();
} catch ( CloneNotSupportedException e ) {
e.printStackTrace();
System.exit( 1 );
}
face = boundingBox.getDCEL();
}
public void setRoot( SearchVertex root ) {
this.root = root;
}
public static
String getSearchPathString( List<SearchVertex> searchPath ) {
StringBuilder path = new StringBuilder();
searchPath.forEach( vertex -> {
path.append( vertex.name ).append( " " );
} );
return path.toString();
}
/**
* set Trapezoids' leafIDs in pre-traversal ordering
* */
public void setLeafIDs() {
List<SearchVertex> list = getAllLeafNodes();
int ID = 1;
for ( SearchVertex vertex : list ) {
if ( vertex.trapezoid.leafID < 0 ) {
vertex.trapezoid.leafID = ID++;
vertex.name = "T" + vertex.trapezoid.leafID;
}
}
}
public List<SearchVertex> getAllXNodePs() {
getAllNodes();
return new ArrayList<>( xNodePs );
}
public List<SearchVertex> getAllXNodeQs() {
getAllNodes();
return new ArrayList<>( xNodeQs );
}
public List<SearchVertex> getAllYNodes() {
getAllNodes();
return new ArrayList<>( yNodes );
}
public List<SearchVertex> getAllLeafNodes() {
getAllNodes();
return new ArrayList<>( leaves );
}
private void resetNodeLists() {
xNodePs.clear();
xNodeQs.clear();
yNodes.clear();
leaves.clear();
}
private void getAllNodes() {
resetNodeLists();
getAllNodes( root );
}
private void getAllNodes( SearchVertex root ) {
switch ( root.type ) {
case X_POINT_P -> xNodePs.add( root );
case X_POINT_Q -> xNodeQs.add( root );
case SEGMENT -> yNodes.add( root );
case TRAPEZOID -> {
assert root.isLeaf() : root;
assert root.trapezoid.check();
leaves.add( root );
return;
}
default -> {
assert false;
}
}
getAllNodes( root.left );
getAllNodes( root.right );
}
/**
* query operation with traversal path
* */
public List<SearchVertex> getPath( Vector p ) {
if ( p == null ) return null;
searchPath.clear();
get( p );
return new ArrayList<>( searchPath );
}
/**
* query operation with point
* */
public SearchVertex get( Vector p ) {
if ( p == null ) return null;
Vector q = new Vector( p.x, p.y + 1 );
return get( new Line( p, q ) );
}
/**
* query operation with line, actually query its startPoint, left EndPoint
* */
public SearchVertex get( Line line ) {
if ( line == null ) return null;
if ( root.left == null && root.right == null ) return root;
// query point( line.startPoint ) lies in the range of the bounding box?
if ( !Polygons.isInsideThisPolygon( face, line.startPoint ) )
return null;
assert Vectors.sortByX( line.startPoint, line.endPoint ) <= 0;
SearchVertex res = get( root, line );
assert res.type == SearchVertex.NodeType.TRAPEZOID;
return res;
}
private SearchVertex get( SearchVertex root, Line line ) {
Vector p = line.startPoint;
assert root != null;
searchPath.add( root );
switch ( root.type ) {
case X_POINT_Q, X_POINT_P -> {
if ( Vectors.isLeft( root.point, p ) )
return get( root.left, line );
// whenever p lies on the vertical line of an x-node,
// we decide that it lies to the right.
return get( root.right, line );
}
case SEGMENT -> {
double res = Triangles.areaTwo( root.line.startPoint, root.line.endPoint, p );
// whenever p lies on a segment s of a y-node
// (this can only happen if si shares its left endpoint, p, with s)
// we compare the slopes of s and si; if the slope of si is larger,
// we decide that p lies above s, otherwise we decide that it is below s.
if ( MyMath.isEqualZero( res ) ) {
if ( Lines.compareBySlope( line, root.line ) > 0 )
return get( root.left, line );
else return get( root.right, line );
}
else if ( MyMath.isPositive( res ) )
return get( root.left, line );
return get( root.right, line );
}
// base case
case TRAPEZOID -> {
return root;
}
default -> {
assert false;
}
}
assert false;
return null;
}
}