Welcome to Campus Atlas -- a Mapping & GIS solution which provides easy access to navigating the campus around you.
Technical Implementation
Building IMDFs
In order to render the insides of a building, we need to construct the data in a format the computer can understand. We chose to use the Indoor Mapping Data Format (IMDF), a superset of the GeoJSON standard, written by Apple for use with Apple Maps.
We started with a floorplan PDF of the ILC. This floorplan is publicly available on the UMass website, and is on display in various parts of the ILC. We overlaid the foorplan on top of Google Maps, and drew polygons around all of the classrooms & hallways. We then added entrance and exit points, corresponding to all doors between classrooms and outside the building.Once we had the ILC sectioned into 'units', we exported these files to KML -- Keyhole Markup Language. This is an XML-like format, that although is standardized, it is not commonly used by many GIS platforms, in favor of more common formats like GeoJSON. Therefore, the second step in our pipeline was to convert the KML to GeoJSON. We used a Python library, alongside a good handful of tweaks, to make the GeoJSON IMDF compliant.
In the end, started had something that looked like this:
xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
<Placemark>
<name>n111name>
<Polygon>
<tessellate>1tessellate>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-72.52647901921534,42.39134650155054,0....
coordinates>
LinearRing>
outerBoundaryIs>
Polygon>
Placemark>
Document>
kml>
And with a press of a python3 geojson_imdf_converter.py
, we got
{
"type": "Feature",
"id": "ef65bb09-3219-4598-a238-34fed876548f",
"feature_type": "unit",
"properties": {
"name": "n111",
"restriction": null,
"accessibility": null,
"level_id": "1ae9c2cb-721a-4a8c-bbb0-c836b0504967",
"category": "classroom",
"alt_name": null,
"display_point": null
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-72.5262255, 42.390991],
[-72.5262188, 42.3909583],
[-72.5261999, 42.3909142],
...
]
]
}
}
The resulting IMDFs are are simply zipped GeoJSONs in a particular format w/ properties describing the attributes of the room (classroom vs hallway vs entryway, for example). There are lots pf properties that can be filled in, but to start we filled in the name and type of the room.
Finally, we needed to validate our IMDFs. These files were thousand of lines long, full of lat&lon coordinates, some of which were compliant, some of which were out of spec, and (at the beginning) some completely invalid. To solve this, we used Apple's own IMDF Sandbox. It allowed us to snap our polygons together, connecting rooms to hallways which weren't already. It allowed us to refine our scripts, fix issues, and visualize the building before we had the branch up and running.
Rendering Indoor Maps
We built an iPhone-native app using SwiftUI, UIKit, and MapKit to display our indoor maps. We request the user's current location to be able to retrieve the proper indoor maps for their given location. Next, we render polygons and annotations described in the IMDF on top of the MKMapView base map.
Locating and Serving the IMDFs
Once we have converted the basic map definitions into the standard IMDF format, we then post the files and host them in our backend; the backend of this project is implemented entirely through AWS. We have a PostgresSQL database hosted by AWS RDS (Relational Database Service), storage space supplied by AWS S3, and several REST API functions hosted on AWS lambdas that are delivered through Amazon's API Gateway.
When we receive an IMDF file to be stored in the database, we first compute the md5 digest and "GeoHash" of the IMDF. This geohash will encode a given latitude and longitude into a string of bits to create a unique identifier of a specific place on Earth. This hash was computed up to six characters to provide us a precision of ±0.61 KM. While the md5 digest is used to prevent duplicate IMDF's from being submitted, the geohash will allow us to perform to efficient locality-sensitive searches to find stored map definitions in the vicinity of a given latitude and longitude. Thus, we store the IMDF file in an Amazon S3 bucket, and submit the file's geohash, md5 digest, and S3 bucket key into RDS.
When the client (i.e. mobile app) wants to get a map definition from the client, it will make an http GET request to our AWS Lambda function hosted through API Gateway. This function will compute the geohash of the sent coordinates, and then look up any geohashes in the database that start with the same first five characters. Since geohash was designed based on the idea of locality sensitive hashing, any found database entries will be in the vicinity of the client. The lambda function will then respond back with the latitude/longitude of all the found entries, along with their key in S3. The client can than query the S3 storage with the provided keys to get the IMDF files of the buildings in its vicinity.