示例#1
0
        /**
         * Forward projection, from geographic to gnomonic.
         * <p>
         * @param lat0 latitude of center point of projection (degrees).
         * @param lon0 longitude of center point of projection (degrees).
         * @param lat latitude of point (degrees).
         * @param lon longitude of point (degrees).
         * @return {@link GnomonicData} object with the following fields:
         *   <i>lat0</i>, <i>lon0</i>, <i>lat</i>, <i>lon</i>, <i>x</i>, <i>y</i>,
         *   <i>azi</i>, <i>rk</i>.
         * <p>
         * <i>lat0</i> and <i>lat</i> should be in the range [&minus;90&deg;,
         * 90&deg;] and <i>lon0</i> and <i>lon</i> should be in the range
         * [&minus;540&deg;, 540&deg;). The scale of the projection is
         * 1/<i>rk<sup>2</sup></i> in the "radial" direction, <i>azi</i> clockwise
         * from true north, and is 1/<i>rk</i> in the direction perpendicular to
         * this. If the point lies "over the horizon", i.e., if <i>rk</i> &le; 0,
         * then NaNs are returned for <i>x</i> and <i>y</i> (the correct values are
         * returned for <i>azi</i> and <i>rk</i>). A call to Forward followed by a
         * call to Reverse will return the original (<i>lat</i>, <i>lon</i>) (to
         * within roundoff) provided the point in not over the horizon.
         */

        public GnomonicData Forward(double lat0, double lon0, double lat, double lon)
        {
            GeodesicData inv =
                _earth.Inverse(lat0, lon0, lat, lon,
                               GeodesicMask.AZIMUTH | GeodesicMask.GEODESICSCALE |
                               GeodesicMask.REDUCEDLENGTH);
            GnomonicData fwd =
                new GnomonicData(lat0, lon0, lat, lon, Double.NaN, Double.NaN,
                                 inv.FinalAzimuth, inv.GeodesicScale12);

            if (inv.GeodesicScale12 > 0)
            {
                double rho = inv.ReducedLength / inv.GeodesicScale12;
                Pair   p   = GeoMath.SinCosD(inv.InitialAzimuth);
                fwd.x = rho * p.First;
                fwd.y = rho * p.Second;
            }

            return(fwd);
        }
示例#2
0
        /**
         * Reverse projection, from gnomonic to geographic.
         * <p>
         * @param lat0 latitude of center point of projection (degrees).
         * @param lon0 longitude of center point of projection (degrees).
         * @param x easting of point (meters).
         * @param y northing of point (meters).
         * @return {@link GnomonicData} object with the following fields:
         *   <i>lat0</i>, <i>lon0</i>, <i>lat</i>, <i>lon</i>, <i>x</i>, <i>y</i>,
         *   <i>azi</i>, <i>rk</i>.
         * <p>
         * <i>lat0</i> should be in the range [&minus;90&deg;, 90&deg;] and
         * <i>lon0</i> should be in the range [&minus;540&deg;, 540&deg;).
         * <i>lat</i> will be in the range [&minus;90&deg;, 90&deg;] and <i>lon</i>
         * will be in the range [&minus;180&deg;, 180&deg;]. The scale of the
         * projection is 1/<i>rk<sup>2</sup></i> in the "radial" direction,
         * <i>azi</i> clockwise from true north, and is 1/<i>rk</i> in the direction
         * perpendicular to this. Even though all inputs should return a valid
         * <i>lat</i> and <i>lon</i>, it's possible that the procedure fails to
         * converge for very large <i>x</i> or <i>y</i>; in this case NaNs are
         * returned for all the output arguments. A call to Reverse followed by a
         * call to Forward will return the original (<i>x</i>, <i>y</i>) (to
         * roundoff).
         */

        public GnomonicData Reverse(double lat0, double lon0, double x, double y)
        {
            GnomonicData rev =
                new GnomonicData(lat0, lon0, Double.NaN, Double.NaN, x, y, Double.NaN,
                                 Double.NaN);

            double azi0   = GeoMath.Atan2d(x, y);
            double rho    = GeoMath.Hypot(x, y);
            double s      = _a * Math.Atan(rho / _a);
            bool   little = rho <= _a;

            if (!little)
            {
                rho = 1 / rho;
            }

            GeodesicLine line =
                _earth.Line(lat0, lon0, azi0, GeodesicMask.LATITUDE
                            | GeodesicMask.LONGITUDE | GeodesicMask.AZIMUTH
                            | GeodesicMask.DISTANCE_IN | GeodesicMask.REDUCEDLENGTH
                            | GeodesicMask.GEODESICSCALE);

            int          count = numit_, trip = 0;
            GeodesicData pos = null;

            while (count-- > 0)
            {
                pos =
                    line.Position(s, GeodesicMask.LONGITUDE | GeodesicMask.LATITUDE
                                  | GeodesicMask.AZIMUTH | GeodesicMask.DISTANCE_IN
                                  | GeodesicMask.REDUCEDLENGTH
                                  | GeodesicMask.GEODESICSCALE);

                if (trip > 0)
                {
                    break;
                }

                double ds =
                    little ? ((pos.ReducedLength / pos.GeodesicScale12) - rho) * pos.GeodesicScale12 * pos.GeodesicScale12
                  : (rho - (pos.GeodesicScale12 / pos.ReducedLength)) * pos.ReducedLength * pos.ReducedLength;
                s -= ds;

                if (Math.Abs(ds) <= eps_ * _a)
                {
                    trip++;
                }
            }

            if (trip == 0)
            {
                return(rev);
            }

            rev.PointLatitude  = pos.Latitude2;
            rev.PointLongitude = pos.Longitude2;
            rev.azi            = pos.FinalAzimuth;
            rev.rk             = pos.GeodesicScale12;

            return(rev);
        }