첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

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
    }
}

 

728x90

 

▶ 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
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요