ar_tourism_flutter_unity/unity/VRProject2/Assets/zhl/zhlScripts/GPSTestRunner.cs
2025-05-14 17:04:13 +08:00

332 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using TMPro; // 添加场景管理命名空间
/// <summary>
/// GPS坐标转换测试器实时设备GPS版
/// 功能:
/// 1. 实时获取设备GPS作为摄像机原点
/// 2. 将模型放置在指定GPS坐标
/// 3. 可视化相对位置
/// </summary>
public class GPSTestRunner : MonoBehaviour
{
[Header("AR设置")]
public Transform targetObject; // 目标物体
public Camera arCamera; // AR主摄像机
public Transform otherObject;
[Header("GPS配置")]
[SerializeField] [Range(1, 60)] private int gpsUpdateInterval = 1; // 秒
[SerializeField] [Range(1, 50)] private float desiredAccuracy = 5; // 米
[SerializeField] private float initializationTimeout = 20; // 秒
[Header("目标坐标")]
public Vector2 targetGPS = new Vector2(36.123456f, 117.654321f);
private Quaternion initialRotation; // 新增:保存初始旋转
private Vector2 currentDeviceGPS;
private bool isTracking = false;
private float lastUpdateTime;
private bool isRefreshing = false;
[Header("区域检测设置")]
public Vector2 cornerPoint1 = new Vector2(36.66174f, 117.01920f);
public Vector2 cornerPoint2 = new Vector2(36.66045f, 117.01930f);
public Vector2 cornerPoint3 = new Vector2(36.66104f, 117.01280f);
public Vector2 cornerPoint4 = new Vector2(36.66084f, 117.01290f);
public string targetSceneName = "SampleScene";
public string otherSceneName = "OtherScene";
private bool hasCheckedLocation = false;
[SerializeField][Header("是否测试")]
private bool isTest = false;
#region
[SerializeField]private TMP_Text text;
#endregion
IEnumerator StartGPSTracking()
{
// 显式请求定位权限Android需要
if (Application.platform == RuntimePlatform.Android)
{
if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.FineLocation))
{
UnityEngine.Android.Permission.RequestUserPermission(UnityEngine.Android.Permission.FineLocation);
yield return new WaitForSeconds(1);
}
}
// 检查定位服务是否可用
if (!Input.location.isEnabledByUser)
{
Debug.LogError("定位服务未启用");
yield break;
}
// 修改启动参数为单次定位
Input.location.Start(desiredAccuracy, 0.1f); // 第二个参数0.1表示最小距离变化
float timer = 0;
while (Input.location.status == LocationServiceStatus.Initializing &&
timer < initializationTimeout)
{
yield return new WaitForSeconds(1);
timer++;
}
if (Input.location.status == LocationServiceStatus.Running)
{
// 仅获取一次数据后立即停止
UpdateDevicePosition();
CheckLocationAndLoadScene(); // 添加检查位置并加载场景
Input.location.Stop();
isTracking = true; // 标记为已获取
}
else
{
Debug.LogError($"定位初始化失败: {Input.location.status}");
}
}
void Awake()
{
initialRotation = targetObject.rotation; // 保存初始旋转
}
void Start()
{
// initialRotation = targetObject.rotation; // 保存初始旋转
StartCoroutine(StartGPSTracking());
}
void Update()
{
if (!isTracking) return;
// 每5秒检测一次区域
if (Time.time % 5f < Time.deltaTime)
{
CheckLocationAndLoadScene();
}
// 根据设定间隔更新位置
if (Time.time - lastUpdateTime >= gpsUpdateInterval)
{
UpdateDevicePosition();
lastUpdateTime = Time.time;
}
UpdateTargetPosition();
}
void UpdateDevicePosition()
{
currentDeviceGPS = new Vector2(
Input.location.lastData.latitude,
Input.location.lastData.longitude
);
Debug.Log($"GPS坐标更新: {currentDeviceGPS}");
}
Vector3 ConvertToLocalSpace(Vector2 target)
{
const float metersPerDegree = 111319.488f;
float latDelta = (target.x - currentDeviceGPS.x) * metersPerDegree;
float lonDelta = (target.y - currentDeviceGPS.y) * metersPerDegree
* Mathf.Cos(currentDeviceGPS.x * Mathf.Deg2Rad);
return new Vector3(lonDelta, 0, latDelta);
}
void UpdateTargetPosition()
{
Vector3 newPosition = ConvertToLocalSpace(targetGPS);
newPosition.y = targetObject.position.y; // 保持原有Y轴
// 仅修改位置,保持初始旋转
targetObject.position = newPosition;
targetObject.rotation = initialRotation; // 保持初始旋转
Debug.Log($"目标位置更新 - 位置: {newPosition}, 旋转: {initialRotation.eulerAngles}");
}
void OnApplicationQuit()
{
if (Input.location.isEnabledByUser)
Input.location.Stop();
}
// void OnGUI()
// {
// GUIStyle labelStyle = new GUIStyle(GUI.skin.label)
// {
// fontSize = 24,
// alignment = TextAnchor.MiddleCenter
// };
//
// if (!isTracking)
// {
// GUI.Label(new Rect(Screen.width/2 - 150, Screen.height/2 - 20, 300, 40),
// "正在初始化定位服务...",
// labelStyle);
// }
// else
// {
// string currentGPS = $"纬度: {currentDeviceGPS.x:F7}\n经度: {currentDeviceGPS.y:F7}";
// string targetPos = $"X: {targetObject.position.x:F7}m\nZ: {targetObject.position.z:F7}m";
// GUI.Label(new Rect(Screen.width/2 - 200, Screen.height/2 - 60, 400, 80),
// $"当前坐标:\n{currentGPS}",
// labelStyle);
//
// GUI.Label(new Rect(Screen.width/2 - 200, Screen.height/2 + 20, 400, 80),
// $"目标位置:\n{targetPos}",
// labelStyle);
// }
// }
void OnDrawGizmos()
{
if (!isTracking) return;
Gizmos.color = Color.green;
Gizmos.DrawWireCube(targetObject.position, Vector3.one * 2f);
Gizmos.color = Color.blue;
Gizmos.DrawSphere(arCamera.transform.position, 0.5f);
}
public void RequestGPSUpdate()
{
if (!isRefreshing)
{
StartCoroutine(RefreshGPS());
}
else
{
Debug.LogWarning("GPS刷新正在进行中");
}
}
private IEnumerator RefreshGPS()
{
isRefreshing = true;
// 停止现有服务
if (Input.location.isEnabledByUser)
{
Input.location.Stop();
yield return new WaitForSeconds(0.5f);
}
// 启动新请求
Input.location.Start(desiredAccuracy, 0.1f);
float timer = 0;
while (Input.location.status == LocationServiceStatus.Initializing &&
timer < initializationTimeout)
{
timer += Time.deltaTime;
yield return null;
}
if (Input.location.status == LocationServiceStatus.Running)
{
UpdateDevicePosition();
isTracking = true;
Debug.Log("GPS手动更新成功");
}
else
{
Debug.LogError($"GPS更新失败: {Input.location.status}");
}
Input.location.Stop();
isRefreshing = false;
}
// 添加检查位置并加载场景的方法
void CheckLocationAndLoadScene()
{
if (hasCheckedLocation) return; // 避免重复检查
if (IsPointInRegion(currentDeviceGPS))
{
Debug.Log("GPS位置在指定区域内加载场景" + targetSceneName);
//SceneManager.LoadScene(targetSceneName);
otherObject.gameObject.SetActive(false);
targetObject.gameObject.SetActive(true);
text.text = "GPS" + targetSceneName;
}
else
{
Debug.Log("GPS位置不在指定区域内加载场景" + otherSceneName);
//SceneManager.LoadScene(otherSceneName);
if(isTest){
otherObject.gameObject.SetActive(false);
targetObject.gameObject.SetActive(true);
}else{
otherObject.gameObject.SetActive(true);
targetObject.gameObject.SetActive(false);
}
text.text = "GPS" + otherSceneName;
}
hasCheckedLocation = true;
}
// 判断点是否在多边形区域内
bool IsPointInRegion(Vector2 point)
{
Vector2[] vertices = new Vector2[]
{
cornerPoint1,
cornerPoint2,
cornerPoint4,
cornerPoint3
};
return IsPointInPolygon(point, vertices);
}
// 使用射线法判断点是否在多边形内
bool IsPointInPolygon(Vector2 point, Vector2[] polygon)
{
int polygonLength = polygon.Length, i = 0;
bool inside = false;
// 射线法: 从点向右发射一条射线,计算与多边形边的交点数量
float pointX = point.x, pointY = point.y;
float startX, startY, endX, endY;
for (i = 0; i < polygonLength; i++)
{
startX = polygon[i].x;
startY = polygon[i].y;
endX = polygon[(i + 1) % polygonLength].x;
endY = polygon[(i + 1) % polygonLength].y;
// 检查射线与边的交点
if (((startY <= pointY && pointY < endY) || (endY <= pointY && pointY < startY)) &&
(pointX < (endX - startX) * (pointY - startY) / (endY - startY) + startX))
{
inside = !inside;
}
}
return inside;
}
// 添加公共方法,允许从外部触发位置检查
public void TriggerLocationCheck()
{
if (!isTracking) return;
CheckLocationAndLoadScene();
}
}