Jun 14

The new version of MapKit in iOS 4 supports polylines, finally. MKPolyline to be precise.

I have been working with the Google Maps API for a while and now I’m learning Objective-C and writing an iPhone app ro Route.ly

Since the best way to send around the net the data to draw a polyline on a map is in encoded format I decided to write a small Objective-C function to decode the encoded string. Since I couldn’t find this anywhere on the net I decided to publish the code here.

You’ll notice that at the beginning of the function I replace “\\\\” with “\\”. This is because I use the encoded data both in web pages with javascript and my iPhone app. In javascript “\\” would be considered an escape and would therefore break my array of points. This is not the case in Objective-C so I switch back to the normal “\\”.

- (NSMutableArray *) decodePolyline:(NSString *)encodedPoints {
        NSString escapedEncodedPoints = [encodedPoints stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"];
        int len = [escapedEncodedPoints length];
        NSMutableArray waypoints = [[NSMutableArray alloc] init];
        int index = 0;
        float lat = 0;
        float lng = 0;
               
        while (index < len) {
                char b;
                int shift = 0;
                int result = 0;
                do {
                        b = [escapedEncodedPoints characterAtIndex:index++] - 63;
                        result |= (b & 0x1f) << shift;
                        shift += 5;
                } while (b >= 0×20);
                   
                float dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
                lat += dlat;
                       
                shift = 0;
                result = 0;
                do {
                        b = [escapedEncodedPoints characterAtIndex:index++] - 63;
                        result |= (b & 0x1f) << shift;
                        shift += 5;
                } while (b >= 0×20);
                   
                float dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
                lng += dlng;
               
                float finalLat = lat * 1e-5;
                float finalLong = lng * 1e-5;
               
                Waypoint *newPoint = [[Waypoint alloc] init];
                newPoint.lat = [[NSString alloc] initWithFormat:@"%f", finalLat];
                newPoint.lng = [[NSString alloc] initWithFormat:@"%f", finalLong];
                [waypoints addObject:newPoint];
                [newPoint release];
        }
        return waypoints;
}

Waypoints is a simple model class I’ve written with two NSString properties: lat and lng.

Tagged with:
Mar 09

I love calculating driving directions on Google Maps and then drag the blue line marking my directions to change the route. Everything is updated automatically on the page and the directions are re-calculated to go through the new point I defined.

I’ve been playing around with the Google Maps APIs recently and imagine my disappointment when I found out that Google does not allow directions calculated through the APIs to be dragged around.

Not put off by this I decided to try and replicate the directions-dragging myself. How hard can it be?
As it turns out. Very, at least if you want to make it look as smooth as Google’s own solution.

When generating directions Google Maps adds a GPolyline element overlay to your map. You can set the returned line to be editable but this makes an awful lot of vertices appear on it, which makes reading your directions quite hard. Even so, once you dragged one of this vertices around you are not editing the route but just changing the shape of the line.

Mine is not a complete solution and I’m interested in feedback and ideas on how to improve it.

First off calculate your directions:

map = new google.maps.Map2(document.getElementById(‘map_canvas’));
var wayPoints = [];
wayPoints.push(startPoint.getLatLng());
wayPoints.push(endPoint.getLatLng());

var myDir = new google.maps.Directions(map)
myDir.loadFromWaypoints(wayPoints, { travelMode: G_TRAVEL_MODE_DRIVING });

This will calculate your driving directions and plot a GPolyline on your map. The line is easily accessible in the GDirections object once the directions are calculated. To intercept this I have decided to use the addoverlay event on the GMap object. This event is triggered every time something is plotted over the map (says on the tin).

google.maps.Event.addListener(myDir, "addoverlay", function() {
var dirLine = myDir.getPolyline(); // Get the polyline from the directions object
});

At this point we can ask the APIs to make the GPolyline editable. This will make the vertices appear on the line and make then draggable. As I said before this only changes the shape of the line and doesn’t actually affect your directions object. Luckily the GPolyline comes with a nifty event called lineupdated.
This is triggered once the user has finished dragging a vertex. By intercepting this we can look through the vertices and know what’s been changed on the line and where the vertex has been moved to.
In order to do this we must also know the previous position of the vertices (latitude and longitude) to be able to compare the old and the new “edited” line.
Another challenge is the fact that the GDirections object can accept only so many waypoints (25 if I’m not wrong). Which means we’ll have to add only the vertex that has changed to the directions and not all of them.

// In the addoverlay event also save the original vertices of the line
var origLine = [];
for (var i = 0; i &lt; dirLine.getVertexCount(); i++) {
origLine.push(dirLine.getVertex(i));
}
// DONE saving vertices

// Now intercept the lineupdated event and add the new waypoints
google.maps.Event.addListener(dirLine, "lineupdated", function() {
routePoints = [];
for (var i = 0; i &lt; dirLine.getVertexCount(); i++) {
var savedPoint = origLine[i];
if (!savedPoint || (savedPoint.lat() != dirLine.getVertex(i).lat() &amp;&amp; savedPoint.lng() != dirLine.getVertex(i).lng())) {
routePoints.push(dirLine.getVertex(i));
}
}

// Now we remove the previous directions and recalculate the route
map.removeOverlay(dirLine)
calcRoute();
});

This works quite well but does not look as smooth as Google’s solution.
The problem is that while you are dragging a vertex only that bit of the GPolyline moves and the rest stays in its original position. which makes the shape of your directions quite awkward while you are dragging. Unforunately the GPolyline does not come with a “startdragging” event, otherwise we could just recalculate the route every few seconds while the vertex is being dragged.

This is not the most elegant of solutions but it does the job.

Tagged with:
Oct 28

Ever since Schmidt resigned from Apple’s board we all knew that a feud between the two companies was about to start.

Google had just launched Android, a Mobile OS. I’m sure we are all too aware of this.
Android wasn’t, and still isn’t a serious competitor for Apple’s iPhone. Google’s OS still has a long way to go to reach the “slickness” of the iPhone OS. Furthermore Google doesn’t have control over the hardware running its OS. Which means that the brilliancy of the OS can be completely overshadowed by the absurdity of the hardware. Honestly, some of the Android phones look like they have been designed by some boffin called Jenkins who was given complete freedom by their boss, Who should have instead said “No Jenkins you imbecile that’s not a phone. It’s crap. Do it again.”

I’m getting side-tracked. Let’s get back to the point.

Today Google announced Google Map Navigation for Android; and somehow I doubt it will make it to the iPhone. My guess is that Google is repaying Apple in kind for the whole Google Voice debacle. This is a serious blow and Apple will have some work to do to catch up with this.

More importantly Google Maps Navigation runs entirely off the net.
I have an iPhone with the Navigon app. It’s great but on my slim 8GB iPhone 25% of the storage is used for Navigon maps. With mobile internet connectivity becoming ever more ubiquitous this is definitely the way to go.

All I can hope for is that the rumor that came out a while ago about Google developing its own mobile phone is true. Then I might seriously consider giving up my iPhone.

UPDATE: AppleInsider reports that Google is in fact planning to port Google Maps Navigation to iPhone. If Apple approves the application, that is. Just PR or are they actually working on it?

“Apple is a close partner,” a Google spokesperson toldĀ AppleInsider Wednesday. “Millions of users experience Google Maps on the iPhone. We will continue to work with Apple to bring innovation, including Latitude and Navigation, to users but you’ll have to speak to Apple about availability.”

Tagged with:
preload preload preload