Programming

GPS 관련 계산 Class

콜러스 XXII 2016. 11. 4. 13:53


음... 살다보면 GPS가지고 할것이 많은데.. 다음 클래스는 해당 사이트에서 C# 버젼은로 컨버팅한것이다.

(Java도 잘되겠지...)


다음은 기능..


- 두 위치간의 거리

- 두위치간에 간격을 잘라서 위치를 생성하는 것

- 두위치간의 중간 위치를 얻는것


정도다.


public class MovableHelper

    {

        // Convert from : http://www.movable-type.co.uk/scripts/latlong.html 


        public static double toRadians(double degree)

        {

            return degree * Math.PI / 180.0;

        }


        public static double toDegrees(double radian)

        {

            return radian * 180.0 / Math.PI;

        }


        /// <summary>

        /// Returns the distance from starting position to destination point (using haversine formula).

        /// </summary>

        /// <param name="startLat">Starting latitude</param>

        /// <param name="startLon">Starting longitude</param>

        /// <param name="endLat">Destination  latitude</param>

        /// <param name="endLon">Destination  longitude</param>

        /// <returns>Distance between starting point and destination point. The unit is meter.</returns>

        public static double getDistance(double startLat, double startLon, double endLat, double endLon)

        {

            // starting example : 37.275340, 127.081525

            // destination example : 37.276202, 127.074272


            double R = 6371000.0; // metres

            double theta1 = toRadians(startLat);

            double theta2 = toRadians(endLat);

            double deltatheta = toRadians(endLat - startLat);

            double deltaramda = toRadians(endLon - startLon);


            double a = Math.Sin(deltatheta / 2.0) * Math.Sin(deltatheta / 2.0) +

                    Math.Cos(theta1) * Math.Cos(theta2) *

                    Math.Sin(deltaramda / 2.0) * Math.Sin(deltaramda / 2.0);

            double c = 2.0 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.0 - a));

            double d = R * c;


            return d;

        }


        /// <summary>

        /// Returns the point at given fraction between starting point and specified point.

        /// </summary>

        /// <param name="thisLat">Starting latitude</param>

        /// <param name="thisLon">Starting longitude</param>

        /// <param name="pointLat">Specified latitude</param>

        /// <param name="pointLon">Specified longitude</param>

        /// <param name="fraction">Fraction between the two points (0 = this point, 1 = specified point).</param>

        /// <returns>Intermediate point between this point and destination point.</returns>

        public static double[] intermediatePointTo(double thisLat, double thisLon,

                                             double pointLat, double pointLon, double fraction)

        {

            double phi1 = toRadians(thisLat);

            double ramda1 = toRadians(thisLon);

            double phi2 = toRadians(pointLat);

            double ramda2 = toRadians(pointLon);

            double sinTheta1 = Math.Sin(phi1);

            double cosTheta1 = Math.Cos(phi1);

            double sinRamda1 = Math.Sin(ramda1);

            double cosRamda1 = Math.Cos(ramda1);

            double sinPhi2 = Math.Sin(phi2);

            double cosPhi2 = Math.Cos(phi2);

            double sinRamda2 = Math.Sin(ramda2);

            double cosRamda2 = Math.Cos(ramda2);


            // distance between points

            double deltaPhi = phi2 - phi1;

            double deltaRamda = ramda2 - ramda1;

            double a = Math.Sin(deltaPhi / 2.0) * Math.Sin(deltaPhi / 2.0) + Math.Cos(phi1) *

                        Math.Cos(phi2) * Math.Sin(deltaRamda / 2.0) * Math.Sin(deltaRamda / 2.0);

            double delta = 2.0 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.0 - a));


            double A = Math.Sin((1.0 - fraction) * delta) / Math.Sin(delta);

            double B = Math.Sin(fraction * delta) / Math.Sin(delta);


            double x = A * cosTheta1 * cosRamda1 + B * cosPhi2 * cosRamda2;

            double y = A * cosTheta1 * sinRamda1 + B * cosPhi2 * sinRamda2;

            double z = A * sinTheta1 + B * sinPhi2;


            double theta3 = Math.Atan2(z, Math.Sqrt(x * x + y * y));

            double ramda3 = Math.Atan2(y, x);


            return new double[] { toDegrees(theta3), (toDegrees(ramda3) + 540.0) % 360.0 - 180.0 }; // normalise lon to −180..+180°

        }


        /// <summary>

        ///  Returns the midpoint between starting point and the supplied point. 

        ///  Could be the same as intermediatePointTo() with fraction 0.5

        /// </summary>

        /// <param name="thisLat">Starting latitude</param>

        /// <param name="thisLon">Starting longitude</param>

        /// <param name="pointLat">Supplied latitude</param>

        /// <param name="pointLon">Supplied longitude</param>

        /// <returns>Midpoint between this point and the supplied point.</returns>

        public static double[] midpointTo(double thisLat, double thisLon, double pointLat, double pointLon)

        {

            // φm = atan2( sinφ1 + sinφ2, √( (cosφ1 + cosφ2⋅cosΔλ) ⋅ (cosφ1 + cosφ2⋅cosΔλ) ) + cos²φ2⋅sin²Δλ )

            // λm = λ1 + atan2(cosφ2⋅sinΔλ, cosφ1 + cosφ2⋅cosΔλ)

            // see http://mathforum.org/library/drmath/view/51822.html for derivation


            double phi1 = toRadians(thisLat);

            double ramda1 = toRadians(thisLon);

            double phi2 = toRadians(pointLat);

            double deltaRamda = toRadians(pointLon - thisLon);


            double Bx = Math.Cos(phi2) * Math.Cos(deltaRamda);

            double By = Math.Cos(phi2) * Math.Sin(deltaRamda);


            double x = Math.Sqrt((Math.Cos(phi1) + Bx) * (Math.Cos(phi1) + Bx) + By * By);

            double y = Math.Sin(phi1) + Math.Sin(phi2);

            double phi3 = Math.Atan2(y, x);


            double ramda3 = ramda1 + Math.Atan2(By, Math.Cos(phi1) + Bx);


            return new double[] { toDegrees(phi3), (toDegrees(ramda3) + 540.0) % 360.0 - 180.0 }; // normalise to −180..+180°

        }


        public static List<double[]> getintermediatePoints(double thisLat, double thisLon, double pointLat, double pointLon, 

                                                           double movingDistance)

        {

            List<double[]> ret = new List<double[]>();


            // 두지점간의 거리를 얻고 그것을 단위 거리로 나눈 갯수                     

            double fraction = getDistance(thisLat, thisLon, pointLat, pointLon) / movingDistance;


            // 나눈지점끼리의 위치를 얻는다.


            double fr = (1.0 / fraction);

            for (double i = 0.0; i < 1.0; i += fr)

            {

                double[] pos = intermediatePointTo(thisLat, thisLon, pointLat, pointLon, i);

                ret.Add(pos);

            }


            double[] posLast = intermediatePointTo(thisLat, thisLon, pointLat, pointLon, 1);

            ret.Add(posLast);


            return ret;

        } 

        

        /// <summary>

        /// Get distance from the speed by a second 

        /// </summary>

        /// <param name="speed">Vehicle speed in km/h unit.</param>

        /// <returns>distance (the unit is meter.)</returns>

        public static double getDistanceFromSpeedByASeconds(double speed)

        {

            return speed * 1000.0 / 3600.0;

        }      

    }