NBowlin / Unity_Coordinate_Mapping

MIT License
53 stars 14 forks source link

Coordinate Mapper

Coordinate Mapper is a free, open source project for visualizing datasets projected onto a globe in Unity. It gives you the flexibility to visualize data without having to set up custom models or adhere to specific JSON schemas without losing the ability to add any customization you need!

Also, Coordinate Mapper will do the spherical UV mapping for you, so no need for custom planet models or meshes.

Installation

Alternative: if you don't wish to use the Asset Store, you can download the Coordinate_Mapper.unitypackage located in the /meta/ folder. Inside of your unity project, right click on the Assets folder and choose Import Package > Custom Package..., then select the downloaded package to import.

Note: This project uses the new render pipelines, so all the shaders should work on the Universal Render Pipeline and the High Definition Render Pipeline. If you are using the Standard Render Pipeline you will have to update the shader assets to get them to display properly.

Initial Setup

Add a planet model: right click on the scene hierarchy and choose Planet or use the Coordinate Mapper > Create Planet menu item. There are 4 preset options:

Include a Planet layer: In order for the plotting to work properly, you must add a Planet layer to your project, and set the created planet to use that layer. You can add a layer by going to Edit > Project Settings > Tags and Layers.

Note: In order to use any of the Coordinate Mapper scripts in code you must include the namespace by adding using CoordinateMapper to the top of your script.

Visualization Options

Coordinate Mapper provides two different paths to visualizing data, a default visualizer and a custom visualizer.

Default Visualization

Add the visualizer script: Once you have setup your planet, select it in the scene view and add the Default Visualizer script. This script will take a dataset, parse it, and plot the points using the default implementations provided with the framework. The supported schemas are outlined below:

Properties:

The default visualizer also supports an optional magnitude key, which will scale the Z value of the point prefab for the location by the magnitude value. (See Earthquake Demo.)

Just fill out the appropriate properties and press Play! You should see your data mapped to the planet!

Custom Visualization

While the default visualizer is great to get something displaying quickly, it is purposefully limited in its use. If you require any extra keys other than Latitude, Longitude, and Magnitude, or if you want to customize the way GameObjects get mapped on to the planet, etc..., you will need to take the customized approach.

The custom approach can be broken out into two processes: parsing your data, and plotting your data.

Parsing Your Data:

IDataLoader: extend this interface on any custom scripts you need to parse your datasets. This is useful if you need to parse out more values than the default visualizer allows (Latitude, Longitude, and Magnitude). IDataLoader ensures your class has the following:

Scripts implementing this protocol should accept a file (dataFile) that you send to the appropriate parser through ParseFile, which returns the necessary info to create your ICoordinatePoint objects and sends them along (using loadComplete) to any scripts that care.

Parsers

There are two parser scripts, JsonParser and CsvParser, each taking its respective file type.

The JsonParser Parse functions accepts:

var jsonParsed = JsonParser.Parse(fileText, new string[] { "latitude", "longitude", "magnitude", "place", "time" });

The CsvParser Parse function accepts:

Note: The dictionary values are returned as an object[]. So it is up to you to convert them to the proper type. For example, if you were dealing with your longitude values, and they are floats in your dataset, you might cast them like this:

var lngs = jsonParsed["longitude"].Select(m => Convert.ToSingle(m)).ToArray();

Once you have everything properly parsed and casted, you can use the result to create and plot ICoordinatePoints

ICoordinatePoint: extend this interface on the actual script that represents what should get plotted onto the planet. ICoordinatePoint ensures your class has the following:

The main point of this protocol is to call the Plot(Transform planet, Transform container, int layer) function and handle the placement of the point to the planet. Typically, you would start by calling PlanetUtility.PlacePoint(), which returns the plotted GameObject. Once you have the GameObject, you can make any adjustments you need.

Here is an example from the Earthquake Demo:

public GameObject Plot(Transform planet, Transform container, int layer) {
    var plotted = PlanetUtility.PlacePoint(planet, container, location, pointPrefab); //Plot the point

    if (plotted != null) {
        plotted.layer = layer; //Set the layer

        //Add a Monobehaviour and store this class on it
        var eqPoint = plotted.AddComponent<EarthquakePoint>(); 
        eqPoint.info = this;

        //Adjust the scaling as a function of magnitude
        plotted.transform.localScale = new Vector3(plotted.transform.localScale.x, plotted.transform.localScale.y, plotted.transform.localScale.z * Mathf.Pow(2f, magnitude));

        //Orient the point to the surface of the planet at this location
        var point = (plotted.transform.position - planet.transform.position).normalized;
        plotted.transform.rotation = Quaternion.LookRotation(point);
    }

    return plotted;
}

Heatmap: can be added to the planet GameObject in order to visualize the data as a heatmap. Contains the following properties:

There are two steps to generating a heatmap:

The typical path for generating a heatmap would be to add the Heatmap script to your GameObject, and then to add the GenerateHeatmapGrid function as an event listener for your IDataLoader's loadComplete event (Which sends along a list of ICoordinatePoints).

Here is an example from the Earthquake demo:

Note: The heatmap only takes the frequency of points at a location into account. The more data points in a given area, the "hotter" the location. It doesn't take additional parameters into account to modify the weight that each plot gives to the heatmap.

Demos

There are two demo projects included within the package to demonstrate how certain implementations work:

Note: In order for either of these demos to work you must have a Planet layer on layer 8, and a Location layer on layer 9.

Earthquake Demo

(located under Coordinate_Mapping > Demos > Earthquake_Demo_Scene)

This demo uses data for all earthquakes that happened around the world from 01/01/2019 to 01/01/2020 with a magnitude of 3.0 or greater. The dataset was obtained from the U.S. Geological Survey website.

Running the demo loads and plots the earthquake data, scaling the points based on their magnitude. It also generates a heatmap for the currently shown earthquake points.

There is a double sided slider in the top left you can use to limit the magnitude range of earthquakes plotted; as you adjust that range, the heatmap regenerates. You can use the mouse to rotate the camera around the Earth, as well as use the z and x keys to zoom the camera in and out.

Pressing the spacebar with the cursor hovering over an earthquake point will display a text box with additional information about the earthquake, and pressing it with the cursor outside of an earthquake point will hide the box.

If you wish to just look at the heatmap, there is a Hide points check-box that allows you to toggle the visibility of the earthquake points.

The space skybox in the background is from the asset store package SpaceSkies Free

Real-time Flights Demo

(located under Coordinate_Mapping > Demos > Realtime_Flights_Demo)

This demo uses The OpenSky Network API to pull real-time data about current flights around the world and plot them over the globe.

Running the demo will hit the OpenSky API (sometimes the response can take a number of seconds) and grabs the first 500 flights returned. It then plots them to the Earth, taking into account their altitude, heading, and velocity. At this scale, the altitude difference between planes isn't noticeable, so I apply a multiplier to exaggerate it.

We then hit the API 10 seconds after each response, and update the information applied to the planes in order to keep them properly situated as they fly.

Pressing the spacebar with the cursor hovering over a plane will display a text box with additional information about that flight and pressing it with the cursor off of a plane will hide the box. You can use the mouse to rotate the camera around the Earth, as well as use the z and x keys to zoom the camera in and out.

License

Coordinate Mapper is free software distributed under the terms of the MIT license, reproduced below. Coordinate Mapper may be used for any purpose, including commercial purposes, at absolutely no cost. No paperwork, no royalties, no GNU-like "copyleft" restrictions. Just download and enjoy.

Copyright (c) 2020 Nicholas Bowlin

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.