Announcement

Collapse
No announcement yet.

How to implement a public non WMS tile set ?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • timoto
    started a topic How to implement a public non WMS tile set ?

    How to implement a public non WMS tile set ?

    Hello

    I'm looking for a way to render a public map tile service such as mapbox or stamen onto a publicly available instance of Nasa Web World Wind.

    Mapbox and Stamen serve their tiles like this:
    http://api.mapbox.com/v4/mapbox.terrain/3/2/3.jpg
    http://tile.stamen.com/watercolor/3/2/3.jpg

    But NWWW appears to require WMS.

    Is there a clear example of how to implement this ?

    Thanks
    Last edited by timoto; 07-27-2018, 03:58 AM. Reason: NOT RESOLVED

  • price5583
    replied
    We used a separate javascript file with the following text in it, then we reference that js file, then we call StamenWaterColorLayer.Create():

    /*
    * This class shows mercator tiles in a layer. (Stamen Water Color)
    */

    var StamenWaterColorLayer = function() //Defines the name of this class
    {
    //class variables
    var layer = null; //The layer that is returned by the Create function
    var levelZeroOffset = 0; //The number of levels deep before the first tiles are used from this tile set. For instance. 0 means a single image for level zero. 1 means there are 4 images for level 0, 2 means there are 16 images for level 0, etc. (as tiles are subdivided in half in width and height (quaded) each zoom level)

    //This is a public function that is called by default.js. This function builds the entire layer and returns it to default.js.
    var Create = function() //Defines a Create function within our TerminalServiceVolumesCore30 function. Currently Create is the only function within the TerminalServiceVolumesCore30 function that is exposed publically.
    {

    var displayName = "Stamen Water Color";
    var imageFormat = "image/png";
    var numLevels = 8;

    //If we were using full sphere we would do the following:
    //var sector = WorldWind.Sector.FULL_SPHERE;
    //var levelZeroDelta = new WorldWind.Location(180, 360);

    //But to avoid the "getting a ton of tiles at the poles" issue, we do the folllowing.
    var sector = new WorldWind.Sector(-85.05, 85.05, -180, 180); //Sets the upper and lower bound to 85.05 instead of full sphere.
    var levelZeroDelta = new WorldWind.Location(85.05, 180); //Since we aren't using full sphere, our level zero delta is adjusted accordingly.

    layer = new WorldWind.MercatorTiledImageLayer(sector , levelZeroDelta, numLevels, imageFormat, displayName, 256, 256);

    layer.imageSize = 256;
    layer.detailControl = .8; // default is 1.75
    layer.displayName = displayName;
    layer.enabled = true;
    layer.detectBlankImages = false;

    layer.mapSizeForLevel = MapSizeForLevel;

    layer.urlBuilder = {};
    layer.urlBuilder.urlForTile = UrlForTile;

    layer.doRender = function(dc) {dc.fadeTime=0; WorldWind.MercatorTiledImageLayer.protot ype.doRender.call(layer, dc);};

    layer.createTopLevelTiles = CreateTopLevelTiles;
    layer.zindex=101;
    return layer;


    }; //End of the Create function

    /*
    * This function calculates the total number of pixels across of all the images combined for a given zoom level
    */
    var MapSizeForLevel = function(levelNumber)
    {
    return 256 * Math.pow(2,(levelNumber + levelZeroOffset)); //The total number of pixels across of all the images combined for this zoom level. For instance for 256 pixel images, level 0, and a zero level offset would be 256, i.e. one 256 pixel image across. Whereas level 1 and a 0 level offset would be 512 pixels across. (i.e. two 256 images wide and two 256 pixel images tall), etc. (And, you can see how the offset would jump you up a zoom level factor, as for 256 pixel images, level 0, and a level 1 offset would be 512 pixels across for zoom level 0)
    };

    /*
    * This function was neccessary in order to set the level zero tiles.
    * (And, as such, this fixes the odd intermittant issue where World Wind would sometimes not be able to obtain ground altitudes)
    */
    var CreateTopLevelTiles = function (dc)
    {
    this.topLevelTiles = [];

    //Here we loop through rows and colums based on the levelZeroOffset in order to push the topLevelsTiles (which is neccessary to correct the intermittant ground altitude bug)
    for (var row = 0; row <= levelZeroOffset; row++) //Loop
    {
    for (var col = 0; col <= levelZeroOffset; col++) //Loop
    {
    this.topLevelTiles.push(this.createTile( null, this.levels.firstLevel(), row, col)); //Note a level 0 tileset will have just one tile (0,0). If it were an offset of 1 then we would set 4 tiles here. 0,0, 0,1, 1,0, and 1,1, and if an offset of 2 then 16 tiles.
    }
    }

    };


    var UrlForTile = function(tile, imageFormat)
    {
    //Example call we are looking for:
    //https://tile.stamen.com/watercolor/0/0/0.jpg
    //Where the first 0 is the zoom level
    //The second 0 is the column
    //And the third 0 is the row.
    //The tile numbering scheme in this tile set are numbered top to bottom, left to right.

    var x = tile.column;
    var y = tile.row;
    var z = tile.level.levelNumber;

    var url = "https://tile.stamen.com/watercolor/" + z + "/" + x + "/" + y + ".jpg";

    //Eventually to use the AOI/SBS Monitor tileset redirector we will be able to use a call like this which will route all tile calls through our server.
    //var url = "tile.ashx?proxyurl=https://tile.stamen.com/watercolor/" + z + "/" + x + "/" + y + ".jpg";



    //The tile numbering scheme in this tile set are numbered top to bottom, left to right.
    //However, some mercator tileset are numbered bottom to top, left to right.
    //Therefore for those types of tile sets you would have to reverse the order of the rows as follows.

    //To reverse the order of our rows we have to subtract the largest possible row value from the row returned, this will reverse the order of our rows for us.

    //var levelPlusFactor = tile.level.levelNumber + 3; //Here we determine our zoom level. Note: We are zooming 3 levels deep for our zero zoom in this tile, but yours may not need that.
    //var reverseRowNumberMax = (Math.floor(Math.pow(levelPlusFactor,2,) )) - 1; // Now we figure out the max possible rows for that zoom level. We do this by raising 2 to the power of our zoom level, then subtract 1 since a zero row is also used. (Note we raise 2 to the power of the zoom level because each zoom level has tiles that are half the width, and half the height of the zoom level higher.)
    //var rowReversed = reverseRowNumberMax - tile.row; //Now that we know our max possible rows, we subrtract that from the what would otherwise be the actual row for a standard mercator tile set that didn't need to be reversed. That in turn yields the correct row number because that reverses the order of the rows. For instance if the row was 2 and the maxrows was 15 then 15-2 = 13 thus taking what was 2 (two up from the bottom) and making it 13 (two down from the top)

    //To figure out how you would get the values for the levelZeroDelta see the following remmed out lines.

    //Here we set the levelZeroDelta based on how many zoom levels deep to start for zoom level 0 which in our case for this tile set which was 3.
    //var levelZeroDelta = new WorldWind.Location(180, 360); //Tells the tile layer how far over in lon and how far down in lat that starts where our first tile begins. i.e. our x and y values start at this lat lon. (we do this for tile sets that were not turned into images from lat zero and lon zero.) i.e. for tiles sets where lat zero and lon zero do not define the top left edge of the tile set (as if it were a single image.) (in other words we need to know the lat and lon of where to start counting our x and y offsets from)(and that is totally dependent on how the tile set was created) This particular tile set starts at 22.5 degrees lat, 45 degrees lon. so that where we'll put our o,o,o tile. (as opposed to lat zero lon zero)

    //We calculate the angle values based on a zoom of 3 the following way.

    //tile.getLevelNumber() + 3 where the + 3 relates to how many zoom levels deep to start for zoom level 0.
    //This "zoom levels deep value to start to start for zoom level 0" is directly related to the levelZeroDelta values.
    //For tile.level.levelNumber + 0 its lat 180 lon 360
    //For tile.level.levelNumber + 1 its lat 90 lon 180
    //for tile.level.levelNumber + 2 its lat 45 lon 90
    //For tile.level.levelNumber + 3 its lat 22.5 lon 45 //Thus we would use 22.5 and 45 for our levelZeroDelta for a zoom level 3 tile set since we would zoom 3 levels deep for zoom level 0.
    //For tile.level.levelNumber + 4 its lat 11.25 lon 22.5 //We would have used these values had we started 4 levels deep.
    //etc.
    //In other words for every zoom level higher where your starting zoom level is, half your lat and lon levelZeroDelta values.

    return url;
    };


    var pub = {};
    pub.Create = Create;
    StamenWaterColorLayer = pub;
    };

    StamenWaterColorLayer(); //Calls the function above. (to create a singleton instantiation)

    Leave a comment:


  • timoto
    replied
    Yes, official guys where are you ?

    Yes, people who use the web are quite erratic and do things like zoom in and out quickly because they are easily distracted and don't have time to waste.

    Ideally there should be some code to deal with this eg

    IF zoom, rotation or position changes THEN stop loading the previous tiles in viewport AND load the new tiles in viewport.

    Obviously that is an over simplification, and perhaps that is not the cause of the issue, but it does seem that the engine gets overloaded with requests and spends a lot of time running through old requests that are no longer of interest.

    By the way Chrome browser cache IS storing files with each zoom, rotation, position change. If you monitor the cache folder whilst zooming in and out you can see the files being created, eventually when all the tiles have loaded for your zoom, the tiles are rendered without delay (but not always), because they are in the cache. Local cache does appear to work.

    Here are some videos:

    Browser cache updates
    https://youtu.be/MZ0m5KJFxdo

    Cache unchanged but with tile render delay
    https://youtu.be/KHXWt3s3pGw

    Fast zooming without blank spots
    https://youtu.be/ZcBA9YeErb8

    Tilting during zoom in always causes blank spots
    https://youtu.be/0rqVMCi-B6I


    It seems to me that even if the tiles are in the cache the engine sometimes has trouble calculating which tiles to render leading to long delays in rendering the scene. Is there a way to resolve this issue ?
    Last edited by timoto; 08-01-2018, 11:13 AM.

    Leave a comment:


  • frenchy
    replied
    Strange behaviours indeed. I dont have any of these with my java version displaying the same layers. Would it be because javascript cant handle multiple threads afaik ? In the first video you probably zoom in-out too much, web mapping doesnt like that.. in the second one, the white tiles are a problem i had years ago with the java but without being stuck.
    it would be good to have an input from official guys to clarify things..


    Leave a comment:


  • timoto
    replied
    There is certainly something odd going on with cache.

    Whilst at times it may appear that there is no cache this simply can't be true. I had a situation where I had modified my map tiles in mapbox to include labels, then viewed those labels in a basic webpage to verify the update was being rendered. But when returning to my NWWW scene, after clearing the browser cache, some tiles in the scene were including the labels where expected, and other tiles were rendering without labels. This means that there must be a cache with NWWW servers, which I'm sorry to say is not behaving as expected.

    In the end I had to create an entirely new mapbox style with a new URL to force the scene to render a fresh tileset and not whatever had been stored on NWWW servers.

    So whilst some tiles can be persistent as demonstrated, lots of tiles are not.

    Tiles Lag

    This video shows how moving the globe around somewhat erratically, will shake up NWWW so much that it takes ages to catch up with the current static screen.


    Cache Dies

    This video shows even after a short time tiles previously loaded are then re-loaded.
    Last edited by timoto; 07-31-2018, 08:02 AM.

    Leave a comment:


  • frenchy
    replied
    Yes, but with a limited size and duration in time. The cache of WWJ was infinite (I have nearly 1To on disk!), and WWJ had no response time for tiles on disk, with a web app, you finally wait a lot to have tiles visible. I think there are cache requests in the Github, don't know if they are resolved. There should be a mechanism to store frequently visible (high altitude) tiles, and frequently visited places, which doesn't seem to be in place, even with Google Maps...
    Seen the hillshades, good, you should now try a site with labels...

    Leave a comment:


  • timoto
    replied
    Hi frenchy

    Actually this prototype now displays 2 layers, Stamen watercolor rastered tiles and Mapbox hillshading vector tiles. The hillshading is more noticeable when you zoom in.

    Most web browsers cache lots more than preferences. They store the html pages you visit and the content files such as images, video etc on your computer.

    Leave a comment:


  • frenchy
    replied
    Hi timoto,
    You may try with mapbox, along with a valid key in the URL... But again copyrights...
    Don't know much the web version, but I imagine caching in the browser is just good for saving preferences stuff, not thousands of "memory files"... ?
    For needSplit, I remember a guy named "vash" from Thales I think, who had a version that worked quite well. Search the forum.
    Cheers!

    Leave a comment:


  • timoto
    replied
    Hi frenchy

    True it would be better to test with a more detailed and predictable tileset.

    That's interesting when you say no caching for web version, do you mean no caching in the client browser ?

    Thank you for pointing out needToSplit I think that will be very useful to play with. I liked this explanation:
    https://forum.worldwindcentral.com/f...1146#post91146

    Leave a comment:


  • frenchy
    replied
    Good! But again the layer is not the best to test render quality. It is all a matter of compromise, between zoom level, labels readability, tile size, number of tiles, speed, your network... For the java version, it was the crucial debate, and AFAIK there is no caching for the web version, so every tile has to go through the wire, at all times. You may search the forum with the "needToSplit" function, if the web version is close to the java one, there must be a similar function you may tweek as you like. Cheers!

    Leave a comment:


  • timoto
    replied
    The developer discovered that reducing the tileWidth and tileHeight values from 256 to 128 improved the quality of tiles rendered to the scene:

    Click image for larger version

Name:	nwww-improved-quality.png
Views:	1
Size:	923.3 KB
ID:	158533



    Is that to be expected ?

    It would be nice to see an explanation of all the variable parameters available to us for the purpose of setting render quality.

    Leave a comment:


  • timoto
    replied
    Hi frenchy

    Thanks for your continued input.

    0. Yes credits will follow, if we can get our test case working.

    1. I now understand that this Web Mercator projection does not provide tiles for the poles.

    2. Whilst we can try to use different levels for the rendering quality, I do notice that other examples provided also suffer from this issue. Both the labels and the map tiles are pixelated:
    https://files.worldwind.arc.nasa.gov...icExample.html

    Click image for larger version

Name:	nwww-render-quality.png
Views:	1
Size:	577.9 KB
ID:	158531


    3. Yes, we use javascript because this is a web application, java is not an option.

    Thanks

    Leave a comment:


  • frenchy
    replied
    0/ Nice! But i advice you to put a logo somewhere, or you'll be in trouble soon, even with opensource stuff.
    1/ That's the way it is. Historically WMS servers don't display at these latitudes (even after 85N, or below 85S) because projection maths go crazy with tangential problems... That's no big deal, because these is not much at these places!
    2/ This artistic layer is perhaps not the best one to see details, maybe there is also more levels (you may try 18 instead of 16) - I created the java file by copying another one...
    3/ Good to see javascript implementation is very close to the java one, I'm not a big fan of javascript... no indentation?
    Congrats anyway.

    Leave a comment:


  • timoto
    replied
    Hi @frenchy

    The developer resolved that issue by incrementing the level for the tile, here is the code for reference:

    Code:
    define( 'layer/StamenWatercolor',
    [
    '../geom/Location',
    '../geom/Sector',
    '../layer/StamenTiledImageLayer',
    '../util/StamenImageryUrlBuilder'
    ],
    function (Location,
    Sector,
    StamenTiledImageLayer,
    StamenImageryUrlBuilder) {
    "use strict";
    
    var StamenWatercolor = function () {
    StamenTiledImageLayer.call(this, "Stamen Watercolor");
    this.urlBuilder = new StamenImageryUrlBuilder("StamenWatercolor");
    };
    StamenWatercolor.prototype = Object.create(StamenTiledImageLayer.prototype);
    
    return StamenWatercolor;
    });
    
    define( 'layer/StamenTiledImageLayer',
    [
    '../geom/Angle',
    '../util/Color',
    '../geom/Location',
    '../util/Offset',
    '../shapes/ScreenImage',
    '../geom/Sector',
    '../layer/MercatorTiledImageLayer'
    ],
    function (Angle,
    Color,
    Location,
    Offset,
    ScreenImage,
    Sector,
    MercatorTiledImageLayer) {
    "use strict";
    
    var StamenTiledImageLayer = function (displayName) {
    this.imageSize = 256;
    MercatorTiledImageLayer.call(this,
    new Sector(-90, 90, -180, 180), new Location(90, 90), 22, "image/jpeg", displayName,
    this.imageSize, this.imageSize);
    this.displayName = displayName;
    // TODO: Picking is enabled as a temporary measure for screen credit hyperlinks to work (see Layer.render)
    this.pickEnabled = true;
    };
    StamenTiledImageLayer.prototype = Object.create(MercatorTiledImageLayer.prototype);
    StamenTiledImageLayer.prototype.doRender = function (dc) {
    MercatorTiledImageLayer.prototype.doRender.call(this, dc);
    };
    
    // Determines the Stamen map size for a specified level number.
    StamenTiledImageLayer.prototype.mapSizeForLevel = function (levelNumber) {
    return 256 << (levelNumber + 1);
    };
    return StamenTiledImageLayer;
    });
    
    define( 'util/StamenImageryUrlBuilder',
    [
    '../error/ArgumentError',
    '../util/Logger',
    '../util/WWUtil'
    ],
    function (ArgumentError,
    Logger,
    WWUtil) {
    "use strict";
    
    var StamenImageryUrlBuilder = function (imagerySet) {
    
    this.imagerySet = imagerySet;
    };
    
    StamenImageryUrlBuilder.prototype.urlForTile = function ( tile, imageFormat ) {
    
    if ( !tile ) {
    
    console.log( "Missing tile!" );
    }
    
    var url = "https://stamen-tiles.a.ssl.fastly.net/watercolor/" + ( tile.level.levelNumber + 1 ) + "/" + tile.column + "/" + tile.row + ".jpg";
    
    return url;
    };
    
    return StamenImageryUrlBuilder;
    });
    At this stage we have 2 further issues with the setup:

    1. Why are the North and South poles missing ?

    Click image for larger version

Name:	nwww-stamen-2.jpg
Views:	1
Size:	383.9 KB
ID:	158526


    This is also seen on NWWW examples:

    Click image for larger version

Name:	nwww-poles-missing.png
Views:	2
Size:	101.9 KB
ID:	158528

    2. Why don't tiles load/render higher resolution of the tiles when expected?

    The levels need to switch earlier.

    Perhaps this is due to levelZeroDelta but we don't know what values should be used.

    36,36 seem to render a really low quality map, where 180,180 renders high quality but only the Northern hemisphere is displayed. Anything more than 90,90 doesn't render the full sphere.

    Current example is here: https://dev.globaltimoto.com

    Thanks
    Attached Files

    Leave a comment:


  • timoto
    replied
    Hi frenchy

    Thanks for the input. I will pass it on.

    Yes credits will follow once prototyping is complete.

    Tim

    Leave a comment:

Working...
X