This repository has been archived on 2025-08-02. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Cryville.EEW.Unity/Assets/Cryville.EEW.Unity/Map/Element/WaveCircleElement.cs

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