项目作者: AugustusZ

项目描述 :
Campus Viewer with AR
高级语言: C#
项目地址: git://github.com/AugustusZ/Spot.git
创建时间: 2016-07-29T20:37:50Z
项目社区:https://github.com/AugustusZ/Spot

开源协议:

下载


Spot

This is a 46-hour team project for Esri Second Annual Weekend of Innovation.

SPOT is a site-specific, outdoor exploration and way finding app that uses augmented reality visualization for the Esri Headquarter. The way this app helps users navigate around a campus can be applied for any other sites such as universities, airport, museums, etc.

Teamwork

Work Anup Deulgaonkar Jake Devost Keyur Kulkarni Yankuan Zhang
Demo and Presentation
Data Communication
Unity3D
Coordinate Algorithm
UI/UX Design

And future work.

Demo and Presentation

Data Communication

REST API of ArcGIS Server.

Callback JSON data structure

For each feature in the array of features in callback, we have building name Building and its description Descriptio as well as latitude x and longitude y for the center point of the object, e.g.,

  1. {
  2. "attributes" :
  3. {
  4. "OBJECTID" : 1,
  5. "Building" : "Building Q",
  6. "Descriptio" : "Corporate"
  7. },
  8. "geometry" :
  9. {
  10. "x" : -117.19569250299996,
  11. "y" : 34.056070361000017
  12. }
  13. },

Note: output spatial reference is 4326

Unity3D

We used Vuforia package for Unity3D. To lighten the app, Vuforia dependency is removed, and native camera is utilized instead. Repo subfolder Spot is the Unity3D project.

Installation guidelines

  1. Open Unity project, Command + Shift + B to build on iOS
  2. Open the Xcode project just generated by Unity and then you can deploy it on your device.

App Design and Implementation

Architecture

Algorithms

Don’t forget to check angle unit (deg or rad) when use trigonometric functions. Here, input lat1, lon1, lat2, lon2 are all in degree. If trigonometric functions are in radian, we will convert coordinates to radian by multiplying by DEG_TO_RAD, value of which is pi/180. If we want to convert from rad to deg, then multiply by RAD_TO_DEG, value of which is 180/pi.

Distance

  1. function distanceBetween(lat1, lon1, lat2, lon2) {
  2. lat1 = lat1 * DEG_TO_RAD;
  3. lon1 = lon1 * DEG_TO_RAD;
  4. lat2 = lat2 * DEG_TO_RAD;
  5. lon2 = lon2 * DEG_TO_RAD;
  6. dLat = lat2 - lat1;
  7. dLon = lon2 - lon1;
  8. a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1) * cos(lat1) * sin(dLon / 2) * sin(dLon / 2);
  9. return EARTH_RADIUS * 2 * atan2(sqrt(a), sqrt(1 - a)); // EARTH_RADIUS ~ 6371 km
  10. }

Font Size

Label font size ranges from 19 to 40. If the distance is greater than 300m, fix the size to 19.

  1. distance = distanceBetween(...);
  2. function getFontSizeFromDistance(distance) {
  3. // unit of distance: meter
  4. if (distance > 300) {
  5. return 19;
  6. }
  7. return ceil(40 - distance / 14);
  8. }

Bearing

The return value ∈ (-180, 180].

  1. function bearingBetween(lat1, lon1, lat2, lon2) {
  2. lat1 = lat1 * DEG_TO_RAD;
  3. lon1 = lon1 * DEG_TO_RAD;
  4. lat2 = lat2 * DEG_TO_RAD;
  5. lon2 = lon2 * DEG_TO_RAD;
  6. y = sin(lon2 - lon1) * cos(lat2);
  7. x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);
  8. return atan2(y, x) * RAD_TO_DEG;
  9. }

Theta

Because

  • bearing(-180, 180]
  • heading[0, 360) (read from device sensor)

So, bearing - heading(-540, 180]. To deduce the range to (-180, 180],

  1. bearing = bearingBetween(...);
  2. heading = compass.trueHeading;
  3. function calculateTheta(bearing, heading) {
  4. theta = bearing - heading;
  5. return (theta < -180) ? theta + 360 : theta;
  6. }

FOV

FOV (field of view) is a camera parameter. For iPhone 6 camera, FOV is 63.54°, according to this. And this number works as well for iPhone 5S/SE.

(Yes, we should read the parameter from device sensor API directly. But the numbers we read did not really make sense to us and would lead to wrong label position calculation. So we hardcoded it for now until we figure it out.)

X-offset on screen

To calculate label xOffset from vertical center line of the screen, we need:

  • FOV
  • theta
  • width of screen (read from device)

Let’s skip the how we get the formula and give it directly:

  1. function getXOffset(theta, fieldOfView, screenWidth) {
  2. theta = theta * DEG_TO_RAD;
  3. fieldOfView = fieldOfView * DEG_TO_RAD;
  4. return 0.5 * tan(theta) / tan(fieldOfView) * screenWidth;
  5. }

Yes, we can do the same calculation for yOffset, with:

  • vertical FOV
  • vertical theta
  • height of screen

UI/UX Design

UI/UX ideation and Graphic Communication

By Jake. See more Jake’s fantastic works, click here.

Splash Screen

App Icon

There will be a version with better quality to be released…

Future Work

  • Refine UI

    • perspective
      • contrast in color
    • better-quality icon
    • label
      • tappable
      • properly organized labels
      • sync label position vertically
      • 3D
  • Face-up

    • explore mode
      • interactive map
      • realtime-location
      • routing visualization
    • detail mode
      • display more info for selected object
  • Enable accessibility

    • Voice control
    • Speak-out