Compute right Zoom/Span for MkPolyline overlay - ios

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];

Related

How to draw dotted circle path route for the walking mode using GMSMapView?

Now i am working with Google maps, I have a requirement to draw route between the source and destination. I am using GMSPolyline to draw route but for walking mode i want to show dotted line as google maps. If any one know please help me on this. THANKS IN ADVANCE
dispatch_async(dispatch_get_main_queue(),{
let path = GMSPath(fromEncodedPath: rout)
var polilin = GMSPolyline(path: path)
polilin = GMSPolyline(path: path)
polilin.title = "WALK"
polilin.strokeWidth = 4.0
polilin.strokeColor = UIColor.redColor()
polilin.map = self.mapView
polilin.tappable = true
})
you can use this with draw dot line.
- (void) createDashedLine:(CLLocationCoordinate2D )thisPoint:(CLLocationCoordinate2D )nextPoint (UIColor *)colour
{
double difLat = nextPoint.latitude - thisPoint.latitude;
double difLng = nextPoint.longitude - thisPoint.longitude;
double scale = camera.zoom * 2;
double divLat = difLat / scale;
double divLng = difLng / scale;
CLLocationCoordinate2D tmpOrig= thisPoint;
GMSMutablePath *singleLinePath = [GMSMutablePath path];
for(int i = 0 ; i < scale ; i ++)
{
CLLocationCoordinate2D tmpOri = tmpOrig;
if(i > 0)
{
tmpOri = CLLocationCoordinate2DMake(tmpOrig.latitude + (divLat * 0.25f),
tmpOrig.longitude + (divLng * 0.25f));
}
[singleLinePath addCoordinate:tmpOri];
[singleLinePath addCoordinate:
CLLocationCoordinate2DMake(tmpOrig.latitude + (divLat * 1.0f),
tmpOrig.longitude + (divLng * 1.0f))];
tmpOri = CLLocationCoordinate2DMake(tmpOrig.latitude + (divLat * 1.0f),
tmpOrig.longitude + (divLng * 1.0f));
}
GMSPolyline *polyline ;
polyline = [GMSPolyline polylineWithPath:singleLinePath];
polyline.geodesic = NO;
polyline.strokeWidth = 5.f;
polyline.strokeColor = colour;
polyline.map = mapView_;
//Setup line style and draw
_lengths = #[#([singleLinePath lengthOfKind:kGMSLengthGeodesic] / 100)];
_polys = #[polyline];
[self setupStyleWithColour:colour];
[self tick];
}
- (void)tick
{
//Create steps for polyline(dotted polylines)
for (GMSPolyline *poly in _polys)
{
poly.spans =
GMSStyleSpans(poly.path, _styles, _lengths, kGMSLengthGeodesic, _pos);
}
_pos -= _step;
}
-(void)setupStyleWithColour:(UIColor *)color
{
GMSStrokeStyle *gradColor = [GMSStrokeStyle gradientFromColor:color toColor:color];
_styles = #[
gradColor,
[GMSStrokeStyle solidColor:[UIColor colorWithWhite:0 alpha:0]],
];
_step = 50000;
}
Swift version of rvios's answer (with the help of Swiftify):
func createDashedLine(thisPoint: CLLocationCoordinate2D, nextPoint: CLLocationCoordinate2D, color: UIColor) {
let difLat = nextPoint.latitude - thisPoint.latitude
let difLng = nextPoint.longitude - thisPoint.longitude
let scale = camera.zoom * 2
let divLat = difLat / scale
let divLng = difLng / scale
let tmpOrig = thisPoint
var singleLinePath = GMSMutablePath()
for i in 0 ..< scale {
var tmpOri = tmpOrig
if i > 0 {
tmpOri = CLLocationCoordinate2DMake(tmpOrig.latitude + (divLat * 0.25), tmpOrig.longitude + (divLng * 0.25))
}
singleLinePath.addCoordinate(tmpOri)
singleLinePath.addCoordinate(CLLocationCoordinate2DMake(tmpOrig.latitude + (divLat * 1.0), tmpOrig.longitude + (divLng * 1.0)))
tmpOri = CLLocationCoordinate2DMake(tmpOrig.latitude + (divLat * 1.0), tmpOrig.longitude + (divLng * 1.0))
}
let polyline = GMSPolyline(path: singleLinePath)
polyline.geodesic = false
polyline.strokeWidth = 5.0
polyline.strokeColor = color
polyline.map = mapView
//Setup line style and draw
lengths = [(singleLinePath.lengthOfKind(kGMSLengthGeodesic) / 100)]
polys = [polyline]
setupStyle(with: color)
tick()
}
func tick() {
for poly in polys {
poly.spans = GMSStyleSpans(poly.path, styles, lengths, kGMSLengthGeodesic, pos)
}
pos -= step
}
func setupStyle(with color: UIColor) {
let gradColor = GMSStrokeStyle.gradient(from: color, to: color)
styles = [gradColor, GMSStrokeStyle.solidColor(.white)]
step = 50000
}

Find the mid point between two CLLocationCoordinate2D when going over 180 degrees

I have the following code to work out the MKCoordinateRegion to display the map including two defined points. The problem is it doesn't work when the longitude goes over 180 or -180 degrees.
CLLocationCoordinate2D tempPoint1 = CLLocationCoordinate2DMake(startLat,startLong);
CLLocationCoordinate2D tempPoint2 = CLLocationCoordinate2DMake(nextLat,nextLong);
if (lineType == 1) {
[self createGreatCircleMKPolylineFromPoint: tempPoint1 toPoint: tempPoint2 forMapView:mapView];
}
else {
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * 2);
coords[0] = tempPoint1;
coords[1] = tempPoint2;
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:2];
free(coords);
[mapView addOverlay:polyline];
}
double lon1 = tempPoint1.longitude * M_PI / 180;
double lon2 = tempPoint2.longitude * M_PI / 180;
double lat1 = tempPoint1.latitude * M_PI / 180;
double lat2 = tempPoint2.latitude * M_PI / 180;
double dLon = lon2 - lon1;
double x = cos(lat2) * cos(dLon);
double y = cos(lat2) * sin(dLon);
double lat3 = atan2( sin(lat1) + sin(lat2), sqrt((cos(lat1) + x) * (cos(lat1) + x) + y * y) );
double lon3 = lon1 + atan2(y, cos(lat1) + x);
CLLocationCoordinate2D center;
center.latitude = lat3 * 180 / M_PI;
center.longitude = lon3 * 180 / M_PI;
MKCoordinateSpan locationSpan;
locationSpan.latitudeDelta = fabs(tempPoint1.latitude - tempPoint2.latitude) * 1.2;
locationSpan.longitudeDelta = fabs(tempPoint1.longitude - tempPoint2.longitude) * 1.2;
MKCoordinateRegion region = {center, locationSpan};
[mapView setRegion:region];
Any ideas how I could alter this code to make sure it can handle the startLong being positive i.e. 174 and the nextLong being negative i.e. -127, and vice versa
As startLong and nextLong are longitude in degrees, so from 0° to 360°, you can make sure they are both positive and nextLong >= startLong:
while( startLong < 0.0 ) startLong += 360.0f;
while( startLong >= 360.0 ) startLong -= 360.0f;
while( nextLong < startLong ) nextLong += 360.0f;
while( nextLong - startLong > 360.0 ) nextLong -= 360.0;
With this, you are sure that :
startLong is between 0.0 and 360.0 (exclusive for the later)
nextLong is between startLong and startLong + 360.0

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.

Adding random MKAnnotations around Current Location in a MKMapView

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
}

Resources