how to get the ray of a circle in meters using getRadius() - openlayers-3

the method getRadius() of class ol.geom.Circle returns the radius of a circle ;
how can I convert this value into meters ?
I draw a circle on a map using a particular projection (e.g Spherical Mercator, LambertIIe, etc.)
then I convert this geometry into degree to process further treatments such as testing if a point (in degrees) is inside this circle
so getting the radius always in the same unit (meter) from a geometry in degree would be useful
thanks in advance
Jean-Marie

You can use the ol.proj.METERS_PER_UNIT table to get the radius in meters:
var units = map.getView().getProjection().getUnits();
var radiusM = circle.getRadius() * ol.proj.METERS_PER_UNIT[units];

I use the following method to get the radius (getFirstCoordinate referring to the center and getLastCoordinate referring to a point on the perimeter) :
var wgs84Sphere = new ol.Sphere(6378137);
var center=circle.getFirstCoordinate();
var ray=getDistance(center[0],center[1],circle.getLastCoordinate()[0],circle.getLastCoordinate()[1]);
// getDistance returns the distance between 2 points (source : http://openlayers.org/en/v3.7.0/examples/measure.html)
function getDistance(long1,lat1,long2,lat2) {
var c1 = [long1,lat1];
var c2 = [long2,lat2];
return wgs84Sphere.haversineDistance(c1,c2);
}

Related

Calculate area using simd_float3

Im using the new RoomPlanner API from iOS 16, and the idea is to calculate every wall area in meters, or at least the widht and height. Is there a way o calculate that using the object
CapturedRoom.Walls ?
Heres the object that im supposed to use;
https://developer.apple.com/documentation/accelerate/simd_float3
Just iterate through CapturedRoom.Walls.
let walls = capturedRoom.walls
var totalWallArea: Float = 0
for wall in walls {
let wallArea = wall.plane.width * wall.plane.height
totalWallArea += wallArea
}
print("Total wall area: \(totalWallArea) square meters")

Calculate coordinates of map square from map center

I want to get the coordinates of the corners of the rectangle. Or to find the coordinate of the north-westest most point, 50 km from the map centre.
Does anyone know how I can do that?
The point is when I move around the map, I want to always have a rectangle(the rectangle does not need to drew, I just need its coordinates for a backend request), with it's corners always at 50 km from the current centre of the map.
I'm thinking of using somehow the distance function from CLLocation, but in this case I have the distance, but not one of the coordinates.
50km = mapCenterLocation.distance(from: coordinatesUnknown)
Not really sure what do you mean, but maybe this can help
func getNewTargetCoordinate(position: CLLocationCoordinate2D, userBearing: Float, distance: Float)-> CLLocationCoordinate2D{
//haversine formula
//r is earth radius
let r = 6378140.0
let latitude1 = position.latitude * (Double.pi/180);
let longitude1 = position.longitude * (Double.pi/180);
//bearing for user heading in degree
let brng = Double(userBearing) * (Double.pi/180);
//calculating user new position based on user distance and bearing can be seen at haversine formula
var latitude2 = asin(sin(latitude1)*cos(Double(distance)/r) + cos(latitude1)*sin(Double(distance)/r)*cos(brng));
var longitude2 = longitude1 + atan2(sin(brng)*sin(Double(distance)/r)*cos(latitude1),cos(Double(distance)/r)-sin(latitude1)*sin(latitude2));
//converting latitude as degree
latitude2 = latitude2 * (180/Double.pi)
longitude2 = longitude2 * (180/Double.pi)
// return location of user
return CLLocationCoordinate2DMake(latitude2, longitude2)
}
This work for NE direction and distance in meters
for the north-west direction, I think you can just put 135 for the degree and 5000 for distance.
For the position, you need to put map center location.
edit:
For custom rectangle., you can first check for the diagonal degree
func getDiagonalDegree(x: Float, y:Float) -> Float{
return atan2(y,x)*(180/Double.pi)
}
So now you can get that returned diagonal degree to and put it in getNewTargetCoordinate. New bearing is 270+diagonalDegree.
Not sure if I understand you correctly, but I think this could help, or at least point you on some direction
CLLocationCoordinate2D northWest;
northWest = [mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:mapView];
With this you will get the coordinates for the top left corner of the map, I think you just need to adjust this to set a point 50 km of your center and get the coordinate with this same logic.

Draw a circle with defined diameter in OpenLayers

I'm trying to write a code which let my users define some points on the map and once they created a point, the program should draw a circle with defined diameter(in kilometers or ... ) around the point.
I can draw a point but I don't know how I could handle what I said.
Here is an example about what I want:
Use the following function to create circular points around a point.
//pass the
//#pointX,
//#pointY,
//#radius of circle (in your case diameter/2)
//#pointsToFind this is how detail you want the circle to be (360 if you want one point for each rad)
function createCirclePointCoords(circleCenterX,circleCenterY,circleRadius,pointsToFind){
var angleToAdd = 360/pointsToFind;
var coords = [];
var angle = 0;
for (var i=0;i<pointsToFind;i++){
angle = angle+angleToAdd;
console.log(angle);
var coordX = circleCenterX + circleRadius * Math.cos(angle*Math.PI/180);
var coordY = circleCenterY + circleRadius * Math.sin(angle*Math.PI/180);
coords.push([coordX,coordY]);
}
return coords;
}
And then create a polygon out of the coordinates returned from the function
var circleCoords = createCirclePointCoords(0,0,1000,360);
var geom = new ol.geom.Polygon([
circleCoords
])

openlayers ol3 linestring getLength not returning expected value

I am using getLength to retrieve the linestring length.
For the same segment:
1- when using google map measure tool, I get 228m
2- when using IGN geoportail measure tool, I get 228m
3- when I use e.feature.getGeometry().getLength() I get 330m
Here are the flat coordinates:
e.feature.getGeometry().getFlatCoordinates() :
[571382.4214041593, 5723486.068714521, 571593.8175605105, 5723741.65502785]
in 4326:
[5.132815622245775, 45.644023326845485, 5.134714626228319, 45.64562844964627]
When I check the coordinates position on either ol3 or google map, I get the same points. The difference must come from the calcul...
Did I miss something and I should not use the getLength method? Please give me some direction if you think this is not an issue.
geometry.getLength() returns the length in the map view projection, which is usually spherical mercator. Spherical mercator distances are stretched at a rate of 1/cos(latitude); in your example: 228/330 ~ cos(45.64).
To get the real spherical distance:
var geometry = feature.getGeometry();
alert (geometry.getLength());
// get points of geometry (for simplicity assume 2 points)
var coordinates = geometry.getCoordinates();
// transform points from map projection (usually spherical mercator) to WGS84
var mapProjection = map.getView().getProjection();
var t1 = ol.proj.transform(coordinates[0], mapProjection, 'EPSG:4326');
var t2 = ol.proj.transform(coordinates[1], mapProjection, 'EPSG:4326');
// create sphere to measure on
var wgs84sphere = new ol.Sphere(6378137); // one of WGS84 earth radius'
// get distance on sphere
var dist = wgs84sphere.haversineDistance(t1, t2);
alert (dist);
For even higher accuracy you have to measure on the WGS84 ellipsoid instead of the sphere.
The above answer is correct, allthough if you are trying to get the length of a LinePoint with several positions it will only calculate between the first ones.
Here is a small addition on working with LinePoints with several positions:
var geometry = feature.getGeometry();
// get points of geometry (for simplicity assume 2 points)
var coordinates = geometry.getCoordinates();
// transform points from map projection (usually spherical mercator) to WGS84
var mapProjection = map.getView().getProjection();
// create sphere to measure on
var wgs84sphere = new ol.Sphere(6378137); // one of WGS84 earth radius'
var dist = 0;
//loop through all coordinates
for(var i = 0; i < coordinates.length -1; i++) {
var t1 = ol.proj.transform(coordinates[i], mapProjection, 'EPSG:4326');
var t2 = ol.proj.transform(coordinates[i+1], mapProjection, 'EPSG:4326');
// get distance on sphere
dist += wgs84sphere.haversineDistance(t1, t2);
}
alert(dist);

Best practice for using lat/long within a UIView (not MKMapView)

Basically i have a list of POI's (name,lat,long) and i want to draw them on the UIView, relative to my current lat/long. I'm looking for some best practice for mapping these POI (lat/long) to a UIView.
I don't want to use MKMapView (no need for displaying map-data).
I was reading:
http://developer.apple.com/library/ios/#documentation/general/conceptual/Devpedia-CocoaApp/CoordinateSystem.html
But I'm clueless how i get from a CLLocation to a (x,y) on my UIView. I only want to draw those POI's around my current location. So, for example if my screen would represent a 20 by 30 KM region, how do i map my POI's to their corresponding (x,y) coordinates?
Thanks.
What you're doing is a little strange, but you can convert latitude/longitude to a CGPoint-like struct called an MKMapPoint. An MKMapPoint has an x and y value which correspond to points on a map. Imagine if you laid out a flat map of the world, and 0,0 was the top left. MKMapPoint is a point on that map using that coordinate system.
Use the function MKMapPointForCoordinate() to convert a CLLocationCoordinate2D to an MKMapPoint
MKMapPoint myMapPoint = MKMapPointForCoordinate(myLocationCoordinate);
When you get the list of points, you'll have to do something like finding the max and min x and y values, then fitting all the points into your view using those values, otherwise you'll end up with a load of very close points in one place in your view.
My guess is that, for a 20KM by 30KM region, you can consider the earth to be flat and there fore linearly extrapolate the coordinates. I am sure you can google and find out as to how much distance is a difference in 0.00001 in latitude and longitude.
So if you have 20Km to be represented on X axis, and your current location is 30.1234567 in latitude, and 0.0000001 is 1 km then you can put your coordinate in the center of the screen and 30.1234557 as the left most X coordinate and so on.
I am not trying to provide an answer here, but just trying to think out loud, because I wanted to do some thing similar as well and did it as an Internet based app (without display though), where given two coordinates, I had to find the distance between them.
There are many (many) different approaches to modelling the planet and translating 3D coordinates onto a 2D surface, and the errors introduced by the various methods vary depending on what part of the globe you are. This question seems to cover most of what you are after though:
Converting Longitude & Latitude to X Y on a map with Calibration points
I think its best way (correctly work for Mercator projection map):
extension UIView
{
func addLocation(coordinate: CLLocationCoordinate2D)
{
// max MKMapPoint values
let maxY = Double(267995781)
let maxX = Double(268435456)
let mapPoint = MKMapPointForCoordinate(coordinate)
let normalizatePointX = CGFloat(mapPoint.x / maxX)
let normalizatePointY = CGFloat(mapPoint.y / maxY)
let pointView = UIView(frame: CGRectMake(0, 0, 5, 5))
pointView.center = CGPointMake(normalizatePointX * frame.width, normalizatePointY * frame.height)
pointView.backgroundColor = UIColor.blueColor()
addSubview(pointView)
}
}
My simple project for adding coordinate on UIView: https://github.com/Glechik/MapCoordinateDrawer

Resources