using SkiaSharp;
namespace EarthQuake.Core;
///
/// 緯度経度と画面座標の変換
///
public static class GeomTransform
{
public const int Zoom = 50;
private static readonly SKPoint Offset = new(135, (float)TranslateFromLat(35));
public const int Height = 150;
private const double MercatorLimit = 85.05112877980659;
///
/// 緯度経度の点を計算された位置に変換します。
///
/// 点(X:経度, Y:緯度)
/// 画面上の座標
public static SKPoint Translate(SKPoint point) => Translate(point.X, point.Y);
public static SKPoint Translate(float lon, float lat)
{
var x = (lon - Offset.X) * Zoom;
var y = -((float)TranslateFromLat(lat) - Offset.Y) * Zoom;
return new SKPoint(x, y);
}
///
/// 経度緯度から計算された位置に変換します。
///
/// 経度
/// 緯度
/// 画面上の座標
public static SKPoint Translate(double lon, double lat)
{
var x = (float)(lon - Offset.X) * Zoom;
var y = -(float)(TranslateFromLat(lat) - Offset.Y) * Zoom;
return new SKPoint(x, y);
}
///
/// 画面上の座標からオフセットを戻します。(
///
/// 画面上X
/// 画面上Y
/// オフセットのない画面座標
public static SKPoint TranslateToNonTransform(float x, float y) => new(x / Zoom + Offset.X, Offset.Y - y / Zoom);
///
/// 緯度から計算された位置に変換します。
///
/// 緯度
/// 画面上Y
private static double TranslateFromLat(double latitude) => Mercator(latitude);
///
/// メルカトル図法
///
/// 緯度
/// 画面上Y
public static double Mercator(double latitude) => latitude <= -MercatorLimit ? -Height :
latitude >= MercatorLimit ? Height : Math.Log(Math.Tan((90 + latitude) * Math.PI / 360)) * Height / Math.PI;
///
/// ミラー図法
///
/// 緯度
/// 画面上Y
public static double Mirror(double latitude) =>
1.25 * Math.Asinh(Math.Tan(0.8 * latitude * Math.PI / 360)) * Height;
public static int RealIndex(int value)
{
return value >= 0 ? value : -value - 1;
}
}