Exemple #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;
        }
Exemple #2
0
        /// <summary>
        /// A simple interface for computing the area of a geodesic polygon.
        /// </summary>
        /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
        /// <param name="lats">An array of latitudes of the polygon vertices (degrees).</param>
        /// <param name="lons">An array of longitudes of the polygon vertices (degrees).</param>
        /// <param name="n">The number of vertices.</param>
        /// <param name="pA">The area of the polygon (square meters).</param>
        /// <param name="pP">The perimeter of the polygon (meters).</param>
        /// <remarks>
        /// lats should be in the range [-90deg, 90deg]; lons should be in the range [-540deg, 540deg).
        ///
        /// Only simple polygons (which are not self-intersecting) are allowed.
        /// There's no need to "close" the polygon by repeating the first vertex. The
        /// area returned is signed with counter-clockwise traversal being treated as
        /// positive.
        /// </remarks>
        public static void geod_polygonarea(geod_geodesic g, double[] lats, double[] lons, int n, out double pA, out double pP)
        {
            geod_polygon p = new geod_polygon(false);

            for (int i = 0; i < n; ++i)
            {
                p.geod_polygon_addpoint(g, lats[i], lons[i]);
            }
            p.geod_polygon_compute(g, false, true, out pA, out pP);
        }
Exemple #3
0
        /// <summary>
        /// Add an edge 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="azi">The azimuth at current point (degrees).</param>
        /// <param name="s">The distance from current point to next point (meters).</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. azi should be in the range
        /// [-540deg, 540deg). This does nothing if no points have been
        /// added yet. The lat and lon fields of p give the location of
        /// the new vertex.
        /// </remarks>
        public void geod_polygon_addedge(geod_geodesic g, double azi, double s)
        {
            if (num != 0)
            {             // Do nothing is num is zero
                double lat, lon, S12 = 0, dummy;
                if (polyline)
                {
                    g.geod_gendirect(this.lat, this.lon, azi, GEOD.LONG_UNROLL, s, GEOD.LATITUDE | GEOD.LONGITUDE, out lat, out lon, out dummy, out dummy, out dummy, out dummy, out dummy, out dummy);
                }
                else
                {
                    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);
                }

                accadd(P, s);
                if (!polyline)
                {
                    accadd(A, S12);
                    crossings += transitdirect(this.lon, lon);
                }
                this.lat = lat; this.lon = lon;
                ++num;
            }
        }
Exemple #4
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);
        }
Exemple #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);
        }
Exemple #6
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);
        }
Exemple #7
0
        public override PJ Init()
        {
            g = new geod_geodesic(a, es / (1 + Math.Sqrt(one_es)));

            phi0 = Proj.pj_param_r(ctx, parameters, "lat_0");
            if (Math.Abs(Math.Abs(phi0) - Proj.HALFPI) < EPS10)
            {
                mode   = phi0 < 0.0?aeqd_mode.S_POLE:aeqd_mode.N_POLE;
                sinph0 = phi0 < 0.0?-1.0:1.0;
                cosph0 = 0.0;
            }
            else if (Math.Abs(phi0) < EPS10)
            {
                mode   = aeqd_mode.EQUIT;
                sinph0 = 0.0;
                cosph0 = 1.0;
            }
            else
            {
                mode   = aeqd_mode.OBLIQ;
                sinph0 = Math.Sin(phi0);
                cosph0 = Math.Cos(phi0);
            }

            if (es == 0)
            {
                inv = s_inverse;
                fwd = s_forward;
            }
            else
            {
                en = Proj.pj_enfn(es);
                if (en == null)
                {
                    return(null);
                }
                if (Proj.pj_param_b(ctx, parameters, "guam"))
                {
                    M1  = Proj.pj_mlfn(phi0, sinph0, cosph0, en);
                    inv = e_guam_inv;
                    fwd = e_guam_fwd;
                }
                else
                {
                    switch (mode)
                    {
                    case aeqd_mode.N_POLE:
                        Mp = Proj.pj_mlfn(Proj.HALFPI, 1.0, 0.0, en);
                        break;

                    case aeqd_mode.S_POLE:
                        Mp = Proj.pj_mlfn(-Proj.HALFPI, -1.0, 0.0, en);
                        break;

                    case aeqd_mode.EQUIT:
                    case aeqd_mode.OBLIQ:
                        inv = e_inverse;
                        fwd = e_forward;
                        N1  = 1.0 / Math.Sqrt(1.0 - es * sinph0 * sinph0);
                        He  = e / Math.Sqrt(one_es);
                        G   = sinph0 * He;
                        He *= cosph0;
                        break;
                    }
                    inv = e_inverse;
                    fwd = e_forward;
                }
            }

            return(this);
        }
 public void Ini()
 {
     GlobalGeodesic = new geod_geodesic(geod_a, geod_f);
 }
Exemple #9
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;
        }
Exemple #10
0
 /// <summary>
 /// A simple interface for computing the area of a geodesic polygon.
 /// </summary>
 /// <param name="g">The geod_geodesic object specifying the ellipsoid.</param>
 /// <param name="lats">An array of latitudes of the polygon vertices (degrees).</param>
 /// <param name="lons">An array of longitudes of the polygon vertices (degrees).</param>
 /// <param name="n">The number of vertices.</param>
 /// <param name="pA">The area of the polygon (square meters).</param>
 /// <param name="pP">The perimeter of the polygon (meters).</param>
 /// <remarks>
 /// lats should be in the range [-90deg, 90deg]; lons should be in the range [-540deg, 540deg).
 ///
 /// Only simple polygons (which are not self-intersecting) are allowed.
 /// There's no need to "close" the polygon by repeating the first vertex. The
 /// area returned is signed with counter-clockwise traversal being treated as
 /// positive.
 /// </remarks>
 public static void geod_polygonarea(geod_geodesic g, double[] lats, double[] lons, int n, out double pA, out double pP)
 {
     geod_polygon p=new geod_polygon(false);
     for(int i=0; i<n; ++i) p.geod_polygon_addpoint(g, lats[i], lons[i]);
     p.geod_polygon_compute(g, false, true, out pA, out pP);
 }
Exemple #11
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;
        }
Exemple #12
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;
        }
Exemple #13
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;
        }
Exemple #14
0
        /// <summary>
        /// Add an edge 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="azi">The azimuth at current point (degrees).</param>
        /// <param name="s">The distance from current point to next point (meters).</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. azi should be in the range
        /// [-540deg, 540deg). This does nothing if no points have been
        /// added yet. The lat and lon fields of p give the location of
        /// the new vertex.
        /// </remarks>
        public void geod_polygon_addedge(geod_geodesic g, double azi, double s)
        {
            if(num!=0)
            { // Do nothing is num is zero
                double lat, lon, S12=0, dummy;
                if(polyline) g.geod_gendirect(this.lat, this.lon, azi, GEOD.LONG_UNROLL, s, GEOD.LATITUDE|GEOD.LONGITUDE, out lat, out lon, out dummy, out dummy, out dummy, out dummy, out dummy, out dummy);
                else 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);

                accadd(P, s);
                if(!polyline)
                {
                    accadd(A, S12);
                    crossings+=transitdirect(this.lon, lon);
                }
                this.lat=lat; this.lon=lon;
                ++num;
            }
        }
        /// <summary>
        /// Initialize a geod_geodesicline object.
        /// </summary>
        /// <param name="g">The <see cref="geod_geodesic"/> object specifying the ellipsoid.</param>
        /// <param name="lat1">Latitude of point 1 (degrees).</param>
        /// <param name="lon1">Longitude of point 1 (degrees).</param>
        /// <param name="azi1">Azimuth at point 1 (degrees).</param>
        /// <param name="caps">Bitor'ed combination of <see cref="geod_mask"/> values. See remarks for more informations.</param>
        /// <remarks>
        /// <paramref name="caps"/> bitor'ed combination of geod_mask() values specifying
        /// the capabilities the geod_geodesicline object should possess, i.e., which
        /// quantities can be returned in calls to geod_position() and
        /// geod_genposition().
        ///
        /// <paramref name="lat1"/> should be in the range [-90deg, 90deg].
        /// <paramref name="lon1"/> and <paramref name="azi1"/> should be in the range [-540deg, 540deg).
        ///
        /// The geod_mask values are:
        /// - caps|=GEOD_LATITUDE for the latitude lat2; this is added automatically,
        /// - caps|=GEOD_LONGITUDE for the latitude lon2,
        /// - caps|=GEOD_AZIMUTH for the latitude azi2; this is added automatically,
        /// - caps|=GEOD_DISTANCE for the distance s12,
        /// - caps|=GEOD_REDUCEDLENGTH for the reduced length m12,
        /// - caps|=GEOD_GEODESICSCALE for the geodesic scales M12 and M21,
        /// - caps|=GEOD_AREA for the area S12,
        /// - caps|=GEOD_DISTANCE_IN permits the length of the
        ///   geodesic to be given in terms of s12; without this capability the
        ///   length can only be specified in terms of arc length.
        ///
        /// A value of caps=0 is treated as GEOD.LATITUDE|GEOD.LONGITUDE|GEOD.AZIMUTH|GEOD.DISTANCE_IN
        /// (to support the solution of the "standard" direct problem).
        /// </remarks>
        public geod_geodesicline(geod_geodesic g, double lat1, double lon1, double azi1, GEOD caps)
        {
            a  = g.a;
            f  = g.f;
            b  = g.b;
            c2 = g.c2;
            f1 = g.f1;

            // If caps is 0 assume the standard direct calculation
            this.caps = (caps != 0?caps:GEOD.DISTANCE_IN | GEOD.LONGITUDE) |
                        GEOD.LATITUDE | GEOD.AZIMUTH | GEOD.LONG_UNROLL;     // always allow latitude and azimuth and unrolling of longitude

            this.lat1 = lat1;
            this.lon1 = lon1;

            // Guard against underflow in salp0
            this.azi1 = AngRound(AngNormalize(azi1));

            // alp1 is in [0, pi]
            double alp1 = this.azi1 * degree;

            // Enforce sin(pi)==0 and cos(pi/2)==0. Better to face the ensuing
            // problems directly than to skirt them.
            salp1 = this.azi1 == -180?0:Math.Sin(alp1);
            calp1 = Math.Abs(this.azi1) == 90?0:Math.Cos(alp1);
            double phi = lat1 * degree;

            // Ensure cbet1=+epsilon at poles
            double sbet1 = f1 * Math.Sin(phi);
            double cbet1 = Math.Abs(lat1) == 90?tiny:Math.Cos(phi);

            norm2(ref sbet1, ref cbet1);
            dn1 = Math.Sqrt(1 + g.ep2 * sq(sbet1));

            // Evaluate alp0 from sin(alp1)*cos(bet1)=sin(alp0),
            salp0 = salp1 * cbet1;         // alp0 in [0, pi/2-|bet1|]

            // Alt: calp0=hypot(sbet1, calp1*cbet1). The following
            // is slightly better (consider the case salp1=0).
            calp0 = hypotx(calp1, salp1 * sbet1);

            // Evaluate sig with tan(bet1)=tan(sig1)*cos(alp1).
            // sig = 0 is nearest northward crossing of equator.
            // With bet1=0, alp1=pi/2, we have sig1=0 (equatorial line).
            // With bet1=pi/2, alp1=-pi, sig1=pi/2
            // With bet1=-pi/2, alp1=0, sig1=-pi/2
            // Evaluate omg1 with tan(omg1)=sin(alp0)*tan(sig1).
            // With alp0 in (0, pi/2], quadrants for sig and omg coincide.
            // No atan2(0, 0) ambiguity at poles since cbet1=+epsilon.
            // With alp0=0, omg1=0 for alp1=0, omg1=pi for alp1=pi.
            ssig1 = sbet1; somg1 = salp0 * sbet1;
            csig1 = comg1 = sbet1 != 0 || calp1 != 0?cbet1 * calp1:1;
            norm2(ref ssig1, ref csig1);             // sig1 in (-pi, pi]
            // norm2(ref somg1, ref comg1); -- don't need to normalize!

            k2 = sq(calp0) * g.ep2;
            double eps = k2 / (2 * (1 + Math.Sqrt(1 + k2)) + k2);

            if ((this.caps & GEOD.CAP_C1) != 0)
            {
                double s, c;
                A1m1 = geod_geodesic.A1m1f(eps);
                geod_geodesic.C1f(eps, C1a);
                B11 = SinCosSeries(true, ssig1, csig1, C1a, nC1);
                s   = Math.Sin(B11); c = Math.Cos(B11);

                // tau1=sig1+B11
                stau1 = ssig1 * c + csig1 * s;
                ctau1 = csig1 * c - ssig1 * s;
                // Not necessary because C1pa reverts C1a
                // B11=-SinCosSeries(TRUE, stau1, ctau1, C1pa, nC1p);
            }

            if ((this.caps & GEOD.CAP_C1p) != 0)
            {
                geod_geodesic.C1pf(eps, C1pa);
            }

            if ((this.caps & GEOD.CAP_C2) != 0)
            {
                A2m1 = geod_geodesic.A2m1f(eps);
                geod_geodesic.C2f(eps, C2a);
                B21 = SinCosSeries(true, ssig1, csig1, C2a, nC2);
            }

            if ((this.caps & GEOD.CAP_C3) != 0)
            {
                g.C3f(eps, C3a);
                A3c = -f *salp0 *g.A3f(eps);

                B31 = SinCosSeries(true, ssig1, csig1, C3a, nC3 - 1);
            }

            if ((this.caps & GEOD.CAP_C4) != 0)
            {
                g.C4f(eps, C4a);
                // Multiplier=a^2*e^2*cos(alpha0)*sin(alpha0)
                A4  = sq(a) * calp0 * salp0 * g.e2;
                B41 = SinCosSeries(false, ssig1, csig1, C4a, nC4);
            }
        }