1 """Define the :class:`~geographiclib.polygonarea.PolygonArea` class 
    3 The constructor initializes a empty polygon.  The available methods are 
    5   * :meth:`~geographiclib.polygonarea.PolygonArea.Clear` reset the 
    7   * :meth:`~geographiclib.polygonarea.PolygonArea.AddPoint` add a vertex 
    9   * :meth:`~geographiclib.polygonarea.PolygonArea.AddEdge` add an edge 
   11   * :meth:`~geographiclib.polygonarea.PolygonArea.Compute` compute the 
   12     properties of the polygon 
   13   * :meth:`~geographiclib.polygonarea.PolygonArea.TestPoint` compute the 
   14     properties of the polygon with a tentative additional vertex 
   15   * :meth:`~geographiclib.polygonarea.PolygonArea.TestEdge` compute the 
   16     properties of the polygon with a tentative additional edge 
   18 The public attributes for this class are 
   20   * :attr:`~geographiclib.polygonarea.PolygonArea.earth` 
   21     :attr:`~geographiclib.polygonarea.PolygonArea.polyline` 
   22     :attr:`~geographiclib.polygonarea.PolygonArea.area0` 
   23     :attr:`~geographiclib.polygonarea.PolygonArea.num` 
   24     :attr:`~geographiclib.polygonarea.PolygonArea.lat1` 
   25     :attr:`~geographiclib.polygonarea.PolygonArea.lon1` 
   52   """Area of a geodesic polygon""" 
   55     """Count crossings of prime meridian for AddPoint.""" 
   59     lon1 = Math.AngNormalize(lon1)
 
   60     lon2 = Math.AngNormalize(lon2)
 
   61     lon12, _ = Math.AngDiff(lon1, lon2)
 
   62     cross = (1 
if lon1 <= 0 
and lon2 > 0 
and lon12 > 0
 
   63              else (-1 
if lon2 <= 0 
and lon1 > 0 
and lon12 < 0 
else 0))
 
   68     """Count crossings of prime meridian for AddEdge.""" 
   73     lon1 = math.fmod(lon1, 720.0); lon2 = math.fmod(lon2, 720.0)
 
   74     return ( (0 
if ((lon2 >= 0 
and lon2 < 360) 
or lon2 < -360) 
else 1) -
 
   75              (0 
if ((lon1 >= 0 
and lon1 < 360) 
or lon1 < -360) 
else 1) )
 
   79     """Construct a PolygonArea object 
   81     :param earth: a :class:`~geographiclib.geodesic.Geodesic` object 
   82     :param polyline: if true, treat object as a polyline instead of a polygon 
   84     Initially the polygon has no vertices. 
   89     """The geodesic object (readonly)""" 
   91     """Is this a polyline? (readonly)""" 
   92     self.
area0 = 4 * math.pi * earth._c2
 
   93     """The total area of the ellipsoid in meter^2 (readonly)""" 
   94     self.
_mask = (Geodesic.LATITUDE | Geodesic.LONGITUDE |
 
   96                   (Geodesic.EMPTY 
if self.
polyline else 
   97                    Geodesic.AREA | Geodesic.LONG_UNROLL))
 
  101     """The current number of points in the polygon (readonly)""" 
  103     """The current latitude in degrees (readonly)""" 
  105     """The current longitude in degrees (readonly)""" 
  109     """Reset to empty polygon.""" 
  117     """Add the next vertex to the polygon 
  119     :param lat: the latitude of the point in degrees 
  120     :param lon: the longitude of the point in degrees 
  122     This adds an edge from the current vertex to the new vertex. 
  129       _, s12, _, _, _, _, _, _, _, S12 = self.
earth._GenInverse(
 
  140     """Add the next edge to the polygon 
  142     :param azi: the azimuth at the current the point in degrees 
  143     :param s: the length of the edge in meters 
  145     This specifies the new vertex in terms of the edge from the current 
  151       _, lat, lon, _, _, _, _, _, S12 = self.
earth._GenDirect(
 
  162   def Compute(self, reverse = False, sign = True):
 
  163     """Compute the properties of the polygon 
  165     :param reverse: if true then clockwise (instead of 
  166       counter-clockwise) traversal counts as a positive area 
  167     :param sign: if true then return a signed result for the area if the 
  168       polygon is traversed in the "wrong" direction instead of returning 
  169       the area for the rest of the earth 
  170     :return: a tuple of number, perimeter (meters), area (meters^2) 
  172     If the object is a polygon (and not a polygon), the perimeter 
  173     includes the length of a final edge connecting the current point to 
  174     the initial point.  If the object is a polyline, then area is nan. 
  176     More points can be added to the polygon after this call. 
  183       return self.
num, perimeter, area
 
  187       return self.
num, perimeter, area
 
  189     _, s12, _, _, _, _, _, _, _, S12 = self.
earth._GenInverse(
 
  196       tempsum.Add( (1 
if tempsum.Sum() < 0 
else -1) * self.
area0/2 )
 
  199     if not reverse: tempsum.Negate()
 
  202       if tempsum.Sum() > self.
area0/2:
 
  203         tempsum.Add( -self.
area0 )
 
  204       elif tempsum.Sum() <= -self.
area0/2:
 
  205         tempsum.Add(  self.
area0 )
 
  207       if tempsum.Sum() >= self.
area0:
 
  208         tempsum.Add( -self.
area0 )
 
  209       elif tempsum.Sum() < 0:
 
  210         tempsum.Add(  self.
area0 )
 
  212     area = 0.0 + tempsum.Sum()
 
  213     return self.
num, perimeter, area
 
  216   def TestPoint(self, lat, lon, reverse = False, sign = True):
 
  217     """Compute the properties for a tentative additional vertex 
  219     :param lat: the latitude of the point in degrees 
  220     :param lon: the longitude of the point in degrees 
  221     :param reverse: if true then clockwise (instead of 
  222       counter-clockwise) traversal counts as a positive area 
  223     :param sign: if true then return a signed result for the area if the 
  224       polygon is traversed in the "wrong" direction instead of returning 
  225       the area for the rest of the earth 
  226     :return: a tuple of number, perimeter (meters), area (meters^2) 
  233       return 1, perimeter, area
 
  238     for i 
in ([0] 
if self.
polyline else [0, 1]):
 
  239       _, s12, _, _, _, _, _, _, _, S12 = self.
earth._GenInverse(
 
  240         self.
lat1 if i == 0 
else lat, self.
lon1 if i == 0 
else lon,
 
  241         self.
_lat0 if i != 0 
else lat, self.
_lon0 if i != 0 
else lon,
 
  246         crossings += PolygonArea._transit(self.
lon1 if i == 0 
else lon,
 
  247                                          self.
_lon0 if i != 0 
else lon)
 
  250       return num, perimeter, area
 
  253       tempsum += (1 
if tempsum < 0 
else -1) * self.
area0/2
 
  256     if not reverse: tempsum *= -1
 
  259       if tempsum > self.
area0/2:
 
  260         tempsum -= self.
area0 
  261       elif tempsum <= -self.
area0/2:
 
  262         tempsum += self.
area0 
  264       if tempsum >= self.
area0:
 
  265         tempsum -= self.
area0 
  267         tempsum += self.
area0 
  270     return num, perimeter, area
 
  273   def TestEdge(self, azi, s, reverse = False, sign = True):
 
  274     """Compute the properties for a tentative additional edge 
  276     :param azi: the azimuth at the current the point in degrees 
  277     :param s: the length of the edge in meters 
  278     :param reverse: if true then clockwise (instead of 
  279       counter-clockwise) traversal counts as a positive area 
  280     :param sign: if true then return a signed result for the area if the 
  281       polygon is traversed in the "wrong" direction instead of returning 
  282       the area for the rest of the earth 
  283     :return: a tuple of number, perimeter (meters), area (meters^2) 
  288       return 0, Math.nan, Math.nan
 
  292       return num, perimeter, Math.nan
 
  296     _, lat, lon, _, _, _, _, _, S12 = self.
earth._GenDirect(
 
  299     crossings += PolygonArea._transitdirect(self.
lon1, lon)
 
  300     _, s12, _, _, _, _, _, _, _, S12 = self.
earth._GenInverse(
 
  304     crossings += PolygonArea._transit(lon, self.
_lon0)
 
  307       tempsum += (1 
if tempsum < 0 
else -1) * self.
area0/2
 
  310     if not reverse: tempsum *= -1
 
  313       if tempsum > self.
area0/2:
 
  314         tempsum -= self.
area0 
  315       elif tempsum <= -self.
area0/2:
 
  316         tempsum += self.
area0 
  318       if tempsum >= self.
area0:
 
  319         tempsum -= self.
area0 
  321         tempsum += self.
area0 
  324     return num, perimeter, area