Files
SHI-Cesium/Assets/Scripts/PolygonMeasureGroup.cs
2025-09-15 22:09:10 +09:00

162 lines
5.6 KiB
C#

using CesiumForUnity;
using System;
using System.Collections.Generic;
using TMPro;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.UI;
public class PolygonMeasureGroup : MeasureGroup
{
private PolygonMeasureGroupInfoPopup polygonMeasureGroupInfoPopup;
private float baseCloseDistance = 10f;
public override void AddPoint(Vector3 pos)
{
if (!polygonMeasureGroupInfoPopup)
{
polygonMeasureGroupInfoPopup = Instantiate(polygonInfoPopupPrefab).GetComponent<PolygonMeasureGroupInfoPopup>();
polygonMeasureGroupInfoPopup.InitUI(infoPopupRoot);
polygonMeasureGroupInfoPopup.transform.position = pos + new Vector3(20, 0, 20);
}
if (points.Count >= 3 && Vector3.Distance(points[0], pos) < baseCloseDistance)
{
ClosePolygon();
return;
}
points.Add(pos);
line.positionCount = points.Count;
line.SetPosition(points.Count - 1, pos);
GameObject label = Instantiate(labelPrefab, pos, Quaternion.identity, labelRoot);
labels.Add(label);
if (points.Count >= 2)
{
Vector3 a = points[points.Count - 2];
Vector3 b = points[points.Count - 1];
double3 llh_a = GeoUtils.GetLonLatHeight(cesiumGeoreference, a);
double3 llh_b = GeoUtils.GetLonLatHeight(cesiumGeoreference, b);
double dist = GeoUtils.Haversine(llh_a.x, llh_a.y, llh_b.x, llh_b.y);
totalDistance += dist;
}
UpdateInfo();
}
private void ClosePolygon()
{
line.positionCount = points.Count + 1;
for (int i = 0; i < points.Count; i++)
line.SetPosition(i, points[i]);
line.SetPosition(points.Count, points[0]);
double3[] llhs = new double3[points.Count];
for (int i = 0; i < points.Count; i++)
llhs[i] = GeoUtils.GetLonLatHeight(cesiumGeoreference, points[i]);
double totalDistance = 0;
for (int i = 0; i < points.Count; i++)
{
int j = (i + 1) % points.Count;
double dist = GeoUtils.Haversine(llhs[i].x, llhs[i].y, llhs[j].x, llhs[j].y);
totalDistance += dist;
Vector3 mid = (points[i] + points[j]) * 0.5f;
labels[i].transform.position = mid;
labels[i].GetComponentInChildren<TextMeshProUGUI>().text = $"{dist:F1} m";
}
double area = GetPolygonArea();
polygonMeasureGroupInfoPopup.UpdateInfo("(¾øÀ½)", llhs[0].x, llhs[0].y, totalDistance, area);
deleteButton = Instantiate(deleteButtonPrefab, points[0], Quaternion.identity, infoPopupRoot);
deleteButton.GetComponentInChildren<Button>().onClick.AddListener(() => DestroyAll());
deleteButton.transform.position = points[0] + new Vector3(-20, 0, 20);
FindAnyObjectByType<MeasureManager>().isMeasuring = false;
}
private void UpdateInfo()
{
if (polygonMeasureGroupInfoPopup == null) return;
double totalDistance = 0;
for (int i = 0; i < points.Count - 1; i++)
{
double3 llh_a = GeoUtils.GetLonLatHeight(cesiumGeoreference, points[i]);
double3 llh_b = GeoUtils.GetLonLatHeight(cesiumGeoreference, points[i + 1]);
totalDistance += GeoUtils.Haversine(llh_a.x, llh_a.y, llh_b.x, llh_b.y);
}
double3 llh_last = GeoUtils.GetLonLatHeight(cesiumGeoreference, points[points.Count - 1]);
polygonMeasureGroupInfoPopup.UpdateInfo("(¾øÀ½)", llh_last.x, llh_last.y, totalDistance, 0);
}
public override void EndMeasure()
{
if (line == null) return;
DestroyAll();
}
public override void DestroyAll()
{
base.DestroyAll();
if (polygonMeasureGroupInfoPopup)
Destroy(polygonMeasureGroupInfoPopup.gameObject);
Destroy(this);
}
public override void LateUpdate()
{
base.LateUpdate();
if (polygonMeasureGroupInfoPopup)
{
polygonMeasureGroupInfoPopup.transform.LookAt(polygonMeasureGroupInfoPopup.transform.position + cam.transform.forward);
float heightDiff = Mathf.Abs(cam.transform.position.y - polygonMeasureGroupInfoPopup.transform.position.y);
polygonMeasureGroupInfoPopup.transform.localScale = Vector3.one * (heightDiff * lineScaleMultiplier);
}
}
public override void UpdatePreviewLine(Vector3 mousePos)
{
if (points.Count == 0 || line == null) return;
if (line.positionCount == points.Count)
line.positionCount++;
line.SetPosition(line.positionCount - 1, mousePos);
Vector3 last = points[points.Count - 1];
Vector3 mid = (last + mousePos) * 0.5f;
labels[labels.Count - 1].transform.position = mid;
double3 llh_a = GeoUtils.GetLonLatHeight(cesiumGeoreference, last);
double3 llh_b = GeoUtils.GetLonLatHeight(cesiumGeoreference, mousePos);
double dist = GeoUtils.Haversine(llh_a.x, llh_a.y, llh_b.x, llh_b.y);
labels[labels.Count - 1].GetComponentInChildren<TextMeshProUGUI>().text = $"{dist:F1} m";
double previewTotal = totalDistance + dist;
polygonMeasureGroupInfoPopup?.UpdateInfo("(¾øÀ½)", llh_b.x, llh_b.y, previewTotal, 0);
}
private double GetPolygonArea()
{
double sum1 = 0, sum2 = 0;
for (int i = 0; i < points.Count - 1; i++)
{
sum1 += points[i].x * points[i + 1].z;
sum2 += points[i + 1].x * points[i].z;
}
sum1 += points[points.Count - 1].x * points[0].z;
sum2 += points[0].x * points[points.Count - 1].z;
return Math.Abs((sum1 - sum2) / 2.0);
}
}