예제 #1
0
        /// <summary>
        /// Add a point to the polygon or polyline.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="lat">The latitude of the point (degrees).</param>
        /// <param name="lon">The longitude of the point (degrees).</param>
        /// <remarks>
        /// g and p must have been initialized with calls to geod_init() and
        /// geod_polygon_init(), respectively. The same g must be used for all the
        /// points and edges in a polygon. lat should be in the range
        /// [-90deg, 90deg] and lon should be in the range [-540deg, 540deg).
        /// </remarks>
        public void geod_polygon_addpoint(geod_geodesic g, double lat, double lon)
        {
            lon = AngNormalize(lon);
            if (num == 0)
            {
                lat0 = this.lat = lat;
                lon0 = this.lon = lon;
            }
            else
            {
                double s12, S12 = 0, dummy;
                if (polyline)
                {
                    g.geod_geninverse(this.lat, this.lon, lat, lon, GEOD.DISTANCE, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out dummy);
                }
                else
                {
                    g.geod_geninverse(this.lat, this.lon, lat, lon, GEOD.DISTANCE | GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);
                }

                accadd(P, s12);
                if (!polyline)
                {
                    accadd(A, S12);
                    crossings += transit(this.lon, lon);
                }
                this.lat = lat; this.lon = lon;
            }
            ++num;
        }
예제 #2
0
        /// <summary>
        /// Return the results assuming a tentative final test point is added via an
        /// azimuth and distance; however, the data for the test point is not saved.
        /// This lets you report a running result for the perimeter and area as the
        /// user moves the mouse cursor. Ordinary floating point arithmetic is used
        /// to accumulate the data for the test point; thus the area and perimeter
        /// returned are less accurate than if geod_polygon_addedge() and
        /// geod_polygon_compute() are used.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="azi">The azimuth at current point (degrees).</param>
        /// <param name="s">The distance from current point to final test point (meters).</param>
        /// <param name="reverse">If set <b>true</b> then clockwise (instead of counter-clockwise)
        /// traversal counts as a positive area.</param>
        /// <param name="sign">If set <b>true</b> 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.</param>
        /// <param name="pA">The area of the polygon (square meters); only set if polyline is set <b>true</b>
        /// in the call to geod_polygon_init().</param>
        /// <param name="pP">The perimeter of the polygon or length of the polyline (meters).</param>
        /// <returns>The number of points.</returns>
        /// <remarks>
        /// azi should be in the range [-540deg, 540deg).
        /// </remarks>
        public int geod_polygon_testedge(geod_geodesic g, double azi, double s, bool reverse, bool sign, out double pA, out double pP)
        {
            pP = pA = NaN;

            int num = this.num + 1;

            if (num == 1)
            {
                return(0);                   // we don't have a starting point!
            }
            double perimeter = P[0] + s;

            if (polyline)
            {
                pP = perimeter;
                return(num);
            }

            double tempsum   = A[0];
            int    crossings = this.crossings;

            {
                double lat, lon, s12, S12, dummy;
                g.geod_gendirect(this.lat, this.lon, azi, GEOD.LONG_UNROLL, s, GEOD.LATITUDE | GEOD.LONGITUDE | GEOD.AREA, out lat, out lon, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);

                tempsum   += S12;
                crossings += transitdirect(this.lon, lon);
                g.geod_geninverse(lat, lon, lat0, lon0, GEOD.DISTANCE | GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);
                perimeter += s12;
                tempsum   += S12;
                crossings += transit(lon, lon0);
            }

            double area0 = 4 * pi * g.c2;

            if ((crossings & 1) != 0)
            {
                tempsum += (tempsum < 0?1:-1) * area0 / 2;
            }

            // area is with the clockwise sense. If !reverse convert to counter-clockwise convention.
            if (!reverse)
            {
                tempsum *= -1;
            }

            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if (sign)
            {
                if (tempsum > area0 / 2)
                {
                    tempsum -= area0;
                }
                else if (tempsum <= -area0 / 2)
                {
                    tempsum += area0;
                }
            }
            else
            {
                if (tempsum >= area0)
                {
                    tempsum -= area0;
                }
                else if (tempsum < 0)
                {
                    tempsum += area0;
                }
            }

            pP = perimeter;
            pA = 0 + tempsum;
            return(num);
        }
예제 #3
0
        /// <summary>
        /// Return the results assuming a tentative final test point is added;
        /// however, the data for the test point is not saved. This lets you report a
        /// running result for the perimeter and area as the user moves the mouse
        /// cursor. Ordinary floating point arithmetic is used to accumulate the data
        /// for the test point; thus the area and perimeter returned are less accurate
        /// than if geod_polygon_addpoint() and geod_polygon_compute() are used.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="lat">The latitude of the test point (degrees).</param>
        /// <param name="lon">The longitude of the test point (degrees).</param>
        /// <param name="reverse">If set <b>true</b> then clockwise (instead of counter-clockwise)
        /// traversal counts as a positive area.</param>
        /// <param name="sign">If set <b>true</b> 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.</param>
        /// <param name="pA">The area of the polygon (square meters); only set if polyline is set <b>true</b>
        /// in the call to geod_polygon_init().</param>
        /// <param name="pP">The perimeter of the polygon or length of the polyline (meters).</param>
        /// <returns>The number of points.</returns>
        /// <remarks>
        /// lat should be in the range [-90deg, 90deg] and lon should be in the range [-540deg, 540deg).
        /// </remarks>
        public int geod_polygon_testpoint(geod_geodesic g, double lat, double lon, bool reverse, bool sign, out double pA, out double pP)
        {
            pP = pA = 0;

            int num = this.num + 1;

            if (num == 1)
            {
                return(num);
            }

            double perimeter = P[0];
            double tempsum   = polyline?0:A[0];
            int    crossings = this.crossings;

            for (int i = 0; i < (polyline?1:2); ++i)
            {
                double s12, dummy;

                if (!polyline)
                {
                    double S12;
                    g.geod_geninverse(i == 0?this.lat:lat, i == 0?this.lon:lon, i != 0?lat0:lat, i != 0?lon0:lon, GEOD.DISTANCE | GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);
                    tempsum   += S12;
                    crossings += transit(i == 0?this.lon:lon, i != 0?this.lon0:lon);
                }
                else
                {
                    g.geod_geninverse(i == 0?this.lat:lat, i == 0?this.lon:lon, i != 0?lat0:lat, i != 0?lon0:lon, GEOD.DISTANCE, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out dummy);
                }

                perimeter += s12;
            }

            pP = perimeter;
            if (polyline)
            {
                return(num);
            }

            double area0 = 4 * pi * g.c2;

            if ((crossings & 1) != 0)
            {
                tempsum += (tempsum < 0?1:-1) * area0 / 2;
            }

            // area is with the clockwise sense. If !reverse convert to counter-clockwise convention.
            if (!reverse)
            {
                tempsum *= -1;
            }

            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if (sign)
            {
                if (tempsum > area0 / 2)
                {
                    tempsum -= area0;
                }
                else if (tempsum <= -area0 / 2)
                {
                    tempsum += area0;
                }
            }
            else
            {
                if (tempsum >= area0)
                {
                    tempsum -= area0;
                }
                else if (tempsum < 0)
                {
                    tempsum += area0;
                }
            }

            pA = 0 + tempsum;
            return(num);
        }
예제 #4
0
        /// <summary>
        /// Return the results for a polygon.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="reverse">If set <b>true</b> then clockwise (instead of counter-clockwise)
        /// traversal counts as a positive area.</param>
        /// <param name="sign">If set <b>true</b> 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.</param>
        /// <param name="pA">The area of the polygon (square meters); only set if polyline is set <b>true</b>
        /// in the call to geod_polygon_init().</param>
        /// <param name="pP">The perimeter of the polygon or length of the polyline (meters).</param>
        /// <returns>The number of points.</returns>
        /// <remarks>
        /// The area and perimeter are accumulated at two times the standard floating
        /// point precision to guard against the loss of accuracy with many-sided
        /// polygons. Only simple polygons (which are not self-intersecting) are
        /// allowed. There's no need to "close" the polygon by repeating the first vertex.
        /// </remarks>
        public int geod_polygon_compute(geod_geodesic g, bool reverse, bool sign, out double pA, out double pP)
        {
            pP = pA = 0;
            if (num < 2)
            {
                return(num);
            }

            if (polyline)
            {
                pP = P[0];
                return(num);
            }

            double s12, S12, dummy;

            g.geod_geninverse(lat, lon, lat0, lon0, GEOD.DISTANCE | GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);

            pP = accsum(P, s12);

            double[] t = new double[2];

            acccopy(A, t);
            accadd(t, S12);
            int    crossings = this.crossings + transit(lon, lon0);
            double area0     = 4 * pi * g.c2;

            if ((crossings & 1) != 0)
            {
                accadd(t, (t[0] < 0?1:-1) * area0 / 2);
            }

            // area is with the clockwise sense. If !reverse convert to
            // counter-clockwise convention.
            if (!reverse)
            {
                accneg(t);
            }

            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if (sign)
            {
                if (t[0] > area0 / 2)
                {
                    accadd(t, -area0);
                }
                else if (t[0] <= -area0 / 2)
                {
                    accadd(t, +area0);
                }
            }
            else
            {
                if (t[0] >= area0)
                {
                    accadd(t, -area0);
                }
                else if (t[0] < 0)
                {
                    accadd(t, +area0);
                }
            }

            pA = 0 + t[0];

            return(num);
        }
예제 #5
0
        /// <summary>
        /// Return the results assuming a tentative final test point is added;
        /// however, the data for the test point is not saved. This lets you report a
        /// running result for the perimeter and area as the user moves the mouse
        /// cursor. Ordinary floating point arithmetic is used to accumulate the data
        /// for the test point; thus the area and perimeter returned are less accurate
        /// than if geod_polygon_addpoint() and geod_polygon_compute() are used.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="lat">The latitude of the test point (degrees).</param>
        /// <param name="lon">The longitude of the test point (degrees).</param>
        /// <param name="reverse">If set <b>true</b> then clockwise (instead of counter-clockwise)
        /// traversal counts as a positive area.</param>
        /// <param name="sign">If set <b>true</b> 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.</param>
        /// <param name="pA">The area of the polygon (square meters); only set if polyline is set <b>true</b>
        /// in the call to geod_polygon_init().</param>
        /// <param name="pP">The perimeter of the polygon or length of the polyline (meters).</param>
        /// <returns>The number of points.</returns>
        /// <remarks>
        /// lat should be in the range [-90deg, 90deg] and lon should be in the range [-540deg, 540deg).
        /// </remarks>
        public int geod_polygon_testpoint(geod_geodesic g, double lat, double lon, bool reverse, bool sign, out double pA, out double pP)
        {
            pP=pA=0;

            int num=this.num+1;
            if(num==1) return num;

            double perimeter=P[0];
            double tempsum=polyline?0:A[0];
            int crossings=this.crossings;
            for(int i=0; i<(polyline?1:2); ++i)
            {
                double s12, dummy;

                if(!polyline)
                {
                    double S12;
                    g.geod_geninverse(i==0?this.lat:lat, i==0?this.lon:lon, i!=0?lat0:lat, i!=0?lon0:lon, GEOD.DISTANCE|GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);
                    tempsum+=S12;
                    crossings+=transit(i==0?this.lon:lon, i!=0?this.lon0:lon);
                }
                else g.geod_geninverse(i==0?this.lat:lat, i==0?this.lon:lon, i!=0?lat0:lat, i!=0?lon0:lon, GEOD.DISTANCE, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out dummy);

                perimeter+=s12;
            }

            pP=perimeter;
            if(polyline) return num;

            double area0=4*pi*g.c2;
            if((crossings&1)!=0) tempsum+=(tempsum<0?1:-1)*area0/2;

            // area is with the clockwise sense. If !reverse convert to counter-clockwise convention.
            if(!reverse) tempsum*=-1;

            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if(sign)
            {
                if(tempsum>area0/2) tempsum-=area0;
                else if(tempsum<=-area0/2) tempsum+=area0;
            }
            else
            {
                if(tempsum>=area0) tempsum-=area0;
                else if(tempsum<0) tempsum+=area0;
            }

            pA=0+tempsum;
            return num;
        }
예제 #6
0
        /// <summary>
        /// Return the results assuming a tentative final test point is added via an
        /// azimuth and distance; however, the data for the test point is not saved.
        /// This lets you report a running result for the perimeter and area as the
        /// user moves the mouse cursor. Ordinary floating point arithmetic is used
        /// to accumulate the data for the test point; thus the area and perimeter
        /// returned are less accurate than if geod_polygon_addedge() and
        /// geod_polygon_compute() are used.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="azi">The azimuth at current point (degrees).</param>
        /// <param name="s">The distance from current point to final test point (meters).</param>
        /// <param name="reverse">If set <b>true</b> then clockwise (instead of counter-clockwise)
        /// traversal counts as a positive area.</param>
        /// <param name="sign">If set <b>true</b> 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.</param>
        /// <param name="pA">The area of the polygon (square meters); only set if polyline is set <b>true</b>
        /// in the call to geod_polygon_init().</param>
        /// <param name="pP">The perimeter of the polygon or length of the polyline (meters).</param>
        /// <returns>The number of points.</returns>
        /// <remarks>
        /// azi should be in the range [-540deg, 540deg).
        /// </remarks>
        public int geod_polygon_testedge(geod_geodesic g, double azi, double s, bool reverse, bool sign, out double pA, out double pP)
        {
            pP=pA=NaN;

            int num=this.num+1;
            if(num==1) return 0; // we don't have a starting point!

            double perimeter=P[0]+s;
            if(polyline)
            {
                pP=perimeter;
                return num;
            }

            double tempsum=A[0];
            int crossings=this.crossings;

            {
                double lat, lon, s12, S12, dummy;
                g.geod_gendirect(this.lat, this.lon, azi, GEOD.LONG_UNROLL, s, GEOD.LATITUDE|GEOD.LONGITUDE|GEOD.AREA, out lat, out lon, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);

                tempsum+=S12;
                crossings+=transitdirect(this.lon, lon);
                g.geod_geninverse(lat, lon, lat0, lon0, GEOD.DISTANCE|GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);
                perimeter+=s12;
                tempsum+=S12;
                crossings+=transit(lon, lon0);
            }

            double area0=4*pi*g.c2;
            if((crossings&1)!=0) tempsum+=(tempsum<0?1:-1)*area0/2;

            // area is with the clockwise sense. If !reverse convert to counter-clockwise convention.
            if(!reverse) tempsum*=-1;

            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if(sign)
            {
                if(tempsum>area0/2) tempsum-=area0;
                else if(tempsum<=-area0/2) tempsum+=area0;
            }
            else
            {
                if(tempsum>=area0) tempsum-=area0;
                else if(tempsum<0) tempsum+=area0;
            }

            pP=perimeter;
            pA=0+tempsum;
            return num;
        }
예제 #7
0
        /// <summary>
        /// Return the results for a polygon.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="reverse">If set <b>true</b> then clockwise (instead of counter-clockwise)
        /// traversal counts as a positive area.</param>
        /// <param name="sign">If set <b>true</b> 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.</param>
        /// <param name="pA">The area of the polygon (square meters); only set if polyline is set <b>true</b>
        /// in the call to geod_polygon_init().</param>
        /// <param name="pP">The perimeter of the polygon or length of the polyline (meters).</param>
        /// <returns>The number of points.</returns>
        /// <remarks>
        /// The area and perimeter are accumulated at two times the standard floating
        /// point precision to guard against the loss of accuracy with many-sided
        /// polygons. Only simple polygons (which are not self-intersecting) are
        /// allowed. There's no need to "close" the polygon by repeating the first vertex.
        /// </remarks>
        public int geod_polygon_compute(geod_geodesic g, bool reverse, bool sign, out double pA, out double pP)
        {
            pP=pA=0;
            if(num<2) return num;

            if(polyline)
            {
                pP=P[0];
                return num;
            }

            double s12, S12, dummy;
            g.geod_geninverse(lat, lon, lat0, lon0, GEOD.DISTANCE|GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);

            pP=accsum(P, s12);

            double[] t=new double[2];

            acccopy(A, t);
            accadd(t, S12);
            int crossings=this.crossings+transit(lon, lon0);
            double area0=4*pi*g.c2;

            if((crossings&1)!=0) accadd(t, (t[0]<0?1:-1)*area0/2);

            // area is with the clockwise sense. If !reverse convert to
            // counter-clockwise convention.
            if(!reverse) accneg(t);

            // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
            if(sign)
            {
                if(t[0]>area0/2) accadd(t, -area0);
                else if(t[0]<=-area0/2) accadd(t, +area0);
            }
            else
            {
                if(t[0]>=area0) accadd(t, -area0);
                else if(t[0]<0) accadd(t, +area0);
            }

            pA=0+t[0];

            return num;
        }
예제 #8
0
        /// <summary>
        /// Add a point to the polygon or polyline.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="p">The geod_polygon object specifying the polygon.</param>
        /// <param name="lat">The latitude of the point (degrees).</param>
        /// <param name="lon">The longitude of the point (degrees).</param>
        /// <remarks>
        /// g and p must have been initialized with calls to geod_init() and
        /// geod_polygon_init(), respectively. The same g must be used for all the
        /// points and edges in a polygon. lat should be in the range
        /// [-90deg, 90deg] and lon should be in the range [-540deg, 540deg).
        /// </remarks>
        public void geod_polygon_addpoint(geod_geodesic g, double lat, double lon)
        {
            lon=AngNormalize(lon);
            if(num==0)
            {
                lat0=this.lat=lat;
                lon0=this.lon=lon;
            }
            else
            {
                double s12, S12=0, dummy;
                if(polyline) g.geod_geninverse(this.lat, this.lon, lat, lon, GEOD.DISTANCE, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out dummy);
                else g.geod_geninverse(this.lat, this.lon, lat, lon, GEOD.DISTANCE|GEOD.AREA, out s12, out dummy, out dummy, out dummy, out dummy, out dummy, out S12);

                accadd(P, s12);
                if(!polyline)
                {
                    accadd(A, S12);
                    crossings+=transit(this.lon, lon);
                }
                this.lat=lat; this.lon=lon;
            }
            ++num;
        }