Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented the algorithm

The two classes can now handle the points aggregation properly.
  • Loading branch information...
commit f674df53019a224bf5a5d7c555d0d893cc44fd16 1 parent a268a17
@elbryan authored
Showing with 200 additions and 71 deletions.
  1. +11 −1 FFMapRoute.h
  2. +41 −2 FFMapRoute.m
  3. +4 −7 FFMapRoutes.h
  4. +144 −61 FFMapRoutes.m
View
12 FFMapRoute.h
@@ -1,6 +1,5 @@
//
// FFMapRoute.h
-// iScout
//
// Created by Fabiano Francesconi on 19/07/10.
// Copyright 2010 Fabiano Francesconi. All rights reserved.
@@ -10,11 +9,22 @@
#import <MapKit/MapKit.h>
@interface FFMapRoute : NSObject {
+ NSMutableArray *points;
NSUInteger level;
MKPolyline *line;
}
@property (nonatomic, retain) MKPolyline *line;
+@property (nonatomic, retain) NSMutableArray *points;
@property (nonatomic, assign) NSUInteger level;
+/* Init the object with a segment */
+- (id) initWithSegment:(NSArray *)segment;
+
+/* Add the points contained in newPoints array to the local array*/
+- (void) addPointsFromArray:(NSArray *)newPoints;
+
+/* Add coordinate to the local array by wrapping it into a NSData object */
+- (void) addPoint:(CLLocationCoordinate2D) coordinate;
+
@end
View
43 FFMapRoute.m
@@ -1,6 +1,5 @@
//
// FFMapRoute.m
-// iScout
//
// Created by Fabiano Francesconi on 19/07/10.
// Copyright 2010 Fabiano Francesconi. All rights reserved.
@@ -8,11 +7,51 @@
#import "FFMapRoute.h"
+@interface FFMapRoute ()
+@end
+
@implementation FFMapRoute
+- (id) initWithSegment:(NSArray *)segment {
+ if (self = [super init]) {
+ points = [[NSMutableArray alloc] initWithArray:segment];
+
+ MKMapPoint *mapPoints = malloc(sizeof(MKMapPoint) * [points count]);
+ int idx=0;
+
+ for (NSData *value in points) {
+ CLLocationCoordinate2D *coordinate = (CLLocationCoordinate2D *) [value bytes];
+ MKMapPoint point = MKMapPointForCoordinate(*coordinate);
+ mapPoints[idx] = point;
+ idx++;
+ }
+
+ /* Generate the new line */
+ MKPolyline *segmentLine = [MKPolyline polylineWithPoints:mapPoints count:[points count]];
+
+ self.line = segmentLine;
+ }
+
+ return self;
+}
+
- (void) dealloc {
- [line dealloc];
+ [line release];
+ [points release];
+
[super dealloc];
}
+#pragma mark -
+#pragma mark Public Methods
+
+- (void) addPointsFromArray:(NSArray *)newPoints {
+ [points addObjectsFromArray:newPoints];
+}
+
+- (void) addPoint:(CLLocationCoordinate2D) coordinate {
+ NSData *newPoint = [NSData dataWithBytes:&coordinate length:sizeof(CLLocationCoordinate2D)];
+ [points addObject:newPoint];
+}
+
@end
View
11 FFMapRoutes.h
@@ -1,6 +1,5 @@
//
// FFMapRoute.h
-// iScout
//
// Created by Fabiano Francesconi on 10/07/10.
// Copyright 2010 Fabiano Francesconi. All rights reserved.
@@ -12,22 +11,20 @@
#import "FFMapRoute.h"
/* Each kAGGREGATION_FACTOR points, aggregate those in a single polyline */
-#define kAGGREGATION_FACTOR 10
+#define kAGGREGATION_FACTOR 3
@interface FFMapRoutes: NSObject {
- NSMutableArray *points;
- NSMutableArray *lines;
-
+ /* The target mapview that will handle overlays */
MKMapView *mapView;
CLLocationCoordinate2D lastCoordinate;
/* Array of routes */
- FFMapRoute **routes;
+ NSMutableArray *routes;
}
@property (nonatomic, assign) MKMapView *mapView;
-- (void) addCoordinate:(CLLocationCoordinate2D)coordinate;
+- (void) addCoordinate:(CLLocationCoordinate2D) coordinate;
@end
View
205 FFMapRoutes.m
@@ -1,6 +1,5 @@
//
// FFMapRoute.m
-// iScout
//
// Created by Fabiano Francesconi on 10/07/10.
// Copyright 2010 Fabiano Francesconi. All rights reserved.
@@ -9,102 +8,186 @@
#import "FFMapRoutes.h"
@interface FFMapRoutes ()
-- (void) addOverlayToMapViewWithCoordinate:(CLLocationCoordinate2D) coordinate;
-- (void) manageOverlaysInMapView;
-
-@property (nonatomic, retain) NSMutableArray *points;
-@property (nonatomic, retain) NSMutableArray *lines;
-@property (nonatomic, assign) CLLocationCoordinate2D lastCoordinate;
+- (void) addCoordinate:(CLLocationCoordinate2D)coordinate toArray:(NSMutableArray *)array;
+- (void) aggregateRoutes;
+BOOL areCoordinateEqual(CLLocationCoordinate2D aCoordinate, CLLocationCoordinate2D bCoordinate);
+- (void) aggregatePoints:(NSArray *)points toArray:(NSMutableArray *)array;
+- (void) checkAggregationIsNeeded;
@end
@implementation FFMapRoutes
- (id) init {
if (self = [super init]) {
- points = [[NSMutableArray alloc] init];
- lines = [[NSMutableArray alloc] init];
- *routes = malloc(class_getInstanceSize([FFMapRoute class]) * kAGGREGATION_FACTOR);
+ routes = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc {
- [points release];
- [lines release];
+ [routes release];
[super dealloc];
}
#pragma mark -
+#pragma mark Public Methods
-- (void) addCoordinate:(CLLocationCoordinate2D)coordinate {
- /* Wrap the coordinate inside a NSData object */
- NSData *value = [NSData dataWithBytes:&coordinate length:sizeof(CLLocationCoordinate2D)];
- [points addObject:value];
-
- [self addOverlayToMapViewWithCoordinate:coordinate];
-}
-
-- (void) addOverlayToMapViewWithCoordinate:(CLLocationCoordinate2D) coordinate {
+- (void) addCoordinate:(CLLocationCoordinate2D) coordinate {
/* If we don't have a last coordinate, then wait for a second point */
if ((lastCoordinate.latitude == 0) && (lastCoordinate.longitude == 0)) {
lastCoordinate = coordinate;
return;
}
+
+ NSMutableArray *lastroutes = [routes lastObject];
- /* If we have kAGGREGATION_FACTOR segments, aggregate those */
- if ([lines count] == kAGGREGATION_FACTOR) {
- [self manageOverlaysInMapView];
- } else {
- /* Add the new segment */
- MKMapPoint *mapPoints = malloc(sizeof(MKMapPoint) * 2);
- mapPoints[0] = MKMapPointForCoordinate(lastCoordinate);
- mapPoints[1] = MKMapPointForCoordinate(coordinate);
-
- /* Generate the polyline */
- MKPolyline *segmentLine = [MKPolyline polylineWithPoints:mapPoints count:2];
-
- /* Add the segment to the mapview overlays */
- [mapView addOverlay:segmentLine];
- [lines addObject:segmentLine];
+ /* If the last object does not exist means that the routes array is empty.
+ So create the first array */
+ if (!lastroutes) {
+ NSMutableArray *newroutes = [[NSMutableArray alloc] initWithCapacity:kAGGREGATION_FACTOR];
+ [self addCoordinate:coordinate toArray:newroutes];
- free(mapPoints);
+ [routes addObject:newroutes];
+
+ [newroutes release];
}
-
+ /* Otherwisely, we need to check the level of the last array */
+ else {
+ /* Extract the existing route */
+ FFMapRoute *route = [lastroutes lastObject];
+
+ /* If the level is the minor one, than we are good */
+ if (route.level == 1)
+ [self addCoordinate:coordinate toArray:lastroutes];
+
+ /* Otherwisely, we have to create a bogus element for all the missing levels */
+ else {
+ int currentLevel = route.level;
+ for (int i=(currentLevel - 1); i>=1; i--) {
+ NSMutableArray *placeholder = [[NSMutableArray alloc] initWithCapacity:kAGGREGATION_FACTOR];
+ FFMapRoute *route = [[FFMapRoute alloc] init];
+ route.level = i;
+ [placeholder addObject:route];
+ [routes addObject:placeholder];
+
+ [route release];
+ [placeholder release];
+ }
+ [self addCoordinate:coordinate];
+ }
+ }
+
lastCoordinate = coordinate;
+
+ [self checkAggregationIsNeeded];
}
-- (void) manageOverlaysInMapView {
- /* Aggregate all the points into a single polyline */
- MKMapPoint *mapPoints = malloc(sizeof(MKMapPoint) * [points count]);
- int idx = 0;
+#pragma mark -
+#pragma mark Private Methods
+
+BOOL areCoordinateEqual(CLLocationCoordinate2D aCoordinate, CLLocationCoordinate2D bCoordinate) {
+ if ((aCoordinate.latitude == bCoordinate.latitude) &&
+ (aCoordinate.longitude == bCoordinate.longitude))
+ return TRUE;
+ return FALSE;
+}
+
+- (void) addCoordinate:(CLLocationCoordinate2D)coordinate toArray:(NSMutableArray *)array {
+ FFMapRoute *route;
+
+ /* Wrap the new segment into a small array and add it to the newroutes array */
+ NSMutableArray *segment = [[NSMutableArray alloc] initWithCapacity:2];
+ NSData *aPoint = [NSData dataWithBytes:&lastCoordinate length:sizeof(CLLocationCoordinate2D)];
+ NSData *bPoint = [NSData dataWithBytes:&coordinate length:sizeof(CLLocationCoordinate2D)];
- for (NSData *value in points) {
- CLLocationCoordinate2D *coordinate = (CLLocationCoordinate2D *) [value bytes];
- MKMapPoint point = MKMapPointForCoordinate(*coordinate);
- mapPoints[idx] = point;
- idx++;
+ [segment addObject:aPoint];
+ [segment addObject:bPoint];
+
+
+ /* Check if we are in a bogus/placeholder situation */
+ route = [array lastObject];
+
+ /* if the polyline doesn't exist, then we have an empty class. Remove it and keep with the job. */
+ if (route && (route.line == nil)) {
+ [array removeLastObject];
+ route = nil;
}
- /* Generate the new line */
- MKPolyline *segmentLine = [MKPolyline polylineWithPoints:mapPoints count:[points count]];
+ /* Otherwisely we have to create it */
+ route = [[FFMapRoute alloc] initWithSegment:segment];
+ /* Any new route has a level value of 1 */
+ route.level = 1;
+ [array addObject:route];
+
+ [mapView addOverlay:[route line]];
+
+ [route release];
+ [segment release];
+}
+
+- (void) checkAggregationIsNeeded {
+ /* check if aggregation algorithm should run */
+ NSArray *lastroutes = [routes lastObject];
+
+ if ([lastroutes count] == kAGGREGATION_FACTOR) {
+ [self aggregateRoutes];
+ [self checkAggregationIsNeeded];
+ }
+}
- /* Discard the old polyline */
- NSMutableArray *discardedLines = [NSMutableArray array];
+- (void) aggregateRoutes {
+ NSArray *lastroutes;
+ NSMutableArray *prevroutes;
- for (MKPolyline *line in lines) {
- [discardedLines addObject:line];
- [mapView removeOverlay:line];
+ /* Extract the last points and remove those from the routes array */
+ lastroutes = [[routes lastObject] retain];
+ [routes removeLastObject];
+
+ /* Extract the previously aggregated array, if any, and performs few checks */
+ prevroutes = [routes lastObject];
+
+ /* If it does not exist, then we have only to aggregate the lastroutes and higher its level */
+ if (!prevroutes) {
+ NSMutableArray *newAggregatePoints = [[NSMutableArray alloc] initWithCapacity:kAGGREGATION_FACTOR];
+ [self aggregatePoints:lastroutes toArray:newAggregatePoints];
- printf("Removed an overlay\n");
+ [routes addObject:newAggregatePoints];
+ [newAggregatePoints release];
+ }
+ /* Else, append it to the existing one */
+ else {
+ [self aggregatePoints:lastroutes toArray:prevroutes];
+ }
+}
+
+- (void) aggregatePoints:(NSArray *)points toArray:(NSMutableArray *)array {
+ CLLocationCoordinate2D prev;
+ NSMutableArray *newPoints = [[NSMutableArray alloc] init];
+ int level = 1;
+
+ /* Check all the routes */
+ for (FFMapRoute *route in points) {
+ for (NSData *value in [route points]) {
+ CLLocationCoordinate2D *coordinate = (CLLocationCoordinate2D *) [value bytes];
+ if (areCoordinateEqual(prev, *coordinate))
+ break;
+ [newPoints addObject:value];
+ prev = *coordinate;
+ }
+ level = route.level;
+ /* Remove the overlay */
+ [mapView removeOverlay:route.line];
}
- [lines removeObjectsInArray:discardedLines];
+ FFMapRoute *newRoute = [[FFMapRoute alloc] initWithSegment:newPoints];
+ [newPoints release];
+ newRoute.level = ++level;
- /* Add the new polyline */
- [mapView addOverlay:segmentLine];
- [lines addObject:segmentLine];
+ [mapView addOverlay:[newRoute line]];
- free(mapPoints);
+ [array addObject:newRoute];
+ [newRoute release];
}
-@end
+
+@end
Please sign in to comment.
Something went wrong with that request. Please try again.