예제 #1
0
        /// <summary>
        /// Return the result of adding a number to sum (but don't change sum).
        /// </summary>
        /// <param name="y">the number to be added to the sum.</param>
        /// <returns><i>sum</i> + <i>y</i>.</returns>
        public double Sum(double y)
        {
            Accumulator a = this;

            a.Add(y);
            return(a._s);
        }
예제 #2
0
 /// <summary>
 /// Clear current instance of <see cref="PolygonArea{T}"/>, allowing a new polygon to be started.
 /// </summary>
 public void Clear()
 {
     _num          = 0;
     _crossings    = 0;
     _areasum      = 0;
     _perimetersum = 0;
     _lat0         = _lon0 = _lat1 = _lon1 = double.NaN;
 }
예제 #3
0
        /**
         * Return the results so far.
         * <p>
         * @param reverse if true then clockwise (instead of counter-clockwise)
         *   traversal counts as a positive area.
         * @param sign if true then return a signed result for the area if
         *   the polygon is traversed in the "wrong" direction instead of returning
         *   the area for the rest of the earth.
         * @return PolygonResult(<i>num</i>, <i>perimeter</i>, <i>area</i>) where
         *   <i>num</i> is the number of vertices, <i>perimeter</i> is the perimeter
         *   of the polygon or the length of the polyline (meters), and <i>area</i>
         *   is the area of the polygon (meters<sup>2</sup>) or Double.NaN of
         *   <i>polyline</i> is true in the constructor.
         * <p>
         * More points can be added to the polygon after this call.
         **********************************************************************/
        public PolygonResult Compute(bool reverse, bool sign)
        {
            if (_num < 2)
            {
                return(new PolygonResult(_num, 0, _polyline ? Double.NaN : 0));
            }
            if (_polyline)
            {
                return(new PolygonResult(_num, _perimetersum.Sum(), Double.NaN));
            }

            GeodesicData g       = _earth.Inverse(_lat1, _lon1, _lat0, _lon0, _mask);
            Accumulator  tempsum = new Accumulator(_areasum);

            tempsum.Add(g.S12);
            int crossings = _crossings + transit(_lon1, _lon0);

            if ((crossings & 1) != 0)
            {
                tempsum.Add((tempsum.Sum() < 0 ? 1 : -1) * _area0 / 2);
            }
            // area is with the clockwise sense.  If !reverse convert to
            // counter-clockwise convention.
            if (!reverse)
            {
                tempsum.Negate();
            }
            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if (sign)
            {
                if (tempsum.Sum() > _area0 / 2)
                {
                    tempsum.Add(-_area0);
                }
                else if (tempsum.Sum() <= -_area0 / 2)
                {
                    tempsum.Add(+_area0);
                }
            }
            else
            {
                if (tempsum.Sum() >= _area0)
                {
                    tempsum.Add(-_area0);
                }
                else if (tempsum.Sum() < 0)
                {
                    tempsum.Add(+_area0);
                }
            }
            return
                (new PolygonResult(_num, _perimetersum.Sum(g.s12), 0 + tempsum.Sum()));
        }
예제 #4
0
 /**
  * Constructor for PolygonArea.
  * <p>
  * @param earth the Geodesic object to use for geodesic calculations.
  * @param polyline if true that treat the points as defining a polyline
  *   instead of a polygon.
  **********************************************************************/
 public PolygonArea(Geodesic earth, bool polyline)
 {
     _earth    = earth;
     _area0    = _earth.EllipsoidArea();
     _polyline = polyline;
     _mask     = GeodesicMask.LATITUDE | GeodesicMask.LONGITUDE |
                 GeodesicMask.DISTANCE |
                 (_polyline ? GeodesicMask.NONE : GeodesicMask.AREA);
     _perimetersum = new Accumulator(0);
     if (!_polyline)
     {
         _areasum = new Accumulator(0);
     }
     Clear();
 }
예제 #5
0
 /// <summary>
 /// Add an edge to the polygon or polyline.
 /// </summary>
 /// <param name="azi">azimuth at current point (degrees).</param>
 /// <param name="s">distance from current point to next point (meters).</param>
 /// <remarks>
 /// This does nothing if no points have been added yet.
 /// Use <see cref="CurrentPoint"/> to determine the position of the new vertex.
 /// </remarks>
 public void AddEdge(double azi, double s)
 {
     if (_num != 0)
     {                 // Do nothing if _num is zero
         _earth.GenDirect(_lat1, _lon1, azi, false, s, _mask,
                          out var lat, out var lon, out _, out _, out _, out _, out _, out var S12);
         _perimetersum += s;
         if (!_polyline)
         {
             _areasum   += S12;
             _crossings += TransitDirect(_lon1, lon);
             lon         = AngNormalize(lon);
         }
         _lat1 = lat; _lon1 = lon;
         ++_num;
     }
 }
예제 #6
0
 /// <summary>
 /// Add a point to the polygon or polyline.
 /// </summary>
 /// <param name="lat">the latitude of the point (degrees).</param>
 /// <param name="lon">the longitude of the point (degrees).</param>
 /// <remarks>
 /// <paramref name="lat"/> should be in the range [−90°, 90°].
 /// </remarks>
 public void AddPoint(double lat, double lon)
 {
     lat = LatFix(lat);
     lon = AngNormalize(lon);
     if (_num == 0)
     {
         _lat0 = _lat1 = lat;
         _lon0 = _lon1 = lon;
     }
     else
     {
         _earth.GenInverse(_lat1, _lon1, lat, lon, _mask,
                           out var s12, out _, out _, out _, out _, out _, out var S12);
         _perimetersum += s12;
         if (!_polyline)
         {
             _areasum   += S12;
             _crossings += Transit(_lon1, lon);
         }
         _lat1 = lat; _lon1 = lon;
     }
     ++_num;
 }
예제 #7
0
 private void AreaReduce(ref Accumulator area, int crossings, bool reverse, bool sign)
 {
     Remainder(ref area);
     if ((crossings & 1) != 0)
     {
         area += (area < 0 ? 1 : -1) * _area0 / 2;
     }
     // area is with the clockwise sense.  If !reverse convert to
     // counter-clockwise convention.
     if (!reverse)
     {
         area *= -1;
     }
     // If sign put area in (-_area0/2, _area0/2], else put area in [0, _area0)
     if (sign)
     {
         if (area > _area0 / 2)
         {
             area -= _area0;
         }
         else if (area <= -_area0 / 2)
         {
             area += _area0;
         }
     }
     else
     {
         if (area >= _area0)
         {
             area -= _area0;
         }
         else if (area < 0)
         {
             area += _area0;
         }
     }
 }
예제 #8
0
 private void Remainder(ref Accumulator a) => a.Remainder(_area0);
예제 #9
0
 /// <summary>
 /// Construct from another Accumulator.
 /// </summary>
 /// <param name="a">set <i>sum</i> = <i>a</i>.</param>
 public Accumulator(Accumulator a)
 {
     _s = a._s;
     _t = a._t;
 }