■ 지구상의 위도와 경도를 거리로 변환하기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


CityInfo.cs

 

 

using System.Text.RegularExpressions;

 

namespace TestProject

{

    /// <summary>

    /// 도시 정보

    /// </summary>

    public class CityInfo

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region Field

 

        /// <summary>

        /// 명칭

        /// </summary>

        public string Name;

 

        /// <summary>

        /// 위도

        /// </summary>

        public double Latitude;

        

        /// <summary>

        /// 경도

        /// </summary>

        public double Longitude;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - CityInfo(name, latitudeDegree, latitudeMinute, latitudeSecond, longitudeDegree, longitudeMinute, longitudeSecond)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="name">명칭</param>

        /// <param name="latitudeDegree">위도 도</param>

        /// <param name="latitudeMinute">위도 분</param>

        /// <param name="latitudeSecond">위도 초</param>

        /// <param name="longitudeDegree">경도 도</param>

        /// <param name="longitudeMinute">경도 분</param>

        /// <param name="longitudeSecond">경도 초</param>

        public CityInfo(string name, int latitudeDegree, int latitudeMinute, int latitudeSecond, int longitudeDegree,

            int longitudeMinute, int longitudeSecond)

        {

            Latitude  = latitudeDegree  + latitudeMinute  / 60 + latitudeSecond  / 3600;

            Longitude = longitudeDegree + longitudeMinute / 60 + longitudeSecond / 3600;

        }

 

        #endregion

        #region 생성자 - CityInfo(name, latitudeDegree, latitudeMinute, longitudeDegree, longitudeMinute)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="name">명칭</param>

        /// <param name="latitudeDegree">위도 도</param>

        /// <param name="latitudeMinute">위도 분</param>

        /// <param name="longitudeDegree">경도 도</param>

        /// <param name="longitudeMinute">경도 분</param>

        public CityInfo(string name, int latitudeDegree, int latitudeMinute, int longitudeDegree, int longitudeMinute) :

            this(name, latitudeDegree, latitudeMinute, 0, longitudeDegree, longitudeMinute, 0)

        {

        }

 

        #endregion

        #region 생성자 - CityInfo(text)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="text">텍스트</param>

        public CityInfo(string text)

        {

            Regex regex = new Regex(@"\d");

            Match match = regex.Match(text);

 

            int position = match.Index;

 

            Name = text.Substring(0, position - 1).Trim();

 

            text = text.Substring(position);

 

            position = text.IndexOf('°');

 

            double latitudeDegree = double.Parse(text.Substring(0, position));

 

            text = text.Substring(position + 1);

 

            position = text.IndexOf('′');

 

            double latitudeMinute = double.Parse(text.Substring(0, position));

 

            text = text.Substring(position + 1);

 

            Latitude = latitudeDegree + latitudeMinute / 60;

 

            if(text.Substring(0, 1).ToUpper() == "S")

            {

                Latitude = -Latitude;

            }

 

            text = text.Substring(1).Trim();

 

            position = text.IndexOf('°');

 

            double longitudeDegree = double.Parse(text.Substring(0, position));

 

            text = text.Substring(position + 1);

 

            position = text.IndexOf('′');

 

            double longitudeMinute = double.Parse(text.Substring(0, position));

 

            text = text.Substring(position + 1);

 

            Longitude = longitudeDegree + longitudeMinute / 60;

 

            if(text.Substring(0, 1).ToUpper() == "E")

            {

                Longitude = -Longitude;

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 문자열 구하기 - ToString()

 

        /// <summary>

        /// 문자열 구하기

        /// </summary>

        /// <returns>문자열</returns>

        public override string ToString()

        {

            return Name;

        }

 

        #endregion

    }

}

 

 

MainForm.cs

 

 

using System;

using System.Windows.Forms;

 

namespace TestProject

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 지구 반지름 (단위 : 마일)

        /// </summary>

        private const double EARTH_RADIUS = 3958.756;

 

        /// <summary>

        /// 도시 정보 배열

        /// </summary>

        private CityInfo[] cityInfoArray =

        {

            new CityInfo("Beijing           39°55′N 116°26′E"),

            new CityInfo("Berlin            52°32′N 13° 25′E"),

            new CityInfo("Cairo             30°03′N 31° 15′E"),

            new CityInfo("Canberra          35°17′S 149°08′E"),

 

            new CityInfo("London            51°30′N 0°  10′W"),

            new CityInfo("Los Angeles       34°03′N 118°15′W"),

            new CityInfo("Mexico City       19°24′N 99° 09′W"),

            new CityInfo("Moscow            55°45′N 37° 42′E"),

            new CityInfo("Mumbai            18°56′N 74° 35′E"),

            new CityInfo("New York City     40°43′N 74° 00′W"),

            new CityInfo("Rio de Janeiro    22°54′S 43° 14′W"),

            new CityInfo("Rome              41°48′N 12° 36′E"),

            new CityInfo("San Diego         32°42′N 117°10′W"),

            new CityInfo("San Francisco     37°47′N 122°26′W"),

            new CityInfo("Tokyo             35°40′N 139°45′E"),

        };

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

 

            #region 이벤트를 설정한다.

 

            Load                                       += Form_Load;

            this.cityFromComboBox.SelectedIndexChanged += cityFromComboBox_SelectedIndexChanged;

            this.cityToComboBox.SelectedIndexChanged   += cityToComboBox_SelectedIndexChanged;

            this.calculateButton.Click                 += calculateButton_Click;

 

            #endregion

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 폼 로드시 처리하기 - Form_Load(sender, e)

 

        /// <summary>

        /// 폼 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Form_Load(object sender, EventArgs e)

        {

            foreach(CityInfo cityInfo in this.cityInfoArray)

            {

                this.cityFromComboBox.Items.Add(cityInfo);

 

                this.cityToComboBox.Items.Add(cityInfo);

            }

 

            this.cityFromComboBox.SelectedIndex = 0;

            this.cityToComboBox.SelectedIndex   = 1;

        }

 

        #endregion

        #region 도시 FROM 콤보 박스 선택 인덱스 변경시 처리하기 - cityFromComboBox_SelectedIndexChanged(sender, e)

 

        /// <summary>

        /// 도시 FROM 콤보 박스 선택 인덱스 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void cityFromComboBox_SelectedIndexChanged(object sender, EventArgs e)

        {

            ComboBox comboBox = sender as ComboBox;

 

            if(comboBox.SelectedItem == null)

            {

                return;

            }

 

            CityInfo cityInfo = comboBox.SelectedItem as CityInfo;

 

            this.latitudeFromTextBox.Text  = cityInfo.Latitude.ToString("0.0000");

            this.longitudeFromTextBox.Text = cityInfo.Longitude.ToString("0.0000");

        }

 

        #endregion

        #region 도시 TO 콤보 박스 선택 인덱스 변경시 처리하기 - cityToComboBox_SelectedIndexChanged(sender, e)

 

        /// <summary>

        /// 도시 TO 콤보 박스 선택 인덱스 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void cityToComboBox_SelectedIndexChanged(object sender, EventArgs e)

        {

            ComboBox comboBox = sender as ComboBox;

 

            if(comboBox.SelectedItem == null)

            {

                return;

            }

 

            CityInfo cityInfo = comboBox.SelectedItem as CityInfo;

 

            this.latitudeToTextBox.Text  = cityInfo.Latitude.ToString("0.0000");

            this.longitudeToTextBox.Text = cityInfo.Longitude.ToString("0.0000");

        }

 

        #endregion

        #region 계산하기 버튼 클릭시 처리하기 - calculateButton_Click(sender, e)

 

        /// <summary>

        /// 계산하기 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void calculateButton_Click(object sender, EventArgs e)

        {

            double latitudeFrom = double.Parse(this.latitudeFromTextBox.Text);

 

            if(latitudeFrom < 0)

            {

                latitudeFrom += 360;

            }

 

            double longitudeFrom = double.Parse(this.longitudeFromTextBox.Text);

 

            if(longitudeFrom < 0)

            {

                longitudeFrom += 360;

            }

 

            double latitudeTo = double.Parse(this.latitudeToTextBox.Text);

 

            if(latitudeTo < 0)

            {

                latitudeTo += 360;

            }

 

            double longitudeTo = double.Parse(this.longitudeToTextBox.Text);

 

            if(longitudeTo < 0)

            {

                longitudeTo += 360;

            }

 

            double differenceLatitude = Math.Abs(latitudeFrom - latitudeTo);

 

            if(differenceLatitude > 180)

            {

                differenceLatitude = 360 - differenceLatitude;

            }

 

            double differenceLongitude = Math.Abs(longitudeFrom - longitudeTo);

 

            if(differenceLongitude > 180)

            {

                differenceLongitude = 360 - differenceLongitude;

            }

 

            this.flatEarthTextBox.Text = CalculateFlatEarthMethod

            (

                latitudeFrom,

                longitudeFrom,

                latitudeTo,

                longitudeTo

            ).ToString("0.0000");

 

            this.haversineTextBox.Text = CalculateHaversineMethod

            (

                latitudeFrom,

                longitudeFrom,

                latitudeTo,

                longitudeTo

            ).ToString("0.0000");

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 라디안 구하기 - GetRadian(degree)

 

        /// <summary>

        /// 라디안 구하기

        /// </summary>

        /// <param name="degree"></param>

        /// <returns>라디안</returns>

        private double GetRadian(double degree)

        {

            return degree / 180 * Math.PI;

        }

 

        #endregion

        #region 플랫 어스 방법으로 계산하기 - CalculateFlatEarthMethod(fromLatitude, fromLongitude, toLatitude, toLongitude)

 

        /// <summary>

        /// 플랫 어스 방법으로 계산하기

        /// </summary>

        /// <param name="fromLatitude">FROM 위도</param>

        /// <param name="fromLongitude">FROM 경로</param>

        /// <param name="toLatitude">TO 위도</param>

        /// <param name="toLongitude">TO 경로</param>

        /// <returns>플랫 어스 방법으로 계산한 값</returns>

        private double CalculateFlatEarthMethod(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude)

        {

            double differenceLatitude = Math.Abs(fromLatitude - toLatitude);

 

            if(differenceLatitude > 180)

            {

                differenceLatitude = 360 - differenceLatitude;

            }

 

            double differenceLongitude = Math.Abs(fromLongitude - toLongitude);

 

            if(differenceLongitude > 180)

            {

                differenceLongitude = 360 - differenceLongitude;

            }

 

            double x = 69.1 * differenceLatitude;

            double y = 53.0 * differenceLongitude;

 

            return Math.Sqrt(x * x + y * y);

        }

 

        #endregion

        #region 하버사인 방법으로 계산하기 - CalculateHaversineMethod(fromLatitude, fromLongitude, toLatitude, toLongitude)

 

        /// <summary>

        /// 하버사인 방법으로 계산하기

        /// </summary>

        /// <param name="fromLatitude">FROM 위도</param>

        /// <param name="fromLongitude">FROM 경로</param>

        /// <param name="toLatitude">TO 위도</param>

        /// <param name="toLongitude">TO 경로</param>

        /// <returns>하버사인 방법으로 계산한 값</returns>

        private double CalculateHaversineMethod(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude)

        {

            double differenceLatitude  = GetRadian(toLatitude  - fromLatitude );

            double differenceLongitude = GetRadian(toLongitude - fromLongitude);

 

            double a = Math.Sin(differenceLatitude / 2) * Math.Sin(differenceLatitude / 2) +

                       Math.Cos(GetRadian(fromLatitude)) * Math.Cos(GetRadian(toLatitude)) *

                       Math.Sin(differenceLongitude / 2) * Math.Sin(differenceLongitude / 2);

 

            return 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)) * EARTH_RADIUS;

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker
TAG