tentone / geo-three

Tile based geographic world map visualization library for threejs
https://tentone.github.io/geo-three/docs/
MIT License
651 stars 105 forks source link
3d-tiles geolocation map map-tiles openstreetmap threejs webgl

Geo-Three

npm versionGitHub version FOSSA Status

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

Data Providers

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

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";
        });
    }
}
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