1
2# -*- coding: utf-8 -*-
3
4# Test module attributes.
5
6__all__ = ('Tests',)
7__version__ = '21.09.05'
8
9from base import coverage, GeodSolve, numpy, TestsBase
10
11from pygeodesy import EPS, EPS4, F_D, NEG0, circin6, circum3, circum4_, \
12                      fstr, intersection3d3 as i3d, IntersectionError, \
13                      isnear0, meeus2, radii11, sphericalNvector, \
14                      soddy4, trilaterate2d2, trilaterate3d2, \
15                      vector2d, vector3d, Vector3d as V3d, VectorError
16from pygeodesy.interns import _DOT_  # INTERNAL
17
18
19class Tests(TestsBase):
20
21    def testIntersection3d3(self):
22
23        self.subtitle(vector3d, i3d.__name__)
24
25        # <https://www.MathOpenRef.com/coordintersection.html>
26        s1, e1 = V3d(15, 10, 1), V3d(49, 25, 2)
27        s2, e2 = V3d(29, 5, 3),  V3d(32, 32, 4)
28        self.test('(30, 17)', i3d(s1, e1, s2, e2, useZ=False), '(Vector3d(30.30584, 16.75258, 0.0), 0, 0)')
29        s2 = V3d(7, 10, 5)
30        self.test('(-1,  3)', i3d(s1, e1, s2, e2, useZ=False), '(Vector3d(-1.0429, 2.92225, 0.0), -1, -2)')
31        s2 = V3d(62, 32, 6)
32        self.test('(65, 32)', i3d(s1, e1, s2, e2, useZ=False), '(Vector3d(64.86667, 32.0, 0.0), 1, -2)')
33        try:
34            s2 = V3d(32 - (49 - 15), 32 - (25 - 10), 7)
35            self.test('(-2, 17)', i3d(s1, e1, s2, e2, useZ=False), IntersectionError.__name__)
36        except Exception as x:
37            self.test('(-2, 17)', x.__class__, IntersectionError)
38        self.test('(49, 25)', i3d(s1, e1, e1, e1, useZ=False), '(Vector3d(49.0, 25.0, 0.0), 0, 0)')
39
40    def testNvectorBase(self, module, **kwds):
41
42        try:
43            Nvector = module.Nvector
44            c = Nvector.__name__
45        except AttributeError:
46            Nvector = module.NvectorBase
47            c = 'Vector4Tuple'
48        self.subtitle(module, Nvector.__name__)
49
50        v = Nvector(0.500, 0.500, 0.707, **kwds)
51        s = module.sumOf((v, v), h=0, name='sumOf')
52        self.test('sumOf', s.__class__.__name__, c)
53
54        p = v.toLatLon(LatLon=None)
55        c = v.toCartesian(Cartesian=None)
56        self.test('ecef.x, .y, .z', fstr(p[:3],  prec=5), fstr(c[:3],  prec=5))
57        self.test('ecef.lat, .lon', fstr(p[3:5], prec=6), fstr(c[3:5], prec=6))
58        self.test('ecef.height', fstr(p.height, prec=6), fstr(c.height, prec=6), known=True)
59        if c.M is not None:
60            self.test('ecef.M', fstr(p.M, prec=9), fstr(c.M, prec=9))
61
62        if coverage:
63            from pygeodesy.namedTuples import LatLon2Tuple, LatLon3Tuple, \
64                                              PhiLam2Tuple, PhiLam3Tuple
65
66            self.test('.isEllipsoidal', v.isEllipsoidal, not v.isSpherical)
67            self.test('.isSpherical',   v.isSpherical,   not v.isEllipsoidal)
68
69            self.test('.latlon', v.latlon, LatLon2Tuple(v.lat, v.lon))
70            self.test('.philam', v.philam, PhiLam2Tuple(v.phi, v.lam))
71
72            self.test('.latlonheight', v.latlonheight, LatLon3Tuple(v.lat, v.lon, v.h), known=v.h in (0, 0.0, NEG0))
73            self.test('.philamheight', v.philamheight, PhiLam3Tuple(v.phi, v.lam, v.h), known=v.h in (0, 0.0, NEG0))
74
75            t = v.parse('0.5, 0.5, 0.707')
76            self.test('parse', t, v)
77            self.test('cmp', t.cmp(v), 0)
78
79            self.test('eq', t == v, True)
80            self.test('ge', t >= v, True)
81            self.test('gt', t >  v, False)
82            self.test('le', t <= v, True)
83            self.test('lt', t <  v, False)
84            self.test('ne', t != v, False)
85
86            m = t * 2
87            self.test('*', m, '(1.0, 1.0, 1.414)')
88            self.test('+', t + v, m)
89            self.test('/', m / 2, t)
90            self.test('-', m - t, t)
91
92            m = v.__matmul__(t)
93            self.test('@', m, '(0.0, 0.0, 0.0)')
94            r = t.__rmatmul__(m)
95            self.test('@', r, m)
96
97            r = v.rotate(m, 45)
98            self.test('rotate', r, '(0.26268, 0.26268, 0.37143)')
99
100            r.crosserrors = True
101            self.test('crosserrors', r.crosserrors, True)
102
103            try:
104                self.test('0', v.dividedBy(0), VectorError.__name__)
105            except Exception as x:
106                self.test('0', str(x), 'factor (0): float division by zero')
107
108            t = vector3d.intersections2(Nvector(   0, 0, 0), 500,
109                                        Nvector(1000, 0, 0), 500, sphere=False)
110            self.test('intersections2', t[0], t[1])  # abutting
111
112            p1, p2 = Nvector(-100, -100, -100), Nvector(100, 100, 100)
113            t = vector2d.nearestOn(Nvector(0, 0, 0), p1, p2)
114            self.test('nearestOn', t, '(0.0, 0.0, 0.0)')
115            t = vector2d.nearestOn(Nvector(-200, -200, 0), p1, p2)
116            self.test('nearestOn', t is p1, True)
117            t = vector2d.nearestOn(Nvector(200, 200, 0), p1, p2)
118            self.test('nearestOn', t, p2)
119            self.test('nearestOn', t is p2, True)
120            t = vector2d.iscolinearWith(Nvector(200, 200, 0), p1, p2)
121            self.test('iscolinearWith', t, False)
122            t = vector2d.iscolinearWith(Nvector(0, 0, 0), p1, p2)
123            self.test('iscolinearWith', t, True)
124
125            p1, p2 = V3d(-100, -100, -100), V3d(100, 100, 100)
126            t = V3d(0, 0, 0).nearestOn(p1, p2)
127            self.test('nearestOn', t, '(0.0, 0.0, 0.0)')
128            t = V3d(-200, -200, 0).nearestOn(p1, p2)
129            self.test('nearestOn', t is p1, True)
130            t = V3d(200, 200, 0).nearestOn(p1, p2)
131            self.test('nearestOn', t, p2)
132            self.test('nearestOn', t is p2, True)
133            t = V3d(200, 200, 0).iscolinearWith(p1, p2)
134            self.test('iscolinearWith', t, False)
135            t = V3d(0, 0, 0).iscolinearWith(p1, p2)
136            self.test('iscolinearWith', t, True)
137
138    def testVectorial(self, module):  # MCCABE 14
139
140        self.subtitle(module, 'Vectorial')
141
142        LatLon, Nvector, meanOf, sumOf = module.LatLon, module.Nvector, module.meanOf, module.sumOf
143
144        if hasattr(LatLon, 'crossTrackDistanceTo'):
145            p = LatLon(53.2611, -0.7972)
146            s = LatLon(53.3206, -1.7297)
147            d = p.crossTrackDistanceTo(s, 96.0)
148            self.test('crossTrackDistanceTo', d, '-305.67', prec=2)  # -305.7
149            e = LatLon(53.1887, 0.1334)
150            d = p.crossTrackDistanceTo(s, e)
151            self.test('crossTrackDistanceTo', d, '-307.55', prec=2)  # -307.5
152
153        if hasattr(LatLon, 'enclosedby'):
154            r = LatLon(45,1), LatLon(45,2), LatLon(46,2), LatLon(46,1)
155            p = LatLon(45.1, 1.1)
156            self.test('enclosedby', p.enclosedby(r), True)
157            r = LatLon(45,1), LatLon(46,2), LatLon(45,2), LatLon(46,1)
158            self.test('enclosedby', p.enclosedby(r), False)
159
160        v = Nvector(0.500, 0.500, 0.707)
161        p = v.toLatLon()
162        self.test('toLatLon', p, '44.995674°N, 045.0°E')  # 45.0°N, 45.0°E
163        c = p.toNvector()
164        self.test('toNvector', c, '(0.50004, 0.50004, 0.70705)')  # 0.500, 0.500, 0.707
165        self.test('isequalTo', c.isequalTo(v), False)
166        self.test('isequalTo', c.isequalTo(v, units=True), True)
167        self.test('length', v.length, '0.99992449715', prec=11)
168        self.test('euclid', v.euclid, '0.99995577', prec=8)
169        self.test('length', c.length, '1.00', prec=2)
170        self.test('euclid', c.euclid, '1.0000', prec=4)
171
172        s = meanOf((p, p, p, p), height=0, LatLon=LatLon)
173        self.test('meanOf', s, '44.995674°N, 045.0°E')
174        self.test('meanOf', s.__class__.__name__, LatLon.__name__)
175
176        class Nv(Nvector):
177            pass
178        v = Nvector(52.205, 0.119, 0.0)
179        s = sumOf((v, c), Vector=Nv, h=0, name='sumOf')
180        self.test('sumOf', s, '(52.70504, 0.61904, 0.70705)')
181        self.test('sumOf', s.__class__.__name__, 'Nv')
182        self.test('sumOf', s._name, 'sumOf')
183        self.test('length', s.length, '52.7134151513', prec=10)
184
185        c = v.copy()
186        self.test('copy', c.isequalTo(v), True)
187        self.test('length', v.length, '52.2051356286', prec=10)
188        self.test('length', c.length, '52.2051356286', prec=10)
189
190        if module is sphericalNvector:  # coverage
191            c = p.toCartesian()
192            self.test('toCartesian', c, '[3185744.919, 3185744.919, 4504643.315]')
193            self.test('toLatLon',  c.toLatLon(), p, known=True)  # '44.995674°N, 045.0°E, -0.00m'
194            self.test('toNvector', c.toNvector(), '(0.50004, 0.50004, 0.70705, -0.00)', known=True)
195
196        if hasattr(LatLon, 'intersection'):
197            # <https://GitHub.com/ChrisVeness/geodesy/blob/master/test/latlon-vectors-tests.js>
198            p = LatLon(1, 1)
199            i = p.intersection(LatLon(2, 2), LatLon(1, 4), LatLon(2, 3))
200            self.test('intersection', i, '02.499372°N, 002.5°E')
201
202        if hasattr(LatLon, 'isenclosedBy'):
203            p = LatLon(45.1, 1.1)
204
205            b = LatLon(45, 1), LatLon(45, 2), LatLon(46, 2), LatLon(46, 1)
206            for _ in self.testiter():
207                self.test('isenclosedBy', p.isenclosedBy(b), True)
208
209            b = LatLon(45, 1), LatLon(45, 3), LatLon(46, 2), LatLon(47, 3), LatLon(47, 1)
210            for _ in self.testiter():
211                try:
212                    self.test('isenclosedBy', p.isenclosedBy(b), True)  # Nvector
213                except ValueError as x:
214                    t = ' '.join(str(x).split()[:3] + ['...)'])
215                    self.test('isenclosedBy', t, 'non-convex: (LatLon(45°00′00.0″N, 001°00′00.0″E), ...)')  # Trig
216
217        if hasattr(LatLon, 'iswithin'):
218            # courtesy of Paulius Šarka  psarka  Aug 30, 2017
219            p = LatLon(1, 1).iswithin(LatLon(2, 2), LatLon(2, 2))
220            self.test('iswithin', p, False)
221            p = LatLon(2, 2).iswithin(LatLon(2, 2), LatLon(2, 2))
222            self.test('iswithin', p, True)
223
224        if hasattr(LatLon, 'nearestOn'):
225            s1 = LatLon(51.0, 1.0)
226            s2 = LatLon(51.0, 2.0)
227
228            s = LatLon(41.0, 0.0)
229            p = s.nearestOn(s1, s2, within=True)
230            self.test('nearestOn', p.toStr(F_D, prec=3), '51.0°N, 001.0°E')
231            p = s.nearestOn(s1, s2, within=False)
232            self.test('nearestOn', p.toStr(F_D, prec=3), '50.987°N, 000.298°W')
233
234            s = LatLon(61.0, 3.0)
235            p = s.nearestOn(s1, s2, within=True)
236            self.test('nearestOn', p.toStr(F_D, prec=3), '51.0°N, 002.0°E')
237            p = s.nearestOn(s1, s2, within=False)
238            self.test('nearestOn', p.toStr(F_D, prec=3), '50.995°N, 002.655°E')
239
240            s = LatLon(51.0, 1.9)
241            p = s.nearestOn(s1, s2)  # 51.0004°N, 001.9000°E
242            self.test('nearestOn', p.toStr(F_D, prec=3), '51.0°N, 001.9°E')
243            self.test('nearestOn', isinstance(p, LatLon), True)
244
245            d = p.distanceTo(s)  # 42.71 m
246            self.test('distanceTo', d, 42.712 if module is sphericalNvector else 42.826, prec=3, known=int(d) == 42)
247            s = LatLon(51.0, 2.1)
248            p = s.nearestOn(s1, s2)  # 51.0000°N, 002.0000°E
249            self.test('nearestOn', p.toStr(F_D), '51.0°N, 002.0°E')
250            self.test('nearestOn', isinstance(p, LatLon), True)
251
252            # courtesy AkimboEG on GitHub
253            s1 = LatLon(0, 0)
254            s2 = LatLon(0, 1)
255            s = LatLon(1, 0)
256            p = s.nearestOn(s1, s2)  # 0.0°N, 0.0°E
257            self.test('nearestOn', p, '00.0°N, 000.0°E')
258            self.test('nearestOn', isinstance(p, LatLon), True)
259
260            p = LatLon(10, -140).nearestOn(LatLon(0, 20), LatLon(0, 40))
261            self.test('nearestOn', p, '00.0°N, 020.0°E')
262            self.test('nearestOn', isinstance(p, LatLon), True)
263
264            # courtesy of Paulius Šarka  psarka  Aug 30, 2017
265            p = LatLon(1, 1).nearestOn(LatLon(2, 2), LatLon(2, 2))
266            self.test('nearestOn', p, '02.0°N, 002.0°E')
267            p = LatLon(2, 2).nearestOn(LatLon(2, 2), LatLon(2, 2))
268            self.test('nearestOn', p, '02.0°N, 002.0°E')  # PYCHOK test attr?
269
270        if hasattr(LatLon, 'triangulate'):
271            # courtesy of pvezid  Feb 10, 2017
272            p = LatLon("47°18.228'N","002°34.326'W")  # Basse Castouillet
273            self.test('BasseC', p, '47.3038°N, 002.5721°W')
274            s = LatLon("47°18.664'N","002°31.717'W")  # Basse Hergo
275            self.test('BasseH', s, '47.311067°N, 002.528617°W')
276            t = p.triangulate(7, s, 295)
277            self.test('triangulate', t, '47.323667°N, 002.568501°W')
278            self.test('triangulate', isinstance(t, LatLon), True)  # PYCHOK test attr?
279
280        if hasattr(LatLon, 'trilaterate'):
281            # <https://GitHub.com/ChrisVeness/geodesy/blob/master/test/latlon-nvector-spherical-tests.js>
282            p = LatLon(37.418436, -121.963477)
283            t = p.trilaterate(265.710701754, LatLon(37.417243, -121.961889), 234.592423446,
284                                             LatLon(37.418692, -121.960194), 54.8954278262)
285            self.test('trilaterate', t, '37.419078°N, 121.960579°W')
286            self.test('trilaterate', isinstance(t, LatLon), True)
287
288            # courtesy Carlos Freitas <https://GitHub.com/mrJean1/PyGeodesy/issues/33>
289            b1 = LatLon(-8.068361, -34.892722)
290            b2 = LatLon(-8.075917, -34.894611)
291            b3 = LatLon(-8.076361, -34.908000)
292            p  = LatLon(-8.068912, -34.888699)
293            d1 = b1.distanceTo(p)
294            d2 = b2.distanceTo(p)
295            d3 = b3.distanceTo(p)
296            t = b1.trilaterate(d1, b2, d2, b3, d3)
297            self.test('trilaterate', t, p)
298            self.test('trilaterate', isinstance(t, LatLon), True)
299            t = b1.trilaterate(d1, b2, d2, b3, d3, useZ=True)
300            self.test('trilaterate', t, p, known=abs(t.lon - p.lon) < 1e-5)
301            self.test('trilaterate', isinstance(t, LatLon), True)
302
303            # courtesy AleixDev <https://GitHub.com/mrJean1/PyGeodesy/issues/43>
304            d  = 5110  # meter
305            p1 = LatLon(42.688839, 2.438857)
306            p2 = LatLon(42.635421, 2.522570)
307            t = p1.trilaterate(d, p2, d, LatLon(42.630788,2.500713), d)
308            self.test('trilaterate', t.toStr(F_D, prec=8), '42.67456065°N, 002.49539502°E')
309            try:
310                t = p1.trilaterate(d, p2, d, LatLon(42.64540, 2.504811), d)
311                self.test('trilaterate', t.toStr(F_D, prec=8), IntersectionError.__name__)
312            except IntersectionError as x:
313                self.test('trilaterate', str(x), str(x))  # PYCHOK test attr?
314
315        self.testNvectorBase(module)
316
317    def testTrilaterate3d(self, module, Vector):
318
319        try:  # need numpy
320            self.subtitle(module, Vector.__name__)
321
322            # <https://GISPoint.de/artikelarchiv/avn/2008/avn-ausgabe-12008/
323            # 2303-direkte-loesung-des-raeumlichen-bogenschnitts-mit-methoden-der-linearen-algebra.html>
324            c1, r1 = Vector( 50.0, 150.0, 13.0), 74.760
325            c2, r2 = Vector(100.0,  50.0, 11.0), 84.623
326            c3, r3 = Vector(200.0, 120.0, 12.0), 82.608
327            t = c1.trilaterate3d2(r1, c2, r2, c3, r3)
328            k = float(numpy.__version__.rsplit('.', 1)[0]) < 1.12  # numpy too old?
329
330            n = _DOT_(c1.named3, Vector.trilaterate3d2.__name__)
331            self.test(n, len(t), 2)
332            self.test(t[0].named3, fstr(t[0].xyz, prec=4), '119.8958, 130.6508, -5.1451', known=k)
333            self.test(t[1].named3, fstr(t[1].xyz, prec=4), '119.9999, 129.9999, 30.0019', known=k)
334
335            # <https://www.ResearchGate.net/publication/
336            # 275027725_An_Algebraic_Solution_to_the_Multilateration_Problem>
337            c1, r1 = Vector(27.297, -4.953, 1.470), 3.851  # 3.857
338            c2, r2 = Vector(25.475, -6.124, 2.360), 3.875  # 3.988
339            c3, r3 = Vector(22.590,  0.524, 1.200), 3.514  # 3.497
340            for C, V in ((vector3d, dict(Vector=Vector)),
341                         (Vector, {})):  # method
342                f = C.trilaterate3d2
343                t = f(c1, r1, c2, r2, c3, r3, **V)
344                n = _DOT_(C.__name__, f.__name__)
345
346                self.test(n, len(t), 2)
347                self.test(t[0].named3, fstr(t[0].xyz, prec=5), '24.31229, -2.52045, 1.53649', known=k)
348                self.test(t[1].named3, fstr(t[1].xyz, prec=5), '24.35062, -2.48109, 1.66673', known=k)
349
350                try:  # concentric
351                    t = f(c3, r1, c2, r2, c3, r3, **V)
352                    self.test(n, t, IntersectionError.__name__)
353                except IntersectionError as x:
354                    t = str(x)
355                    self.test(n, t, t)
356
357                try:  # too distant
358                    t = f(c1, r1 * 0.1, c2, r2 * 0.1, c3, r3, **V)
359                    self.test(n, t, IntersectionError.__name__)
360                except IntersectionError as x:
361                    t = str(x)
362                    self.test(n, t, t)
363
364                try:  # colinear
365                    t = f(Vector(0, 0, 0), 10, Vector(0, 9, 0), 10, Vector(0, -9, 0), 10)
366                    self.test(n, t, IntersectionError.__name__)
367                except IntersectionError as x:
368                    t = str(x)
369                    self.test(n, t, t)
370
371        except ImportError as x:
372            self.skip(str(x), n=14)
373
374    def testTrilaterate2d2(self):
375
376        self.subtitle(vector2d, trilaterate2d2.__name__.capitalize())
377        # courtesy MartinManganiello <https://GitHub.com/mrJean1/PyGeodesy/issues/49>
378        t = trilaterate2d2(2, 2, 1, 3, 3, 1, 1, 4, 1.4142)
379        self.test(trilaterate2d2.__name__, t.toStr(prec=1), '(2.0, 3.0)')  # XXX ?
380        try:
381            t = trilaterate2d2(2, 2, 1, 3, 3, 1, 1, 4, 1.4142, eps=EPS)
382            self.test(trilaterate2d2.__name__, t.toStr(prec=1), IntersectionError.__name__)
383        except ValueError as x:
384            self.test(trilaterate2d2.__name__, str(x), str(x))
385
386        t = trilaterate2d2(-500, -200,  450,
387                            100, -100,  694.6221994724903,
388                            500,  100, 1011.1874208078342)
389        self.test(trilaterate2d2.__name__, t.toStr(prec=1), '(-500.0, 250.0)')
390
391        v1, v2, v3 = V3d(1, 1), V3d(2, 4), V3d(5, 3)
392        r, c = v1.meeus2(v2, v3)  # PYCHOK Meeus2Tuple
393        self.test(meeus2.__name__, fstr((r, c.x, c.y, c.z), prec=3), '2.236, 3.0, 2.0, 0.0')
394        t = v1.trilaterate2d2(r, v2, r, v3, r)
395        self.test(meeus2.__name__, t, '(3.0, 2.0, 0)')
396
397        v, c, d = circum3(v1, v2, v3, useZ=False, eps=1e-14)
398        self.test(circum3.__name__, v, r, prec=4)
399        self.test(circum3.__name__, c, t)
400        self.test(circum3.__name__, d, None, known=d)
401
402        try:  # need numpy
403            v, c, k, s = circum4_(v1, v2, v3)
404            self.test(circum4_.__name__, v, r, prec=4)
405            self.test(circum4_.__name__, c, t, known=isnear0(c.z))
406            self.test(circum4_.__name__, k, 3, known=True)
407            self.test(circum4_.__name__, s, (), known=True)
408
409            # v1, v2, v3 = V3d(0, 0), V3d(100, 0), V3d(0, 100)
410            t = radii11(v1, v2, v3).toRepr()
411            self.test(radii11.__name__, t, t)  # XXX
412            t = circin6(v1, v2, v3, eps=1e-14).toRepr()
413            self.test(circin6.__name__, t, t)  # XXX
414            t = soddy4(v1, v2, v3, eps=1e-14).toRepr()
415            self.test(soddy4.__name__, t, t)  # XXX
416        except ImportError as x:
417            self.skip(str(x), n=7)
418
419    def testTrilaterate3d2(self, Vector):
420
421        try:  # need numpy
422            self.subtitle(vector2d, trilaterate3d2.__name__.capitalize())
423            n = _DOT_(vector2d.__name__, trilaterate3d2.__name__)
424
425            # coutesy Martin Manganiello <https://GitHub.com/mrJean1/PyGeodesy/issues/49>
426            c1, r1 = Vector(-500, -200, 0),  450.0
427            c2, r2 = Vector( 100, -100, 0),  694.6221994724903
428            c3, r3 = Vector( 500,  100, 0), 1011.1874208078342
429
430            try:  # no intersection, no perturbation for eps=0
431                t = trilaterate3d2(c1, r1, c2, r2, c3, r3, eps=0)
432                self.test(n, t, IntersectionError.__name__)
433            except IntersectionError as x:
434                t = str(x)
435                self.test(n, t, t)
436
437            # by default, perturbation at EPS and qsrt(EPS)
438            t = trilaterate3d2(c1, r1, c2, r2, c3, r3)  # eps=EPS
439            self.test(n, len(t), 2)
440            for v in t:
441                self.test(v.named3, fstr(v.xyz, prec=5), '-500.0, 250.0, 0.0', known=v.z)
442
443            v1, v2, v3 = V3d(-1, 0, -1), V3d(0, 2), V3d(1, 0, 1)
444            r, t = meeus2(v1, v2, v3)
445            self.test(meeus2.__name__, r, 1.5, prec=2)
446            self.test(meeus2.__name__, t, None)
447            for c in v1.trilaterate3d2(r, v2, r, v3, r, eps=EPS4):
448                self.test(meeus2.__name__, fstr(c.xyz, prec=9), '0.0, 0.5, 0.0', known=c.z)
449
450            t, c, d = v1.circum3(v2, v3)  # PYCHOK unpacking eps=EPS4
451            self.test(circum3.__name__, t, r, prec=2)
452            self.test(circum3.__name__, fstr(c.xyz, prec=9), '0.0, 0.5, 0.0', known=c.z)
453            self.test(circum3.__name__, d, None, known=d)
454
455            t, c, k, s = v1.circum4_(v2, v3)
456            self.test(circum4_.__name__, t, r, prec=2)
457            self.test(circum4_.__name__, fstr(c.xyz, prec=9), '0.0, 0.5, 0.0', known=c.z)
458            self.test(circum4_.__name__, k, 3, known=True)
459            self.test(circum4_.__name__, s, (), known=True)
460
461            # v1, v2, v3 = V3d(3, 3), V3d(6, 6), V3d(10, -4)  # (5.835, (8, 1), None)
462            # t = v1.circum3(v2, v3, eps=1e-14).toRepr()
463            # self.test(circum3.__name__, t, t)
464
465            # v1, v2, v3 = V3d(0, 0), V3d(100, 0), V3d(0, 100)
466            t = v1.radii11(v2, v3).toRepr()
467            self.test(radii11.__name__, t, t)  # XXX
468            t = v1.circin6(v2, v3, eps=1e-14).toRepr()
469            self.test(circin6.__name__, t, t)  # XXX
470            t = v1.soddy4(v2, v3, eps=1e-14).toRepr()
471            self.test(soddy4.__name__, t, t)  # XXX
472        except ImportError as x:
473            self.skip(str(x), n=18)
474
475
476if __name__ == '__main__':
477
478    from pygeodesy import Datums, cartesianBase, ellipsoidalExact, ellipsoidalKarney, \
479                          ellipsoidalNvector, ellipsoidalVincenty, nvectorBase, \
480                          sphericalTrigonometry
481
482    t = Tests(__file__, __version__)
483
484    t.testVectorial(ellipsoidalNvector)
485    t.testVectorial(sphericalNvector)
486
487    t.testNvectorBase(nvectorBase, datum=Datums.Sphere)
488    t.testNvectorBase(nvectorBase, datum=Datums.WGS84)
489
490    t.testTrilaterate3d(sphericalNvector,      sphericalNvector.Cartesian)
491    t.testTrilaterate3d(sphericalTrigonometry, sphericalTrigonometry.Cartesian)
492
493    t.testTrilaterate3d(ellipsoidalNvector,  ellipsoidalNvector.Cartesian)
494    t.testTrilaterate3d(ellipsoidalVincenty, ellipsoidalVincenty.Cartesian)
495    t.testTrilaterate3d(ellipsoidalKarney,   ellipsoidalKarney.Cartesian)
496    t.testTrilaterate3d(ellipsoidalExact,    ellipsoidalExact.Cartesian)
497
498    if GeodSolve:
499        from pygeodesy import ellipsoidalGeodSolve
500        t.testTrilaterate3d(ellipsoidalGeodSolve, ellipsoidalGeodSolve.Cartesian)
501
502    t.testTrilaterate3d(cartesianBase,         cartesianBase.CartesianBase)
503    t.testTrilaterate3d(nvectorBase,           nvectorBase.NvectorBase)
504    t.testTrilaterate3d(vector2d,              vector3d.Vector3d)
505
506    t.testTrilaterate2d2()
507    t.testTrilaterate3d2(vector3d.Vector3d)
508
509    t.testIntersection3d3()
510
511    t.results()
512    t.exit()
513