1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.spherical.twod;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Objects;
22
23 import org.apache.commons.geometry.euclidean.internal.AbstractPathConnector;
24 import org.apache.commons.geometry.euclidean.threed.Vector3D;
25
26
27
28
29 public abstract class AbstractGreatArcConnector
30 extends AbstractPathConnector<AbstractGreatArcConnector.ConnectableGreatArc> {
31
32
33
34
35
36
37 public void add(final GreatArc arc) {
38 addPathElement(new ConnectableGreatArc(arc));
39 }
40
41
42
43
44
45
46
47
48
49 public void add(final Iterable<GreatArc> arcs) {
50 for (final GreatArc segment : arcs) {
51 add(segment);
52 }
53 }
54
55
56
57
58
59
60
61
62
63
64
65 public void connect(final Iterable<GreatArc> arcs) {
66 final List<ConnectableGreatArc> newEntries = new ArrayList<>();
67
68 for (final GreatArc segment : arcs) {
69 newEntries.add(new ConnectableGreatArc(segment));
70 }
71
72 connectPathElements(newEntries);
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public List<GreatArcPath> connectAll(final Iterable<GreatArc> arcs) {
90 add(arcs);
91 return connectAll();
92 }
93
94
95
96
97
98
99
100
101 public List<GreatArcPath> connectAll() {
102 final List<ConnectableGreatArc> roots = computePathRoots();
103 final List<GreatArcPath> paths = new ArrayList<>(roots.size());
104
105 for (final ConnectableGreatArc root : roots) {
106 paths.add(toPath(root));
107 }
108
109 return paths;
110 }
111
112
113
114
115
116
117 private GreatArcPath toPath(final ConnectableGreatArc root) {
118 final GreatArcPath.Builder builder = GreatArcPath.builder(null);
119
120 builder.append(root.getArc());
121
122 ConnectableGreatArc current = root.getNext();
123
124 while (current != null && current != root) {
125 builder.append(current.getArc());
126 current = current.getNext();
127 }
128
129 return builder.build();
130 }
131
132
133
134 protected static class ConnectableGreatArc extends AbstractPathConnector.ConnectableElement<ConnectableGreatArc> {
135
136 private final Point2S start;
137
138
139 private final GreatArc arc;
140
141
142
143
144
145 public ConnectableGreatArc(final Point2S start) {
146 this(start, null);
147 }
148
149
150
151
152 public ConnectableGreatArc(final GreatArc arc) {
153 this(arc.getStartPoint(), arc);
154 }
155
156
157
158
159
160 private ConnectableGreatArc(final Point2S start, final GreatArc arc) {
161 this.start = start;
162 this.arc = arc;
163 }
164
165
166
167
168 public GreatArc getArc() {
169 return arc;
170 }
171
172
173 @Override
174 public boolean hasStart() {
175 return start != null;
176 }
177
178
179 @Override
180 public boolean hasEnd() {
181 return arc.getEndPoint() != null;
182 }
183
184
185 @Override
186 public boolean endPointsEq(final ConnectableGreatArc other) {
187 if (hasEnd() && other.hasEnd()) {
188 return arc.getEndPoint()
189 .eq(other.arc.getEndPoint(), arc.getCircle().getPrecision());
190 }
191
192 return false;
193 }
194
195
196
197
198 public boolean hasZeroSize() {
199 return arc != null && arc.getCircle().getPrecision().eqZero(arc.getSize());
200 }
201
202
203 @Override
204 public boolean canConnectTo(final ConnectableGreatArc next) {
205 final Point2S end = arc.getEndPoint();
206 final Point2S nextStart = next.start;
207
208 return end != null && nextStart != null &&
209 end.eq(nextStart, arc.getCircle().getPrecision());
210 }
211
212
213 @Override
214 public double getRelativeAngle(final ConnectableGreatArc other) {
215 return arc.getCircle().angle(other.getArc().getCircle());
216 }
217
218
219 @Override
220 public ConnectableGreatArc getConnectionSearchKey() {
221 return new ConnectableGreatArc(arc.getEndPoint());
222 }
223
224
225 @Override
226 public boolean shouldContinueConnectionSearch(final ConnectableGreatArc candidate,
227 final boolean ascending) {
228
229 if (candidate.hasStart()) {
230 final double candidatePolar = candidate.getArc().getStartPoint().getPolar();
231 final double thisPolar = arc.getEndPoint().getPolar();
232 final int cmp = arc.getCircle().getPrecision().compare(candidatePolar, thisPolar);
233
234 return ascending ? cmp <= 0 : cmp >= 0;
235 }
236
237 return true;
238 }
239
240
241 @Override
242 public int compareTo(final ConnectableGreatArc other) {
243 int cmp = Point2S.POLAR_AZIMUTH_ASCENDING_ORDER.compare(start, other.start);
244
245 if (cmp == 0) {
246
247 final boolean thisHasArc = arc != null;
248 final boolean otherHasArc = other.arc != null;
249
250 cmp = Boolean.compare(thisHasArc, otherHasArc);
251
252 if (cmp == 0 && thisHasArc) {
253
254 cmp = Boolean.compare(this.hasZeroSize(), other.hasZeroSize());
255
256 if (cmp == 0) {
257
258 cmp = Vector3D.COORDINATE_ASCENDING_ORDER.compare(
259 arc.getCircle().getPole(),
260 other.arc.getCircle().getPole());
261 }
262 }
263 }
264
265 return cmp;
266 }
267
268
269 @Override
270 public int hashCode() {
271 return Objects.hash(start, arc);
272 }
273
274
275 @Override
276 public boolean equals(final Object obj) {
277 if (this == obj) {
278 return true;
279 }
280 if (obj == null || !this.getClass().equals(obj.getClass())) {
281 return false;
282 }
283
284 final ConnectableGreatArc other = (ConnectableGreatArc) obj;
285 return Objects.equals(this.start, other.start) &&
286 Objects.equals(this.arc, other.arc);
287 }
288
289
290 @Override
291 protected ConnectableGreatArc getSelf() {
292 return this;
293 }
294 }
295 }