맵을 클릭하였을 때 GPS값이 나오도록 만들었다.
X : 1px 당 0.09577588(m)
Y : 1px 당 0.0959613(m)
의 실험적인 결과를 통하여 마우스의 상대적인 위치를 계산하여 GPS값이 출력되도록 만들었다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
public class GoogleMap : MonoBehaviour
{
float pivotX = 450; //맵 X 중심점
float pivotY = 450; //맵 Y 중심점
float mapsize = 800; //맵 사이즈
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log(Input.mousePosition);
Debug.Log(Flat2LLh(float.Parse(LATInput.text),
float.Parse(LONInput.text),
(Input.mousePosition.x - pivotX) * 0.095775f,
(Input.mousePosition.y - pivotY) * 0.095961f));
}
}
string Flat2LLh(float startLAT, float startLON, float x, float y)
{
startLAT *= (Mathf.PI / 180.0f);
startLON *= (Mathf.PI / 180.0f);
float re = 6378137;
float e = 0.0818f;
print("re : " + re + " e : " + e);
float RN = re / Mathf.Sqrt(1 - e * e * Mathf.Sin(startLAT) * Mathf.Sin(startLON));
float RM = RN * (1 - e * e) / Mathf.Sqrt(1 - e * e * Mathf.Sin(startLAT) * Mathf.Sin(startLON));
Mathf.Atan2(1, RN * Mathf.Cos(startLAT) : " + Mathf.Atan2(1, RN * Mathf.Cos(startLAT))) ;
float Lat = (y * Mathf.Atan2(1, RM) + startLAT) * (180.0f / Mathf.PI) * 100000;
float Lon = (x * Mathf.Atan2(1, RN * Mathf.Cos(startLAT)) + startLON) * (180.0f / Mathf.PI) * 100000;
print(">>> LAT : " + Lat + " Lon : " + Lon);
string result = "Lat : " + Lat.ToString() + "Lon : "+ Lon.ToString();
return (result);
}
}
💢 하지만 심각한 문제가 발생하였다...
유니티에서 소수점 계산에 대한 정확도 문제가 발생하여 위도 경도를 소수점 5번째 자리까지 계산한다.... 현실에서는 수 m 까지 오차가 발생하기 때문에 cm, mm 까지 계산하도록 정확도를 높여야 한다.
C# 소수점 정확도 문제를 해결하기 위해 decimal 자료형이 있지만 Mathf 라이브러리는 float형식만 지원하기 때문에 사용이 불가능하다.
using UnityEngine; //Unity Mathf class
❗❗ 알고보니 Mathf 클래스는 UnityEngine에 있었고 이는 float 파라미터와 리턴 값이 모두 float형 이였다.
using System; //C# Math class
❕❕ 그래서 using System 을 추가하여 C# 에서 자체적으로 지원하는 Math 클래스를 사용하여 해결하였다.
C# Math Class
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
public class GoogleMap : MonoBehaviour
{
float pivotX = 450; //맵 X 중심점
float pivotY = 450; //맵 Y 중심점
float mapsize = 800; //맵 사이즈
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log(Input.mousePosition);
Debug.Log(Flat2LLh(double.Parse(LATInput.text),
double.Parse(LONInput.text),
(double)(Input.mousePosition.x - pivotX) * 0.095775f,
(double)(Input.mousePosition.y - pivotY) * 0.095961f));
}
}
string Flat2LLh(double startLAT, double startLON, double x, double y)
{
startLAT *= (Math.PI / 180.0f);
startLON *= (Math.PI / 180.0f);
double re = 6378137;
double e = 0.0818f;
print("re : " + re + " e : " + e);
double RN = re / Math.Sqrt(1 - e * e * Math.Sin(startLAT) * Math.Sin(startLON));
double RM = RN * (1 - e * e) / Math.Sqrt(1 - e * e * Math.Sin(startLAT) * Math.Sin(startLON));
print("RN : " + RN + " RM : " + RM);
print("Mathf.Atan2(1, RM) : " + Math.Atan2(1, RM) + " Mathf.Atan2(1, RN * Mathf.Cos(startLAT) : " + Math.Atan2(1, RN * Math.Cos(startLAT))) ;
print(Mathf.PI);
print(180.0f / Mathf.PI);
double Lat = (y * Math.Atan2(1, RM) + startLAT) * (180.0f / Mathf.PI);
double Lon = (x * Math.Atan2(1, RN * Math.Cos(startLAT)) + startLON) * (180.0f / Math.PI);
print(Math.Round(Lat,7)+","+ Math.Round(Lon, 7));
string result = ">>>>" + Lat.ToString() + ","+ Lon.ToString();
return (result);
}
}
코드를 float형을 모두 double 형으로 바꾸고 Mathf Class를 Math Class로 바꾸니 해결되었다.
결과는 소수점 16번째 정도까지 계산이 되었고 소수점 아래 7자리까지 사용하였다.
(추후 방향 표시를 위해 화살표 UI를 추가하였다.)
유니티에서 기준점을 잡고 끝 4점을 클릭하였을때 GPS값이 다음과 같이 출력되는 것을 볼 수 있다.
이 결과를 https://staticmapmaker.com/google/
이 사이트에 GPS값을 입력하여 확인해본 결과
네 꼭짓점 모두 정확하게 나오는 것으로 확인된다.
이렇게 유니티를 이용하여 GPS MAP을 만들고 임의의 점을 클릭했을 때 GPS 데이터가 출력되게 하였다.
같은 구글 맵을 사용하였지만 GoogleStaticMap API와 map.google.com에 같은 GPS값을 입력했을 때 오차가 발생했다.
꼭짓점의 GPS좌표가 2개로 나타난다. 뭐가 맞는 데이터 인지는 모르겠지만 이는 기준점(centerGPS)이 동일하게 설정된다면 추후에 문제가 발생하지 않기 때문에 시스템 동기화 문제일 것으로 예상하고 넘어가도록 해야겠다..
◽ GPS데이터가 실시간으로 MAP에 반영되도록 화살표를 움직이기
◽ N방향을 기준으로 ±180°의 각도 데이터가 들어오면 화살표 UI가 방향에 맞게 회전하게 만들기
◽ Unity - ROS 통신하는 방법 공부하기