kartena / Proj4Leaflet

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

Custom Projection not working #61

Closed pkeller3 closed 10 years ago

pkeller3 commented 10 years ago

I've been trying to get EPSG:2263 working with Proj4Leaflet and haven't had any luck so far. All I get is a gray map area. I have an aerial tif image that I broke into tiles using MapTiler (http://www.maptiler.org/). The options in the tool allowed me to georeference the image and select my spatial reference system.

I tried following what was suggested here https://github.com/kartena/Proj4Leaflet/issues/28#issuecomment-18295865 and adjusting the values for my projection, but nothing seems to work. I don't get any errors and I tried to step through the source on both calls into leaflet and it seemed like the no tiles were being added to the queue in _addTilesFromCenterOut, but now I can't even get into that call and can't figure out what change I made caused that.

I used the bounding extents defined in an xml file that I got with the tif to create the bounds array. Looks like it came from esri or arcgis

<westBL Sync="TRUE">1030000.000000</westBL>
<eastBL Sync="TRUE">1055600.000000</eastBL>
<southBL Sync="TRUE">164500.000000</southBL>
<northBL Sync="TRUE">182500.000000</northBL>

My tiles are local right now, working on transferring them to an example setup. I'll update with a link to it once they are done transferring. For now here's the code I'm working with.

<script>
var resolutions = [256, 128, 64, 32, 16, 8, 4, 2, 1];
// these values were generated by maptiler so I tried to use them with no luck
//var resolutions = [127.99999999999942, 63.99999999999971,  31.99999999999985, 
//15.99999999999993, 7.99999999999996, 3.99999999999998, 1.99999999999999, 
//0.50000000000000,  0.25000000000000]; 

var crs = new L.Proj.CRS.TMS('EPSG:2263', '+proj=lcc +lat_1=41.03333333333333 
+lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 ' + 
'+x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 
+to_meter=0.3048006096012192 +no_defs ',
           [1030000, 182500, 1055600, 164500],
            {
                resolutions: resolutions
            }
        );

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

        var tileUrl = 'Tiles/{z}/{x}/{y}.png',
            tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
                maxZoom: 8
                , minZoom: 0
                , continuousWorld: true
            });
    </script>
pkeller3 commented 10 years ago

Looks like I'm missing the addTo call on the tilelayer with what I posted but I'm still not able to get things working. Also still transferring my tiles (took my computer home from work last night) to an aws so I can post the example.

tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
                maxZoom: 8
                , minZoom: 0
                , continuousWorld: true
            }).addTo(map);
pkeller3 commented 10 years ago

Sorry for posting so many times, just wanted to update. I've managed to get a little farther, but still not getting my tiles loaded. I changed my bounds to the bounds for EPSG:2263 and not the aerial and changed to use the resolutions calculated by maptiler that I have commented out above. Bounds: [909126.0155, 110626.2880, 1610215.3590, 424498.0529]

Now _addTilesFromCenterOut is finding tiles to load, but when its gets into _loadTile, he tilePoint is not correct causing an error trying to find the tile because no tile exists for the point it's trying to use.

Finally got a test setup: https://hosting.appliedpavement.com/Aerials/ I'm guessing either my tile structure was generated incorrectly or the parameters I'm using are causing the wrong tilePoint to be calculated.

perliedman commented 10 years ago

I'm not familiar with MapTiler, but to begin with: are you sure you should be using TMS for tiling? The MapTiler site says it's for creating overlays to Google Maps, and Google Maps does not use TMS.

If your tiles are not using TMS, that would explain weird tile coordinates, since TMS has the y axis flipped compared to Google Maps (and Leaflet's default).

Without TMS, you just have to specify the tiles' origin (where tile (0,0) is), not the entire bounds.

pkeller3 commented 10 years ago

Thanks for taking a look at this. I only found out about maptiler from multiple posts people have made on the leaflet google group. I've never done any mapping before so I'm figuring things out as I go.

I was finally able to get the tiles to display correctly today, but I'm still trying to figure out how to plot things using the epsg 2263 projection. I've updated my code below in case it helps someone else in the future. The first marker creation attempts to use the projection coordinates but seems to create a marker at the edge of the image at the starting zoom level and then the marker moves around as the zoom level changes.

I've also updated the test page here https://hosting.appliedpavement.com/Aerials/, I'm not sure how long that will remain active though because we are planning on moving away from that hosting provider shortly.

<script>

        var resolutions = [127.99999999999942, 63.99999999999971, 31.99999999999985, 15.99999999999993, 7.99999999999996, 3.99999999999998, 1.99999999999999, 1.00000000000000, 0.50000000000000, 0.25000000000000];
        var crs = new L.Proj.CRS('EPSG:2263',
          '+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 ' +
          '+x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs ',
            {
                origin: [1030000, 182500],                              // origin of aerial, top left
                resolutions: resolutions
            }
        );

        var map = new L.Map('map', {
            crs: crs,
            continuousWorld: true,
            worldCopyJump: false,
            // setting max bounds makes it so you can not pan outside of the area you want to show
            //maxBounds: new L.LatLngBounds([40.62685618771871, -73.83524318683413], [40.57719281838508, -73.74309481282909])
        });

        var tileUrl = 'Tiles/{z}/{x}/{y}.png',

            tile = new L.TileLayer(tileUrl, {
                maxZoom: 9,
                minZoom: 2,
                tms: true,
                noWrap: true
            });

        map.setView(new L.LatLng(40.60224305197215, -73.7956045205781), 2).addLayer(tile);

        var latlng11 = L.latLng(1035546.12, 176231.75);
        var mark11 = L.marker(latlng11).addTo(map);

        // markers on the corners
        var latlng1 = L.latLng(40.62685618771871, -73.83524318683413);
        var mark1 = L.marker(latlng1).addTo(map);
        var latlng2 = L.latLng(40.626686909535934, -73.74296193767485);
        var mark2 = L.marker(latlng2).addTo(map);
        var latlng3 = L.latLng(40.57719281838508, -73.74309481282909);
        var mark3 = L.marker(latlng3).addTo(map);
        var latlng4 = L.latLng(40.577405934958406, -73.83530757095961);
        var mark4 = L.marker(latlng4).addTo(map);

        map.on('click', function (e) {
            console.log("map click: " + e.latlng.lat + "," + e.latlng.lng);
        });
    </script>
perliedman commented 10 years ago

In Leaflet, LatLngs are always latitude and longitudes in degrees, never projected coordinates (which is different compared to for example OpenLayers). So you should not use the projected coordinates when adding for example markers.

If you need to convert a projected coordinate to a LatLng, you can use your projection's project method, and unproject to go the other way around:

var latlng11 = crs.projection.project(L.point(1035546.12, 176231.75));
var projPoint = crs.projection.unproject(L.latLng(40.62685618771871, -73.83524318683413));

I'll close this issue for now!

pkeller3 commented 10 years ago

Thanks so much for your help getting me on the right track. I think you may have transposed the arguments passed to project and unproject because it looks like project expects a latLng and unproject expects a point. This is working for me:

var projPoint = crs.projection.project(L.latLng(40.60450521004777, -73.78384293901497));
var latlng11 = crs.projection.unproject(L.point(1044272, 159587.9999999417));

and I am now able to create a marker using the unprojected latlng.

perliedman commented 10 years ago

Yes, you're absolutely right, I was too quick and mixed up project/unproject.

Great that it's working!