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