Coverage for pygeodesy/sphericalNvector.py : 94%

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 -*-
(ECEF) L{Cartesian} and L{Nvector} and functions L{areaOf}, L{intersection}, L{meanOf}, L{nearestOn2}, L{triangulate} and L{trilaterate}, I{all spherical}.
Pure Python implementation of n-vector-based spherical geodetic (lat-/longitude) methods, transcribed from JavaScript originals by I{(C) Chris Veness 2011-2016}, published under the same MIT Licence**. See U{Vector-based geodesy <https://www.Movable-Type.co.UK/scripts/latlong-vectors.html>} and U{Module latlon-nvector-spherical <https://www.Movable-Type.co.UK/scripts/geodesy/docs/module-latlon-nvector-spherical.html>}.
Tools for working with points and paths on (a spherical model of) the earth’s surface using using n-vectors rather than the more common spherical trigonometry. N-vectors make many calculations much simpler, and easier to follow, compared with the trigonometric equivalents.
Based on Kenneth Gade’s U{‘Non-singular Horizontal Position Representation’ <https://www.NavLab.net/Publications/A_Nonsingular_Horizontal_Position_Representation.pdf>}, The Journal of Navigation (2010), vol 63, nr 3, pp 395-417.
Note that the formulations below take x => 0°N,0°E, y => 0°N,90°E and z => 90°N while Gade uses x => 90°N, y => 0°N,90°E, z => 0°N,0°E.
Also note that on a spherical earth model, an n-vector is equivalent to a normalised version of an (ECEF) cartesian coordinate.
@newfield example: Example, Examples '''
isscalar, map1 NvectorBase, sumOf as _sumOf sincos2, sincos2d, _TypeError
# all public contants, classes and functions 'Cartesian', 'LatLon', 'Nvector', # classes 'areaOf', # functions 'intersection', 'ispolar', 'meanOf', 'nearestOn2', 'perimeterOf', 'sumOf', 'triangulate', 'trilaterate')
'''Extended to convert geocentric, L{Cartesian} points to L{Nvector} and n-vector-based, spherical L{LatLon}. '''
'''Convert this cartesian to an C{Nvector}-based geodetic point.
@keyword kwds: Optional, additional B{C{LatLon}} keyword arguments, ignored if C{B{LatLon}=None}. For example, use C{LatLon=...} to override the L{LatLon} (sub-)class or specify C{B{LatLon}=None}.
@return: The B{C{LatLon}} point (L{LatLon}) or if C{B{LatLon}=None}, an L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with C{C} and C{M} if available.
@raise TypeError: Invalid B{C{LatLon}} or B{C{kwds}}. ''' kwds = _2kwds(kwds, LatLon=LatLon, datum=self.datum) return CartesianSphericalBase.toLatLon(self, **kwds)
'''Convert this cartesian to L{Nvector} components, I{including height}.
@keyword kwds: Optional, additional B{C{Nvector}} keyword arguments, ignored if C{B{Nvector}=None}. For example, use C{Nvector=...} to override the L{Nvector} (sub-)class or specify
@return: The B{C{Nvector}} components (L{Nvector}) or a L{Vector4Tuple}C{(x, y, z, h)} if C{B{Nvector}=None}.
@raise TypeError: Invalid B{C{Nvector}} or B{C{kwds}}. ''' # ll = CartesianBase.toLatLon(self, LatLon=LatLon, # datum=datum or self.datum) # kwds = _2kwds(kwds, Nvector=Nvector) # return ll.toNvector(**kwds) kwds = _2kwds(kwds, Nvector=Nvector, datum=self.datum) return CartesianSphericalBase.toNvector(self, **kwds)
'''New n-vector based point on a spherical earth model.
Tools for working with points and paths on (a spherical model of) the earth's surface using vector-based methods.
@example:
>>> from sphericalNvector import LatLon >>> p = LatLon(52.205, 0.119) '''
'''(INTERNAL) Return great circle, start and end Nvectors. ''' else:
'''(INTERNAL) Clear caches id updated. ''' self._Nv._fromll = None self._Nv = None
'''Compute the (signed) distance from the start to the closest point on the great circle path defined by a start and an end point.
That is, if a perpendicular is drawn from this point to the great circle path, the along-track distance is the distance from the start point to the point where the perpendicular crosses the path.
@param start: Start point of great circle path (L{LatLon}). @param end: End point of great circle path (L{LatLon}) or initial bearing from start point (compass C{degrees360}). @keyword radius: Optional, mean earth radius (C{meter}).
@return: Distance along the great circle path (positive if after the start toward the end point of the path or negative if before the start point).
@raise TypeError: If B{C{start}} or B{C{end}} point is not L{LatLon}.
@raise Valuerror: Some points coincide.
@example:
>>> p = LatLon(53.2611, -0.7972)
>>> s = LatLon(53.3206, -1.7297) >>> e = LatLon(53.1887, 0.1334) >>> d = p.alongTrackDistanceTo(s, e) # 62331.58 '''
'''DEPRECATED, use method C{initialBearingTo}. ''' return self.initialBearingTo(other)
'''Copy this point.
@return: The copy (L{LatLon} or subclass thereof). '''
'''Compute the (signed) distance from this point to great circle defined by a start and end point.
@param start: Start point of great circle path (L{LatLon}). @param end: End point of great circle path (L{LatLon}) or initial bearing from start point (compass C{degrees360}). @keyword radius: Optional, mean earth radius (C{meter}).
@return: Distance to great circle (negative if to the left or positive if to the right of the path).
@raise TypeError: If B{C{start}} or B{C{end}} point is not L{LatLon}.
@raise Valuerror: Some points coincide.
@example:
>>> p = LatLon(53.2611, -0.7972)
>>> s = LatLon(53.3206, -1.7297) >>> d = p.crossTrackDistanceTo(s, 96) # -305.7
>>> e = LatLon(53.1887, 0.1334) >>> d = p.crossTrackDistanceTo(s, e) # -307.5 '''
'''Locate the destination from this point after having travelled the given distance on the given bearing.
@param distance: Distance travelled (C{meter}, same units as B{C{radius}}). @param bearing: Bearing from this point (compass C{degrees360}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword height: Optional height at destination, overriding the default height (C{meter}, same units as B{C{radius}}).
@return: Destination point (L{LatLon}).
@raise Valuerror: Polar coincidence.
@example:
>>> p = LatLon(51.4778, -0.0015) >>> q = p.destination(7794, 300.7) >>> q.toStr() # 51.513546°N, 000.098345°W
@JSname: I{destinationPoint}. '''
'''Compute the distance from this to an other point.
@param other: The other point (L{LatLon}). @keyword radius: Optional, mean earth radius (C{meter}).
@return: Distance between this and the B{C{other}} point (C{meter}, same units as B{C{radius}}).
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@example:
>>> p = LatLon(52.205, 0.119) >>> q = LatLon(48.857, 2.351); >>> d = p.distanceTo(q) # 404.3 km '''
'''Compute the vector normal to great circle obtained by heading on the given bearing from this point.
Direction of vector is such that initial bearing vector b = c × n, where n is an n-vector representing this point.
@param bearing: Bearing from this point (compass C{degrees360}).
@return: N-vector representing great circle (L{Nvector}).
@example:
>>> p = LatLon(53.3206, -1.7297) >>> gc = p.greatCircle(96.0) >>> gc.toStr() # [-0.794, 0.129, 0.594] '''
-cb * ct - sa * sb * st, ca * st, name=self.name) # XXX .unit()
'''Compute the vector normal to great circle obtained by heading from this to an other point or on a given bearing.
Direction of vector is such that initial bearing vector b = c × n, where n is an n-vector representing this point.
@param other: The other point (L{LatLon}) or the bearing from this point (compass C{degrees360}).
@return: N-vector representing great circle (L{Nvector}).
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@raise Valuerror: Points coincide.
@example:
>>> p = LatLon(53.3206, -1.7297) >>> gc = p.greatCircle(96.0) >>> gc.toStr() # (-0.79408, 0.12856, 0.59406)
>>> q = LatLon(53.1887, 0.1334) >>> g = p.greatCircleTo(q) >>> g.toStr() # (-0.79408, 0.12859, 0.59406) '''
'''Compute the initial bearing (forward azimuth) from this to an other point.
@param other: The other point (L{LatLon}). @param unused: Optional keyword argument B{C{wrap}} ignored.
@return: Initial bearing (compass C{degrees360}).
@raise Crosserror: This point coincides with the B{C{other}} point or the C{NorthPole}, provided L{crosserrors} is C{True}.
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@example:
>>> p1 = LatLon(52.205, 0.119) >>> p2 = LatLon(48.857, 2.351) >>> b = p1.initialBearingTo(p2) # 156.2
@JSname: I{bearingTo}. ''' # see <https://MathForum.org/library/drmath/view/55417.html> # gc1 = self.greatCircleTo(other) # gc2 = self.greatCircleTo(NorthPole)
'''Locate the point projected from the point at given fraction on a straight line (chord) between this and an other point.
@param other: The other point (L{LatLon}). @param fraction: Fraction between both points (float, 0.0 = this point, 1.0 = other point). @keyword height: Optional height at the intermediate point, overriding the fractional height (C{meter}).
@return: Intermediate point (L{LatLon}).
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@example:
>>> p = LatLon(52.205, 0.119) >>> q = LatLon(48.857, 2.351) >>> i = p.intermediateChordTo(q, 0.25) # 51.3723°N, 000.7072°E
@JSname: I{intermediatePointOnChordTo}, I{intermediatePointDirectlyTo}. '''
self.toNvector().times(1 - fraction)) # i = other.toNvector() * fraction + \ # self.toNvector() * (1 - fraction))
'''Locate the point at a given fraction between this and an other point.
@param other: The other point (L{LatLon}). @param fraction: Fraction between both points (float, 0.0 = this point, 1.0 = the other point). @keyword height: Optional height at the intermediate point, overriding the fractional height (C{meter}).
@return: Intermediate point (L{LatLon}).
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@raise Valuerror: Points coincide.
@example:
>>> p = LatLon(52.205, 0.119) >>> q = LatLon(48.857, 2.351) >>> i = p.intermediateTo(q, 0.25) # 51.3721°N, 000.7074°E
@JSname: I{intermediatePointTo}. '''
# angular distance α, tan(α) = |p × q| / p ⋅ q
'''Locate the intersection point of two paths each defined by two points or a start point and bearing from North.
@param end1: End point of the first path (L{LatLon}) or the initial bearing at this point (compass C{degrees360}). @param start2: Start point of the second path (L{LatLon}). @param end2: End point of the second path (L{LatLon}) or the initial bearing at the second point (compass C{degrees}). @keyword height: Optional height at the intersection point, overriding the mean height (C{meter}).
@return: The intersection point (L{LatLon}) or C{None} if no unique intersection exists.
@raise TypeError: If B{C{start2}}, B{C{end1}} or B{C{end2}} point is not L{LatLon}.
@raise ValueError: Intersection is ambiguous or infinite or the paths are parallel, coincident or null.
@example:
>>> s = LatLon(51.8853, 0.2545) >>> e = LatLon(49.0034, 2.5735) >>> i = s.intersection(108.55, e, 32.44) # 50.9076°N, 004.5086°E ''' height=height, LatLon=self.classof)
'''Check whether this point is enclosed by a (convex) polygon.
@param points: The polygon points (L{LatLon}[]).
@return: C{True} if the polygon encloses this point, C{False} otherwise.
@raise TypeError: Some B{C{points}} are not L{LatLon}.
@raise ValueError: Insufficient number of B{C{points}}.
@example:
>>> b = LatLon(45,1), LatLon(45,2), LatLon(46,2), LatLon(46,1) >>> p = LatLon(45.1, 1.1) >>> inside = p.isEnclosedBy(b) # True
@JSname: I{enclosedBy}. '''
# use normal vector to this point for sign of α
# sum subtended angles
else: # get vectors from this to each point # close the polygon
# sum subtended angles of each edge (using n0 to determine sign)
# Note, this method uses angle summation test: on a plane, # angles for an enclosed point will sum to 360°, angles for # an exterior point will sum to 0°. On a sphere, enclosed # point angles will sum to less than 360° (due to spherical # excess), exterior point angles will be small but non-zero.
# XXX are winding number optimisations equally applicable to # spherical surface?
'''DEPRECATED, use method C{isenclosedBy}. '''
'''Check whether this point is between two other points.
If this point is not on the great circle arc defined by both points, return whether it is within the area bound by perpendiculars to the great circle at each point (in the same hemispere).
@param point1: Start point of the arc (L{LatLon}). @param point2: End point of the arc (L{LatLon}).
@return: C{True} if this point is within the arc, C{False} otherwise.
@raise TypeError: If B{C{point1}} or B{C{point2}} is not L{LatLon}.
@JSname: I{isBetween}. '''
# corner case, null arc
# get vectors representing d0=p0->p1 and d2=p2->p1 # and dot product d0⋅d2 tells us if p0 is on the # p2 side of p1 or on the other side (similarly # for d0=p0->p2 and d1=p1->p2 and dot product # d0⋅d1 and p0 on the p1 side of p2 or not) n0.minus(n2).dot(n1.minus(n2)) >= 0
'''DEPRECATED, use method C{iswithin}. '''
'''Find the midpoint between this and an other point.
@param other: The other point (L{LatLon}). @keyword height: Optional height at the midpoint, overriding the mean height (C{meter}).
@return: Midpoint (L{LatLon}).
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@example:
>>> p1 = LatLon(52.205, 0.119) >>> p2 = LatLon(48.857, 2.351) >>> m = p1.midpointTo(p2) # '50.5363°N, 001.2746°E' '''
'''Locate the point on the great circle arc between two points closest to this point.
If this point is within the extent of the arc between both end points, return the closest point on the arc. Otherwise, return the closest of the arc's end points.
@param point1: Start point of the arc (L{LatLon}). @param point2: End point of the arc (L{LatLon}). @keyword height: Optional height, overriding the mean height for the point within the arc (C{meter}).
@return: Closest point on the arc (L{LatLon}).
@raise TypeError: If B{C{point1}} or B{C{point2}} is not L{LatLon}.
@example:
>>> s1 = LatLon(51.0, 1.0) >>> s2 = LatLon(51.0, 2.0)
>>> s = LatLon(51.0, 1.9) >>> p = s.nearestOn(s1, s2) # 51.0004°N, 001.9000°E
>>> d = p.distanceTo(s) # 42.71 m
>>> s = LatLon(51.0, 2.1) >>> p = s.nearestOn(s1, s2) # 51.0000°N, 002.0000°E
@JSname: I{nearestPointOnSegment}. ''' # closer to arc than to its endpoints, # find the closest point on the arc
# beyond arc extent, take closer endpoint else:
'''Locate the point on a polygon (with great circle arcs joining consecutive points) closest to this point.
If this point is within the extent of any great circle arc, the closest point is on that arc. Otherwise, the closest is the nearest of the arc's end points.
@param points: The polygon points (L{LatLon}[]). @keyword closed: Optionally, close the polygon (C{bool}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword height: Optional height, overriding the mean height for a point within the arc (C{meter}).
@return: 2-Tuple (closest, distance) of the closest point (L{LatLon}) on the polygon and the distance to that point from the given point in C{meter}, same units of B{C{radius}}.
@raise TypeError: Some B{C{points}} are not C{LatLon}.
@raise ValueError: No B{C{points}}. '''
'''Convert this point to C{Nvector}-based cartesian (ECEF) coordinates.
@keyword kwds: Optional, additional B{C{Cartesian}} keyword arguments, ignored if C{B{Cartesian}=None}. For example, use C{Cartesian=...} to override the L{Cartesian} (sub-)class or specify
@return: The B{C{Cartesian}} point (L{Cartesian}) or if C{B{Cartesian}=None}, an L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with C{C} and C{M} if available.
@raise TypeError: Invalid B{C{Cartesian}} or B{C{attrs}}. ''' kwds = _2kwds(kwds, Cartesian=Cartesian, datum=self.datum) return LatLonSphericalBase.toCartesian(self, **kwds)
'''Convert this point to L{Nvector} components, I{including height}.
@keyword kwds: Optional, additional B{C{Nvector}} keyword arguments, ignored if C{B{Nvector}=None}. For example, use C{Nvector=...} to override the L{Nvector} (sub-)class or specify
@return: The B{C{Nvector}} components (L{Nvector}) or a L{Vector4Tuple}C{(x, y, z, h)} if C{B{Nvector}=None}.
@raise TypeError: Invalid B{C{Nvector}} or B{C{kwds}}.
@example:
>>> p = LatLon(45, 45) >>> n = p.toNvector() >>> n.toStr() # [0.50, 0.50, 0.70710]
@JSname: I{toVector}. '''
'''Locate a point given this and an other point and a bearing at this and the other point.
@param bearing1: Bearing at this point (compass C{degrees360}). @param other: The other point (L{LatLon}). @param bearing2: Bearing at the other point (compass C{degrees360}). @keyword height: Optional height at the triangulated point, overriding the mean height (C{meter}).
@return: Triangulated point (L{LatLon}).
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@raise Valuerror: Points coincide.
@example:
>>> p = LatLon("47°18.228'N","002°34.326'W") # Basse Castouillet >>> q = LatLon("47°18.664'N","002°31.717'W") # Basse Hergo >>> t = p.triangulate(7, q, 295) # 47.323667°N, 002.568501°W' ''' height=height, LatLon=self.classof)
radius=R_M, height=None, useZ=False): '''Locate a point at given distances from this and two other points. See also U{Trilateration<https://WikiPedia.org/wiki/Trilateration>}.
@param distance1: Distance to this point (C{meter}, same units as B{C{radius}}). @param point2: Second reference point (L{LatLon}). @param distance2: Distance to point2 (C{meter}, same units as B{C{radius}}). @param point3: Third reference point (L{LatLon}). @param distance3: Distance to point3 (C{meter}, same units as B{C{radius}}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword height: Optional height at trilaterated point, overriding the mean height (C{meter}, same units as B{C{radius}}). @keyword useZ: Include Z component iff non-NaN, non-zero (C{bool}).
@return: Trilaterated point (L{LatLon}).
@raise TypeError: Some B{C{points}} are not L{LatLon}.
@raise ValueError: Distance(s) exceeds trilateration or some B{C{points}} coincide. ''' point3, distance3, radius=radius, height=height, LatLon=self.classof, useZ=useZ)
'''An n-vector is a position representation using a (unit) vector normal to the earth's surface. Unlike lat-/longitude points, n-vectors have no singularities or discontinuities.
For many applications, n-vectors are more convenient to work with than other position representations like lat-/longitude, earth-centred earth-fixed (ECEF) vectors, UTM coordinates, etc.
On a spherical model earth, an n-vector is equivalent to an earth-centred earth-fixed (ECEF) vector.
Note commonality with L{ellipsoidalNvector.Nvector}. '''
'''Convert this n-vector to C{Nvector}-based cartesian (ECEF) coordinates.
@keyword kwds: Optional, additional B{C{Cartesian}} keyword arguments, ignored if C{B{Cartesian}=None}. For example, use C{Cartesian=...} to override the L{Cartesian} (sub-)class or specify
@return: The B{C{Cartesian}} point (L{Cartesian}) or if C{B{Cartesian}=None}, an L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with C{C} and C{M} if available.
@raise TypeError: Invalid B{C{Cartesian}}, B{C{datum}} or B{C{kwds}}. '''
'''Convert this n-vector to an C{Nvector}-based geodetic point.
@keyword kwds: Optional, additional B{C{LatLon}} keyword arguments, ignored if C{B{LatLon}=None}. For example, use C{LatLon=...} to override the L{LatLon} (sub-)class or specify C{B{LatLon}=None}.
@return: The B{C{LatLon}} point (L{LatLon}) or if C{B{LatLon}=None} or a L{LatLon3Tuple}C{(lat, lon, height)} if B{C{LatLon}} is C{None}.
@raise TypeError: Invalid B{C{LatLon}} or B{C{kwds}}. '''
'''Compute the n-vector normal to great circle obtained by heading on given compass bearing from this point as its n-vector.
Direction of vector is such that initial bearing vector b = c × p.
@param bearing: Initial compass bearing (C{degrees}).
@return: N-vector representing great circle (L{Nvector}).
@raise Valuerror: Polar coincidence.
@example:
>>> n = LatLon(53.3206, -1.7297).toNvector() >>> gc = n.greatCircle(96.0) # [-0.794, 0.129, 0.594] '''
'''Calculate the area of a (spherical) polygon (with great circle arcs joining consecutive points).
@param points: The polygon points (L{LatLon}[]). @keyword radius: Optional, mean earth radius (C{meter}).
@return: Polygon area (C{meter}, same units as B{C{radius}}, squared).
@raise TypeError: Some B{C{points}} are not L{LatLon}.
@raise ValueError: Insufficient number of B{C{points}}.
@see: L{pygeodesy.areaOf}, L{sphericalTrigonometry.areaOf} and L{ellipsoidalKarney.areaOf}.
@example:
>>> b = LatLon(45, 1), LatLon(45, 2), LatLon(46, 2), LatLon(46, 1) >>> areaOf(b) # 8666058750.718977 '''
# use vector to 1st point as plane normal for sign of α
# sum interior angles
else: # get great-circle vector for each edge gc, v1 = [], points[n-1].toNvector() for i in range(n): v2 = points[i].toNvector() gc.append(v1.cross(v2)) # PYCHOK false, does have .cross v1 = v2 gc.append(gc[0]) # XXX needed?
# sum interior angles: depending on whether polygon is cw or ccw, # angle between edges is π−α or π+α, where α is angle between # great-circle vectors; so sum α, then take n·π − |Σα| (cannot # use Σ(π−|α|) as concave polygons would fail) s = fsum(gc[i].angleTo(gc[i+1], vSign=n0) for i in range(n))
# using Girard’s theorem: A = [Σθᵢ − (n−2)·π]·R² # (PI2 - abs(s) == (n*PI - abs(s)) - (n-2)*PI)
height=None, LatLon=LatLon): '''Locate the intersection of two paths each defined by two points or by a start point and an initial bearing.
@param start1: Start point of the first path (L{LatLon}). @param end1: End point of the first path (L{LatLon}) or the initial bearing at the first start point (compass C{degrees360}). @param start2: Start point of the second path (L{LatLon}). @param end2: End point of the second path (L{LatLon}) or the initial bearing at the second start point (compass C{degrees360}). @keyword height: Optional height at the intersection point, overriding the mean height (C{meter}). @keyword LatLon: Optional (sub-)class to return the intersection point (L{LatLon}).
@return: The intersection point (B{C{LatLon}}) or 3-tuple (C{degrees90}, C{degrees180}, height) if B{C{LatLon}} is C{None} or C{None} if no unique intersection exists.
@raise TypeError: If B{C{start*}} or B{C{end*}} is not L{LatLon}.
@raise ValueError: Intersection is ambiguous or infinite or the paths are parallel, coincident or null.
@example:
>>> p = LatLon(51.8853, 0.2545) >>> q = LatLon(49.0034, 2.5735) >>> i = intersection(p, 108.55, q, 32.44) # 50.9076°N, 004.5086°E '''
# If gc1 and gc2 are great circles through start and end points # (or defined by start point and bearing), then the candidate # intersections are simply gc1 × gc2 and gc2 × gc1. Most of the # work is deciding the correct intersection point to select! If # bearing is given, that determines the intersection, but if both # paths are defined by start/end points, take closer intersection.
# there are two (antipodal) candidate intersection # points ... we have to choose the one to return # postpone computing i2 until needed # i2 = gc2.cross(gc1, raiser='paths')
# selection of intersection point depends on how # paths are defined (by bearings or endpoints) # gc2 x v2 . i1 +ve means v2 bearing points to i1 # gc1 x v1 . i1 +ve means v1 bearing points to i1 else: # bearing+bearing # if gc x v . i1 is +ve, initial bearing is # towards i1, otherwise towards antipodal i2 else: # d1, d2 opposite signs # intersection is at further-away intersection # point, take opposite intersection from mid- # point of v1 and v2 [is this always true?]
'''Compute the geographic mean of the supplied points.
@param points: Array of points to be averaged (L{LatLon}[]). @keyword height: Optional height, overriding the mean height (C{meter}). @keyword LatLon: Optional (sub-)class to return the mean point (L{LatLon}).
@return: Point at geographic mean and mean height (B{C{LatLon}}).
@raise ValueError: Insufficient number of B{C{points}}. ''' # geographic mean
'''Locate the point on a polygon (with great circle arcs joining consecutive points) closest to an other point.
If the given point is within the extent of any great circle arc, the closest point is on that arc. Otherwise, the closest is the nearest of the arc's end points.
@param point: The other, reference point (L{LatLon}). @param points: The polygon points (L{LatLon}[]). @keyword closed: Optionally, close the polygon (C{bool}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword height: Optional height, overriding the mean height for a point within the arc (C{meter}).
@return: 2-Tuple C{(closest, distance)} of the closest point (L{LatLon}) on the polygon and the C{distance} from the C{closest} to the other B{C{point}} in C{meter}, same units as B{C{radius}}.
@raise TypeError: Some B{C{points}} or B{C{point}} not C{LatLon}.
@raise ValueError: No B{C{points}}. '''
'''Compute the perimeter of a (spherical) polygon (with great circle arcs joining consecutive points).
@param points: The polygon points (L{LatLon}[]). @keyword closed: Optionally, close the polygon (C{bool}). @keyword radius: Optional, mean earth radius (C{meter}).
@return: Polygon perimeter (C{meter}, same units as B{C{radius}}).
@raise TypeError: Some B{C{points}} are not L{LatLon}.
@raise ValueError: Insufficient number of B{C{points}}.
@see: L{pygeodesy.perimeterOf}, L{sphericalTrigonometry.perimeterOf} and L{ellipsoidalKarney.perimeterOf}. '''
'''Return the vectorial sum of two or more n-vectors.
@param nvectors: Vectors to be added (L{Nvector}[]). @keyword Vector: Optional class for the vectorial sum (L{Nvector}). @keyword h: Optional height, overriding the mean height (C{meter}). @keyword kwds: Optional, additional B{C{Vector}} keyword arguments.
@return: Vectorial sum (B{C{Vector}}).
@raise VectorError: No B{C{nvectors}}. '''
height=None, LatLon=LatLon): '''Locate a point given two known points and initial bearings from those points.
@param point1: First reference point (L{LatLon}). @param bearing1: Bearing at the first point (compass C{degrees360}). @param point2: Second reference point (L{LatLon}). @param bearing2: Bearing at the second point (compass C{degrees360}). @keyword height: Optional height at the triangulated point, overriding the mean height (C{meter}). @keyword LatLon: Optional (sub-)class to return the triangulated point (L{LatLon}).
@return: Triangulated point (B{C{LatLon}}).
@raise TypeError: If B{C{point1}} or B{C{point2}} is not L{LatLon}.
@raise Valuerror: Points coincide.
@example:
>>> p = LatLon("47°18.228'N","002°34.326'W") # Basse Castouillet >>> q = LatLon("47°18.664'N","002°31.717'W") # Basse Hergo >>> t = triangulate(p, 7, q, 295) # 47.323667°N, 002.568501°W' '''
raise ValueError('%s %s: %r' % ('coincident', 'points', point2))
radius=R_M, height=None, LatLon=LatLon, useZ=False): '''Locate a point at given distances from three other points. See also U{Trilateration<https://WikiPedia.org/wiki/Trilateration>}.
@param point1: First point (L{LatLon}). @param distance1: Distance to the first point (C{meter}, same units as B{C{radius}}). @param point2: Second point (L{LatLon}). @param distance2: Distance to the second point (C{meter}, same units as B{C{radius}}). @param point3: Third point (L{LatLon}). @param distance3: Distance to the third point (C{meter}, same units as B{C{radius}}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword height: Optional height at the trilaterated point, overriding the IDW height (C{meter}, same units as B{C{radius}}). @keyword LatLon: Optional (sub-)class to return the trilaterated point (L{LatLon}). @keyword useZ: Include Z component iff non-NaN, non-zero (C{bool}).
@return: Trilaterated point (B{C{LatLon}}).
@raise TypeError: If B{C{point1}}, B{C{point2}} or B{C{point3}} is not L{LatLon}.
@raise ValueError: Invalid B{C{radius}}, some B{C{distances}} exceed trilateration or some B{C{points}} coincide. ''' # return Nvector and radial distance squared raise ValueError('%s %s: %r' % ('coincident', 'points', p))
raise ValueError('%s %s: %r' % ('radius', 'invalid', radius))
# the following uses x,y coordinate system with origin at n1, x axis n1->n2
# courtesy Carlos Freitas <https://GitHub.com/mrJean1/PyGeodesy/issues/33>
Z = X.cross(Y) # unit vector perpendicular to plane n = n.plus(Z.times(sqrt(z)))
map1(fabs, distance1, distance2, distance3)) else: h = height
# no intersection, d < EPS_2 or j < EPS_2 raise ValueError('no %s for %r, %r, %r at %r, %r, %r' % ('trilaterate', point1, point2, point3, distance1, distance2, distance3))
# **) MIT License # # Copyright (C) 2016-2020 -- 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. |