Files
beyond/Assets/ThirdParty/PlayMaker/Actions/Device/ProjectLocationToMap.cs
2024-11-20 15:21:28 +01:00

157 lines
3.8 KiB
C#

// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.
using UnityEngine;
namespace HutongGames.PlayMaker.Actions
{
[ActionCategory(ActionCategory.Device)]
[Tooltip("Projects the location found with Get Location Info to a 2d map using common projections.")]
public class ProjectLocationToMap : FsmStateAction
{
// TODO: more projections
public enum MapProjection
{
EquidistantCylindrical,
Mercator
}
[Tooltip("Location vector in degrees longitude and latitude. Typically returned by the Get Location Info action.")]
public FsmVector3 GPSLocation;
[Tooltip("The projection used by the map.")]
public MapProjection mapProjection;
[ActionSection("Map Region")]
//TODO: FsmRect screen region
[HasFloatSlider(-180,180)]
public FsmFloat minLongitude;
[HasFloatSlider(-180,180)]
public FsmFloat maxLongitude;
[HasFloatSlider(-90,90)]
public FsmFloat minLatitude;
[HasFloatSlider(-90,90)]
public FsmFloat maxLatitude;
[ActionSection("Screen Region")]
//TODO: FsmRect screen region
public FsmFloat minX;
public FsmFloat minY;
public FsmFloat width;
public FsmFloat height;
[ActionSection("Projection")]
[UIHint(UIHint.Variable)]
[Tooltip("Store the projected X coordinate in a Float Variable. Use this to display a marker on the map.")]
public FsmFloat projectedX;
[UIHint(UIHint.Variable)]
[Tooltip("Store the projected Y coordinate in a Float Variable. Use this to display a marker on the map.")]
public FsmFloat projectedY;
[Tooltip("If true all coordinates in this action are normalized (0-1); otherwise coordinates are in pixels.")]
public FsmBool normalized;
public bool everyFrame;
private float x,y;
public override void Reset()
{
GPSLocation = new FsmVector3 { UseVariable = true };
mapProjection = MapProjection.EquidistantCylindrical;
minLongitude = -180f;
maxLongitude = 180f;
minLatitude = -90f;
maxLatitude = 90f;
minX = 0;
minY = 0;
width = 1;
height = 1;
normalized = true;
projectedX = null;
projectedY = null;
everyFrame = false;
}
public override void OnEnter()
{
if (GPSLocation.IsNone)
{
Finish();
return;
}
DoProjectGPSLocation();
if (!everyFrame)
{
Finish();
}
}
public override void OnUpdate()
{
DoProjectGPSLocation();
}
void DoProjectGPSLocation()
{
x = Mathf.Clamp(GPSLocation.Value.x, minLongitude.Value, maxLongitude.Value);
y = Mathf.Clamp(GPSLocation.Value.y, minLatitude.Value, maxLatitude.Value);
// projection methods should produce normalized coordinates inside the map region
switch (mapProjection)
{
case MapProjection.EquidistantCylindrical:
DoEquidistantCylindrical();
break;
case MapProjection.Mercator:
DoMercatorProjection();
break;
}
x *= width.Value;
y *= height.Value;
projectedX.Value = normalized.Value ? minX.Value + x : minX.Value + x * Screen.width;
projectedY.Value = normalized.Value ? minY.Value + y : minY.Value + y * Screen.height;
}
void DoEquidistantCylindrical()
{
x = (x - minLongitude.Value) / (maxLongitude.Value - minLongitude.Value);
y = (y - minLatitude.Value) / (maxLatitude.Value - minLatitude.Value);
}
void DoMercatorProjection()
{
x = (x - minLongitude.Value) / (maxLongitude.Value - minLongitude.Value);
var minYProjected = LatitudeToMercator(minLatitude.Value);
var maxYProjected = LatitudeToMercator(maxLatitude.Value);
y = (LatitudeToMercator(GPSLocation.Value.y) - minYProjected) / (maxYProjected - minYProjected);
}
static float LatitudeToMercator(float latitudeInDegrees)
{
var lat = Mathf.Clamp(latitudeInDegrees, -85, 85);
lat = Mathf.Deg2Rad * lat;
return Mathf.Log(Mathf.Tan(lat / 2f + Mathf.PI / 4f));
}
}
}