Projection of Geodesic line and a turf polygon onto leaflet - leaflet

I am using leaflet and turf.js to determine if a line passes through a polygon using turf.booleanIntersects(). I have the code working but with one slight inconsistency. The line in the attached image according to turf.booleanIntersects() passes through both of the polygons in the image, but the line drawn on map doesn't actually pass through the both polygons according to the image. Is the image incorrect (if so how can I fix it?) or does the line not actually go through the top polygon. Is it the projection inconsistency of a Geodesic line and geoJson turf polygon onto leaflet map?
Thank you
A snippet of important bit of my code
LayerGroup = L.layerGroup().addTo(mymap);
var line = new L.Geodesic([[point1, point2]], geodesicOptions).addTo(LayerGroup);
LinesList.push(line);
var line = turf.lineString([
[LinesList[i].points[0][0].lng, LinesList[i].points[0][0].lat],
[LinesList[i].points[0][1].lng, LinesList[i].points[0][1].lat]
]);
//multiple points make up polygonlines array
var point= [end.lng, end.lat];
polygonlines.push(point);
var geojsonPolygon =
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [polygonlines]
}
}
var turfpolygon = turf.polygon(geojsonPolygon.geometry.coordinates);
if (turf.booleanIntersects(line, turfpolygon) == true) {
const p2 = L.geoJSON(turfpolygon).addTo(mymap);
}

Related

Show geojson featureCollection with Leaflet

with QGIS I´ve exported a polygon layer as geojson which I´d like to publish with leaflet. This is how the geojson looks like [exluded due to SO character limits]:
https://gist.github.com/t-book/88806d12d7f05024b147715be82e6844
This is what I´ve tried:
Wrapped geojson as var:
var states = [{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::31468" } },
"features": [
{ "type": "Feature", "properties": ...
}];
Added as new Layer:
L.geoJSON(states, {
style: function(feature) {
switch (feature.properties.party) {
case 'Euerbach': return {color: "#ff0000"};
case 'Werneck': return {color: "#0000ff"};
}
}
}).addTo(map);
Unfortunately nothing is rendered. How do I correctly add this geojson featureCollection to my map?
The problem is that your data is projected - Leaflet is expecting your data to be unprojected (composed of long/lat pairs, or "projected" in WGS84/EPSG 4326). There are a few solutions, two come to mind here:
In QGIS, export your data so that it is composed of long/lat coordinate pairs
Use proj4.js to reproject your coordinates when displaying the geojson.
For number two, you'll need to set the coordsToLatLng option when adding the geojson as a layer:
var geojson = L.geoJSON(states, {
coordsToLatLng: function (p) {
// return get lat/lng point here.
})
The body of this function will take a coordinate in the geojson's coordinate reference system (CRS) and return it in WGS84 using proj4.
Also, coordsToLatLng function expects you to return lat/long pairs. As your geojson and proj4 represent data that is [x,y], we need to swap our values before returning the new point.
This could look like:
var geojson = L.geoJSON(states, {
coordsToLatLng: function (p) {
p = proj4(fromProjection,toProjection,p); // reproject each point
p = [p[1],p[0]] // swap the values
return p; // return the lat/lng pair
}
}).addTo(map);
Of course, we need to define our CRSs. I looked up your CRS (it is specified in the geojson itself) on spatialreference.org and used the provided description for that CRS and EPSG4326 (WGS84) to set my fromProjection and toPojection:
var fromProjection = '+proj=tmerc +lat_0=0 +lon_0=12 +k=1 +x_0=4500000 +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs ';
var toProjection = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ";
Altogether that gives us something like this.
Keep in mind, that if you have large files, reprojecting them in javascript will take longer than if you export them in the proper CRS.

Mapbox GL JS: zoom to filtered polygon?

I am using Mapbox GL JS to display a polygon layer. I would to allow the user to choose a name from a dropdown, and then highlight and zoom to the matching polygon.
I already know how to highlight the matching polygon using map.setFilter, but I don't know how to zoom to the bounds of the matching polygon. This is my current code:
map.addLayer({
'id': 'polygon_hover',
'source': 'mysource',
'source-layer': 'mylayer',
'type': 'fill',
'paint': {
'fill-color': 'red',
"fill-opacity": 0.6
},
"filter": ["==", 'CUSTNAME', ""]
});
// Get details from dropdown
custname.on("change", function(e) {
// get details of name from select event
map.setFilter('polygon_hover', ["==", 'CUSTNAME', name]);
// Get bounds of filtered polygon somehow?
// var bounds = ??;
// map.fitBounds(bounds);
});
I have examined the Mapbox example of zooming to bounds, but it assumes that you already know what the bounds are.
Is there any way it's possible to get the bounds of the polygon matching a map filter in Mapbox?
I've the following code to fitBounds to Polygon center coords:
var coordinates = f.geometry.coordinates[0];
var bounds = coordinates.reduce(function (bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 20
});
Where f is one Feature.
I found a solution to your problem. Leaflet has a polygon Class which takes an Array of polygon coordinates and has a function called getBounds() that returns south west and north east bounds. However, Leaflet doesn't follow the convention of LngLat, its format is LatLng. Therefore, you have to switch it. I took an example out from Mapbox Show drawn polygon area, and added exactly what you're looking for.
var polygon = data.features[0].geometry.coordinates;
var fit = new L.Polygon(polygon).getBounds();
var southWest = new mapboxgl.LngLat(fit['_southWest']['lat'], fit['_southWest']['lng']);
var northEast = new mapboxgl.LngLat(fit['_northEast']['lat'], fit['_northEast']['lng']);
var center = new mapboxgl.LngLatBounds(southWest, northEast).getCenter();
// map.flyTo({center: center, zoom: 10});
map.fitBounds(new mapboxgl.LngLatBounds(southWest, northEast));
I see that the question is still relevant - I solved it making a separate request to the database containing all points of a given polygon and building bounds [[minLng, minLat], [maxLng, maxLat]].
All attempts to address geometry of already rendered or source features didn't work for me - most probably because Mapbox doesn't keep initial geoJSON in the tiles.

add image to rect polygon in leaflet

Here is the working JSFiddle
what I need is to add image to rect polygon and also don't want it to repeat itself as when zooming in or out and want it to be fixed. any suggestions will be appreciated and if there is any other way to achieve so.
If it can be placed in geojson that will be great as I have to give some properties to each polygon. And create all the rect polygon dynamically.
code is below
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib});
var map = new L.Map('map', {layers: [osm], center: new L.LatLng(24, 121), zoom: 9});
var states = [{
"type": "Feature",
"properties": {"party": "Republican"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-104.05, 48.99],
[-96.58, 45.94],
[-104.03, 45.94],
[-104.05, 48.99]
]]
}
}, {
"type": "Feature",
"properties": {"party": "Democrat"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}];
var poly1 = [
[24, 121],
[24.5, 121],
[24.5, 121.9],
[24, 121.9]
];
L.polygon(poly1, {fill:'url(http://i.imgur.com/ktPFJKC.jpg)'}).addTo(map);
L.geoJson(states, {
style: function(feature) {
switch (feature.properties.party) {
case 'Republican': return {color:'#ff0000'};
case 'Democrat': return {color: "#0000ff"};
}
}
}).addTo(map);
The best thing to do here is use an ImageOverlay, which is designed for precisely this case. You can use the coordinates of your polygon object to create both the image overlay and an invisible GeoJSON layer that sits on top of it. If you are dynamically creating the polygon objects in the same format as your example poly1, then you can reference the indices of the corner points like this when creating the image overlay:
var imageUrl = 'http://i.imgur.com/ktPFJKC.jpg';
var imageBounds = L.latLngBounds([
poly1[0],
poly1[2]
]);
var imageLayer = L.imageOverlay(imageUrl, imageBounds).addTo(map).bringToBack();
The .bringToBack may be unnecessary if you always create the image before the GeoJSON polygon, but it does ensure that the image overlay doesn't interfere with other layer interactions. You can create a temporary GeoJSON object from the polygon object using .toGeoJSON, and set any GeoJSON properties you like:
var polyTemp = L.polygon(poly1).toGeoJSON();
polyTemp.properties.name = 'pineapple';
Then create an invisible L.GeoJSON layer to handle the interactions:
var boxOptions = {fillOpacity:0, opacity:0, onEachFeature: onEachBox};
var imageBox = L.geoJson(polyTemp, boxOptions).addTo(map);
function onEachBox(feature, layer) {
layer.bindPopup("Hello, I'm a " + polyTemp.properties.name);
}
The onEachBox function here is of course just an example to illustrate that you can access the GeoJSON properties. Here is an updated fiddle:
https://jsfiddle.net/17Ld98fv/

Difference between leaflet Marker and mapbox featureLayer

I understood that I can use the general Leaflet layer, and the more advanced map-box featureLayer, that provides useful functions as the filter.
However, I don't understand the difference between
marker = L.Marker (new L.LatLng(lat, lng),
{
icon: L.mapbox.marker.icon(
{'marker-color': 'fc4353'
'marker-size': 'large'
}),
title: name,
});
map.addLayer(marker);
and
var poijson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [lng, lat]
},
"properties": {
"title": poi.name,
"marker-color": "#fc4353",
"marker-size": "large"
}
};
map.featureLayer.setGeoJSON(geojson);
Is it just the same?
[UPDATE]
Moreover, if I had many markers, should I add a new layer for each marker? It seems not a good thing for performance..
For instance, If I do:
var pois; //loaded with pois info
var geojson=[]; //will contain geojson data
for (p=0; p< pois.length; p++)
{
var poi = pois[p];
var poijson =
{
"type": "Feature",
"geometry":
{
"type": "Point",
"coordinates": [poi.lng, poi.lat]
}
};
geojson.push(poijson);
}
map.featureLayer.setGeoJSON(geojson);
Does it will create many layers for each poi, or just one layer with all the markers?
thank you
When you add a marker to a Leaflet map via map.addLayer(marker);, the marker is added to the 'leaflet-maker-pane'. The markers are plain images/icons.
You can use a geoJSON layer to draw GIS features: points, lines, polygons, etc.
See here: http://leafletjs.com/examples/geojson.html
Mapbox's featureLayers is just an extension to Leaflet's geoJSONLayer
To add multiple markers, call addMarker multiple times. Leaflet will create a new layer for each of the markers. Each marker will be added as an image element to the leaflet-marker-pane div:
http://bl.ocks.org/d3noob/9150014
Updated response:
If you add a GeoJSON layer with multiple features, Leaflet will create separate layer for each of the features. You can inspect the layers of the map by calling map._layers after adding the GeoJSON Layer.
marker.addTo(map) and map.addLayer(marker) are doing the same thing.
Here's the addTo function taken from the source
addTo: function (map) {
map.addLayer(this);
return this;
},

Start-Marker from geojson polyline

i have a map with some walking- and bike-routes and popups with a few details an a pic. Now i want to set a marker on the first vertex of a geojson polyline, but i cant find out how. Btw. i´m new to leaflet/mapbox, and i put my map togehter from code snippets.
Here is the map now:
This is how i create the polylines now. I call them via layercontrol.
var mtb = L.geoJson(radjs, {
filter: function (feature, layer) {
if (feature.properties) {
// If the property "underConstruction" exists and is true, return false (don't render features under construction)
return feature.properties.typ === 'mtb';
}
return true;
},
style: {
"color": '#6699cc',
dashArray: '',
"weight": 4,
"opacity": 0.6
}, onEachFeature: onEachFeature2}).addTo(rad);
Thank you for your help,
Marc
You could just add a Feature to your geojson with the latitude and longitude like the do it in the Leaflet GeoJSON Example.
Probably it will be more convenient to read the geometry.coordinates from geojson features and define a new marker.
Beside you have an error on line 569. You should change:
var map = L.mapbox.map('map','',{
to:
var map = L.mapbox.map('map',null,{
Create a simple marker object and add it to the map.
marker = L.marker([0, 0], {
icon: L.mapbox.marker.icon()
}).addTo(map)
Then set the latitude and longitude to the first coordinates of your geoJSON. Assuming your geoJSON is set to the var geojson, you can access the coordinates by indexing into the array.
marker.setLatLng(L.latLng(
geojson.coordinates[0][1],
geojson.coordinates[0][0]))