I have an image 8640x11520 pixels from a part of the map in real scale. I need convert my x, y point to coordinate, anyone has an idea to find out it??
var mapWidth = 8640;
var mapHeight = 11520;
var mapLatitudeStart = 28.349768989955244;
var mapLongitudeStart = -81.55803680419922;
var maxLatitude = 28.349806758250104;
var maxLongitude = -81.541128;
var pointNeedConversion = {'x': 4813.10 'y': 2674.84};
var pointLatitude = ??
As you are mapping to lat/long, beware, you can't do that with a linear proportion, instead you have to check what kind of projection is applied to the map, then convert coordinates accordingly.
Usually maps are WGS84 Projections so you have to apply the inverse formulas for the Mercator projection.
The task is not trivial so my advice is to rely on libraries like Proj4js
The usage of the library is simple, you provide a reference system to work on, then you can trasform coordinates on another projection.
// include the library
<script src="lib/proj4js-combined.js"></script> //adjust the path for your server
//or else use the compressed version
// creating source and destination Proj4js objects
// once initialized, these may be re-used as often as needed
var source = new Proj4js.Proj('EPSG:4326'); //source coordinates will be in Longitude/Latitude, WGS84
var dest = new Proj4js.Proj('EPSG:3785'); //destination coordinates in meters, global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/
// transforming point coordinates
var p = new Proj4js.Point(-76.0,45.0); //any object will do as long as it has 'x' and 'y' properties
Proj4js.transform(source, dest, p); //do the transformation. x and y are modified in place
//p.x and p.y are now EPSG:3785 in meters
Credit for the snippet: Convert long/lat to pixel x/y on a given picture
Working example:
var dest = new proj4.Proj('EPSG:4326'); //destination coordinates coordinates will be in Longitude/Latitude, WGS84 , global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/
var source = new proj4.Proj('EPSG:3785'); //source coordinates in meters
$("#convert").on("click", function(){
var p = new proj4.Point($("#x").val(), $("#y").val() );
proj4.transform(source, dest, p);
alert("lng : " +p.x + " \nlat : " + p.y);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.3/proj4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
x : <input type="number" id="x" />
y : <input type="number" id="y" />
<button id="convert">Convert</button>
Note: it is essential to know what is the lat/lon of the corner of your map if you intend to use it to map a GPS signal.
Here a graph example that visually explains why a linear proportion is not suitable:
Take a close look to (Eg) the size of the Greenland, on mercator projection space coordinates it looks bigger than north America. Of course it is not!
Related
I have a situation where I'm using Cesium.js entities to draw bearing lines from a point. In addition, I'd like to have a label attached to these bearing lines on the entity to show what it is. This is easy enough to do by attaching a label to the polyline entity. So far what I'm doing is creating a "really long" line along the bearing from the reference point and using the midpoint along that line as an anchor for the label (in Typescript):
let newEntity : Cesium.Entity;
let gccalc : gc.GreatCircle = new gc.GreatCircle();
let bearing : number = 45.0; //Bearing for the line
//this.currentPos is the lat/lon for the reference point for our bearing line
//gccalc is a simple class for computing great circle lines and has been omitted here (it is not relevant to the problem)
let destination = gccalc.destination(this.currentPos[0], this.currentPos[1], bearing, 1500, 'MI');
let anchorLabel = gccalc.destination(this.currentPos[0], this.currentPos[1], bearing, 50, 'MI');
const lineMat = new Cesium.PolylineDashMaterialProperty({
color : this.typeColorMap.get(contact.type)
});
const poses = Cesium.Cartesian3.fromDegreesArrayHeights([this.currentPos[1], this.currentPos[0], 500,
destination[1], destination[0], 500]); //500 is an arbitrary altitude for aesthetics
const nameString : string = "StringLabel";
let lineLabel = {
text: nameString,
font: '16px Helvetica',
fillColor : this.typeColorMap.get(contact.type),
outlineColor : Cesium.Color.BLACK,
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.MIDDLE,
horizontalOrigin : Cesium.HorizontalOrigin.MIDDLE,
pixelOffset : new Cesium.Cartesian2(20, 0),
//pixelOffsetScaleByDistance : new Cesium.NearFarScalar(1.5e-1, 30.0, 1.5e7, 0.5)
};
let bearingLine = new Cesium.PolylineGraphics();
bearingLine.positions = poses;
bearingLine.width = 4;
bearingLine.material = lineMat;
bearingLine.arcType = Cesium.ArcType.NONE;
const lineEntity = {
name : 'Bearing Line',
polyline : bearingLine,
position : Cesium.Cartesian3.fromDegrees(anchorLabel[1], anchorLabel[0]),
show : true,
label : new Cesium.LabelGraphics(
lineLabel,
) as Cesium.LabelGraphics,
};
newEntity = new Cesium.Entity(lineEntity);
But the problem is the label is in geodesic (lat/lon) coordinates and does not stay on the screen as the user zooms in and out on the bearing line. So I also attempted to scale the position using the pixelOffsetScaleByDistance property, but this also doesn't work very well, and doesn't keep the label near the line
under 3d rotations (because the X and Y scaling would technically have to change).
It seems what I really need are the screen-space positions of the line endpoints, and a way to create the entity label at that midpoint. Is there a way to do this? If not, what is the best way to ensure that my label is always near my polyline regardless of user interactions with the Cesium map (such as zooms and rotations)?
To give an idea of what I'm trying to do, here's a screencap of Cesium with the labels as implemented. They look correct here, but only because I've made sure the zoom level and rotation is correct:
I have to draw a polygon on openlayers Map. This is my code:
draw = new Draw({
source: this.vectorSource,
type: 'Polygon'
})
draw.on('drawend', e => {
// sol 1, result is not as required
let coords = e.feature.getGeometry().getCoordinates()
//sol 2, give correct results, but drawn polygon gone
let coords = e..feature.getGeometry().transform('EPSG:3857', 'EPSG:4326').getCoordinates()
}
this.olmap.addInteraction(draw)
I have to store the transformed coordinates in DB, but solution #2 does not maintain the visibility of drawn poloygon.
In case of solution #1, it does not gives the required formated coordinates, if I try to transform them later using
transform(coords, 'EPSG:3857', 'EPSG:4326')
it does not return formated coordinates.
please guide me where i am wrong to maintain the visibility of polygon and get the transformed coordinates.
You need to clone the geometry
let coords = e..feature.getGeometry().clone().transform('EPSG:3857', 'EPSG:4326').getCoordinates();
otherwise you wil move the feature somewhere close to point [0, 0] in view cooordinates
I'm trying to find a way to specify a lat and long and retrieve a close up image. The code below allows me to enter a lat and long but the image is very blurry. Is there a simple way to get a higher resolution image?
My main issue is specifying the zoom level and I haven't found any examples of people retrieving close up images.
var image = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_044034_20140318').select(['B4','B3','B2']);
// Create a circle with buffer around a point.
var roi = ee.Geometry.Point([-122.4481, 37.7599]).buffer(3000);
Map.centerObject(image, 15)
var a = image.getThumbURL({
image: image,
region:roi.getInfo()
});
//print URL
print(a);
You can add a dimensions parameter to the .getThumbURL() that will define the number of pixels in the output image. Here is the your example with a 2000x2000 output thumb:
var image = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_044034_20140318').select(['B4','B3','B2']);
// Create a circle with buffer around a point.
var roi = ee.Geometry.Point([-122.4481, 37.7599]).buffer(3000);
Map.centerObject(image, 15)
var a = image.getThumbURL({
image: image,
dimensions:[2000,2000], // specify output thumb size here
region:roi.getInfo()
});
//print URL
print(a);
If you just want to see an image on the map (as displayed), you can do it using the UI facilities.
like:
var textbox = ui.Textbox({
placeholder: 'Point coordinates: long, lat',
onChange: function(text) {
var splitStr = text.split(",");
var lon = parseFloat(splitStr[0]);
var lat = parseFloat(splitStr[1]);
var p = ee.Geometry.Point(lon, lat);
Map.addLayer(p);
Map.centerObject(p, 12);
}
});
print(textbox);
This code will move the map to the given point coordinates and draw it.
I have a set of coordinates that I want to use them to draw a polygon with OpenLayers. The coordinates are the following:
[["50.12345","30.12345"],["40.12345","20.12345"],["60.12345","10.12345"],["70.12345","90.12345"]]
How can I draw a polygon with those coordinates? I'm trying the following but it doesn't seem to work:
var coords = "[["50.12345","30.12345"],["40.12345","20.12345"],["60.12345","10.12345"],["70.12345","90.12345"]]";
var polygon = new ol.geom.Polygon([coords]);
polygon.transform('ESPG:4326','ESPG:3857');
var feature = new ol.feature(polygon);
var vectorSource = new ol.source.Vector({});
vectorSource.addFeature(feature);
layer = new ol.layer.Vector({
source: vectorSource});
map.addLayer(layer);
Any ideas? Thanks!
// instead of this - a string
var coords = "[["50.12345","30.12345"],["40.12345","20.12345"],["60.12345","10.12345"],["70.12345","90.12345"]]";
// change to an array of arrays - remove the beginning quotes
var coords = [["50.12345","30.12345"],["40.12345","20.12345"],["60.12345","10.12345"],["70.12345","90.12345"]];
// and then you have to convert these string coordinates to number type
coords.map(function(coord){
return [parseFloat(coord[0]), parseFloat(coord[1])];
});
Proceed with the remainder - note that ol.Feature is written with capital letter.
I have 2 OpenLayers.LonLat objects, and I want to determine the distance in pixels for the current zoom between the 2. I'm using OpenLayers.Layer.getViewPortPxFromLonLat() to determine the x and y of the points and then subtract to see the difference between the 2, but the values that I get are very small for points that are 2000km apart.
Here is my code:
var center_lonlat = new OpenLayers.LonLat(geometry.lon, geometry.lat);
var center_px = layer.getViewPortPxFromLonLat(center_lonlat);
var radius_m = parseFloat(feature.attributes["radius"]);
var radius_lonlat = OpenLayers.Util.destinationVincenty(center_lonlat, 0, radius_m);
var radius_px = layer.getViewPortPxFromLonLat(radius_lonlat);
var radius = radius_px.y - center_px.y;
I'm trying here to draw a circle, giving that I receive a center point and a radius in meters. The LonLat object seems to be ok.
Am I doing something wrong ?
I found the issue: destinationVincenty() need and returns coordinates in wgs84 where my map was using spherical mercator projection.
I hope I got correctly the answer, because projections make me dizzy and never really understood them :(. I was looking in the console to the numbers for my coordinates and the coordinates from the map.getExtent() that is used to calculate the getViewPortPxFromLonLat() and I realised they are not in the right order of magnitude, and then it hit me.
So, the code is now:
var spherical_mercator = new OpenLayers.Projection("EPSG:900913");
var wgs84 = new OpenLayers.Projection("EPSG:4326");
var map = feature.layer.map;
var geometry = feature.geometry;
var center_lonlat = new OpenLayers.LonLat(geometry.y, geometry.x);
var center_px = map.getViewPortPxFromLonLat(center_lonlat);
var radius_m = parseFloat(feature.attributes["radius"]);
var radius_lonlat = OpenLayers.Util.destinationVincenty(center_lonlat.clone().transform(spherical_mercator, wgs84), 0, radius_m).transform(wgs84, spherical_mercator);
var radius_px = map.getViewPortPxFromLonLat(radius_lonlat);
var radius = Math.abs(radius_px.y - center_px.y);
Measured the circles with the OpenLayers.Control.ScaleLine, and the size is dead on :D
You seem to be doing right. If the distance you get is too small, maybe there is a problem with OpenLayers.Util.destinationVincenty function? Have you tried to replace the bearing (0) with anything else - its value seem to be not important in your case. But frankly speaking, I wasn't able to understand how it works while browsing the source