melowntech / vts-browser-js

JavaScript WebGL 3D map rendering engine
BSD 2-Clause "Simplified" License
218 stars 42 forks source link

geodata polygons #179

Closed jrjdavidson closed 4 years ago

jrjdavidson commented 4 years ago

Hi,

Got an error when playing around with geojson polygons for the first time. When I tried to find out what the error was, I noticed that on one of the jsFiddles it says: //import GeoJSON data //polygon are not supported yet

Is that still the case or is the error on my end?

davidmtech commented 4 years ago

Hi,

polygon support is still experimental and undocumented. But is should sort of work. Try this example:

https://davidmtech.github.io/geojson/?pos=obj,14.326574,33.264271,fix,95.41,-1.07,-84.25,0.00,7390416.75,55.00

source code: https://github.com/davidmtech/davidmtech.github.io/blob/master/geojson/demo.js

jrjdavidson commented 4 years ago

David- that looks stunning! I'm looking forward to trying this. I'll have another go when I have a moment and post any specific errors here.

jrjdavidson commented 4 years ago

Hi again David,

I was able to replicate what you did and it looks great. I tried uploading my own file and got an error, it looks like it's in. Geojson file here: https://www.holoceneadventures.com/chchsg/geojson/TCcat.geojson

Error attached: vts-browser.min.js:5 Uncaught TypeError: Cannot read property 'x' of null at r (vts-browser.min.js:5) at Object.forward (vts-browser.min.js:5) at c.getPolygonCenter (vts-browser.min.js:5) at c.addPolygon3 (vts-browser.min.js:5) at c.addPolygon (vts-browser.min.js:5) at r.processGeometry (vts-browser.min.js:5) at r.processFeature (vts-browser.min.js:5) at r.processCollection (vts-browser.min.js:5) at r.processJSON (vts-browser.min.js:5) at c.importGeoJson (vts-browser.min.js:5)

davidmtech commented 4 years ago

Hi,

your geojson is in unknown projected coordinate system and that leads to error. One solution is to convert coordinates in geojson to standard longlat (WGS84). Or provide proj4 string as srs parameter in import function (e.g. '+proj=longlat +datum=WGS84 +no_defs' ). Using srs parameter is experimental feature, so it may not work.

Other thing is that coordinates in your geojson does not have heights. So it expects that heights have 0 values. It can be OK in same case. But sometime you need your polygon on the terrain surface. In that case you can use floating heights mode. Which meas that heights are considered to be relative to terrain height. This mode is more processing intensive in its initial stage, but can give sufficient results.

There is example of 'float' mode and srs parameter:

https://davidmtech.github.io/geojson2/?pos=obj,14.283645,50.374467,fix,281.68,-2.85,-42.47,0.00,4338.63,55.00

source code: https://github.com/davidmtech/davidmtech.github.io/blob/master/geojson2/demo.js

jrjdavidson commented 4 years ago

Thanks again David.

I did notice the projection issue, it was on a local NZ grid. I converted the polygons to lines ( i hadn't heard from you yet), and reprojected. As you mentioned, when attempting to load the file it takes quite a long time and slows the computer right down. Once it is loaded it looks great! I'll have to consider carefully whether it is worth the the load time.

I've re-uploaded the same file in WGS84 https://www.holoceneadventures.com/chchsg/geojson/TCcat.geojson I've also uploaded another polygon file in WGS84, that one crashes the site on loading: https://www.holoceneadventures.com/chchsg/geojson/liqWGS84.geojson

On another note- I was curious about getting more information about melown cloud as a paid subscription. I sent a message through the form on the melown site, but haven't heard anything. Do you know who I can get in touch with?

davidmtech commented 4 years ago

I was lucky to see liqWGS84.geojson. I have used same setup as this: https://github.com/davidmtech/davidmtech.github.io/blob/master/geojson/demo.js

Result of tessellation and height processing can stored by this function.

var json = geodata.makeGeodata();

You can store that json as a file or copy it from javascript console.

Next time you can load only this json and import it by this function:

geodata.importVTSGeodata(json_data);

It should save some loading/processing time.

As far as I know, fate of melown cloud will be decided in the future. Melown Technologies was acquired by Hexagon. It probably needs some time to let things settle down.

jrjdavidson commented 4 years ago

Hi David, Thanks for the suggestion, I'm real keen to try it out. I float processed heights on the liqWGS84.geojson file and was able to get a nice view. image

I retrieved the json data from the makeGeodata method : https://www.holoceneadventures.com/chchsg/geojson/liqWGS84vts.json

I haven't been able to load it properly using geodata.importVTSGeodata(json_data), I've lost a few hours trying all kinds of methods. Can you show me an example code of how you would use it?

davidmtech commented 4 years ago

There was bug in importVTSGeodata function. Bug fix is not part of master branch yet, but fixed library can be accessed here:

https://davidmtech.github.io/libs/vts-browser.min.js

demo code is here:

https://github.com/davidmtech/davidmtech.github.io/blob/master/geojson2/demo2.js

you can reduce size of liqWGS84vts.json from 55MB to 14MB by removing white spaces and new line characters. For example in linux shell:

cat liqWGS84vts.json | tr -d " \t\n\r" > liqWGS84vts.json

jrjdavidson commented 4 years ago

Thanks David. That works great.

I've been using vts browser more and more, and have been impressed by how far I can push it. I think that we'll be using it a lot in the near future - I'm hoping of animating an erupting volcano in iceland all in js (next on the list once I'm done this project). Shouldn't be too hard to do since ballistic trajectories are already created in autopilot?

We did install vts-backend on one of our machines, but I find that melown cloud is worth the time it saves me. If you do hear anything about what happens with it, please let me know.

Cheers, Jonathan

jrjdavidson commented 4 years ago

Looks like it is not possible to access properties of polygons for styling purposes, is that correct?

davidmtech commented 4 years ago

Properties of polygons should be accessible same way as for other elements (points, lines). For example:

"polygon-extrude" : "$NameOfPropertyWithExtrudeValue"

even mapping values is possible:

"polygon-color" : { "map" : ["$rockType", [["rockA", [0,0,0,255]], ["rockB", [255,0,0,255]]], [255,255,255,255]] }

More about styles is here: https://github.com/melowntech/vts-browser-js/wiki/VTS-Geodata-Format#style-property-values

Errors in style syntax are logged to javascript console.

Style editor is also very useful. Here is how to activate this editor (Ctrl+Shit+D, Shift+E):

https://github.com/melowntech/vts-browser-js/wiki/VTS-Browser-Inspector-Mode

Trajectories in autopilot are not exactly ballistic, they are sin function + slowing start and end even more. But you can use this function to compute position and then replace height with you own value.

map.movePositionCoordsTo(position, azimuth, distance)

jrjdavidson commented 4 years ago

Hi David,

Thanks again for all your help, I've learnt a lot. Thought I'd show you a first try at creating a volcano erupting - looks pretty silly but I'll show it to some colleagues to see if it's worth putting a bit more effort into: https://www.holoceneadventures.com/ivft2/

Cheers, JD

` export function initAnimation(browser, posObj){ browser.on('map-loaded', onMapLoaded); var animationIteration = 200;

function onMapLoaded(){
    browser.on('tick', onTick);

    var map = browser.map;
    var renderer= browser.renderer;

    function createBallistic(id,offset){
        let iteration= animationIteration-offset
        var posFrom = posObj.from;
        function getRndInteger(min, max) {
          return Math.floor(Math.random() * (max - min + 1) ) + min;
        }

        if ("to" in posObj) {var posTo = posObj.to;}
        else if ("azimuth" in posObj && "distance" in posObj) var posTo = map.movePositionCoordsTo(posFrom, posObj.azimuth, posObj.distance);
        else {
            const azimuth = getRndInteger(0,360);
            const distance= getRndInteger(10000,15000);
            var posTo = map.movePositionCoordsTo(posFrom, azimuth, distance);
        }   

        let trajectoryArray = browser.map.generateTrajectory(posFrom,posTo,{type:"ballistic"});

        var modelOBJ = null;
        var modelPath = "obj/crystal.obj";

        map.addRenderSlot('custom-models'+id, onDrawModel, true);
        map.moveRenderSlotAfter('after-map-render', 'custom-models'+id);
        modelOBJ = new ModelOBJ(map, renderer, {path:modelPath});

        modelOBJ.show = true;
        modelOBJ.ambientLight = [0,0,0];

        let modelScaleX = 1000;
        let modelScaleY = 1000;
        let modelScaleZ = 1000;

        let rotation = iteration;

        function onDrawModel(renderChannel) {
            iteration= animationIteration-offset
            let modelHeight = trajectoryArray[iteration][4];
            let modelLat = trajectoryArray[iteration][2];
            let modelLong = trajectoryArray[iteration][1];
            let rotation = iteration;
            let modelRotationX = rotation;
            let modelRotationY = rotation;
            let modelRotationZ = rotation;
            let modelNavCoords = [modelLong, modelLat , modelHeight];
            let modelOBJScale = [modelScaleX, modelScaleY, modelScaleZ];
            let modelRotation = [modelRotationX ,modelRotationY,modelRotationZ];

            if (renderChannel != 'base') {
                return; //draw only in base channel
            }

            //draw models when all model resources are ready

            if (modelOBJ && modelOBJ.ready && modelOBJ.show) {
                modelOBJ.draw({
                    navCoords: modelNavCoords,
                    heightMode: 'fix',
                    rotation: modelRotation,
                    scale: modelOBJScale,
                    ambientLight: modelOBJ.ambientLight
                });
            }

            if (iteration > trajectoryArray.length-200){
                offset += trajectoryArray.length-400
            }

        }
    }

    createBallistic(0,0)

    let ballistic = 0;

    function onTick() {
        animationIteration++;
        console.log(animationIteration)
        if( ballistic < 30) {
            if (animationIteration%30 == 0){
                createBallistic(animationIteration%30, animationIteration-200);
                console.log('Created new ballistic');
                ballistic++
            }
        }    

        browser.map.redraw();

    }

}

}`

davidmtech commented 4 years ago

Hi,

thanks for sharing. It looks great.