Issue
When I click on the map I want to transform the coordinates to format of 4326. When I do this it seems the Latitude part of the array transforms fine, but the Longitude part is incorrect and not valid.
Code
When I click on the Map, the SingleClick event fires, I then get the coordinates of where the user clicked:
Example of pPointClicked = [-40364190.03366159, 7054830.416117247];
session.Map.on('singleclick', function (e) {
var pPointClicked = e.coordinate;
});
I try and transform these coordinates into 4326 by using the code below:
Example of coord4326 = [-362.59768838343064, 53.38659640004323];
session.Map.on('singleclick', function (e) {
var pPointClicked = e.coordinate;
var coord4326 = ol.proj.transform(pPointClicked, 'EPSG:3857', 'EPSG:4326');
});
As you can see the first value in the transformed variable is -362.59768838343064 which is incorrect? Does anyone know why this is happening.
The transformation seems to be working. Here's what I think is happening: you are not within the "original extent" of your map, i.e. you panned west and wrapped the entire world at least twice.
Try zooming out completely, then pan at the "same" location to the east twice, then click again. You should have the coordinate you're looking for.
Here's an other tip: the world extent, in EPSG:3857, is:
[
-20037508.342789244,
-20037508.342789244,
20037508.342789244,
20037508.342789244
]
[-40364190.03366159, 7054830.416117247] is out of that extent, but if you pan to wrap the world twice, you should get: 289173.348083102, 7054830.416117247], which is within the extent.
Related
My purpose is to display only features that have coordinate inside my map viewport (map area currently displayed).
I get the extent of the viewport by doing:
var mapExtent = this.map.getView().calculateExtent(this.map.getSize());
mapExtent = ol.proj.transformExtent(mapExtent, 'EPSG:3857', 'EPSG:4326');
and after, in a loop where I am reading the element of one store,
var point = ol.proj.fromLonLat([
element.get('longitude'),
element.get('latitude')
]);
elementPoint = new ol.geom.Point(point);
var feature = new ol.Feature(elementPoint);
var coordsFeatures = feature.getGeometry().getCoordinates();
and after, just to quickly see if the point is inside my viewport, I use just a console log:
console.log(ol.extent.containsXY(mapExtent, coordsFeatures[0],coordsFeatures[1]));
/*if(!ol.extent.containsXY(mapExtent, coordsFeatures[0],coordsFeatures[1])){
return true;
}*/
But I don't know why, the result is only false, even if for sure there are points inside the map area currently displayed.
Whart I am doing wrong?
You are mixing projections.
For the extent, you change from 3857 to 4326.
For the point, by applying ol.proj.fromLonLat(), you change from 4326 to 3857 (the default)
Just use 3857 or 4326 for both
So I will post the correct code in case someone else may need it. As mentioned by #GH (thank you again) my problem was the mixing projections, so I changed my code in this way:
instead of using the coordinate, I get the extent of the feature:
var extentFeature = feature.getGeometry().getExtent();
and after i applied to it the same transformExtent used for the map:
extentFeature = ol.proj.transformExtent(extentFeature, 'EPSG:3857', 'EPSG:4326');
if(!ol.extent.containsExtent(mapExtent, extentFeature)){
return true;
}
and now it works! :D
I am using leaflet to show an interactive map to our users.
We want to let them browse through a limited area, and inform them they have to subscribe in case they want to see something too far away (using a pop up or equivalent).
So far I have seen that Leaflet supports a maxBounds option.
This is a good start that lets me prevent users to see larger areas.
Now I would like to be able to detect a maxBounds 'event' to show the user a pop up.
I have been looking into the Leaflet source code, but couldn't find an obvious way to do it.
so far I have found that the maxBounds option is fed into the setView method.
This method itself uses the _limitCenter method to define the center.
This goes a few levels deeper, down to the _getBoundsOffset method that finally uses the bounds.
_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
var projectedMaxBounds = toBounds(
this.project(maxBounds.getNorthEast(), zoom),
this.project(maxBounds.getSouthWest(), zoom)
),
minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
dx = this._rebound(minOffset.x, -maxOffset.x),
dy = this._rebound(minOffset.y, -maxOffset.y);
return new Point(dx, dy);
},
The closest I could find so far would be to hook into the moveend event and check whether the center is out of my bounds manually.
However, it seems like this would be redundant with what leaflet is already doing.
Is there a better to leverage leaflet to achieve this?
Thanks
Just check if your defined bounds contain the map bounds. As long as the map bounds are inside the defined bounds, this will do nothing:
var myBounds = L.latLngBounds(...)
map.on('move moveend zoomend', function(){
if (!myBounds.contains(map.getBounds())) {
// Display popup or whatever
}
});
it seems like this would be redundant with what leaflet is already doing.
Don't worry about that. The overhead is negligible for this use case.
In my app I added a mapquest layer with open layers 3, drawed points and lines...
Now i need to know the pixel coordinates from a long/lat point in the map (visible area) using
map.getPixelFromCoordinate(coordinate).
this function always returns null (testing):
center = map.getView().getCenter();
px = map.getPixelFromCoordinate(center);
alert(JSON.stringify(px));
What i'm doing wrong or what i didn't understand properly?
I found this answer:
I'd be careful with this. You might get wrong results, e.g. when the map does not have the final layout yet. It is better to wait with the first coordinate to pixel conversion until the map is rendered. You do not need a timeout for this, we have the 'postrender' event on ol.Map. So in your initialisation code, you could do something like this:
map.once('postrender', function() {
// safe to call map.getPixelFromCoordinate from now on
});
Source: github.com/openlayers/ol3/issues/5456
I hope this helps.
This question is related to these two:
Cesium how to scale a polygon to match Lat-Lon positions while zoom-in/zoom-out
Cesium - using camera to scale a polygon to match Lat-Lon positions while zoom-in/zoom-out
The sample code I am following to get lat-lon-alt positions from the camera is located in the gold standard that appears to be baked into the existing camera controller. With this code I can retrieve lat-lon-alt positions from the distance of the camera to get values that are almost exact to the original lat-lon position selected and a height above the surface of the earth. Perfect!
All examples and documentation show polygon creation using degrees or points from degrees.
Now what? Maybe I'm missing something but the intent I thought was to be able to create the polygon using specific x, y, z coordinates so the polygon would "stick" to the top of my house on zoom-in, zoom-out, and camera movement. Now that I have those values, what is the secret to drawing the polygon with those values?
FYI, these are the value I currently have:
=========================NEW INFORMATION===========================
The code for the redPolygon works:
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
-115.0, 32.0,
-102.0, 31.0,
-102.0, 35.0,
-102.0, 35.0]),
material : Cesium.Color.RED
}
});
viewer.flyTo(redPolygon);
The code for the bluePolygon does not work:
var bluePolygon = viewer.entities.add({
name : 'Blue polygon on surface',
polygon : {
//hierarchy: collection.latlonalt,
hierarchy: Cesium.Cartesian3.fromArray(collection.latlonalt),
material : Cesium.Color.BLUE
}
});
viewer.flyTo(bluePolygon);
If I use hierarchy: collection.latlonalt, I receive the following error:
So I changed the code to hierarchy: Cesium.Cartesian3.fromArray(collection.latlonalt), where collection.latlonalt is my Cartesian3 array:
But nothing gets drawn. No errors. This is what I see in the console:
Just for test, I tried adding a z position to the redPolygon and changing .fromDegreesArray to .fromArray like this:
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : Cesium.Cartesian3.fromArray([-115.0, 37.0, 10.0,
-115.0, 32.0, 10.0,
-102.0, 31.0, 10.0,
-102.0, 35.0, 10.0,
-102.0, 35.0, 10.0]),
material : Cesium.Color.RED
}
});
viewer.flyTo(redPolygon);
That didn't work either.
Cesium has helper functions like Cartesian3.fromDegreesArray that are used by the Polygon Demo, but, these helper functions are not needed now that you've got your hands on actual Cartesian3 values.
For example, the polygon demo code looks like this:
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
-115.0, 32.0,
-107.0, 33.0,
-102.0, 31.0,
-102.0, 35.0]),
material : Cesium.Color.RED
}
});
In the above code, fromDegreesArray in this case just takes a list of 5 lot/lan value pairs, and converts them into a JavaScript array of 5 instances of the Cartesian3 class. This array of 5 Cartesian3s is then stored as the value of hierarchy in the polygon definition. If you inspect that definition at runtime, you'll find the original lon/lat values have been discarded, replaced by the actual Cartesian3s, thanks to the helper function.
So in your code, you'll need an array of Cartesian3s that the user has clicked on thus far. This starts as the empty array, and you'll need to gather at least three clicks, converting each click into a Cartesian3 as you've shown works in your question above, and push that value into the array. Once the array has accumulated 3 or more clicks, you can then pass that array as the hierarchy field of the polygon definition.
In this manner, you've avoided calling fromDegreesArray because your click handler is doing the more detailed work of gathering an exact Cartesian position per click. This gathering has to happen at the time of each click, in case the camera is moved between clicks. So, the array "in progress" has to survive between clicks, until all the clicks have been gathered and a polygon can be created.
EDIT: Here's an example of the code structure I'm trying to describe. I don't show the actual click handlers here, since you seem to have Cartesian3 values coming out of your mouse clicks already. Instead, I show three such values being used to create a polygon.
var viewer = new Cesium.Viewer('cesiumContainer');
// Create an empty array of click positions at the start.
var clickPositions = [];
// When the first mouse click is received, convert to Cartesian3, and push it into the array.
var click1 = new Cesium.Cartesian3(-2155350.2, -4622163.4, 3817393.1);
clickPositions.push(click1);
// Later, more mouse clicks are received and pushed into the array.
var click2 = new Cesium.Cartesian3(-2288079.8, -4906803.1, 3360431.4);
clickPositions.push(click2);
var click3 = new Cesium.Cartesian3(-1087466.8, -5116129.4, 3637866.9);
clickPositions.push(click3);
// Finally, draw the polygon.
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : clickPositions,
material : Cesium.Color.RED
}
});
Notice nothing happens to clickPositions when it's assigned to hierarchy. The array of Cartesian3 values is already in the form needed by Cesium here.
I have a map with a dragable point and after drag, I update latitude and longitude fields in the form. But when I do that like this:
drag = new OpenLayers.Control.DragFeature(vectors, {
autoActivate: true,
onComplete: function() {
$('#place_latitude').val(point.transform(mapp, wgs84).y);
return $('#place_longitude').val(point.transform(mapp, wgs84).x);
}
});
After attempt to make second drag (from one point to another) point goes to 0,0. Without onComplete everything is ok.
You are transforming the point two times... transform method modifies point itself, it doesn't create new object.
You may use point.clone() instead of point.