Skip to content

Instantly share code, notes, and snippets.

@AppWerft
Created May 18, 2015 07:12
ti.augmentedreality.js
var isAndroid = Ti.Platform.osname == 'android';
var numberOfpanels = 4;
/*if (isAndroid) {
// Landscape Mode
var screenWidth = Ti.Platform.displayCaps.platformHeight;
var screenHeight = Ti.Platform.displayCaps.platformWidth;
} else {*/
var LDF = Ti.Platform.displayCaps.logicalDensityFactor || 1;
var screenWidth = (Math.max(Ti.Platform.displayCaps.platformWidth, Ti.Platform.displayCaps.platformHeight)) / LDF;
var screenHeight = (Math.min(Ti.Platform.displayCaps.platformWidth, Ti.Platform.displayCaps.platformHeight)) / LDF;
console.log('SCREENWIDTH=' + screenWidth);
//}
// https://github.com/jeffbonnes/parmavision
var MAX_ZOOM = 1.2;
var MIN_ZOOM = 0.1;
var DELTA_ZOOM = MAX_ZOOM - MIN_ZOOM;
var MIN_Y = Math.floor(screenHeight * 0.1);
var MAX_Y = Math.floor(screenHeight * 1);
var DELTA_Y = MAX_Y - MIN_Y;
// Setup the location properties for callbacks
Ti.Geolocation.purpose = 'Augmented Reality';
Ti.Geolocation.getCurrentHeading(function() {
});
Ti.Geolocation.headingFilter = 1;
Ti.Geolocation.showCalibration = false;
// https://jira.appcelerator.org/browse/TIMOB-9434
if (isAndroid) {
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_LOW;
} else {
Ti.Geolocation.distanceFilter = 10;
Ti.Geolocation.preferredProvider = "gps";
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_NEAREST_TEN_METERS;
Ti.Geolocation.purpose = "Augmented Reality";
}
// function to create the window
exports.createARWindow = function(params) {
function showAR() {
Ti.Geolocation.addEventListener('heading', headingCallback);
Ti.Geolocation.addEventListener('location', locationCallback);
Ti.Media.showCamera({
success : function() {
},
cancel : function() {
// only gets called if Android
closeAR();
},
error : function(error) {
alert('unable to open AR Window');
closeAR();
},
mediaTypes : [Ti.Media.MEDIA_TYPE_VIDEO, Ti.Media.MEDIA_TYPE_PHOTO],
showControls : false,
autohide : false,
autofocus : "off",
animated : false,
overlay : overlay
});
}
function closeAR() {
Ti.Geolocation.removeEventListener('heading', headingCallback);
Ti.Geolocation.removeEventListener('location', locationCallback);
if (!isAndroid) {
Ti.Media.hideCamera();
}
setTimeout(function() {
win.close();
}, 500);
}
var panels = [];
// background colors for debugging
var showColors = false;
var colors = ['red', 'yellow', 'pink', 'green', 'purple', 'orange', 'blue', 'aqua', 'white', 'silver'];
var myLocation = null;
// Create the main view - only as wide as the viewport
var overlay = Ti.UI.createView({
top : 0,
height : screenHeight,
left : 0,
width : screenWidth,
backgroundColor : 'transparent'
});
// Create all the view that will contain the points of interest
for (var i = 0; i < numberOfpanels; i++) {
// create a view 1.6x the screen width
// they will overlap so any poi view that
// are near the edge will continue over into the
// 'next' view.
panels[i] = Ti.UI.createView({
top : 0,
height : screenHeight,
right : 0,
width : (screenWidth * 1.6),
visible : false
});
if (showColors) {
panels[i].backgroundColor = colors[i];
panels[i].opacity = 0.6;
}
overlay.add(panels[i]);
};
var radar = Ti.UI.createView({
backgroundImage : '/assets/radar.png',
width : '80dp',
height : '80dp',
bottom : '10dp',
left : '10dp',
zIndex : 9999,
opacity : 0.6
});
var compass = Ti.UI.createLabel({
left : '50dp',color:'#009FE0',
bottom : 2,visible:false
});
overlay.add(compass);
overlay.add(radar);
if (params.overlay) {
overlay.add(params.overlay);
}
if (!isAndroid) {
var button = Ti.UI.createButton({
top : '5dp',
right : '5dp',
height : '45dp',
width : '45dp',
backgroundImage : '/images/close.png'
});
button.addEventListener('click', closeAR);
overlay.add(button);
}
var lastActiveView = -1;
var viewChange = false;
var centerY = screenHeight / 2;
var activePois;
var lastBearing = 0;
var TP = new (require('vendor/tiefpass'))();
function headingCallback(e) {
var currBearing = e.heading.trueHeading || e.heading.magneticHeading;
currBearing = TP.add(currBearing);
if (currBearing == lastBearing)
return;
lastBearing = currBearing;
// Rotate the radar
radar.transform = Ti.UI.create2DMatrix().rotate(-currBearing);
compass.text = currBearing;
var internalBearing = currBearing / (360 / panels.length);
var activeView = Math.floor(internalBearing);
var pixelOffset = screenWidth - (Math.floor((internalBearing % 1) * screenWidth));
// console.log('currBearing ' + currBearing);
// console.log('internalBearing ' + internalBearing);
// console.log('activeView ' + activeView);
if (activeView != lastActiveView) {
viewChange = true;
lastActiveView = activeView;
} else {
viewChange = false;
}
for (var i = 0; i < panels.length; i++) {
var diff = activeView - i;
if (diff >= -1 && diff <= 1) {
panels[i].center = {
y : centerY,
x : pixelOffset - (diff * screenWidth)
};
if (viewChange) {
panels[i].visible = true;
}
} else {
if (viewChange) {
panels[i].visible = false;
}
}
}
if (activeView == 0) { // first panel
panels[panels.length - 1].center = {
y : centerY,
x : panels[0].center.x - screenWidth
};
if (viewChange) {
panels[panels.length - 1].visible = true;
}
} else if (activeView == (panels.length - 1 )) { // last panel
panels[0].center = {
y : centerY,
x : panels[panels.length - 1].center.x + screenWidth
};
if (viewChange) {
panels[0].visible = true;
}
}
}// end of heading changing
// Just a container window to hold all these objects
// user will never know
var win = Ti.UI.createWindow({
modal : true,
navBarHidden : true,
fullscreen : true,
theme : 'Theme.NoActionBar',
orientationModes : [Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT]
});
if (params.maxDistance) {
win.maxDistance = params.maxDistance;
}
win.doClose = function() {
closeAR();
};
win.addEventListener('open', function() {
Ti.API.debug('AR Window Open...');
setTimeout(showAR, 500);
});
win.assignPOIs = function(pois) {
win.pois = pois;
// TODO - something here to make sure the pois redraw
// even if the location doesn't update
};
function poiClick(e) {
Ti.API.debug('heard a click');
Ti.API.debug('number=' + e.source.number);
var poi = activePois[e.source.number];
var view = poi.view;
view.fireEvent('click', {
source : poi.view,
poi : poi
});
}
function locationCallback(e) {
myLocation = e.coords;
redrawPois();
};
function redrawPois() {
if (!myLocation) {
Ti.API.warn("location not known. Can't draw pois");
return;
}
// remove any existing panels
for (var i = 0; i < panels.length; i++) {
panels[i].removeAllChildren();
}
radar.removeAllChildren();
// Draw the Points of Interest on the panels
activePois = [];
for (var i = 0; i < win.pois.length; i++) {
var poi = win.pois[i];
if (poi.view) {
var distance = calculateDistance(myLocation, poi);
var addPoint = true;
if (win.maxDistance && distance > win.maxDistance) {
addPoint = false;
}
if (addPoint) {
var bearing = calculateBearing(myLocation, poi);
var internalBearing = bearing / (360 / panels.length);
var activeView = Math.floor(internalBearing);
if (activeView >= panels.length) {
activeView = 0;
}
var pixelOffset = Math.floor((internalBearing % 1) * screenWidth) + ((panels[0].width - screenWidth) / 2);
poi.distance = distance;
poi.pixelOffset = pixelOffset;
poi.activeView = activeView;
poi.bearing = bearing;
activePois.push(poi);
} else {
Ti.API.debug(poi.title + " not added, maxDistance=" + win.maxDistance);
}
}
}
// Sort by Distance
activePois.sort(function(a, b) {
return b.distance - a.distance;
});
if (activePois[0]) {
var maxDistance = activePois[0].distance;
var minDistance = activePois[activePois.length - 1].distance;
var distanceDelta = maxDistance - minDistance;
// Add the view
for (var i = 0; i < activePois.length; i++) {
var poi = activePois[i];
Ti.API.debug(poi.title);
if (showColors) {
Ti.API.debug('viewColor======' + panels[poi.activeView].backgroundColor);
}
// Ti.API.debug('bearing=' + poi.bearing);
// Calcuate the Scaling (for distance)
var distanceFromSmallest = poi.distance - minDistance;
var percentFromSmallest = 1 - (distanceFromSmallest / distanceDelta);
var zoom = (percentFromSmallest * DELTA_ZOOM) + MIN_ZOOM;
// Calculate the y (farther away = higher )
var y = MIN_Y + (percentFromSmallest * DELTA_Y);
var view = poi.view;
// Apply the transform
var transform = Ti.UI.create2DMatrix();
transform = transform.scale(zoom);
view.transform = transform;
// Ti.API.debug('pixelOffset=' + poi.pixelOffset);
view.center = {
x : poi.pixelOffset,
y : y
};
// Testing Click Handlers
/*
if (view.clickHandler) {
view.clickHandler.removeEventListener('click', poiClick);
view.remove(view.clickHandler);
view.clickHandler = null;
}
var clickHandler = Ti.UI.createView({
width : Ti.UI.FILL,
height : Ti.UI.FILL
});
var number = i;
clickHandler.number = number;
clickHandler.addEventListener('click', poiClick);
view.add(clickHandler);
view.clickHandler = clickHandler;
*/
panels[poi.activeView].add(view);
// Ti.API.debug('panelsize=' + view.width + "," + view.height);
// need to create a second click handler
// on the closest view in case there is overlap
/*var clickHandler2 = Ti.UI.createView({
width : view.width,
height : view.height,
transform : transform
});
clickHandler2.number = number;
clickHandler2.addEventListener('click', poiClick);
*/
var nextView;
var nextOffset;
if (poi.pixelOffset > (panels[0].width / 2 )) {
nextView = poi.activeView + 1;
nextOffset = poi.pixelOffset - screenWidth;
} else {
nextView = poi.activeView - 1;
nextOffset = poi.pixelOffset + screenWidth;
}
if (nextView < 0) {
nextView = panels.length - 1;
} else if (nextView == panels.length) {
nextView = 0;
}
// Ti.API.debug('nextView=' + nextView);
// Ti.API.debug('nextOffset=' + nextOffset);
/* clickHandler2.center = {
x : nextOffset,
y : y
};*/
// panels[nextView].add(clickHandler2);
// End Click Handlers
// add to blip to the radar
// The Radar Blips ....
var rad = toRad(poi.bearing);
var relativeDistance = poi.distance / (maxDistance * 1.2);
var centerX = (40 + (relativeDistance * 40 * Math.sin(rad)));
var centerY = (40 - (relativeDistance * 40 * Math.cos(rad)));
var displayBlip = Ti.UI.createView({
height : '2dp',
width : '2dp',
backgroundColor : 'white',
borderRadius : 2,
top : (centerY - 1) + "dp",
left : (centerX - 1) + "dp"
});
radar.add(displayBlip);
}
}
};
if (params.pois) {
win.assignPOIs(params.pois);
}
return win;
};
function toRad(val) {
return val * Math.PI / 180;
};
function calculateBearing(point1, point2) {
var lat1 = toRad(point1.latitude);
var lat2 = toRad(point2.latitude);
var dlng = toRad((point2.longitude - point1.longitude));
var y = Math.sin(dlng) * Math.cos(lat2);
var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dlng);
var brng = Math.atan2(y, x);
return ((brng * (180 / Math.PI)) + 360) % 360;
};
function calculateDistance(loc1, loc2) {
var R = 6371;
// Radius of the earth in km
var dLat = (toRad(loc2.latitude - loc1.latitude));
// Javascript functions in radians
var dLon = (toRad(loc2.longitude - loc1.longitude));
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(loc1.latitude)) * Math.cos(toRad(loc2.latitude)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
// Distance in m
return R * c * 1000;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment