1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.geometry.spherical.twod;
23
24 import org.hipparchus.exception.MathIllegalArgumentException;
25 import org.hipparchus.geometry.euclidean.threed.Rotation;
26 import org.hipparchus.geometry.euclidean.threed.Vector3D;
27 import org.hipparchus.geometry.partitioning.Embedding;
28 import org.hipparchus.geometry.partitioning.Hyperplane;
29 import org.hipparchus.geometry.partitioning.RegionFactory;
30 import org.hipparchus.geometry.partitioning.Transform;
31 import org.hipparchus.geometry.spherical.oned.Arc;
32 import org.hipparchus.geometry.spherical.oned.ArcsSet;
33 import org.hipparchus.geometry.spherical.oned.LimitAngle;
34 import org.hipparchus.geometry.spherical.oned.S1Point;
35 import org.hipparchus.geometry.spherical.oned.Sphere1D;
36 import org.hipparchus.geometry.spherical.oned.SubLimitAngle;
37 import org.hipparchus.util.FastMath;
38 import org.hipparchus.util.MathUtils;
39 import org.hipparchus.util.SinCos;
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class Circle
54 implements Hyperplane<Sphere2D, S2Point, Circle, SubCircle>,
55 Embedding<Sphere2D, S2Point, Sphere1D, S1Point> {
56
57
58 private Vector3D pole;
59
60
61 private Vector3D x;
62
63
64 private Vector3D y;
65
66
67 private final double tolerance;
68
69
70
71
72
73
74
75 public Circle(final Vector3D pole, final double tolerance)
76 throws MathIllegalArgumentException {
77 Sphere2D.checkTolerance(tolerance);
78 reset(pole);
79 this.tolerance = tolerance;
80 }
81
82
83
84
85
86
87
88
89 public Circle(final S2Point first, final S2Point second, final double tolerance)
90 throws MathIllegalArgumentException {
91 Sphere2D.checkTolerance(tolerance);
92 reset(first.getVector().crossProduct(second.getVector()));
93 this.tolerance = tolerance;
94 }
95
96
97
98
99
100
101
102
103
104 private Circle(final Vector3D pole, final Vector3D x, final Vector3D y, final double tolerance)
105 throws MathIllegalArgumentException {
106 Sphere2D.checkTolerance(tolerance);
107 this.pole = pole;
108 this.x = x;
109 this.y = y;
110 this.tolerance = tolerance;
111 }
112
113
114
115
116
117
118 public Circle(final Circle circle) {
119 this(circle.pole, circle.x, circle.y, circle.tolerance);
120 }
121
122
123 @Override
124 public Circle copySelf() {
125 return new Circle(this);
126 }
127
128
129
130
131
132 public void reset(final Vector3D newPole) {
133 this.pole = newPole.normalize();
134 this.x = newPole.orthogonal();
135 this.y = Vector3D.crossProduct(newPole, x).normalize();
136 }
137
138
139
140 public void revertSelf() {
141
142 y = y.negate();
143 pole = pole.negate();
144 }
145
146
147
148
149
150
151 public Circle getReverse() {
152 return new Circle(pole.negate(), x, y.negate(), tolerance);
153 }
154
155
156 @Override
157 public S2Point project(S2Point point) {
158 return toSpace(toSubSpace(point));
159 }
160
161
162 @Override
163 public double getTolerance() {
164 return tolerance;
165 }
166
167
168
169
170 @Override
171 public S1Point toSubSpace(final S2Point point) {
172 return new S1Point(getPhase(point.getVector()));
173 }
174
175
176
177
178
179
180
181
182
183
184
185 public double getPhase(final Vector3D direction) {
186 return FastMath.PI + FastMath.atan2(-direction.dotProduct(y), -direction.dotProduct(x));
187 }
188
189
190
191
192 @Override
193 public S2Point toSpace(final S1Point point) {
194 return new S2Point(getPointAt(point.getAlpha()));
195 }
196
197
198
199
200
201
202
203
204 public Vector3D getPointAt(final double alpha) {
205 final SinCos sc = FastMath.sinCos(alpha);
206 return new Vector3D(sc.cos(), x, sc.sin(), y);
207 }
208
209
210
211
212
213
214
215
216
217
218
219
220 public Vector3D getXAxis() {
221 return x;
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235 public Vector3D getYAxis() {
236 return y;
237 }
238
239
240
241
242
243
244
245
246
247
248 public Vector3D getPole() {
249 return pole;
250 }
251
252
253
254
255
256 public Arc getInsideArc(final Circle other) {
257 final double alpha = getPhase(other.pole);
258 return new Arc(alpha - MathUtils.SEMI_PI, alpha + MathUtils.SEMI_PI, tolerance);
259 }
260
261
262 @Override
263 public SubCircle wholeHyperplane() {
264 return new SubCircle(this, new ArcsSet(tolerance));
265 }
266
267
268 @Override
269 public SubCircle emptyHyperplane() {
270 final RegionFactory<Sphere1D, S1Point, LimitAngle, SubLimitAngle> factory = new RegionFactory<>();
271 return new SubCircle(this, factory.getComplement(new ArcsSet(tolerance)));
272 }
273
274
275
276
277
278 @Override
279 public SphericalPolygonsSet wholeSpace() {
280 return new SphericalPolygonsSet(tolerance);
281 }
282
283
284
285
286 @Override
287 public double getOffset(final S2Point point) {
288 return getOffset(point.getVector());
289 }
290
291
292
293
294
295
296
297
298
299
300 public double getOffset(final Vector3D direction) {
301 return Vector3D.angle(pole, direction) - MathUtils.SEMI_PI;
302 }
303
304
305 @Override
306 public S2Point moveToOffset(final S2Point point, final double offset) {
307 final SinCos scOld = FastMath.sinCos(getOffset(point));
308 final SinCos scNew = FastMath.sinCos(offset);
309 final double ratio = scNew.cos() / scOld.cos();
310 return new S2Point(new Vector3D(ratio * scOld.sin() - scNew.sin(), pole,
311 ratio, point.getVector()));
312 }
313
314
315 @Override
316 public S2Point arbitraryPoint() {
317 return new S2Point(pole.orthogonal());
318 }
319
320
321 @Override
322 public boolean sameOrientationAs(final Circle other) {
323 return Vector3D.dotProduct(pole, other.pole) >= 0.0;
324 }
325
326
327
328
329
330
331
332
333
334 public Arc getArc(final S2Point a, final S2Point b) {
335 final double phaseA = getPhase(a.getVector());
336 double phaseB = getPhase(b.getVector());
337 if (phaseB < phaseA) {
338 phaseB += 2 * FastMath.PI;
339 }
340 return new Arc(phaseA, phaseB, tolerance);
341 }
342
343
344
345
346
347
348
349
350
351 public static Transform<Sphere2D, S2Point, Circle, SubCircle, Sphere1D, S1Point, LimitAngle, SubLimitAngle>
352 getTransform(final Rotation rotation) {
353 return new CircleTransform(rotation);
354 }
355
356
357 private static class CircleTransform
358 implements Transform<Sphere2D, S2Point, Circle, SubCircle, Sphere1D, S1Point, LimitAngle, SubLimitAngle> {
359
360
361 private final Rotation rotation;
362
363
364
365
366 CircleTransform(final Rotation rotation) {
367 this.rotation = rotation;
368 }
369
370
371 @Override
372 public S2Point apply(final S2Point point) {
373 return new S2Point(rotation.applyTo(point.getVector()));
374 }
375
376
377 @Override
378 public Circle apply(final Circle circle) {
379 return new Circle(rotation.applyTo(circle.pole),
380 rotation.applyTo(circle.x),
381 rotation.applyTo(circle.y),
382 circle.tolerance);
383 }
384
385
386 @Override
387 public SubLimitAngle apply(final SubLimitAngle sub, final Circle original, final Circle transformed) {
388
389 return sub;
390 }
391
392 }
393
394 }