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}. '''
PointsError, TriangleError, _xError, _xkwds _EPS4e8, _a_, _and_, _b_, _c_, _center_, _coincident_, \ _colinear_, _concentric_, _COMMASPACE_, _few_, \ _intersection_, _invalid_, _near_, _no_, _radius_, \ _rIn_, _s_, _SPACE_, _too_, _0_0, _0_5, \ _1_0, _N_1_0, _1_0_T, _2_0, _N_2_0, _4_0 # from pygeodesy.streprs import Fmt # 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} and 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{In- 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{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{Incircle <https://MathWorld.Wolfram.com/Incircle.html>} and U{Contact Triangle <https://MathWorld.Wolfram.com/ContactTriangle.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} otherwise 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: U{Jean Meeus, "Astronomical Algorithms", 2nd Ed. 1998, page 127ff <http://www.Agopax.IT/Libri_astronomia/pdf/Astronomical%20Algorithms.pdf>}, U{circumradius<https://MathWorld.Wolfram.com/Circumradius.html>}, U{circumcircle<https://MathWorld.Wolfram.com/Circumcircle.html>} and functions L{pygeodesy.circum4_} and L{pygeodesy.meeus2}. ''' 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 Vector_and_kwds: Optional class C{B{Vector}=None} to return the center and optional, additional B{C{Vector}} keyword arguments, otherwise the first B{C{points}}' (sub-)class.
@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: U{Charles F. Jekel, "Least Squares Sphere Fit", Sep 13, 2015 <https://Jekel.me/2015/Least-Squares-Sphere-Fit/>} and 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>}, U{Eberly 6<https://www.sci.Utah.EDU/~balling/FEtools/doc_files/LeastSquaresFitting.pdf>} and functions L{pygeodesy.circum3} and L{pygeodesy.meeus2}. ''' 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 non-zero C{circumradius} always, ignoring the I{Meeus}' Type I 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)}.
@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: U{Jean Meeus, "Astronomical Algorithms", 2nd Ed. 1998, page 127ff <http://www.Agopax.IT/Libri_astronomia/pdf/Astronomical%20Algorithms.pdf>}, U{circumradius<https://MathWorld.Wolfram.com/Circumradius.html>}, U{circumcircle<https://MathWorld.Wolfram.com/Circumcircle.html>} and functions L{pygeodesy.circum3} and L{pygeodesy.circum4_}. ''' clas=point1.classof) except (TypeError, ValueError) as x: raise _xError(x, point1=point1, point2=point2, point3=point3, circum=circum)
# (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
# (INTERNAL) Return the nullspace and rank of matrix A # @see: <https://SciPy-Cookbook.ReadTheDocs.io/items/RankNullspace.html>, # <https://NumPy.org/doc/stable/reference/generated/numpy.linalg.svd.html>, # <https://StackOverflow.com/questions/19820921>, # <https://StackOverflow.com/questions/2992947> and # <https://StackOverflow.com/questions/5889142> raise _AssertionError(shape=m, txt=_null_space2.__name__) # if needed, square A, pad with zeros # try: # no numpy.linalg.null_space <https://docs.SciPy.org/doc/> # return scipy.linalg.null_space(A) # XXX no scipy.linalg? # except AttributeError: # pass raise _AssertionError(shape=s, txt=_null_space2.__name__) raise _AssertionError(res=e, tol=t, txt=_null_space2.__name__) else: # coincident, colinear, concentric centers, ambiguous, etc. # del A, s, vh # release numpy
# (INTERNAL) Yield numpy with any errors raised as NumPyError global _numpy_1_10
except Exception as x: # mostly FloatingPointError? raise NumPyError(x.__class__.__name__, arg, txt=str(x)) # _xError2? finally: # restore numpy error handling
'''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.
@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}. '''
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}}
# perturbe radii to handle corner cases like this # <https://GitHub.com/mrJean1/PyGeodesy/issues/49>
# only real, non-complex roots of a polynomial, if any
Radius_(radius3=r3, low=eps)]
# get null_space Z, pseudo-inverse A and vector B, once raise _trilaterror(c1, r1, c2, r2, c3, r3, eps, coin)
# quadratic polynomial coefficients, ordered (^0, ^1, ^2) (fdot(Z, -_0_5, *x.xyz) * _2_0), z2) else: # coincident, concentric, colinear, too distant, no intersection, etc. raise _trilaterror(c1, r1, c2, r2, c3, r3, eps, coin)
t = v, v t = v, v else: # "lowest" intersection first (to avoid test failures)
# return IntersectionError with the cause of the error
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)
_txt(c1, r1, c3, r3) or \ _txt(c2, r2, c3, r3) or ( _colinear_ if _iscolinearWith(c1, c2, c3, eps=eps) else _no_intersection())
# check for near-coincident/-concentric or too distant spheres/circles _coincident_ if coin else _concentric_) if h < abs(r1 - r2) else NN)
# **) 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. |