I have an app that uses MKMapView. In my app, I have declared an array that will hold the response from the API. The data from the API are the jobs to be pinned in the map (clustered annotations). The array that holds the jobs from the API will/needs to be filtered by the jobs pins that are visible in the map. I am able to filter the coordinates (visible or not visible in the map) but I am having troubles on storing the data (coordinates that are visible) in a new array.
Here's what I have so far:
In regionDidChangeAnimated in my mapview
[ar objectAtIndex:0];
NSMutableDictionary *visibleJobs;
for(NSDictionary *loc in ar)
{
CLLocationDegrees Lat = [[[loc objectForKey:#"sub_slots"] objectForKey:#"latitude"] doubleValue];
CLLocationDegrees longTitude = [[[loc objectForKey:#"sub_slots"] objectForKey:#"longitude"] doubleValue];
CLLocationCoordinate2D point = CLLocationCoordinate2DMake(Lat, longTitude);
MKMapPoint mkPoint = MKMapPointForCoordinate(point);
BOOL contains = MKMapRectContainsPoint(mapView.visibleMapRect, mkPoint);
if(contains)
{
NSLog(#"Contains:1");
}
else
{
NSLog(#"Contains:0");
}
}
Any help will be very much appreciated.
Thanks!
why don't you use NSMutableArray
try this
NSMutableArray *visibleJobs = [[NSMutableArray alloc]init];
for(NSDictionary *loc in ar)
{
CLLocationDegrees Lat = [[[loc objectForKey:#"sub_slots"] objectForKey:#"latitude"] doubleValue];
CLLocationDegrees longTitude = [[[loc objectForKey:#"sub_slots"] objectForKey:#"longitude"] doubleValue];
CLLocationCoordinate2D point = CLLocationCoordinate2DMake(Lat, longTitude);
MKMapPoint mkPoint = MKMapPointForCoordinate(point);
BOOL contains = MKMapRectContainsPoint(mapView.visibleMapRect, mkPoint);
if(contains)
{
NSLog(#"Contains:1");
[visibleJobs addObject:loc];
}
else
{
NSLog(#"Contains:0");
}
}
Now visible jobs array contains dictionary of all pin data which in currently visible on map
Related
i am working on a project in which i have to show the distance of multiple locations from user's locations. locations are based on latitude and longitude.
i am using the following code to get the distance between two locations is shows nearly same distance
CLLocation *locA = [[CLLocation alloc] initWithLatitude:28.6379 longitude: 77.2432];
CLLocation *locB = [[CLLocation alloc] initWithLatitude:28.6562 longitude:77.2410];
CLLocationDistance distance = [locA distanceFromLocation:locB];
NSLog(#"Distance is %f",distance);
float i = distance/1000;
NSLog(#"distance between two places is %f KM", i);
but now i am struct to get the distance of multiple locations from my location: locaA.
for example i take NSarray for latitude and longitude as
NSArray * latArray = [[NSArray alloc]initWithObjects:#"28.6129",#"28.6020",#"28.5244", nil];
NSArray * longArray = [[NSArray alloc]initWithObjects:#"77.2295",#"77.2478",#"77.1855", nil];
Please help me to resolve it
Take locaA as user's location
You can use below method to find distance
#define DEG2RAD(degrees) (degrees * 0.01745327)
double currentLatitudeRad = DEG2RAD(currentLatitude);
double currentLongitudeRad = DEG2RAD(currentLongitude);
double destinationLatitudeRad = DEG2RAD(destinationLatitude);
double destinationLongitudeRad = DEG2RAD(destinationLongitude);
double distance = acos(sin(currentLatitudeRad) * sin(destinationLatitudeRad) + cos(currentLatitudeRad) * cos(destinationLatitudeRad) * cos(currentLongitudeRad - destinationLongitudeRad)) * 6880.1295896;
Here, currentLatitude and currentLongitude is user's location. destinationLatitude and destinationLongitude is each object from your array "latArray" and "longArray" which you can iterate via for loop. distance is the distance between user's location and locations in array. Obtained distance will be in kilometres.
CLLocation *currentLocation = ... // This is a reference to your current location as a CLLocation
NSArray *arrayOfOtherCLLocationObjects = ... // This is an array that contains all of the other points you want to calculate the distance to as CLLocations
NSMutableArray *distancesFromCurrentLocation = [[NSMutableArray alloc] initWithCapacity:arrayOfOtherCLLocationObjects.count]; // We will add all of the calculated distances to this array
for (CLLocation *location in arrayOfOtherCLLocationObjects) // Iterate through each location object
{
CLLocationDistance distance = [location distanceFromLocation:currentLocation]; // Calculate distance
[distancesFromCurrentLocation addObject:#(distance)]; // Append distance to array. You need to wrap the distance object as an NSNumber so you can append it to the array.
}
// At this point, you have the distance for each location point in the array distancesFromCurrentLocation
Swift version:
let currentLocation: CLLocation = //current location
let otherLocations: [CLLocation] = //the locations you want to know their distance to currentLocation
let distances = otherLocations.map { $0.distanceFromLocation(currentLocation) }
I have an array full of longitudes and latitudes. I have two double variables with my users location. I'd like to test the distance between my user's locations against my array to see which location is the closest. How do I do this?
This will get the distance between 2 location but stuggeling to understand
how I'd test it against an array of locations.
CLLocation *startLocation = [[CLLocation alloc] initWithLatitude:userlatitude longitude:userlongitude];
CLLocation *endLocation = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
CLLocationDistance distance = [startLocation distanceFromLocation:endLocation];
You just need to iterate through the array checking the distances.
NSArray *locations = //your array of CLLocation objects
CLLocation *currentLocation = //current device Location
CLLocation *closestLocation;
CLLocationDistance smallestDistance = DOUBLE_MAX;
for (CLLocation *location in locations) {
CLLocationDistance distance = [currentLocation distanceFromLocation:location];
if (distance < smallestDistance) {
smallestDistance = distance;
closestLocation = location;
}
}
At the end of the loop you will have the smallest distance and the closest location.
#Fogmeister
I think this is a mistake which must be set right about DBL_MAX and an assignment.
First : Use DBL_MAX instead of DOUBLE_MAX.
DBL_MAX is a #define variable in math.h.
It's the value of maximum representable finite floating-point (double) number.
Second : In your condition, your assignment is wrong :
if (distance < smallestDistance) {
distance = smallestDistance;
closestLocation = location;
}
You must do :
if (distance < smallestDistance) {
smallestDistance = distance;
closestLocation = location;
}
The difference is that will be assign distance value into smallestDistance, and not the opposite.
The final result :
NSArray *locations = //your array of CLLocation objects
CLLocation *currentLocation = //current device Location
CLLocation *closestLocation;
CLLocationDistance smallestDistance = DBL_MAX; // set the max value
for (CLLocation *location in locations) {
CLLocationDistance distance = [currentLocation distanceFromLocation:location];
if (distance < smallestDistance) {
smallestDistance = distance;
closestLocation = location;
}
}
NSLog(#"smallestDistance = %f", smallestDistance);
Can you confirm that is correct ?
I have this situation where my app crashes when I zoom out the map.
The problem arises because of the large number of annotations that I'm adding. Please have a look at my code below :
- (void) plotUsersInMap
{
for (id<MKAnnotation> annotation in self.mapView.annotations) {
[self.mapView removeAnnotation:annotation];
}
NSUInteger count = //get total count
NSLog(#"count * %d", count);
for (int i = 0; i < count; i++)
{
NSNumber *latitude = //get latitude from json
NSNumber *longitude = //get longitude from json
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;
#autoreleasepool {
MyLocation *annotation = [[MyLocation alloc] initWithName:#"test" coordinate:coordinate QuestionId:nil];
//annotations are added
[self.mapView addAnnotation:annotation];
}
}
}
Here I'm trying to add more than 400 pins which I think is the cause of crash [probably a memory leak!]. I would like to know if there is any way to add the pins one by one as I zoom out?
Map in initial stage, without any problem :
And when I zoom out :
Try clustering. Basically you group together annotations.
The code repo from the article I linked to: https://github.com/applidium/ADClusterMapView
I have an array named allposts that has 4 objects in it. When I run the loop below, only the first annotation is put onto the map. I print out the latitude and longitude of each "point" and they are indeed different, so Im not sure whats going on
for (PFObject *post in _allPosts)
{
NSLog(#"NEWANNOTATION");
PFGeoPoint *point = [post objectForKey:#"Location"];
NSLog(#"lat: %f long: %f", point.latitude, point.longitude);
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude);
CCBAnnotation *annotation = [[CCBAnnotation alloc] initWithCoordinate:coordinate];
[self.mapView addAnnotation:annotation];
}
You should also inspect mapView.annotations after doing this in order to determine if it's an adding problem or a display problem.
I have an array of waypoints stored which have latitude and longitude values. I have created a for loop to loop through the array and compare my current CLLocation positions latitude and longitude to find which of the waypoints i am closest to. I also need to get the second closest waypoint and store this ac s a CLLocation object as well but cannot get it working.
The logic would be something like this
am I closest
yes
move closest location to second closest
set as second closest
loop again to get the closest point
My code:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
//set latestlocation as the last object from the locations array
CLLocation *currentLocation = [locations lastObject];
//declare a closestpoint object
CLLocation *closestWayPointToCurrentLocation;
//declare a second closest point object
CLLocation *secondClosestWayPointToCurrentLocation;
//set the distance to a high number
float distance = 10000000;
float secondClosestWaypointDistance = 10000000;
//load in plist
NSString *plistName = [self.mapsInfo objectForKey:#"plistName"];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Chester" ofType:#"plist"];
NSString *path = [[NSBundle mainBundle] pathForResource:plistName ofType:#"plist"];
//store in array called waypoints
NSArray *waypoints= [NSArray arrayWithContentsOfFile:path];
//declare a variable for locationNum (the waypoints)
int locationNum = 0;
for (NSDictionary *point in waypoints) {
CLLocation *waypointLocation = [[CLLocation alloc]initWithLatitude:[(NSNumber *)[point objectForKey:#"Lat"]floatValue] longitude:[(NSNumber *)[point objectForKey:#"Long"]floatValue]];
float waypointDistanceFromCurrentLocation = [currentLocation distanceFromLocation:waypointLocation];
//secondClosestWayPointToCurrentLocation = waypointLocation;
if(waypointDistanceFromCurrentLocation < distance) {
//todo: move the current closestWayPointToCurrentLocation into second postion
//update the second closest waypoint distance variable also with distance
distance = waypointDistanceFromCurrentLocation;
closestWayPointToCurrentLocation = waypointLocation;
if(closestWayPointToCurrentLocation == waypointLocation) {
}
}
else
{
//check against the second position
//if closer than second position, replace it with new waypoint with code similar to above
}
If you are sure the point you is always the penultimate then you can retrive it like this
int totalNumberOfWaypoints = [waypoints count];
//Get penultimate waypoints
NSDictionary *penultimateWaypoint = [waypoints objectAtIndex:(totalNumberOfWaypoints - 2)];
Why dont you just make a sorted array of points, sorted by distance in ascending order?
NSMutableArray *waypoints= [NSArray arrayWithContentsOfFile:path];
for (NSDictionary *point in waypoints) {
[waypoints sortUsingComparator: (NSComparisonResult) ^ (id obj1, id obj2) {
CLLocation *waypointLocation1 = [[CLLocation alloc]initWithLatitude:[(NSNumber *)[obj1 objectForKey:#"Lat"]floatValue] longitude:[(NSNumber *)[obj1 objectForKey:#"Long"]floatValue]];
CLLocation *waypointLocation2 = [[CLLocation alloc]initWithLatitude:[(NSNumber *)[obj2 objectForKey:#"Lat"]floatValue] longitude:[(NSNumber *)[obj2 objectForKey:#"Long"]floatValue]];
float distance1 = [currentLocation distanceFromLocation:waypointLocation1];
float distance2 = [currentLocation distanceFromLocation:waypointLocation2];
if (distance1 < distance2) {
return NSOrderedAscending;
}
else if (distance1 > distance2) {
return NSOrderedDescending
}
else
return NSOrderedSame;
}];
This way you can always have the closest point at [waypoints objectAtIndex:0] and second closest point at [waypoints objectAtIndex:1] and so on.
less work, better result IMHO