Home

Awesome

Geo-Three

npm versionGitHub version FOSSA Status

<img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/screenshot/b.png" width="380"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/screenshot/c.png" width="380"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/screenshot/e.png" width="380"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/screenshot/d.png" width="380">

Example

Usage

// Create a map tiles provider object
var provider = new OpenStreetMapsProvider();

// Create the map view and add it to your THREE scene
var map = new MapView(MapView.PLANAR, provider);
scene.add(map);

// By default coordinates are to meter, can be resized to kilometer
map.scale.set(0.001, 0.001, 0.001);

Coordinates

var coords = Geo.UnitsUtils.datumsToSpherical(40.940119, -8.535589);
controls.target.set(coords.x, 0, -coords.y);

Tile Loading

<img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/tiles.png" width="350">

Data Providers

<img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/bing_sat.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/heremaps_sat.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/mapbox_sat.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/bing_vector.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/heremaps_vector.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/mapbox_vector.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/osm_vector.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/debug.png" width="270"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/providers/mapbox_height.png" width="270">

LOD Control

export class DistanceLOD extends LODControl
{
	constructor() {super();}

	updateLOD(view, camera, renderer, scene)
	{
        // Get world position of the camera.
        var pov = new Vector3();
        camera.getWorldPosition(pov);

        view.traverse(function(node)
        {
            // Check if child in a MapNode
            if(node instanceof MapNode)
            {
                var position = new Vector3();
                node.getWorldPosition(position);
				
                // Distance between camera and tile
                var distance = pov.distanceTo(position);
                
                // Normalize distance based on tile level
                distance /= Math.pow(2, 20 - node.level);
                
                // If closer than X subdivide
                if (distance < 50)
                {
                    node.subdivide();
                }
                // If far away, simplify parent
                else if (distance > 200 node.parentNode)
                {
                    node.parentNode.simplify();
                }
            }
        });
	}
}

Tiles Map Nodes

<img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/planar.png" width="350"><img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/spherical.png" width="350">

<img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/shader.jpg" width="600">

Custom Data Providers

export class OpenStreetMapsProvider extends MapProvider
{
	constructor(address) {super();}

	fetchTile(zoom, x, y)
	{
		return new Promise((resolve, reject) =>
		{
			var image = document.createElement("img");
			image.onload = function(){resolve(image);};
			image.onerror = function(){reject();};
			image.crossOrigin = "Anonymous";
			image.src = "https://a.tile.openstreetmap.org/" + zoom + "/" + x + "/" + y + ".png";
		});
	}
}
<img src="https://raw.githubusercontent.com/tentone/geo-three/master/readme/coords.png" width="600">
import {Color} from "three";

export class BlueToRedProvider extends MapProvider
{
	fetchTile(zoom, x, y)
	{
		const canvas = new OffscreenCanvas(16, 16);
		const context = canvas.getContext('2d');
		
		const blue = new Color(0x0000FF);
		const red = new Color(0xFF0000);
		const color = blue.lerpHSL(red, (zoom - this.minZoom) / (this.maxZoom - this.minZoom));
		
		context.fillStyle = color.getStyle();
		context.fillRect(0, 0, 16, 16);
		return Promise.resolve(canvas);
	}
}

Custom Map Nodes

import {SphereGeometry, MeshBasicMaterial, Vector3} from "three";

// The MapNode inherits from three Mesh object and requires a geometry and material
export class CustomMapNode extends MapNode
{
	constructor(parentNode = null, mapView = null, location = MapNode.ROOT, level = 0, x = 0, y = 0)
	{
		super(CustomMapNode.GEOMETRY, CustomMapNode.MATERIAL, parentNode, mapView, location, level, x, y);
	}
	
	static GEOMETRY = new SphereGeometry(0.5, 32, 32); 
	
	static MATERIAL = new MeshBasicMaterial();
	
	// Base geometry applied to the map view.
	static BASE_GEOMETRY = new MapNodeGeometry(1, 1, 1, 1);
	
	// Base scale is applied to the map view
	static BASE_SCALE = new Vector3(UnitsUtils.EARTH_PERIMETER, 1, UnitsUtils.EARTH_PERIMETER);

	initialize() {
		// Method to initialize data of the node (e.g fetch assets)
	}

	createChildNodes()
	{
		// Method called on subdivision to craete child nodes
	}
}

License

FOSSA Status