Coverage for pygeodesy/vector2d.py : 96%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
L{iscolinearWith}, L{meeus2}, L{nearestOn}, L{radii11} and L{soddy4}. '''
_EPS4e8, isnear0, _0_0, _0_25, _0_5, _N_0_5, \ _1_0, _1_0_1T, _N_1_0, _2_0, _N_2_0, _4_0 PointsError, TriangleError, _xError, _xkwds _colinear_, _concentric_, _COMMASPACE_, _few_, \ _intersection_, _invalid_, _near_, _no_, _radius_, \ _rIn_, _s_, _SPACE_, _too_, _with_ # from pygeodesy.lazily import _ALL_LAZY # from .named # from pygeodesy.props import Property_RO # from .named trilaterate2d2, trilaterate3d2, Vector3d # PYCHOK unused
'''6-Tuple C{(radius, center, deltas, cA, cB, cC)} with the C{radius}, the trilaterated C{center} and contact points of the I{inscribed} aka I{In- circle} of a triangle. The C{center} is I{un}ambiguous if C{deltas} is C{None}, otherwise C{center} is the mean and C{deltas} the differences of the L{pygeodesy.trilaterate3d2} results. Contact points C{cA}, C{cB} and C{cC} are the points of tangency, aka the corners of the U{Contact Triangle <https://MathWorld.Wolfram.com/ContactTriangle.html>}. '''
'''3-Tuple C{(radius, center, deltas)} with the C{circumradius} and trilaterated C{circumcenter} of the C{circumcircle} through 3 points (aka {Meeus}' Type II circle) or the C{radius} and C{center} of the smallest I{Meeus}' Type I circle. The C{center} is I{un}ambiguous if C{deltas} is C{None}, otherwise C{center} is the mean and C{deltas} the differences of the L{pygeodesy.trilaterate3d2} results. '''
'''4-Tuple C{(radius, center, rank, residuals)} with C{radius} and C{center} of a sphere I{least-squares} fitted through given points and the C{rank} and C{residuals} -if any- from U{numpy.linalg.lstsq <https://NumPy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html>}. '''
'''2-Tuple C{(radius, Type)} with C{radius} and I{Meeus}' C{Type} of the smallest circle I{containing} 3 points. C{Type} is C{None} for a I{Meeus}' Type II C{circumcircle} passing through all 3 points. Otherwise C{Type} is the center of a I{Meeus}' Type I circle with 2 points on (a diameter of) and 1 point inside the circle. '''
'''11-Tuple C{(rA, rB, rC, cR, rIn, riS, roS, a, b, c, s)} with the C{Tangent} circle radii C{rA}, C{rB} and C{rC}, the C{circumradius} C{cR}, the C{Incircle} radius C{rIn} aka C{inradius}, the inner and outer I{Soddy} circle radii C{riS} and C{roS}, the sides C{a}, C{b} and C{c} and semi-perimeter C{s} of a triangle, all in C{meter} conventionally.
@note: C{Circumradius} C{cR} and outer I{Soddy} radius C{roS} may be C{INF}. '''
'''4-Tuple C{(radius, center, deltas, outer)} with C{radius} and (trilaterated) C{center} of the I{inner} I{Soddy} circle and the radius of the C{outer} I{Soddy} circle. The C{center} is I{un}ambiguous if C{deltas} is C{None}, otherwise C{center} is the mean and C{deltas} the differences of the L{pygeodesy.trilaterate3d2} results.
@note: The outer I{Soddy} radius C{outer} may be C{INF}. '''
'''Return the radius and center of the I{inscribed} aka I{Incircle} of a (2- or 3-D) triangle.
@arg point1: First point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point2: Second point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point3: Third point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @kwarg eps: Tolerance for function L{pygeodesy.trilaterate3d2} if C{B{useZ} is True} else L{pygeodesy.trilaterate2d2}. @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
@return: L{Circin6Tuple}C{(radius, center, deltas, cA, cB, cC)}. The C{center} and contact points C{cA}, C{cB} and C{cC}, each an instance of B{C{point1}}'s (sub-)class, are co-planar with the three given points.
@raise ImportError: Package C{numpy} not found, not installed or older than version 1.10 and C{B{useZ} is True}.
@raise IntersectionError: Near-coincident or -colinear points or a trilateration or C{numpy} issue.
@raise TypeError: Invalid B{C{point1}}, B{C{point2}} or B{C{point3}}.
@see: Functions L{radii11} and L{circum3}, U{Contact Triangle <https://MathWorld.Wolfram.com/ContactTriangle.html>} and U{Incircle<https://MathWorld.Wolfram.com/Incircle.html>}. ''' except (AssertionError, TypeError, ValueError) as x: raise _xError(x, point1=point1, point2=point2, point3=point3)
# (INTERNAL) Radius, center, deltas, 3 contact points
p3.intermediateTo(p2, _fraction(r3, a))
**_xkwds(Vector_kwds, Vector=V, name=circin6.__name__))
'''Return the radius and center of the smallest circle I{through} or I{containing} three (2- or 3-D) points.
@arg point1: First point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple} or C{Vector4Tuple}). @arg point2: Second point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple} or C{Vector4Tuple}). @arg point3: Third point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple} or C{Vector4Tuple}). @kwarg circum: If C{True} return the C{circumradius} and C{circumcenter} always, ignoring the I{Meeus}' Type I case (C{bool}). @kwarg eps: Tolerance for function L{pygeodesy.trilaterate3d2} if C{B{useZ} is True} else L{pygeodesy.trilaterate2d2}. @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
@return: A L{Circum3Tuple}C{(radius, center, deltas)}. The C{center}, an instance of B{C{point1}}'s (sub-)class, is co-planar with the three given points.
@raise ImportError: Package C{numpy} not found, not installed or older than version 1.10 and C{B{useZ} is True}.
@raise IntersectionError: Near-coincident or -colinear points or a trilateration or C{numpy} issue.
@raise TypeError: Invalid B{C{point1}}, B{C{point2}} or B{C{point3}}.
@see: Functions L{pygeodesy.circum4_} and L{pygeodesy.meeus2} and Meeus, J. U{I{Astronomical Algorithms}<http://www.Agopax.IT/Libri_astronomia/pdf/ Astronomical%20Algorithms.pdf>}, 2nd Ed. 1998, page 127ff, U{circumradius <https://MathWorld.Wolfram.com/Circumradius.html>} and U{circumcircle <https://MathWorld.Wolfram.com/Circumcircle.html>}. ''' clas=point1.classof) except (AssertionError, TypeError, ValueError) as x: raise _xError(x, point1=point1, point2=point2, point3=point3, circum=circum)
clas=Vector3d, **clas_kwds): # in .latlonBase # (INTERNAL) Radius, center, deltas clas=clas, **clas_kwds) else: # Meeus' Type I c, d = d, None
'''Best-fit a sphere through three or more (3-D) points.
@arg points: The points (each a C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, or C{Vector4Tuple}). @kwarg useZ_Vector_and_kwds: Keyword arguments C{B{useZ}=True} (C{bool}) to use the Z components, otherwise force all C{z=INT0}, class C{B{Vector}=None} to return the center point with optionally, additional nB{C{Vector}} keyword arguments, otherwise the first B{C{points}}' (sub-)class is used.
@return: L{Circum4Tuple}C{(radius, center, rank, residuals)} with C{center} an instance of C{B{points}[0]}' (sub-)class or B{C{Vector}} if specified.
@raise ImportError: Package C{numpy} not found, not installed or older than version 1.10.
@raise NumPyError: Some C{numpy} issue.
@raise PointsError: Too few B{C{points}}.
@raise TypeError: One of the B{C{points}} is invalid.
@see: Functions L{pygeodesy.circum3} and L{pygeodesy.meeus2}, Jekel, Charles F. U{I{Least Squares Sphere Fit}<https://Jekel.me/2015/Least-Squares-Sphere-Fit/>} Sep 13, 2015, U{Appendix A<https://hdl.handle.net/10019.1/98627>}, U{numpy.linalg.lstsq<https:// NumPy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html>} and U{Eberly 6 <https://www.sci.Utah.EDU/~balling/FEtools/doc_files/LeastSquaresFitting.pdf>}. '''
raise PointsError(points=n, txt=_too_(_few_))
# (INTERNAL) Check colinear, see L{iscolinearWith} above, # separated to allow callers to embellish any exceptions
'''Return the radius and I{Meeus}' Type of the smallest circle I{through} or I{containing} three (2- or 3-D) points.
@arg point1: First point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point2: Second point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point3: Third point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @kwarg circum: If C{True} return the C{circumradius} and C{circumcenter} always, overriding I{Meeus}' Type II case (C{bool}). @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
@return: L{Meeus2Tuple}C{(radius, Type)}, with C{Type} the C{circumcenter} iff C{B{circum}=True}.
@raise IntersectionError: Near-coincident or -colinear points, iff C{B{circum}=True}.
@raise TypeError: Invalid B{C{point1}}, B{C{point2}} or B{C{point3}}.
@see: Functions L{pygeodesy.circum3} and L{pygeodesy.circum4_} and Meeus, J. U{I{Astronomical Algorithms}<http://www.Agopax.IT/Libri_astronomia/pdf/ Astronomical%20Algorithms.pdf>}, 2nd Ed. 1998, page 127ff, U{circumradius <https://MathWorld.Wolfram.com/Circumradius.html>} and U{circumcircle <https://MathWorld.Wolfram.com/Circumcircle.html>}. ''' except (TypeError, ValueError) as x: raise _xError(x, point1=point1, point2=point2, point3=point3, circum=circum)
# (INTERNAL) Radius and center or Meeus' Type
# (INTERNAL) Radius and Meeus' Type
raise IntersectionError(_coincident_ if b < EPS0 or c < EPS0 else ( _colinear_ if _iscolinearWith(A, B, C) else _invalid_)) else: # obtuse or right angle at A
'''(INTERNAL) Partial C{NumPy} wrapper. ''' '''(INTERNAL) Yield self with any errors raised as L{NumPyError}. ''' except Exception as x: # mostly FloatingPointError? t = unstr(where, *args, **kwds) raise NumPyError(t, cause=x) # _xError2? finally: # restore numpy error handling
'''Linear least-squares function. '''
'''Import numpy 1.10+ once. '''
'''Return the C{null_space} and C{rank} of matrix B{C{A}}.
@see: U{Source<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.linalg.null_space.html>} U{SciPY Cookbook<https://SciPy-Cookbook.ReadTheDocs.io/items/RankNullspace.html>}, U{here <https://NumPy.org/doc/stable/reference/generated/numpy.linalg.svd.html>}, U{here <https://StackOverflow.com/questions/19820921>}, U{here <https://StackOverflow.com/questions/2992947>} and U{here <https://StackOverflow.com/questions/5889142>}. ''' return _AssertionError(txt=txt, **kwds)
raise _Error(shape=m) # if needed, square A, pad with zeros # try: # no np.linalg.null_space <https://docs.SciPy.org/doc/> # Z = scipy.linalg.null_space(A) # XXX no scipy.linalg? # return Z, ... # except AttributeError: # pass raise _Error(shape=s, m=m) raise _Error(dot=tuple(D.ravel()), norm=n, tol=t) else: # coincident, colinear, concentric centers, ambiguous, etc. # del A, S, U, V # release numpy
'''Moore-Penrose pseudo-inverse function. '''
'''Compute the real, non-complex roots of a polynomial. '''
'''Return the radii of the C{In-}, I{Soddy} and C{Tangent} circles of a (2- or 3-D) triangle.
@arg point1: First point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point2: Second point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point3: Third point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
@return: L{Radii11Tuple}C{(rA, rB, rC, cR, rIn, riS, roS, a, b, c, s)}.
@raise TriangleError: Near-coincident or -colinear points.
@raise TypeError: Invalid B{C{point1}}, B{C{point2}} or B{C{point3}}.
@see: U{Circumradius<https://MathWorld.Wolfram.com/Circumradius.html>}, U{Incircle<https://MathWorld.Wolfram.com/Incircle.html>}, U{Soddy Circles<https://MathWorld.Wolfram.com/SoddyCircles.html>} and U{Tangent Circles<https://MathWorld.Wolfram.com/TangentCircles.html>}. ''' except (TypeError, ValueError) as x: raise _xError(x, point1=point1, point2=point2, point3=point3)
# (INTERNAL) Tangent, Circum, Incircle, Soddy radii, sides and semi-perimeter
# t = r1 * r2 * r3 * (r1 + r2 + r3) # = r1**2 * r2 * r3 * (1 + r2 / r1 + r3 / r1) # = (r1 * r2)**2 * (r3 / r2) * (1 + r2 / r1 + r3 / r1) # d = r1 * r2 + r2 * r3 + r3 * r1 # = r1 * (r2 + r2 * r3 / r1 + r3) # = r1 * r2 * (1 + r3 / r1 + r3 / r2) # si/o = r1 * r2 * r3 / (r1 * r2 * (d +/- t)) # = r3 / (d +/- t) # ci = sqrt(r1 * r2 * r3 / s) # = r1 * sqrt(r2 * r3 / r1 / s) # co = a * b * c / (4 * ci * s)
raise TriangleError(_near_(_coincident_) if min(a, b, c) < EPS0 else ( _colinear_ if _iscolinearWith(A, B, C) else _invalid_))
'''Return the radius and center of the C{inner} I{Soddy} circle of a (2- or 3-D) triangle.
@arg point1: First point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point2: Second point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @arg point3: Third point (C{Cartesian}, L{Vector3d}, C{Vector3Tuple}, C{Vector4Tuple} or C{Vector2Tuple} if C{B{useZ}=False}). @kwarg eps: Tolerance for function L{pygeodesy.trilaterate3d2} if C{B{useZ} is True} otherwise L{pygeodesy.trilaterate2d2}. @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
@return: L{Soddy4Tuple}C{(radius, center, deltas, outer)}. The C{center}, an instance of B{C{point1}}'s (sub-)class, is co-planar with the three given points. The C{outer} I{Soddy} radius may be C{INF}.
@raise ImportError: Package C{numpy} not found, not installed or older than version 1.10 and C{B{useZ} is True}.
@raise IntersectionError: Near-coincident or -colinear points or a trilateration or C{numpy} issue.
@raise TypeError: Invalid B{C{point1}}, B{C{point2}} or B{C{point3}}.
@see: Functions L{radii11} and L{circum3} and U{Soddy Circles <https://MathWorld.Wolfram.com/SoddyCircles.html>}. '''
p2, t.rB + r, p3, t.rC + r, eps=eps, useZ=useZ, Vector=point1.classof, name=soddy4.__name__)
# (INTERNAL) Trilaterate and disambiguate the 3-D center c = a # == b else: b.lon - a.lon, b.height - a.height, name=_deltas_) else: d = b.minus(a) # vectorial deltas else: p2.x, p2.y, r2, p3.x, p3.y, r3, **kwds)
coin=False, eps=None, Vector=None, **Vector_kwds): # (INTERNAL) Trilaterate three circles, see L{pygeodesy.trilaterate2d2}
return Fmt.PAREN(_COMMASPACE_(*(Fmt.EQUAL(*t) for t in kwds.items())))
raise IntersectionError(_and(_astr(x1=x1, y1=y1, radius1=r1), _astr(x2=x2, y2=y2, radius2=r2)), txt=t)
raise IntersectionError(_and(_astr(x2=x2, y2=y2, radius2=r2), _astr(x3=x3, y3=y3, radius3=r3)), txt=t)
raise IntersectionError(_and(_astr(x3=x3, y3=y3, radius3=r3), _astr(x1=x1, y1=y1, radius1=r1)), txt=t)
t = _no_(_intersection_) raise IntersectionError(_and(_astr(x1=x1, y1=y1, radius1=r1), _astr(x2=x2, y2=y2, radius2=r2), _astr(x3=x3, y3=y3, radius3=r3)), txt=t) (a * f - c * d) / q, name=trilaterate2d2.__name__)
Float(distance=d).toRepr(), t.toRepr()) raise IntersectionError(t, txt=Fmt.exceeds_eps(eps))
**clas_Vector_and_kwds): # (INTERNAL) Intersect three spheres or circles, see L{pygeodesy.trilaterate3d2}, # separated to allow callers to embellish any exceptions, like # C{FloatingPointError}s from C{numpy}
# map numpy 4-vector to floats tuple and Vector3d
# compute x, y and z and return as B{C{clas}} or B{C{Vector}}
Radius_(radius3=r3, low=EPS))
# get matrix A[3 x 4], its null_space Z and pseudo-invert A # perturbe radii and vector b slightly by eps and eps * 4 # quadratic polynomial, coefficients ordered (^0, ^1, ^2) fdot(Z, _N_0_5, *x.xyz) * _2_0, z2) t = v, v t = v, v else: # "lowest" intersection first (to avoid test failures)
# coincident, concentric, colinear, too distant, no intersection: # create the explanation and and throw an IntersectionError
def _reprs(*crs): return _and(*map(repr, crs))
r = repr(r1) if r1 == r2 == r3 else _reprs(r1, r2, r3) t = _SPACE_(t, _of_, _reprs(c1, c2, c3), _with_, _radius_, r) t = _COMMASPACE_(t, _no_(_numpy.null_space2.__name__))
_tri4near2far(c1, r1, c3, r3, coin) or \ _tri4near2far(c2, r2, c3, r3, coin) or ( _colinear_ if _iscolinearWith(c1, c2, c3, eps=eps) else _no_intersection(coin)) raise IntersectionError(t, txt=None)
# check for near-coincident/-concentric or too distant spheres/circles _coincident_ if coin else _concentric_) if h < abs(r1 - r2) else NN)
# check for near-coincident/-concentric or too distant spheres/circles
# perturb the radii to handle this corner case # <https://GitHub.com/mrJean1/PyGeodesy/issues/49>
# **) MIT License # # Copyright (C) 2016-2022 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. |