Adding random MKAnnotations around Current Location in a MKMapView - ios

I have an MKMapView that shows the current users location. When I click a button in the navigation bar, I want to randomly drop 10 MKAnnotation pins. These can be dropped anywhere, randomly, but only within the current visible map area and around the current location.
How would go about doing something like this? Is there a way to have a long/lat range that is around the users location, but within the map area? Then, I could randomly choose from this range?
Basically, I need to find what coordinates are available in the current MKCoordinateRegion.
Is there a better way to go about this?

You can get your annotations using the distance between user location and other location
check out below code
#define DISTANCE_RADIUS 10.0 // in KM
-(NSArray *)findNearMe:(NSArray *)lounges {
NSMutableArray *arNearme = [NSMutableArray array];
CLLocation *currentLocation;
for(NSDictionary *d in lounges)
{
currentLocation = [[CLLocation alloc] initWithLatitude:29.33891 longitude:48.077202];
CGFloat latitude=[[d valueForKey:#"latitude"] floatValue];
CGFloat longitude=[[d valueForKey:#"longitude"] floatValue];
CLLocation *newPinLocation=[[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
double distanceValue=[currentLocation distanceFromLocation:newPinLocation];
if(distanceValue/1000.0<=DISTANCE_RADIUS) {
[arNearme addObject:d];
}
}
return arNearme;
}
It will returns you an array of range of 1 to 1000 km near user location.
Used the annotations array and show your annotations in to map view with user location.

I figured it out, here is how I did it:
/**
* Adds new pins to the map
*
* #version $Revision: 0.1
*/
+ (void)addPinsToMap:(MKMapView *)mapView amount:(int)howMany {
//First we need to calculate the corners of the map so we get the points
CGPoint nePoint = CGPointMake(mapView.bounds.origin.x + mapView.bounds.size.width, mapView.bounds.origin.y);
CGPoint swPoint = CGPointMake((mapView.bounds.origin.x), (mapView.bounds.origin.y + mapView.bounds.size.height));
//Then transform those point into lat,lng values
CLLocationCoordinate2D neCoord = [mapView convertPoint:nePoint toCoordinateFromView:mapView];
CLLocationCoordinate2D swCoord = [mapView convertPoint:swPoint toCoordinateFromView:mapView];
// Loop
for (int y = 0; y < howMany; y++) {
double latRange = [MapUtility randomFloatBetween:neCoord.latitude andBig:swCoord.latitude];
double longRange = [MapUtility randomFloatBetween:neCoord.longitude andBig:swCoord.longitude];
// Add new waypoint to map
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(latRange, longRange);
MPin *pin = [[MPin alloc] init];
pin.coordinate = location;
[mapView addAnnotation:pin];
}//end
}//end
/**
* Random numbers
*
* #version $Revision: 0.1
*/
+ (double)randomFloatBetween:(double)smallNumber andBig:(double)bigNumber {
double diff = bigNumber - smallNumber;
return (((double) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + smallNumber;
}//end

In Swift 3.0
func addPins() {
let nePoint = CGPoint(x: mapView.bounds.origin.x + mapView.bounds.size.width, y: mapView.bounds.origin.y)
let sePoint = CGPoint(x: mapView.bounds.origin.x, y: mapView.bounds.origin.y + mapView.bounds.size.height)
let neCoord = mapView.convert(nePoint, toCoordinateFrom: mapView)
let seCoord = mapView.convert(sePoint, toCoordinateFrom: mapView)
var y = 5
while y > 0 {
let latRange = randomBetweenNumbers(firstNum: Float(neCoord.latitude), secondNum: Float(seCoord.latitude))
let longRange = randomBetweenNumbers(firstNum: Float(neCoord.longitude), secondNum: Float(seCoord.longitude))
let location = CLLocationCoordinate2D(latitude: CLLocationDegrees(latRange), longitude: CLLocationDegrees(longRange))
let pin = MKPointAnnotation()
pin.coordinate = location
pin.title = "Home"
mapView.addAnnotation(pin)
y -= 1
}
}
func randomBetweenNumbers(firstNum: Float, secondNum: Float) -> Float{
return Float(arc4random()) / Float(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
}

swift 4:
// returned coordinates all restricted to the provided bound
// nwCoordinate: north West coordinate of the target bound
// seCoordinate: south east coordinate of the target bound
func createRandomLocation(nwCoordinate: CLLocationCoordinate2D, seCoordinate: CLLocationCoordinate2D) -> [CLLocationCoordinate2D]
{
return (0 ... 30).enumerated().map { _ in
let latitude = randomFloatBetween(nwCoordinate.latitude, andBig: seCoordinate.latitude)
let longitude = randomFloatBetween(nwCoordinate.longitude, andBig: seCoordinate.longitude)
return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
}
private func randomFloatBetween(_ smallNumber: Double, andBig bigNumber: Double) -> Double {
let diff: Double = bigNumber - smallNumber
return ((Double(arc4random() % (UInt32(RAND_MAX) + 1)) / Double(RAND_MAX)) * diff) + smallNumber
}

Related

How to convert an ios esri arcGIS Point into latitude and longitude

I have a service return arcgis json format , i want to convert this geometry points to longitude and latitude ios
example :
"geometryType": "esriGeometryPoint",
"geometry": {
"x": 445340.99496,
"y": 2423705.6300004,
"spatialReference": {
"wkid": 32637,
"latestWkid": 32637
}
}
i convert the point
AGSGraphic *testGraphic = [[AGSGraphic alloc] initWithJSON:jsonData] ;
how i can get from AGSGraphic longitude and latitude
this solved the problem , just send xPoint and yPoint and it will return CLLocation Object contain lng and latit
-(CLLocation *) convertToLongAndLat:(double) xPoint andYPoint :(double) yPoint {
double originShift = 2 * M_PI * 6378137 / 2.0;
double lon = (xPoint / originShift) * 180.0;
double lat = (yPoint / originShift) * 180.0;
lat = 180 / M_PI * (2 * atan( exp( lat * M_PI / 180.0)) - M_PI / 2.0);
return [[CLLocation alloc] initWithLatitude:lat longitude:lon];
}
I think that you want to change the spatial reference based on what you want .
Ex :
//AA : Get the clicked point
let gpsPoint = clickedMapPoint
let engine = AGSGeometryEngine.defaultGeometryEngine()
//AA : Change the spatial ref to get real lon and lat
let mapPoint = engine.projectGeometry(gpsPoint, toSpatialReference: AGSSpatialReference.wgs84SpatialReference()) as! AGSPoint

How to calculate the center coordinates of CLLocationDistance

I want calculate the center point between my location and some annotation. So far I have done this:
CLLocation *myLoc = self.locMgr.location;
MKPointAnnotation *middleAnnotation = [locationV.annotations objectAtIndex:locationV.annotations.count/2];
CLLocation *someStuiodLoc = [[CLLocation alloc] initWithLatitude:middleAnnotation.coordinate.latitude longitude:middleAnnotation.coordinate.longitude];
CLLocationDistance dist = [myLoc distanceFromLocation:someStuiodLoc];
How can I calculate the center point/cordinate of "dist" ??
#define ToRadian(x) ((x) * M_PI/180)
#define ToDegrees(x) ((x) * 180/M_PI)
+ (CLLocationCoordinate2D)midpointBetweenCoordinate:(CLLocationCoordinate2D)c1 andCoordinate:(CLLocationCoordinate2D)c2
{
c1.latitude = ToRadian(c1.latitude);
c2.latitude = ToRadian(c2.latitude);
CLLocationDegrees dLon = ToRadian(c2.longitude - c1.longitude);
CLLocationDegrees bx = cos(c2.latitude) * cos(dLon);
CLLocationDegrees by = cos(c2.latitude) * sin(dLon);
CLLocationDegrees latitude = atan2(sin(c1.latitude) + sin(c2.latitude), sqrt((cos(c1.latitude) + bx) * (cos(c1.latitude) + bx) + by*by));
CLLocationDegrees longitude = ToRadian(c1.longitude) + atan2(by, cos(c1.latitude) + bx);
CLLocationCoordinate2D midpointCoordinate;
midpointCoordinate.longitude = ToDegrees(longitude);
midpointCoordinate.latitude = ToDegrees(latitude);
return midpointCoordinate;
}
I have written library function in Swift to calculate the midpoint between multiple coordinates as following:
// /** Degrees to Radian **/
class func degreeToRadian(angle:CLLocationDegrees) -> CGFloat{
return ( (CGFloat(angle)) / 180.0 * CGFloat(M_PI) )
}
// /** Radians to Degrees **/
class func radianToDegree(radian:CGFloat) -> CLLocationDegrees{
return CLLocationDegrees( radian * CGFloat(180.0 / M_PI) )
}
class func middlePointOfListMarkers(listCoords: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D{
var x = 0.0 as CGFloat
var y = 0.0 as CGFloat
var z = 0.0 as CGFloat
for coordinate in listCoords{
var lat:CGFloat = degreeToRadian(coordinate.latitude)
var lon:CGFloat = degreeToRadian(coordinate.longitude)
x = x + cos(lat) * cos(lon)
y = y + cos(lat) * sin(lon);
z = z + sin(lat);
}
x = x/CGFloat(listCoords.count)
y = y/CGFloat(listCoords.count)
z = z/CGFloat(listCoords.count)
var resultLon: CGFloat = atan2(y, x)
var resultHyp: CGFloat = sqrt(x*x+y*y)
var resultLat:CGFloat = atan2(z, resultHyp)
var newLat = radianToDegree(resultLat)
var newLon = radianToDegree(resultLon)
var result:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: newLat, longitude: newLon)
return result
}
Detailed answer can be found here
U can calculate the midPoint of two coordinates using the mid point formula (http://www.purplemath.com/modules/midpoint.htm) which gives a close approximation to the actual geographical point if the distances are lesser than 500 miles. If you consider that the earth is spherical, then a more complex treatment of the points would be involved.

Create a random CLLocationCoordinate in a certain area

I've got an MKMapRect.
How do I create a random CLLocationCoordinate inside there?
I know there is arc4random(), but how can I use it for GPS Coordinates?
#define ARC4RANDOM_MAX 0x100000000
...
//val is a double between 0 and 1
double xOffset = ((double)arc4random() / ARC4RANDOM_MAX);
double yOffset = ((double)arc4random() / ARC4RANDOM_MAX);
MKMapPoint randomPoint;
randomPoint.x = maprect.origin.x + xOffset*maprect.size.width;
randomPoint.y = maprect.origin.y + yOffset*maprect.size.height;
CLLocationCoordinate2D randomCoordinate = MKCoordinateForMapPoint(randomPoint);
From the MapRect, you could got MKMapPoint origin and MKMapSize size, then the random CLLocationCoordinate should be {origin.x + [0 ~ size.width], origin.y + [0 ~ size.height]}
typedef struct {
MKMapPoint origin;
MKMapSize size;
} MKMapRect;
the code like this:
#define ARC4RANDOM_MAX 0x100000000
- (double)createRandomsizeValueFloat:(double)fromFloat toFloat:(double)toFloat
{
if (toFloat < fromFloat) {
return toFloat;
} else if (toFloat == fromFloat) {
return fromFloat;
}
return ((double)arc4random() / ARC4RANDOM_MAX) * (toFloat - fromFloat) + fromFloat;
}
//CLLocationDegrees lat = mapRect.origin.x + [self createRandomsizeValueFloat:0 toFloat:mapRect.size.width];
//CLLocationDegrees lng = mapRect.origin.y + [self createRandomsizeValueFloat:0 toFloat:mapRect.size.height];
Just set the latitude and longitude properties of your CLLocationCoordinate instance.
Take care about ranges : -90 < latitude < 90, -180 < longitude < 180.
Hope this helps.

How to get area for MKPolygon in iOS

How to you get the area of a MKPolygon or MKOverlay in iOS?
I have been able to breakup the Polygon into triangles and do some math to get the area. But, doesn't work well with irregular polygons.
I was thinking about doing something like the "A more complex case" here: http://www.mathopenref.com/coordpolygonarea2.html
I was hoping there is a simpler solution with MapKit.
Thanks,
Tim
Here's the implementation I'm using.
#define kEarthRadius 6378137
#implementation MKPolygon (AreaCalculation)
- (double) area {
double area = 0;
NSMutableArray *coords = [[self coordinates] mutableCopy];
[coords addObject:[coords firstObject]];
if (coords.count > 2) {
CLLocationCoordinate2D p1, p2;
for (int i = 0; i < coords.count - 1; i++) {
p1 = [coords[i] MKCoordinateValue];
p2 = [coords[i + 1] MKCoordinateValue];
area += degreesToRadians(p2.longitude - p1.longitude) * (2 + sinf(degreesToRadians(p1.latitude)) + sinf(degreesToRadians(p2.latitude)));
}
area = - (area * kEarthRadius * kEarthRadius / 2);
}
return area;
}
- (NSArray *)coordinates {
NSMutableArray *points = [NSMutableArray arrayWithCapacity:self.pointCount];
for (int i = 0; i < self.pointCount; i++) {
MKMapPoint *point = &self.points[i];
[points addObject:[NSValue valueWithMKCoordinate:MKCoordinateForMapPoint(* point)]];
}
return points.copy;
}
double degreesToRadians(double radius) {
return radius * M_PI / 180;
}
In Swift 3:
let kEarthRadius = 6378137.0
extension MKPolygon {
func degreesToRadians(_ radius: Double) -> Double {
return radius * .pi / 180.0
}
func area() -> Double {
var area: Double = 0
var coords = self.coordinates()
coords.append(coords.first!)
if (coords.count > 2) {
var p1: CLLocationCoordinate2D, p2: CLLocationCoordinate2D
for i in 0..<coords.count-1 {
p1 = coords[i]
p2 = coords[i+1]
area += degreesToRadians(p2.longitude - p1.longitude) * (2 + sin(degreesToRadians(p1.latitude)) + sin(degreesToRadians(p2.latitude)))
}
area = abs(area * kEarthRadius * kEarthRadius / 2)
}
return area
}
func coordinates() -> [CLLocationCoordinate2D] {
var points: [CLLocationCoordinate2D] = []
for i in 0..<self.pointCount {
let point = self.points()[i]
points.append(MKCoordinateForMapPoint(point))
}
return Array(points)
}
}
I figured this out by doing a little loop through the points in the polygon. For every 3 points, I check if the center of that triangle is in the polygon. If it is continue, if not, connect the polygon so that there are no dips in the polygon. Once done, get the triangles in the polygon and do the math to get the area. Then subtract the triangles that were removed.
Hope this helps someone.

Compute right Zoom/Span for MkPolyline overlay

Hi try to compute the right zoom/span for an MkPolyline, It work () but it's not closer...
This is my method :
-(void)showPathForIndex:(int)index{
//calculate new region to show on map
double center_long = 0.0f;
double center_lat = 0.0f;
double max_long = 0.0f;
double min_long = 0.0f;
double max_lat = 0.0f;
double min_lat = 0.0f;
for (CLLocation *cll in [[self.routes objectAtIndex:index]coordinates]) {
//Find maximum & minimum value
if (cll.coordinate.latitude > max_lat) {
max_lat = cll.coordinate.latitude;
}
if (cll.coordinate.latitude < min_lat){
min_lat = cll.coordinate.latitude;
}
if (cll.coordinate.longitude > max_long) {
max_long = cll.coordinate.longitude;
}
if (cll.coordinate.longitude < min_long) {
min_long = cll.coordinate.longitude;
}
center_lat = center_lat + cll.coordinate.latitude;
center_long = center_long + cll.coordinate.longitude;
}
//calculate average long / lat
center_lat = center_lat / [[[self.routes objectAtIndex:index]coordinates]count];
center_long = center_long / [[[self.routes objectAtIndex:index]coordinates]count];
CLLocationCoordinate2D coord = {latitude: center_lat, longitude: center_long};
MKCoordinateSpan span = MKCoordinateSpanMake(abs(max_lat) + abs(min_lat), abs(max_long) + abs(min_long));
MKCoordinateRegion region = {coord, span};
[self.parentMapView setRegion:region];
//Add the overlay
[self.parentMapView addOverlay:[[self.routes objectAtIndex:index]polyline]];
}
Someone could help me!?
Thanks
This line of code solve my problem:
[self.parentMapView setVisibleMapRect:[[[self.routes objectAtIndex:index]polyline]boundingMapRect] animated:YES];

Resources