kartena / Proj4Leaflet

Smooth Proj4js integration with Leaflet.
http://kartena.github.io/Proj4Leaflet/
BSD 2-Clause "Simplified" License
587 stars 172 forks source link

Problem with TMS tiled EPSG:3067 map #28

Closed muurain closed 11 years ago

muurain commented 11 years ago

Hello!

..this is actually more like a support request than an issue.

Anyway, I'm trying to get a TMS tiled map of a local area working with Proj4Leaflet. I used gdal2tiles to create tiles from 6 tif -maps with EPSG:3067 coordinate system. (National Land Survey of Finland provides pretty extensive maps of Finland for free, http://www.maanmittauslaitos.fi/en)

The problem is that I cannot get the map to display at all with it's proj4 projection in leaflet. I started to experiment with Proj4Leaflet provided tms-tiled example and modified it so that it would get the job done with EPSG:3067 and my custom maps:

var crs = new L.Proj.CRS.TMS('EPSG:3067',
    '+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,-0,-0,-0,0 +units=m +no_defs',
    [6810000, 308000, 6834000, 344000],
    {
        resolutions: [
                256,
                128,
                64,
                32,
                16,
                8,
                4,
                2,
                1
        ]
    });

var map = new L.Map('map', {
    crs: crs,
    continuousWorld: true,
    worldCopyJump: false
});

var tileUrl = '{z}/{x}/{y}.png',
    attrib = '© Testi',
    tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
        maxZoom: 8
        ,minZoom: 0
        ,continuousWorld: true
        ,attribution: attrib
    });

map.addLayer(tilelayer);
map.setView([61.46875, 23.56964], 4);

This only seems to get me a grey leaflet template with no map. I have made the modifications on the example based on tilemapresource.xml -file generated by gdal2tiles and gdalinfo output for my map.

proj4 from gdalinfo -proj4 Temp2.vrt: (same as in http://www.spatialreference.org/ref/epsg/3067/ ?)

PROJ.4 string is:
'+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,-0,-0,-0,0 +units=m +no_defs '

Tilemapresource.xml:

<?xml version="1.0" encoding="utf-8"?>
    <TileMap version="1.0.0" tilemapservice="http://tms.osgeo.org/1.0.0">
      <Title>Temp2.vrt</Title>
      <Abstract></Abstract>
      <SRS>PROJCS["unnamed",GEOGCS["unnamed",DATUM["Euref_98",SPHEROID["GRS 80",6378137,298.257222101],TOWGS84[0,0,0,-0,-0,-0,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",27],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]</SRS>
      <BoundingBox minx="6810000.00000000000000" miny="308000.00000000000000" maxx="6834000.00000000000000" maxy="344000.00000000000000"/>
      <Origin x="6810000.00000000000000" y="308000.00000000000000"/>
      <TileFormat width="256" height="256" mime-type="image/png" extension="png"/>
      <TileSets profile="raster">
        <TileSet href="0" units-per-pixel="256.00000000000000" order="0"/>
        <TileSet href="1" units-per-pixel="128.00000000000000" order="1"/>
        <TileSet href="2" units-per-pixel="64.00000000000000" order="2"/>
        <TileSet href="3" units-per-pixel="32.00000000000000" order="3"/>
        <TileSet href="4" units-per-pixel="16.00000000000000" order="4"/>
        <TileSet href="5" units-per-pixel="8.00000000000000" order="5"/>
        <TileSet href="6" units-per-pixel="4.00000000000000" order="6"/>
        <TileSet href="7" units-per-pixel="2.00000000000000" order="7"/>
        <TileSet href="8" units-per-pixel="1.00000000000000" order="8"/>
      </TileSets>
    </TileMap>

Am I missing something? I don't really understand all the things regarding map projections, but shouldn't this be enough to define the map for Proj4Leaflet?

I managed to get the map to show with plain Leaflet with tms : true, but obviously the coordinate system got all messed up since the real map projection is on a different continent.

perliedman commented 11 years ago

Hi, from a quick look, your setup seems sensible and good, no apparent problems there.

Given that I can't check the tiles myself, I think your best bet is to check in your browser's debugger what tiles are actually being loaded, and compare that to what tiles you actually have. I'm guessing that the grey map you see means that you get 404:s or something similar on the tiles.

In Chrome, you can enable Developer Tools and check under the network tab to see what tile URLs are being accessed. In Firefox, you need the Firebug plugin or similar. In Internet Explorer, there's also some built in developer tools that you can use.

muurain commented 11 years ago

Thank you for quick reply!

I just realized that Chrome debugger was giving some errors with the map page:

proj4leaflet.js:116

Uncaught Error: Projected bounds does not match grid at zoom 0 proj4leaflet.js:116
L.Proj.TileLayer.TMS.L.TileLayer.extend.initialize proj4leaflet.js:116
NewClass leaflet-src.js:185
(anonymous function)

leaflet-src.js:546

Uncaught TypeError: Cannot call method 'add' of undefined leaflet-src.js:5461
L.Draggable.L.Class.extend._onMove leaflet-src.js:5461
handler

I also noticed that if option resolutions would be left out of the code it would run correctly. Exept for the fact that it is trying to get tiles like /4/-114036253/104188939.png where my own corresponding tiles would be something around /4/10/36.png. ({z}/{x}/{y}.png)

After fixing the map bounds to [-6810000, 308000, 6834000, 344000] the map is now getting tiles from positive x axel. Now the problem seems to be that my map tiles start from origo, 0,0, and only picture the area withnin bounds stated earlier. Shouldn't map bounds in L.Proj.CRS.TMS() also affect the origo of the tile grid? Or is the problem with my tile naming as my map does not include the whole area of EPSG:3067?

muurain commented 11 years ago

My test page can be found at http://muurain.net/maps/index-example-1.html I just dumped the tiles at http://muurain.net/maps/{z}/{x}/{y}.png, with zoom levels from 0 to 8.

perliedman commented 11 years ago

Hi, and thanks for the test setup.

I've fixed your example, and there were two issues:

First, the TMS layer documentation in Proj4Leaflet is sort of lacking. In particular, it fails to mention that the maximum y coordinate of the bounds currently must match the tile grid at all zoom levels; that is why you got the "Projected bounds does not match grid at zoom 0" message. This is easily fixed by simply manipulating the upper bound. I should fix this in Proj4Leaflet really, since this is both confusing and unnecessary. Sorry about that.

Second, it appears that the x and y axis was swapped in your bounds. Looking at the coordinate (6810000, 308000) puts me somewhere south of the southern tip of Africa, while (308000, 6810000) puts me in Finland. Swapping x and y fixes this, and I get pretty tiles in the map. (As a side note: I've made the swapped x/y mistake at least a hundred times in my career, fun stuff.)

Here's a copy of the working setup I used:

var crs = new L.Proj.CRS.TMS('EPSG:3067',
    '+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,-0,-0,-0,0 +units=m +no_defs',
    [308000, 6810000, 373536, 6875536],
    {
        resolutions: [256,128,64,32,16,8,4,2,1] 
    });

var map = new L.Map('map', {
    crs: crs,
    continuousWorld: true,
    worldCopyJump: false
});

var tileUrl = 'http://muurain.net/maps/{z}/{x}/{y}.png',
    attrib = '&copy; Testi',
    tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
        maxZoom: 8
        ,minZoom: 0
        ,continuousWorld: true
        ,attribution: attrib
    });
diouck commented 11 years ago

Hello I just saw your code looks to me interesting. I tested it on my data and it does not work is that you might look for what it does not work Here is the code var crs = new L.Proj.CRS.TMS ('EPSG: 3948' '+ proj = lcc + lat_1 lat_2 = 47.25 + 48.75 + = + lon_0 lat_0 = 48 = 3 + x_0 = 1700000 + y_0 = 7200000 + ellps = GRS80 + towgs84 = 0,0,0,0,0,0,0 + units = m + no_defs'

[308000, 6810000, 373536, 6875536] { resolutions: [256,128,64,32,16,8,4,2,1] });

var map = new L.Map ('map', { crs: crs, continuousWorld: true, worldCopyJump: false });

tileUrl var = 'http://www.geo.rennesmetropole.fr/tms/4564/Plan% 20of% 20ville / {z} / {x} / {y}. png' attrib = '© Testi' tilelayer = new L.Proj.TileLayer.TMS (tileUrl, crs, { maxZoom: 8 , minZoom: 0 , continuousWorld: true , attribution: attrib });

map.addLayer (tilelayer);

map.setView ([-1.67, 48.1], 2); var marker = L.marker ([-1.67, 48.1]) addTo (map).;

Thank you for your understanding

perliedman commented 11 years ago

Your code seems pretty garbled somehow. Lots of misplaced spaces etc.

I tried to clean it up, and got it working up to the point that I get HTTP 500 messages back from your tile server. You will have to look closer at why that is.

Here's my cleaned up version of your code:

var crs = new L.Proj.CRS.TMS('EPSG:3948',
    '+proj=lcc +lat_1=47.25 +lat_2=48.75 +lat_0=48 +lon_0=3 +x_0=1700000 +y_0=7200000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ',
    [308000, 6810000, 373536, 6875536],
    {
        resolutions: [256,128,64,32,16,8,4,2,1]
    });

var map = new L.Map ('map', {
        crs: crs,
        continuousWorld: true,
        worldCopyJump: false
    });

var tileUrl = 'http://www.geo.rennesmetropole.fr/tms/4564/Plan%20of%20ville/{z}/{x}/{y}.png',
    attrib = '© Testi',
    tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
        maxZoom: 8
        , minZoom: 0
        , continuousWorld: true
        , attribution: attrib
    });

map.addLayer (tilelayer);
map.setView([-1.67, 48.1], 2);

Good luck!

diouck commented 11 years ago

Hello Thank you for your response I have finally solved the problem but I tried to do the same thing this time with a projection system in 2154 but the map does not appear and I do not know where is that AC could come c is certainly the processing

Here is the code

var options = {}; options.continuousWorld = true; options.markerZoomAnimation = false; options.inertia = false; var map = L.map('map', options);

// register the custom projection with Proj4JS
Proj4js.defs['EPSG:2154'] = "+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs";

// create Transformation
var transformation = new L.Transformation(1, -1318451.0, -1, 7198441.0);

// set the CRS within Leaflet
map.options.crs = L.CRS.proj4js("EPSG:2154", undefined, transformation);

// resolutions
var res = [53.97500000000001,6.987500000000004,16.192500000000003,8.096250000000001,6.746875000000001,4.048125000000001,2.6987500000000004,2.0240625000000003,1.3493750000000002,0.9445625000000001,0.6746875000000001,0.5397500000000001,0.4048125000000001,0.26987500000000003,0.13493750000000002];
map.options.crs.scale = function (zoom) {
    return 1 / res[zoom];
};

var layerOptions = {};
layerOptions.minZoom = 0;
//layerOptions.maxZoom = res.length - 1;
layerOptions.detectRetina = true;
// if not set to true, will only load positive tiles
layerOptions.continuousWorld = true;
var tileLayer = new L.TileLayer('http://www.geo.rennesmetropole.fr/tms/4566/PVI_2154/{z}/{x}/{y}.png', layerOptions);
// alter getTileUrl because Y axis is inverted (TMS profile is locale)
tileLayer.getTileUrl = function (tilePoint, zoom) {
    console.log(tilePoint);
    var toRet;
    toRet = L.Util.template(this._url, L.Util.extend({
        "z":this._getZoomForUrl(),
        x:tilePoint.x,
        //y: Math.pow(2,zoom) - tilePoint.y -1
        y:-tilePoint.y - 1
    }, this._urlParams));
    return toRet;
}
map.addLayer(tileLayer);
map.setView([48.1, -1.67], 2);

var marker=new L.Marker(new L.LatLng(48.11, -1.67), {
  title: 'Je suis a Renes'
});
map.addLayer(marker);

Thank you for your response

perliedman commented 11 years ago

I have a bit of a hard time understanding that code.

You don't have to register the projection with Proj4js manually, Proj4Leaflet will do it for you (as you did in the first example). Also, I don't understand why you're overriding getTileUrl, and not just using L.Proj.TileLayer.TMS like you did in the first example - that is what it's for.

It appears that you try to mimic some of what Proj4Leaflet comes package with in L.Proj.CRS.TMS and L.Proj.TileLayer.TMS. Any reason in particular why you wouldn't use those classes directly instead of doing it yourself?

diouck commented 11 years ago

Hello Above sea very much for your thumbs Let me explain: In fact TMS is beautiful and well in 2154 and the transformation was well done The problem was the resolution:

var res = [53.97500000000001,6.987500000000004,16.192500000000003,8.096250000000001,6.746875000000001,4.048125000000001,2.6987500000000004,2.0240625000000003,1.3493750000000002,0.9445625000000001,0.6746875000000001,0.5397500000000001,0.4048125000000001,0.26987500000000003,0.13493750000000002];

therefore it was necessary to var res = [156543.033928,78271.516964,39135.758482,19567.879241,9783.939621,4891.96981,2445.984905,1222.992453,611.496226,305.748113,152.874057,76.437028,38.218514,19.109257,9.554629,4.777314,2.388657,1.194329];

and zoom=12

Thank you