Using OneMap in iOS map application

I am learning Swift, the new programming language developed by Apple for iOS and OSX application development, and ArcGIS iOS SDK. I am planning  to make a series of tutorials based on what I have learned progressively.

In this tutorial, I am going to show you how to use Singapore’s official map platform, OneMap (www.onemap.sg), in iOS 8 application.

OneMap is an integrated map system for government agencies to deliver location-based services and information. It is a multi-agency collaboration with many government agencies currently participating and contributing information. ~ http://www.onemap.sg/home

To use OneMap in our iOS app, we need to use ArcGIS iOS SDK from Esri.  First download the ArcGIS SDK for iOS from https://developers.arcgis.com/ios/. Follow the guide to install and setup the development environment. ArcGIS has a very comprehensive guide for installing and setting up the development environment.

To use OneMap, first you need to add a UIView to your storyboard. In the Identity Inspector, change the UIView class name to AGCMapView.

MapView

Connect the map view to the view controller by creating an outlet in in ViewController.swift file.

Outlet

Import the ArcGIS framework in view controller’s swift file to use ArcGIS SDK for ios.


// import ArcGIS framework
import UIKit
import ArcGIS

view raw

import_arcgis

hosted with ❤ by GitHub

In the viewDidLoad method of ViewController.swift file, create a tiled map layer using OneMap map service and add it to the map:


override func viewDidLoad() {
super.viewDidLoad()
// set OneMap base map url
let url = NSURL(string: "http://e1.onemap.sg/arcgis/rest/services/BASEMAP/MapServer")
// create a tiled map layer
let tiledLayer = AGSTiledMapServiceLayer(URL: url)
// add layer to the mapView UIView
self.mapView.addMapLayer(tiledLayer, withName: "Basemap Tiled Layer")
}

view raw

gistfile1.swift

hosted with ❤ by GitHub

Run the application and you will see the map application displaying onemap.sg base map in the map view.

Initial Run

Right now, our map displays the whole Singapore, but we want it to be focus on a particular area in Singapore when it is loaded. To do this we need to define the initial map extent to zoom in display. We need to pass the envelope geometry to the  zoomToEnvelope:animated: method to zoom to the area we are interested in. 

An envelope is defined by a pair of X-Y coordinates representing the lower-left and upper-right corners of a rectangular bounding-box.

To create an envelope geometry, we need X min, Y min, X max and Y max. How do we find out this values? Pretty easy. We can get the current map’s extent from mapView.visibleAreaEnvelope property. So we just have to zoom in to the area of interest and inspect the current mapView.visibleAreaEnvelope values and use them as the initial extent in viewDidLoad method.

Our View Controller must adapt to the  AGSMapViewLayerDelegate protocol and set itself as the delegate of mapView‘s layerDelegate.


class ViewController: UIViewController, AGSMapViewLayerDelegate {

view raw

gistfile1.swift

hosted with ❤ by GitHub

In the viewDidLoad method, add this line to set delegate. See the API reference documentation for the AGSMapViewLayerDelegate protocol to learn more on layerDelegate


self.mapView.layerDelegate = self

view raw

gistfile1.swift

hosted with ❤ by GitHub

Then implement mapViewDidLoad delegate method to add observer for mapView pan and zoom notifications.


func mapViewDidLoad(mapView:AGSMapView!){
NSNotificationCenter.defaultCenter().addObserver(self, selector: "responseToEventChanged:", name: AGSMapViewDidEndZoomingNotification, object: nil)
}
func responseToEventChanged(notification: NSNotification){
let theString = "xmin = \(mapView.visibleAreaEnvelope.xmin),\nymin = \(mapView.visibleAreaEnvelope.ymin),\nxmax = \(mapView.visibleAreaEnvelope.xmax),\nymax = \(mapView.visibleAreaEnvelope.ymax)"
println(theString);
}

view raw

gistfile1.swift

hosted with ❤ by GitHub

Run the application and zoom to the area you want to show on initial start up. As you zoom in to the area, you can see then envelope geometry data printed out in Xcode console. When you are satisfied with the view, copy the X min, Y min, X max and Y max from the console and use them as initial extent.

I choose Nanyang Polytechnic as my starting view and create an envelop geometry from it. Following is the complete code:


import UIKit
import ArcGIS
class ViewController: UIViewController, AGSMapViewLayerDelegate {
@IBOutlet weak var mapView: AGSMapView!
let xmin = 29495.9472786567
let ymin = 39801.9418330241
let xmax = 30037.5707551916
let ymax = 40765.3094566208
override func viewDidLoad() {
super.viewDidLoad()
// add base map
let url = NSURL(string: "http://e1.onemap.sg/arcgis/rest/services/BASEMAP/MapServer")
let tiledLayer = AGSTiledMapServiceLayer(URL: url)
self.mapView.addMapLayer(tiledLayer, withName: "Basemap Tiled Layer")
self.mapView.layerDelegate = self
let envelope = AGSEnvelope(xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax, spatialReference: self.mapView.spatialReference);
self.mapView.zoomToEnvelope(envelope, animated: false)
}
func mapViewDidLoad(mapView:AGSMapView!){
NSNotificationCenter.defaultCenter().addObserver(self, selector: "responseToEventChanged:", name: AGSMapViewDidEndZoomingNotification, object: nil)
}
func responseToEventChanged(notification: NSNotification){
let theString = "xmin = \(mapView.visibleAreaEnvelope.xmin),\nymin = \(mapView.visibleAreaEnvelope.ymin),\nxmax = \(mapView.visibleAreaEnvelope.xmax),\nymax = \(mapView.visibleAreaEnvelope.ymax)"
println(theString);
}
}

view raw

gistfile1.swift

hosted with ❤ by GitHub

Mat on NYP

In this tutorial, we have learned how to add OneMap as based map to the iOS application and setting up initial map extent to the location of interest by using envelop geometry. If you want to know more about OneMap features and services, please visit to their API help page http://www.onemap.sg/api/help/.

Look forward for more tutorials on using OneMap from me and please leave a comment if you find any error or have difficulty following the steps above.

Batch Geocoding Tool For Singapore SVY21 Coordinate System

I have created a tool to geocode large amount Singapore postal codes into X, Y values of SVY21 coordinate system. SVY21 is the Singapore standard coordinate system used by Singapore Land Authority.

You can get the X, Y values of an address by using search function provided in www.onemap.sg. But if you have a few thousands of addresses to geocode, my batch geocoding tool can help you better. You need internet connection to use the tool because the program is the wrapper written in c# to call web service provided by onemap.

Download link:  Batch Geocoder Installer 

Download the installer and unzip the folder. Run setup to install the tool on your computer. You may need .NET runtime to run the program. After installation run the tool from start menu.

batch-geocode

Simply provide an input file containing a column of Singapore postal codes. Give the name and location of the output file where the result (X, Y) values are to be written. Click Run button to start the batch process. It may take a while depending on the number of postal codes you are processing.

Right now, the tool can only accept postal codes as input. In the future, I am planning to extend it to accept whole or partial addresses as input. The source code is hosted on Github https://github.com/zkkmin/BatchGeoCodeOneMap for anyone who is interested to look at it.

Focus productivity with Kanbanflow

We are getting more and more busy each day without accomplishing much. When we are not busy, we get distracted by other people, devices and even cats on the internet. We end up feeling exhausted at the end of the day without getting nearer to our life long goals, without finishing off our side projects and without writing as much as we should. We only have 24 hours a day and It is important that we spend them on the tasks that really matter. There are many productivity tools out there which can help you get more things done, but I found the tool call  Kanbanflow to be simple and very effective.

Kanbanflow combines the ideas of Pomodoro™  technique and Kanban board. It helps me visualize the important tasks I need to carry out during the week and focus on each tasks by using Pomodoro™ technique. The default Kanbanflow board has 4 columns named __ To-do, Do Today, In Progress and Done. You can add or remove columns as you like. Kanban board helps you manage the tasks visually. Built in Pomodoro™ timer allows you to focus on current task and track the time spending on it. Your productivity can be measured not only by the tasks you have completed but also by how many Pomodoro™ periods you have done for the day. You can also review how long did it take for a task to finish.

The simplest way to use Kanbanflow is to create a list of important tasks in To-do column. Each morning, plan your day by assigning the tasks from To-do column into Do today column. Move the task you are going to do next to In progress column. Use Pomodoro™ timer to work on them. When you finish a task, move it into Done column. If you like to plan for the week, add columns for each day of the week and put tasks in there.

I am a very happy user of this tool now and I can plan and execute my important tasks better than before. Do give it a try if you haven’t done so.

kanbanflow