123 lines
4.8 KiB
C#
123 lines
4.8 KiB
C#
using Cryville.EEW.Core;
|
|
using Cryville.EEW.Core.Map;
|
|
using System;
|
|
using System.Drawing;
|
|
using UnityEngine;
|
|
|
|
namespace Cryville.EEW.Unity.Map.Element {
|
|
class WaveCircleElement : MapElement {
|
|
PointF _hypocenterLocation;
|
|
PointF _hypocenterTilePos;
|
|
internal void SetHypocenterLocation(PointF value, ref int order) {
|
|
_hypocenterLocation = value;
|
|
_hypocenterTilePos = MapTileUtils.WorldToTilePos(value);
|
|
transform.localPosition = new(0, 0, OrderToZ(ref order));
|
|
}
|
|
|
|
public override RectangleF? AABB {
|
|
get {
|
|
var time = (float)(DateTime.UtcNow - OriginTime).TotalSeconds;
|
|
float angle = WaveTimeCalculator.Instance.CalculatePWaveAngleOrPercentage(Depth, time);
|
|
if (float.IsNaN(angle)) angle = WaveTimeCalculator.Instance.CalculateSWaveAngleOrPercentage(Depth, time);
|
|
if (float.IsNaN(angle)) {
|
|
var rTime = (float?)(ReportTime - OriginTime)?.TotalSeconds;
|
|
if (rTime != null) {
|
|
angle = WaveTimeCalculator.Instance.CalculatePWaveAngleOrPercentage(Depth, rTime.Value);
|
|
if (float.IsNaN(angle)) angle = WaveTimeCalculator.Instance.CalculateSWaveAngleOrPercentage(Depth, rTime.Value);
|
|
}
|
|
}
|
|
var inflation = angle > 0 ? angle / 180 : 0;
|
|
return RectangleF.Inflate(new(_hypocenterTilePos, SizeF.Empty), inflation, inflation);
|
|
}
|
|
}
|
|
|
|
public DateTime OriginTime { get; set; }
|
|
public float Depth { get; set; }
|
|
public DateTime? ReportTime { get; set; }
|
|
|
|
[SerializeField] MultiLineRenderer m_lineRendererP;
|
|
[SerializeField] MultiLineRenderer m_lineRendererS;
|
|
[SerializeField] Material m_ongoingMaterial;
|
|
[SerializeField] Material m_historyMaterial;
|
|
|
|
protected override void OnSetScale() {
|
|
m_lineRendererP.Width = ComputedScale / 256;
|
|
m_lineRendererS.Width = ComputedScale / 256;
|
|
}
|
|
|
|
void Update() {
|
|
var time = (float)(DateTime.UtcNow - OriginTime).TotalSeconds;
|
|
var rTime = (float?)(ReportTime - OriginTime)?.TotalSeconds;
|
|
|
|
float pAngle = WaveTimeCalculator.Instance.CalculatePWaveAngleOrPercentage(Depth, time);
|
|
if (float.IsNaN(pAngle) && rTime != null) {
|
|
DrawCore(WaveTimeCalculator.Instance.CalculatePWaveAngleOrPercentage(Depth, rTime.Value), m_lineRendererP, true);
|
|
}
|
|
else {
|
|
DrawCore(pAngle, m_lineRendererP);
|
|
}
|
|
|
|
float sAngle = WaveTimeCalculator.Instance.CalculateSWaveAngleOrPercentage(Depth, time);
|
|
if (float.IsNaN(sAngle) && rTime != null) {
|
|
DrawCore(WaveTimeCalculator.Instance.CalculateSWaveAngleOrPercentage(Depth, rTime.Value), m_lineRendererS, true);
|
|
}
|
|
else {
|
|
DrawCore(sAngle, m_lineRendererS);
|
|
}
|
|
}
|
|
|
|
readonly Vector2[] _vertexBuffer = new Vector2[361];
|
|
void DrawCore(float angle, MultiLineRenderer renderer, bool isHistory = false) {
|
|
renderer.Clear();
|
|
if (float.IsNaN(angle)) return;
|
|
if (angle < -1) return;
|
|
if (angle < 0) {
|
|
renderer.Width = ComputedScale / 64;
|
|
renderer.TilingScale = 1;
|
|
var point = _hypocenterTilePos.ToVector2();
|
|
var offset = ComputedScale / 20;
|
|
angle = (angle + 1) * 360;
|
|
int segCount = (int)Math.Ceiling(angle);
|
|
for (int d = 0; d < segCount - 1; d++) {
|
|
float rad = d * Mathf.PI / 180;
|
|
_vertexBuffer[d] = point + offset * new Vector2(Mathf.Sin(rad), Mathf.Cos(rad));
|
|
}
|
|
float rad2 = angle * Mathf.PI / 180;
|
|
if (segCount > 0) _vertexBuffer[segCount - 1] = point + offset * new Vector2(Mathf.Sin(rad2), Mathf.Cos(rad2));
|
|
renderer.AddSegment(_vertexBuffer, 0, segCount);
|
|
}
|
|
else {
|
|
renderer.Width = ComputedScale / 256;
|
|
renderer.TilingScale = 8;
|
|
float radlat = _hypocenterLocation.Y / 180f * MathF.PI, radlon = _hypocenterLocation.X / 180f * MathF.PI;
|
|
float rplat = radlat + angle / 180f * MathF.PI;
|
|
Vector3 rp = new(MathF.Cos(radlon) * MathF.Cos(rplat), MathF.Sin(rplat), MathF.Sin(radlon) * MathF.Cos(rplat));
|
|
Vector3 axis = new(MathF.Cos(radlon) * MathF.Cos(radlat), MathF.Sin(radlat), MathF.Sin(radlon) * MathF.Cos(radlat));
|
|
Vector2? lp2 = null;
|
|
int segmentIndex = 0;
|
|
for (int d = 0; d < 360; d++) {
|
|
Quaternion q = Quaternion.AngleAxis(d, axis);
|
|
Vector3 p = q * rp;
|
|
AddVertex(renderer, ref lp2, ref segmentIndex, d, p);
|
|
}
|
|
AddVertex(renderer, ref lp2, ref segmentIndex, 360, rp);
|
|
renderer.AddSegment(_vertexBuffer, segmentIndex, 361 - segmentIndex);
|
|
}
|
|
renderer.SetMaterial(isHistory ? m_historyMaterial : m_ongoingMaterial);
|
|
}
|
|
|
|
void AddVertex(MultiLineRenderer renderer, ref Vector2? lp2, ref int segmentIndex, int d, Vector3 p) {
|
|
Vector2 p2 = ToTilePos(p).ToVector2();
|
|
if (lp2 != null && MathF.Abs(p2.x - lp2.Value.x) >= 0.5) {
|
|
_vertexBuffer[d] = p2.x < 0.5 ? p2 + new Vector2(1, 0) : p2 - new Vector2(1, 0);
|
|
renderer.AddSegment(_vertexBuffer, segmentIndex, d - segmentIndex + 1);
|
|
segmentIndex = d;
|
|
}
|
|
_vertexBuffer[d] = p2;
|
|
lp2 = p2;
|
|
}
|
|
|
|
static PointF ToTilePos(Vector3 p) => MapTileUtils.WorldToTilePos(new(MathF.Atan2(p.z, p.x) / MathF.PI * 180f, MathF.Asin(p.y) / MathF.PI * 180f));
|
|
}
|
|
}
|