When I set out to build Sun Surveyor, I knew I wanted to give users an easy way of visualizing the location of the sun and the moon. Sun Surveyor has an augmented reality (AR) feature, which overlays sun and moon paths on top of the device camera’s view. This is useful for understanding how light will change over time at a particular location. While I also created a Map View to show the paths on a Google Map for remote locations, it was not as intuitive as augmented reality.
Visualizing the sun and moon paths in augmented reality and map views
When Street View launched in the Google Maps SDK for iOS in v1.4.0 (July, 2013), I couldn’t wait to visualize the sun and moon paths within an interactive panorama. Street View panoramas bridge the gap between Sun Surveyor’s Map View and AR experiences by giving users an augmented reality experience, wherever they want to go.
Sun and moon paths with Street View panoramas
Implementing a sun path Overlay on Street View
I took a creative approach to working with the Google Maps SDK for iOs. While polylines can be implemented in Map View, this isn’t yet possible in a Street View panorama. To display paths and other items that move with the Street View panorama, I needed to:
- Create an overlay on top of the panorama upon which to draw the items
- Synchronize the positions of the overlay items with the panorama as it moves
- Determine which data are visible and where on the screen to draw them
I. Creating an Overlay
In our main
UIViewController, we add a subclass of
UIViewfor the overlay, make its background color transparent, and place the
GMSPanoramaViewbelow it in the view hierarchy.
Representing Overlay Items
We represent the overlay items with a protocol having two methods:
updateWithPanoramaViewand draw. The
updateWithPanoramaViewmethod updates an item’s screen location geometry, while draw draws it to the current graphics context.
We store all items to be drawn in a collection, update their positions based on the panorama position, and draw the collection in our view’s standard
If we want to make sure these items are drawn in a certain order that might change based on the data, we can add z-indexes to them and then sort the collection by z-index after we update them and before drawing.
II. Syncing the Overlay with the Panorama
To make sure this overlay view stays updated as the panorama moves beneath it, we can update the view’s data in an implementation of
didMoveCameramethod. We can use a
CADisplayLinkto ensure the overlay view is redrawn at regular intervals, and use a flag to make sure it is only redrawn when necessary.
CoreGraphicscan be a bottleneck.
[NSString drawAtPoint]are expensive as you can see by profiling with Instruments. For performance intensive applications, an alternative is to use OpenGL. Avoiding overdraw is always a good idea, so the first optimization, if needed, is to carefully examine what is being drawn to the screen, and draw only what is necessary.
III. Mapping data to the panorama view
GMSProjectionclass has a
pointForCoordinatemethod that returns the screen pixel location for a coordinate on the Map. This is useful for overlaying elements on top of a
GMSMapView, and is used in the Sun Surveyor Map View to draw text related to sun and moon paths on top of the Map.
GMSPanoramaViewhas a similar method,
pointForOrientation. This method allows us to query the panorama for a screen pixel location given a
GMSOrientation(bearing and pitch tuple) relative to the panorama location, where the camera is stationed, at ground level. This is useful to make sure an item we overlay onto the view remains in the same location relative to the scene, even as the camera moves and the view shifts.
Because the camera has a Field of View that determines what is visible on the screen, some orientations are not visible (such as behind the camera position).
NAN(not a number) for such orientations, so we know the given orientation is not visible.
With sun path data already expressed in terms of orientation relative to the ground level of the viewer, drawing corresponding paths with screen pixel locations is easy. We map our data with
pointForOrientation, and draw what is visible by checking the result for
The sample project uses a panorama of Sydney, Australia, looking west, with a sun path for 12/20/2013.
Version 1.4.1 of the SDK added support for changing the
GMSPanoramaCamera’sfield of view (FOV). The field of view determines how much of the scene is visible on a device screen, as well as how much distortion around the edges of the view is present. Smaller values for FOV are the equivalent of having a telephoto lens on a real camera: it brings distant objects closer.
Left: FOV of 60 degrees. Middle: 90 degrees (default). Right: 130 degrees.
Street View Panoramas are awesome and easy
The Street View panorama viewer in the Google Maps SDK for iOS is an example of a great API. The
GMSPanoramaViewclass is simple to understand and use. In the course of a weekend, I was able to deliver a fun, interactive and highly requested feature to Sun Surveyor’s iOS users. I can’t wait to see what people are able to do with this new Street View Panorama feature in my app, and I look forward to seeing all the other implementations that others develop!
Stonehenge, as seen from a Street View panorama in Sun Surveyor
Posted by Monica Tran, Google Maps API
Sun Surveyor visualizes the sun and moon in a variety of ways for photographers, filmmakers, solar industry professionals, architects, homebuyers, gardeners, and anyone needing to predict or understand the movement of the sun and moon.
Adam Ratana is a Carnegie Mellon University graduate living in, and loving, Pittsburgh, PA. He produces dance music as a member of Pittsburgh Track Authority, enjoys photography, traveling with his wife, and writing fun software in his free time. Adam also enjoys attending the Pittsburgh Cocoaheads chapter meetings.