terriajs
Version:
Geospatial data visualization platform.
708 lines (593 loc) • 47.3 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: Models/AugmentedVirtuality.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: Models/AugmentedVirtuality.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>'use strict';
import defined from 'terriajs-cesium/Source/Core/defined';
import defaultValue from 'terriajs-cesium/Source/Core/defaultValue';
import knockout from 'terriajs-cesium/Source/ThirdParty/knockout';
import CesiumMath from 'terriajs-cesium/Source/Core/Math.js';
import CesiumMatrix3 from 'terriajs-cesium/Source/Core/Matrix3.js';
import CesiumCartesian3 from 'terriajs-cesium/Source/Core/Cartesian3.js';
import EllipsoidTerrainProvider from 'terriajs-cesium/Source/Core/EllipsoidTerrainProvider';
import sampleTerrainMostDetailed from 'terriajs-cesium/Source/Core/sampleTerrainMostDetailed';
/**
* Manages state for Augmented Virtuality mode.
*
* This mode uses the devices orientation sensors to change the viewers viewport to match the change in orientation.
*
* Term Augmented Virtuality:
* "The use of real-world sensor information (e.g., gyroscopes) to control a virtual environment is an additional form
* of augmented virtuality, in which external inputs provide context for the virtual view."
* {@link https://en.wikipedia.org/wiki/Mixed_reality}
*
* @alias AugmentedVirtuality
* @constructor
*/
var AugmentedVirtuality = function(terria) {
const that = this;
this._terria = terria;
// Note: We create a persistant object and define a transient property, since knockout needs a persistant variable
// to track, but for state we want a 'maybe' intervalId.
this._eventLoopState = {};
this._manualAlignment = false;
this._maximumUpdatesPerSecond = AugmentedVirtuality.DEFAULT_MAXIMUM_UPDATES_PER_SECOND;
this._orientationUpdated = false;
this._alpha = 0;
this._beta = 0;
this._gamma = 0;
this._realignAlpha = 0;
this._realignHeading = 0;
// Set the default height to be the last height so that when we first toggle (and increment) we cycle and go to the first height.
this._hoverLevel = AugmentedVirtuality.PRESET_HEIGHTS.length-1;
// Always run the device orientation event, this way as soon as we enable we know where we are and set the
// orientation rather then having to wait for the next update.
// The following is disabled because chrome does not currently support deviceorientationabsolute correctly:
// if ('ondeviceorientationabsolute' in window)
// {
// window.addEventListener('deviceorientationabsolute', function(event) {that._orientationUpdate(event);} );
// }
// else
if ('ondeviceorientation' in window) {
window.addEventListener('deviceorientation', function(event) {that._storeOrientation(event);});
}
// Make the variables used by the object properties knockout observable so that changes in the state notify the UI
// and cause a UI update. Note: These are all of the variables used just by the getters (not the setters), since
// these unqiquely define what the current state is and are the only things that can effect/cause the state to change
// (note: _eventLoopState is hidden behind ._eventLoopRunning() ).
knockout.track(this, ['_eventLoopState', '_manualAlignment', '_maximumUpdatesPerSecond',
'_realignAlpha', '_realignHeading', '_hoverLevel']);
// Note: The following properties are defined as knockout properties so that they can be used to trigger updates on the UI.
/**
* Gets or sets whether Augmented Virtuality mode is currently enabled (true) or not (false).
*
* Note: If {@link AugmentedVirtuality#manualAlignment} is enabled and the state is changed it will be disabled.
*
* @memberOf AugmentedVirtuality.prototype
* @member {Boolean} enabled
*/
knockout.defineProperty(this, 'enabled', {
get : function() {
return this._eventLoopRunning() || this._manualAlignment;
},
set : function(enable) {
if (enable !== true) {
enable = false;
this.resetAlignment();
}
if (enable !== this.enabled) {
// If we are changing the enabled state then disable manual alignment.
// We only do this if we are changing the enabled state so that the client can repeatedly call the
// setting without having any effect if they aren't changing the enabled state, but so that every time
// that the state is changed that the manual alignment is turned back off initally.
this._manualAlignment = false;
this._startEventLoop(enable);
}
}
});
/**
* Gets or sets whether manual realignment mode is currently enabled (true) or not (false).
*
* @memberOf AugmentedVirtuality.prototype
* @member {Boolean} manualAlignment
*/
knockout.defineProperty(this, 'manualAlignment', {
get : function() {
return this._getManualAlignment();
},
set : function(startEnd) {
this._setManualAlignment(startEnd);
}
});
/**
* Gets whether a manual realignment has been specified (true) or not (false).
*
* @memberOf AugmentedVirtuality.prototype
* @member {Boolean} manualAlignmentSet
*/
knockout.defineProperty(this, 'manualAlignmentSet', {
get : function() {
return (this._realignAlpha !== 0.0) || (this._realignHeading !== 0.0);
},
});
/**
* Gets the index of the current hover level.
*
* Use <code>AugmentedVirtuality.PRESET_HEIGHTS.length</code> to find the total avaliable levels.
*
* @memberOf AugmentedVirtuality.prototype
* @member {int} hoverLevel
*/
knockout.defineProperty(this, 'hoverLevel', {
get : function() {
return this._hoverLevel;
},
});
/**
* Gets or sets the the maximum number of times that the camera orientation will be updated per second. This is
* the number of camera orientation updates per seconds is capped to (explicitly the number of times the
* orientation is updated per second might be less but it won't be more then this number). We want the number of
* times that the orientation is updated capped so that we don't consume to much battery life updating to
* frequently, but responsiveness is still acceptable.
*
* @memberOf AugmentedVirtuality.prototype
* @member {Float} maximumUpdatesPerSecond
*/
knockout.defineProperty(this, 'maximumUpdatesPerSecond', {
get : function() {
return this._maximumUpdatesPerSecond;
},
set : function(maximumUpdatesPerSecond) {
this._maximumUpdatesPerSecond = maximumUpdatesPerSecond;
// If we are currently enabled reset to update the timing interval used.
if (this._eventLoopRunning()) {
this._startEventLoop(false);
this._startEventLoop(true);
}
}
});
this.enabled = false;
};
/**
* Gets the the maximum number of times that the camera orientation will be updated per second by default. This is the
* number of camera orientation updates per seconds is capped to by default (explicitly the number of times the
* orientation is updated per second might be less but it won't be more then this number). We want the number of times
* that the orientation is updated capped so that we don't consume to much battery life updating to frequently, but
* responsiveness is still acceptable.
*/
AugmentedVirtuality.DEFAULT_MAXIMUM_UPDATES_PER_SECOND = 10.0;
/**
* The minimum height that the viewer is allowed to hover at.
*/
AugmentedVirtuality.MINIMUM_HOVER_HEIGHT = 20.0;
/* These are the heights that we can toggle through (in meters - above the surface height).
*/
AugmentedVirtuality.PRESET_HEIGHTS = [1000, 250, 20];
/**
* Toggles whether the AugmentedVirutuality mode is enabled or disabled.
*/
AugmentedVirtuality.prototype.toggleEnabled = function() {
this.enabled = !this.enabled;
};
/**
* Toggles whether manual alignement is enabled or disabled.
*/
AugmentedVirtuality.prototype.toggleManualAlignment = function() {
this.manualAlignment = !this.manualAlignment;
};
/**
* Resets the alignment so that the alignement matches the devices absolute alignment.
*/
AugmentedVirtuality.prototype.resetAlignment = function() {
this._orientationUpdated = true;
this._realignAlpha = 0;
this._realignHeading = 0;
};
/**
* Toggles the viewer between a range of predefined heights, setting the cameras orientation so that it matches the
* correct orientation.
*/
AugmentedVirtuality.prototype.toggleHoverHeight = function() {
this._hoverLevel = (this._hoverLevel + 1) % AugmentedVirtuality.PRESET_HEIGHTS.length;
this.hover(AugmentedVirtuality.PRESET_HEIGHTS[this._hoverLevel]);
};
/**
* Moves the viewer to a specified height, setting the orientation so that it matches the correct Augmented Virtuality
* orientation.
*
* @param {Float} height The height in Meters above the globe surface. Note: If height is below
* {@link AugmentedVirtuality.MINIMUM_HOVER_HEIGHT} the height will be set to
* {@link AugmentedVirtuality.MINIMUM_HOVER_HEIGHT} to avoid visual artifacts when the viewer
* becomes to close to the surface.
* @param {Cartographic} [position] The location to hover over. If not specified the current camera location will be used.
* @param {Boolean} [flyTo=true] Whether to fly to the location (true) or whether to jump to the location (false).
*/
AugmentedVirtuality.prototype.hover = function(height, position, flyTo) {
const that = this;
// Get access to the camera...if it is not avaliable we can't set the new height so just return now.
if (!defined(this._terria.cesium) ||
!defined(this._terria.cesium.viewer) ||
!defined(this._terria.cesium.viewer.camera)) {
return;
}
const camera = this._terria.cesium.viewer.camera;
if (!defined(position)) {
position = camera.positionCartographic.clone();
}
flyTo = defaultValue(flyTo, true);
// Clamp the minimum hover height (heights below this value could lead to poor visual artifacts).
if (height < AugmentedVirtuality.MINIMUM_HOVER_HEIGHT) {
height = AugmentedVirtuality.MINIMUM_HOVER_HEIGHT;
}
// Reset the viewer height.
function flyToHeight(surfaceHeight) {
if (defined(surfaceHeight)) {
height += surfaceHeight;
}
const newPosition = CesiumCartesian3.fromRadians(position.longitude, position.latitude, height);
const pose = that._getCurrentOrientation();
pose.destination = newPosition;
if (flyTo) {
camera.flyTo(pose);
} else {
camera.setView(pose);
}
// Needed on mobile to make sure that the render is marked as dirty so that once AV mode has been disabled for a
// while and then is reenabled the .setView() function still has effect (otherwise dispite the call the .setView()
// the view orientation does not visually update until the user manualy moves the camera position).
that._terria.currentViewer.notifyRepaintRequired();
}
// Get the ground surface height at this location and offset the height by it.
if ((!defined(this._terria.cesium) ||
!defined(this._terria.cesium.scene) ||
!defined(this._terria.cesium.scene.terrainProvider)) ||
(this._terria.cesium.scene.terrainProvider instanceof EllipsoidTerrainProvider)) {
// If we can't get access to the terrain provider or we can get access to the terrain provider and the provider is just the Ellipsoid then use the height of 0.
flyToHeight(0);
} else {
const terrainProvider = this._terria.cesium.scene.terrainProvider;
sampleTerrainMostDetailed(terrainProvider, [position]).then(function(updatedPosition) {
flyToHeight(updatedPosition[0].height);
});
}
};
/**
* Moves the viewer to a specified location while maintaining the current height and the correct Augmented Virtuality
* orientation.
*
* @param {Cartographic} position The location to hover move to.
* @param {Float} [maximumHeight] The maximum height (in meters) to cap the current camera height to (if this value is
* specified and the viewer is above this height the camera will be restricted to this height).
* @param {Boolean} [flyTo] Whether to fly to the location (true) or whether to jump to the location (false).
*
* When the manual alignment is enabled this function has no effect.
*/
AugmentedVirtuality.prototype.moveTo = function(position, maximumHeight, flyTo) {
const that = this;
// If we are in manual alignment mode we don't allow the viewer to move (since this would create a jaring UX for most use cases).
if (this._manualAlignment) {
return;
}
// Get access to the camera...if it is not avaliable we can't get the current height (or set the new location) so just return now.
if (!defined(this._terria.cesium) ||
!defined(this._terria.cesium.viewer) ||
!defined(this._terria.cesium.viewer.camera)) {
return;
}
const camera = this._terria.cesium.viewer.camera;
const cameraPosition = camera.positionCartographic.clone();
const viewerHeight = cameraPosition.height;
// Reset the viewer height.
function moveToLocation(surfaceHeight) {
if (!defined(surfaceHeight)) {
surfaceHeight = 0;
}
let hoverHeight = viewerHeight - surfaceHeight;
if (defined(maximumHeight) &&
(hoverHeight > maximumHeight)) {
hoverHeight = maximumHeight;
}
that.hover(hoverHeight, position, flyTo);
}
// Get the ground surface height at this location and offset the height by it.
if ((!defined(this._terria.cesium) ||
!defined(this._terria.cesium.scene) ||
!defined(this._terria.cesium.scene.terrainProvider)) ||
(this._terria.cesium.scene.terrainProvider instanceof EllipsoidTerrainProvider)) {
// If we can't get access to the terrain provider or we can get access to the terrain provider and the provider is just the Ellipsoid then use the height of 0.
moveToLocation(undefined);
} else {
const terrainProvider = this._terria.cesium.scene.terrainProvider;
sampleTerrainMostDetailed(terrainProvider, [cameraPosition]).then(function(updatedPosition) {
moveToLocation(updatedPosition[0].height);
});
}
};
/**
* Whether the user is currently setting a manual alignment.
*
* See also {@link AugmentedVirtuality#_setManualAlignment}.
*
* @return {Boolean} Whether the user is currently setting a manual alignment (true) or not (false).
* @private
*/
AugmentedVirtuality.prototype._getManualAlignment = function() {
return this.enabled && this._manualAlignment;
};
/**
* Starts / stops manual alignment.
*
* When manual realignment is enabled it allows the user to specify a new origin for the alignment between the devices
* physical and virtual alignment. When manual alignment is enabled the orientation is locked, to allow the user to
* realign a visual landmark with a physical landmark.
*
* Note: Manual alignment is only done for the heading axis, this is because in practice we have found that the heading
* axis is often out as mobile devices seem to have difficulty obtaining the compass direction, but seem to perform
* relatively well in the other axes.
*
* Note: Realignment is only possible when AugmentedVirtuality is enabled. If AugmentedVirtuality is disabled while
* manual alignment is in progress it will be cancelled.
*
* See also {@link AugmentedVirtuality#_getManualAlignment}.
*
* @param {Boolean} startEnd Whether the user is starting (true) or ending (false) the realignment.
* @private
*/
AugmentedVirtuality.prototype._setManualAlignment = function(startEnd) {
// Only allow manual alignment changes when the module is enabled.
if (this.enabled !== true) {
return;
}
// Sanitise the input value to a boolean.
if (startEnd !== true) {
startEnd = false;
}
if ((startEnd === false) &&
defined(this._terria.cesium) &&
defined(this._terria.cesium.viewer) &&
defined(this._terria.cesium.viewer.camera)) {
this._realignAlpha = this._alpha;
this._realignHeading = CesiumMath.toDegrees(this._terria.cesium.viewer.camera.heading);
}
if (this._manualAlignment !== startEnd) {
this._manualAlignment = startEnd;
this._startEventLoop(!this._manualAlignment);
}
};
/**
* Whether the event loop is currently running.
*
* @return {Boolean} enable Whether to start the event loop is currently running (true) or not (false).
* @private
*/
AugmentedVirtuality.prototype._eventLoopRunning = function() {
return defined(this._eventLoopState.intervalId);
};
/**
* Start or stop the Augmented Virutuality mode event loop. When enabled the orientation will effect the cameras
* view and when disabled the device orientation will not effect the cameras view.
*
* @param {Boolean} enable Whether to start the event loop (true) or stop the event loop (false).
* @private
*/
AugmentedVirtuality.prototype._startEventLoop = function(enable) {
// Are we actually changing the state?
if (this._eventLoopRunning() !== enable) {
if (enable === true) {
const that = this;
this._orientationUpdated = true;
const intervalMs = 1000 / this._maximumUpdatesPerSecond;
const id = setInterval(function() {
that._updateOrientation();
}, intervalMs);
this._eventLoopState = {intervalId:id};
} else {
clearInterval(this._eventLoopState.intervalId);
this._eventLoopState = {};
}
}
};
/**
* Device orientation update event callback function. Stores the updated orientation into the object state.
*
* @param {Object} event Contains the updated device orientation (in .alpha, .beta, .gamma).
* @private
*/
AugmentedVirtuality.prototype._storeOrientation = function(event) {
this._alpha = event.alpha;
this._beta = event.beta;
this._gamma = event.gamma;
this._orientationUpdated = true;
};
/**
* This function updates the cameras orientation using the last orientation recorded and the current screen orientation.
*
* @private
*/
AugmentedVirtuality.prototype._updateOrientation = function() {
// Check if the screen orientation has changed and mark the orientation updated if it has.
const screenOrientation = this._getCurrentScreenOrientation();
if (screenOrientation !== this._lastScreenOrientation) {
this._orientationUpdated = true;
}
this._lastScreenOrientation = screenOrientation;
// Optomise by only updating the camera view if some part of the orientation calculation has changed.
if (!this._orientationUpdated) {
// The orientation has not been updated so don't waste time changing the orientation.
return;
}
this._orientationUpdated = false;
// Get access to the camera...if it is not avaliable we can't set the orientation so just return now.
if (!defined(this._terria.cesium) ||
!defined(this._terria.cesium.viewer) ||
!defined(this._terria.cesium.viewer.camera)) {
return;
}
const camera = this._terria.cesium.viewer.camera;
camera.setView(this._getCurrentOrientation(screenOrientation));
// Needed on mobile to make sure that the render is marked as dirty so that once AV mode has been disabled for a
// while and then is reenabled the .setView() function still has effect (otherwise dispite the call the .setView()
// the view orientation does not visually update until the user manualy moves the camera position).
this._terria.currentViewer.notifyRepaintRequired();
};
/**
* Gets the current orientation stored in the object state and returns the roll, pitch and heading which can be used to set the cameras orientation.
*
* @param {Float} screenOrientation The screen orientation in degrees. Note: This field is optional, if supplied this value will be used for the screen orientation, otherwise the screen orientation will be obtained during the execution of this function.
* @return {Object} A object with the roll, pitch and heading stored into the orientation.
* @private
*/
AugmentedVirtuality.prototype._getCurrentOrientation = function(screenOrientation) {
const alpha = this._alpha;
const beta = this._beta;
const gamma = this._gamma;
const realignAlpha = this._realignAlpha;
const realignHeading = this._realignHeading;
if (!defined(screenOrientation)) {
screenOrientation = this._getCurrentScreenOrientation();
}
return this._computeTerriaOrientation(alpha, beta, gamma, screenOrientation, realignAlpha, realignHeading);
};
/**
* Turns the orientation in the device frame of reference into an orientation suitable for specifying the Terria camera orientation.
*
* @param {Float} alpha The alpha value of the device orientation in degrees (this is the alpha value in the device's frame of reference).
* @param {Float} beta The beta value of the device orientation in degrees (this is the beta value in the device's frame of reference).
* @param {Float} gamma The gamma value of the device orientation in degrees (this is the gamma value in the device's frame of reference).
* @param {Float} screenOrientation The screen orientation in degrees.
* @param {Float} realignAlpha The value of the alpha value the last time realignment was completed (supply zero if realignment is not supported).
* @param {Float} realignHeading The value of the heading value the last time realignment was completed (supply zero if realignment is not supported).
* @return {Object} An object with the roll, pitch and heading stored into the orientation.
* @private
*/
AugmentedVirtuality.prototype._computeTerriaOrientation = function(alpha, beta, gamma, screenOrientation, realignAlpha, realignHeading) {
// Note: The algorithmic formulation in this function is for simplicity of mathematical expression, readability,
// maintainability and modification (i.e. it is easy to understand how to update or insert new offsets or features).
// This is not the simplest form which clearly flows from the current formuleation and clearly simplify the
// logic and operations but would increase the cost of future modifications and reduce the readability of the
// expression. It is not anticipated that the current verbose implementation would have a significant impact
// on performance or accuracy, but obviously there will be some impact on both and it can be simplified in
// future if needed.
const rotation = CesiumMatrix3.clone(CesiumMatrix3.IDENTITY, rotation);
let rotationIncrement;
// Roll - Counteract the change in the (orientation) frame of reference when the screen is rotated and the
// rotation lock is not on (the browser reorients the frame of reference to align with the new screen
// orientation - where as we want it of the device relative to the world).
rotationIncrement = CesiumMatrix3.fromRotationZ(CesiumMath.toRadians(screenOrientation));
CesiumMatrix3.multiply(rotation, rotationIncrement, rotation);
// Pitch - Align the device orientation frame with the ceasium orientation frame.
rotationIncrement = CesiumMatrix3.fromRotationX(CesiumMath.toRadians(90));
CesiumMatrix3.multiply(rotation, rotationIncrement, rotation);
// Roll - Apply the deivce roll.
rotationIncrement = CesiumMatrix3.fromRotationZ(CesiumMath.toRadians(gamma));
CesiumMatrix3.multiply(rotation, rotationIncrement, rotation);
// Pitch - Apply the deivce pitch.
rotationIncrement = CesiumMatrix3.fromRotationX(CesiumMath.toRadians(-beta));
CesiumMatrix3.multiply(rotation, rotationIncrement, rotation);
// Heading - Apply the incremental deivce heading (from when start was last triggered).
rotationIncrement = CesiumMatrix3.fromRotationY(CesiumMath.toRadians(-(alpha-realignAlpha)));
CesiumMatrix3.multiply(rotation, rotationIncrement, rotation);
// Heading - Use the offset when the orientation was last started.
// Note: This is logically different from the alpha value and can only be applied here in the same way
// since Cesium camera is RPH (Heading last - most local). See Cesium camera rotation decomposition
// for more information on the Cesium camera formuleation.
rotationIncrement = CesiumMatrix3.fromRotationY(CesiumMath.toRadians(realignHeading));
CesiumMatrix3.multiply(rotation, rotationIncrement, rotation);
// Decompose rotation matrix into roll, pitch and heading to supply to Cesium camera.
//
// Use notation:
// R = Roll, P = Pitch, H = Heading
// SH = Sin(Heading), CH = Cos(Heading)
//
// Ceasium camera rotation = RPH:
// [ CR, -SR, 0][ 1, 0, 0][ CH, 0, SH] [CRCH-SRSPSH, -SRCP, CRSH-SRSPCH]
// [ SR, CR, 0][ 0, CP, SP][ 0, 1, 0] = [SRCH-CRSPSH, CRCP, SRSH+CRSPCH]
// [ 0, 0, 1][ 0, -SP, CP][-SH, 0, CH] [ -CPSH , -SP, CPCH ]
// Note: The sign difference of the Sin terms in pitch is different to the standard right handed rotation since
// Cesium rotates pitch in the left handed direction. Both heading and roll are right handed rotations.
//
// Use the following notation to refer to elements in the Cesium camera rotation matrix:
// [R00, R10, R20]
// [R01, R11, R21]
// [R02, R12, R22]
//
// Also note: Tan(X) = Sin(X) / Cos(X)
//
// Decompose matrix:
// H = ATan(Tan(H)) = ATan(Sin(H)/Cos(H)) = ATan (SH / CH) = ATan(CPSH/CPCH) = ATan (-R02 / R22)
// R = ATan(Tan(R)) = ATan(Sin(R)/Cos(R)) = ATan (SR / CR) = ATan(SRCP/CRCP) = ATan (-R10 / R11)
// P = ATan(Tan(P)) = ATan(Sin(P)/Cos(P)) = ATan (SP / CP)
// SP = -R12
// Need to find CP:
// CP = Sqrt(CP^2)
// = Sqrt(CP^2*(CH^2+SH^2)) Since: (Cos@^2 + Sin@^2) = 1
// = Sqrt((CP^2)*(CH^2) + (CP^2)*(SH^2)) Expand
// = Sqrt((CPCH)^2 + (CPSH)^2) Since: N^2*M^2 = (NM)^2
// = Sqrt(R22^2 + (-R02)^2) Substitute
// = Sqrt(R22^2 + R02^2) Since: (-N)^2 = N^2
// So P = ATan (-R12 / Sqrt(R22^2 + R02^2))
// Simplify notation for readability:
const r10 = rotation[CesiumMatrix3.COLUMN1ROW0];
const r11 = rotation[CesiumMatrix3.COLUMN1ROW1];
const r02 = rotation[CesiumMatrix3.COLUMN0ROW2];
const r12 = rotation[CesiumMatrix3.COLUMN1ROW2];
const r22 = rotation[CesiumMatrix3.COLUMN2ROW2];
const heading = CesiumMath.toDegrees(Math.atan2(-r02, r22));
const roll = CesiumMath.toDegrees(Math.atan2(-r10, r11));
const pitch = CesiumMath.toDegrees(Math.atan2(-r12, Math.sqrt(r02*r02 + r22*r22)));
// Create an object with the roll, pitch and heading we just computed.
return {
orientation:
{
roll : CesiumMath.toRadians(roll),
pitch : CesiumMath.toRadians(pitch),
heading : CesiumMath.toRadians(heading)
}
};
};
/**
* Gets the current screen orientation.
*
* @return {Object} The current screen orientation in degrees.
* @private
*/
AugmentedVirtuality.prototype._getCurrentScreenOrientation = function() {
if (defined(screen.orientation) &&
defined(screen.orientation.angle)) {
return screen.orientation.angle;
}
if (defined(window.orientation)) {
return window.orientation;
}
return 0;
};
module.exports = AugmentedVirtuality;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="AbsCode.html">AbsCode</a></li><li><a href="AbsConcept.html">AbsConcept</a></li><li><a href="AbsDataset.html">AbsDataset</a></li><li><a href="AbsIttCatalogGroup.html">AbsIttCatalogGroup</a></li><li><a href="AbsIttCatalogItem.html">AbsIttCatalogItem</a></li><li><a href="AddressGeocoder.html">AddressGeocoder</a></li><li><a href="ArcGisCatalogGroup.html">ArcGisCatalogGroup</a></li><li><a href="ArcGisFeatureServerCatalogGroup.html">ArcGisFeatureServerCatalogGroup</a></li><li><a href="ArcGisFeatureServerCatalogItem.html">ArcGisFeatureServerCatalogItem</a></li><li><a href="ArcGisMapServerCatalogGroup.html">ArcGisMapServerCatalogGroup</a></li><li><a href="ArcGisMapServerCatalogItem.html">ArcGisMapServerCatalogItem</a></li><li><a href="AugmentedVirtuality.html">AugmentedVirtuality</a></li><li><a href="BingMapsCatalogItem.html">BingMapsCatalogItem</a></li><li><a href="BooleanParameter.html">BooleanParameter</a></li><li><a href="BulkAddressGeocoderResult.html">BulkAddressGeocoderResult</a></li><li><a href="CameraView.html">CameraView</a></li><li><a href="Catalog.html">Catalog</a></li><li><a href="CatalogFunction.html">CatalogFunction</a></li><li><a href="CatalogGroup.html">CatalogGroup</a></li><li><a href="CatalogItem.html">CatalogItem</a></li><li><a href="CatalogMember.html">CatalogMember</a></li><li><a href="Cesium.html">Cesium</a></li><li><a href="Cesium3DTilesCatalogItem.html">Cesium3DTilesCatalogItem</a></li><li><a href="CesiumDragPoints.html">CesiumDragPoints</a></li><li><a href="CesiumTerrainCatalogItem.html">CesiumTerrainCatalogItem</a></li><li><a href="CkanCatalogGroup.html">CkanCatalogGroup</a></li><li><a href="CkanCatalogItem.html">CkanCatalogItem</a></li><li><a href="Clock.html">Clock</a></li><li><a href="CompositeCatalogItem.html">CompositeCatalogItem</a></li><li><a href="Concept.html">Concept</a></li><li><a href="CorsProxy.html">CorsProxy</a></li><li><a href="CsvCatalogItem.html">CsvCatalogItem</a></li><li><a href="CswCatalogGroup.html">CswCatalogGroup</a></li><li><a href="CustomComponentType.html">CustomComponentType</a></li><li><a href="CzmlCatalogItem.html">CzmlCatalogItem</a></li><li><a href="DataSourceCatalogItem.html">DataSourceCatalogItem</a></li><li><a href="DateTimeParameter.html">DateTimeParameter</a></li><li><a href="DisplayVariablesConcept.html">DisplayVariablesConcept</a></li><li><a href="EnumerationParameter.html">EnumerationParameter</a></li><li><a href="Feature.html">Feature</a></li><li><a href="FunctionParameter.html">FunctionParameter</a></li><li><a href="GeoJsonCatalogItem.html">GeoJsonCatalogItem</a></li><li><a href="GlobeOrMap.html">GlobeOrMap</a></li><li><a href="GnafAddressGeocoder.html">GnafAddressGeocoder</a></li><li><a href="GnafApi.html">GnafApi</a></li><li><a href="GnafSearchProviderViewModel.html">GnafSearchProviderViewModel</a></li><li><a href="GpxCatalogItem.html">GpxCatalogItem</a></li><li><a href="HelpScreen.html">HelpScreen</a></li><li><a href="HelpSequence.html">HelpSequence</a></li><li><a href="HelpSequences.html">HelpSequences</a></li><li><a href="HelpViewState.html">HelpViewState</a></li><li><a href="ImageryLayerCatalogItem____.html">ImageryLayerCatalogItem</a></li><li><a href="IonImageryCatalogItem.html">IonImageryCatalogItem</a></li><li><a href="KmlCatalogItem.html">KmlCatalogItem</a></li><li><a href="Leaflet.html">Leaflet</a></li><li><a href="LeafletDataSourceDisplay.html">LeafletDataSourceDisplay</a></li><li><a href="LeafletDragPoints.html">LeafletDragPoints</a></li><li><a href="LeafletGeomVisualizer.html">LeafletGeomVisualizer</a></li><li><a href="LegendHelper.html">LegendHelper</a></li><li><a href="LegendUrl.html">LegendUrl</a></li><li><a href="LineParameter.html">LineParameter</a></li><li><a href="MagdaCatalogItem.html">MagdaCatalogItem</a></li><li><a href="MapboxMapCatalogItem.html">MapboxMapCatalogItem</a></li><li><a href="MapInteractionMode.html">MapInteractionMode</a></li><li><a href="Metadata.html">Metadata</a></li><li><a href="MetadataItem.html">MetadataItem</a></li><li><a href="module.html#.exports">exports</a></li><li><a href="OgrCatalogItem.html">OgrCatalogItem</a></li><li><a href="OpenStreetMapCatalogItem.html">OpenStreetMapCatalogItem</a></li><li><a href="PlacesLikeMeCatalogfunction.html">PlacesLikeMeCatalogfunction</a></li><li><a href="PointParameter.html">PointParameter</a></li><li><a href="Polling.html">Polling</a></li><li><a href="PolygonParameter.html">PolygonParameter</a></li><li><a href="RectangleParameter.html">RectangleParameter</a></li><li><a href="RegionDataParameter.html">RegionDataParameter</a></li><li><a href="RegionMapping.html">RegionMapping</a></li><li><a href="RegionParameter.html">RegionParameter</a></li><li><a href="RegionProvider.html">RegionProvider</a></li><li><a href="RegionProviderList.html">RegionProviderList</a></li><li><a href="RegionTypeParameter.html">RegionTypeParameter</a></li><li><a href="ResultPendingCatalogItem.html">ResultPendingCatalogItem</a></li><li><a href="SdmxJsonCatalogItem.html">SdmxJsonCatalogItem</a></li><li><a href="SensorObservationServiceCatalogItem.html">SensorObservationServiceCatalogItem</a></li><li><a href="SocrataCatalogGroup.html">SocrataCatalogGroup</a></li><li><a href="SpatialDetailingCatalogFunction.html">SpatialDetailingCatalogFunction</a></li><li><a href="StringParameter.html">StringParameter</a></li><li><a href="SummaryConcept.html">SummaryConcept</a></li><li><a href="TableCatalogItem.html">TableCatalogItem</a></li><li><a href="TableColumn.html">TableColumn</a></li><li><a href="TableColumnStyle.html">TableColumnStyle</a></li><li><a href="TableDataSource.html">TableDataSource</a></li><li><a href="TableStructure.html">TableStructure</a></li><li><a href="TableStyle.html">TableStyle</a></li><li><a href="TerrainCatalogItem.html">TerrainCatalogItem</a></li><li><a href="Terria.html">Terria</a></li><li><a href="TerriaError.html">TerriaError</a></li><li><a href="TerriaJsonCatalogFunction.html">TerriaJsonCatalogFunction</a></li><li><a href="TimeSeriesStack.html">TimeSeriesStack</a></li><li><a href="UrlTemplateCatalogItem.html">UrlTemplateCatalogItem</a></li><li><a href="UrthecastCatalogGroup.html">UrthecastCatalogGroup</a></li><li><a href="UrthecastServerCatalogItem.html">UrthecastServerCatalogItem</a></li><li><a href="UserDrawing.html">UserDrawing</a></li><li><a href="VariableConcept.html">VariableConcept</a></li><li><a href="ViewerModes..html">ViewerModes.</a></li><li><a href="WebFeatureServiceCatalogGroup.html">WebFeatureServiceCatalogGroup</a></li><li><a href="WebFeatureServiceCatalogItem.html">WebFeatureServiceCatalogItem</a></li><li><a href="WebMapServiceCatalogGroup.html">WebMapServiceCatalogGroup</a></li><li><a href="WebMapServiceCatalogItem.html">WebMapServiceCatalogItem</a></li><li><a href="WebMapTileServiceCatalogGroup.html">WebMapTileServiceCatalogGroup</a></li><li><a href="WebMapTileServiceCatalogItem.html">WebMapTileServiceCatalogItem</a></li><li><a href="WebProcessingServiceCatalogFunction.html">WebProcessingServiceCatalogFunction</a></li><li><a href="WebProcessingServiceCatalogGroup.html">WebProcessingServiceCatalogGroup</a></li><li><a href="WebProcessingServiceCatalogItem.html">WebProcessingServiceCatalogItem</a></li><li><a href="WfsFeaturesCatalogGroup.html">WfsFeaturesCatalogGroup</a></li><li><a href="WhyAmISpecialCatalogFunction.html">WhyAmISpecialCatalogFunction</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_bumpyTerrainProvider">_bumpyTerrainProvider</a></li><li><a href="global.html#_terrain">_terrain</a></li><li><a href="global.html#activeTimeColumnNameIdOrIndex">activeTimeColumnNameIdOrIndex</a></li><li><a href="global.html#addBoundingBox">addBoundingBox</a></li><li><a href="global.html#addMarker">addMarker</a></li><li><a href="global.html#addUserCatalogMember">addUserCatalogMember</a></li><li><a href="global.html#allFeaturesAvailablePromise">allFeaturesAvailablePromise</a></li><li><a href="global.html#allShareKeys">allShareKeys</a></li><li><a href="global.html#arrayProduct">arrayProduct</a></li><li><a href="global.html#barHeightMax">barHeightMax</a></li><li><a href="global.html#barHeightMin">barHeightMin</a></li><li><a href="global.html#barLeft">barLeft</a></li><li><a href="global.html#barTop">barTop</a></li><li><a href="global.html#buildEmptyAccumulator">buildEmptyAccumulator</a></li><li><a href="global.html#buildRequestData">buildRequestData</a></li><li><a href="global.html#buildShareLink">buildShareLink</a></li><li><a href="global.html#buildShortShareLink">buildShortShareLink</a></li><li><a href="global.html#calculateFinishDatesFromStartDates">calculateFinishDatesFromStartDates</a></li><li><a href="global.html#canShorten">canShorten</a></li><li><a href="global.html#categoryName">categoryName</a></li><li><a href="global.html#ChartData">ChartData</a></li><li><a href="global.html#color">color</a></li><li><a href="global.html#ColorMap">ColorMap</a></li><li><a href="global.html#combineData">combineData</a></li><li><a href="global.html#combineFilters">combineFilters</a></li><li><a href="global.html#combineRepeated">combineRepeated</a></li><li><a href="global.html#combineValueArrays">combineValueArrays</a></li><li><a href="global.html#computeRingWindingOrder">computeRingWindingOrder</a></li><li><a href="global.html#computeScreenSpacePosition">computeScreenSpacePosition</a></li><li><a href="global.html#config">config</a></li><li><a href="global.html#containsAny">containsAny</a></li><li><a href="global.html#convertLuceneHit">convertLuceneHit</a></li><li><a href="global.html#convertToDates">convertToDates</a></li><li><a href="global.html#correctEntityHeight">correctEntityHeight</a></li><li><a href="global.html#createCatalogItemFromFileOrUrl">createCatalogItemFromFileOrUrl</a></li><li><a href="global.html#createCatalogItemFromUrl">createCatalogItemFromUrl</a></li><li><a href="global.html#createCatalogMemberFromType">createCatalogMemberFromType</a></li><li><a href="global.html#createLeafletCredit">createLeafletCredit</a></li><li><a href="global.html#createParameterFromType">createParameterFromType</a></li><li><a href="global.html#createRegexDeserializer">createRegexDeserializer</a></li><li><a href="global.html#createRegexSerializer">createRegexSerializer</a></li><li><a href="global.html#cssClass">cssClass</a></li><li><a href="global.html#CustomComponents">CustomComponents</a></li><li><a href="global.html#deIndexWithDescendants">deIndexWithDescendants</a></li><li><a href="global.html#Description">Description</a></li><li><a href="global.html#direction">direction</a></li><li><a href="global.html#disposeSubscription">disposeSubscription</a></li><li><a href="global.html#EarthGravityModel1996">EarthGravityModel1996</a></li><li><a href="global.html#error">error</a></li><li><a href="global.html#extendLoad">extendLoad</a></li><li><a href="global.html#extent">extent</a></li><li><a href="global.html#featureClicked">featureClicked</a></li><li><a href="global.html#featureDataToGeoJson">featureDataToGeoJson</a></li><li><a href="global.html#featureMousedown">featureMousedown</a></li><li><a href="global.html#features">features</a></li><li><a href="global.html#findKeyForGroupElement">findKeyForGroupElement</a></li><li><a href="global.html#flattenCatalog">flattenCatalog</a></li><li><a href="global.html#formatDate">formatDate</a></li><li><a href="global.html#formatDateTime">formatDateTime</a></li><li><a href="global.html#formatNumberForLocale">formatNumberForLocale</a></li><li><a href="global.html#formatPropertyValue">formatPropertyValue</a></li><li><a href="global.html#formatTime">formatTime</a></li><li><a href="global.html#getAncestors">getAncestors</a></li><li><a href="global.html#getColumnOptions">getColumnOptions</a></li><li><a href="global.html#getColumnWithNameIdOrIndex">getColumnWithNameIdOrIndex</a></li><li><a href="global.html#getDataUriFormat">getDataUriFormat</a></li><li><a href="global.html#getGroupChildren">getGroupChildren</a></li><li><a href="global.html#getShareData">getShareData</a></li><li><a href="global.html#getTemporalFiltersContext">getTemporalFiltersContext</a></li><li><a href="global.html#getUniqueValues">getUniqueValues</a></li><li><a href="global.html#gmlToGeoJson">gmlToGeoJson</a></li><li><a href="global.html#gradientColorMap">gradientColorMap</a></li><li><a href="global.html#hasAddress">hasAddress</a></li><li><a href="global.html#hasChildren">hasChildren</a></li><li><a href="global.html#hasLatitudeAndLongitude">hasLatitudeAndLongitude</a></li><li><a href="global.html#hostInDomains">hostInDomains</a></li><li><a href="global.html#id">id</a></li><li><a href="global.html#infoWithoutSources">infoWithoutSources</a></li><li><a href="global.html#isBrowserCompatible">isBrowserCompatible</a></li><li><a href="global.html#isCommonMobilePlatform">isCommonMobilePlatform</a></li><li><a href="global.html#isLoading">isLoading</a></li><li><a href="global.html#isVisible">isVisible</a></li><li><a href="global.html#itemHeight">itemHeight</a></li><li><a href="global.html#itemHeightMin">itemHeightMin</a></li><li><a href="global.html#items">items</a></li><li><a href="global.html#itemSpacing">itemSpacing</a></li><li><a href="global.html#itemWidth">itemWidth</a></li><li><a href="global.html#Legend">Legend</a></li><li><a href="global.html#legendUrl">legendUrl</a></li><li><a href="global.html#map">map</a></li><li><a href="global.html#markdownToHtml">markdownToHtml</a></li><li><a href="global.html#markerVisible">markerVisible</a></li><li><a href="global.html#name">name</a></li><li><a href="global.html#NowViewing">NowViewing</a></li><li><a href="global.html#overrideProperty">overrideProperty</a></li><li><a href="global.html#pad">pad</a></li><li><a href="global.html#parseCustomHtmlToReact">parseCustomHtmlToReact</a></li><li><a href="global.html#parseCustomMarkdownToReact">parseCustomMarkdownToReact</a></li><li><a href="global.html#PickedFeatures">PickedFeatures</a></li><li><a href="global.html#pickPosition">pickPosition</a></li><li><a href="global.html#point">point</a></li><li><a href="global.html#points">points</a></li><li><a href="global.html#position">position</a></li><li><a href="global.html#prettifyCoordinates">prettifyCoordinates</a></li><li><a href="global.html#prettifyProjection">prettifyProjection</a></li><li><a href="global.html#printWindow">printWindow</a></li><li><a href="global.html#processAddress">processAddress</a></li><li><a href="global.html#Proj4Definitions">Proj4Definitions</a></li><li><a href="global.html#propertyGetTimeValues">propertyGetTimeValues</a></li><li><a href="global.html#readJson">readJson</a></li><li><a href="global.html#rectangle">rectangle</a></li><li><a href="global.html#rectangleToLatLngBounds">rectangleToLatLngBounds</a></li><li><a href="global.html#RegionDataValue">RegionDataValue</a></li><li><a href="global.html#regionDetails">regionDetails</a></li><li><a href="global.html#registerCustomComponentTypes">registerCustomComponentTypes</a></li><li><a href="global.html#rememberRejections">rememberRejections</a></li><li><a href="global.html#removeMarker">removeMarker</a></li><li><a href="global.html#replaceUnderscores">replaceUnderscores</a></li><li><a href="global.html#sanitiseAddressNumber">sanitiseAddressNumber</a></li><li><a href="global.html#selectBaseMap">selectBaseMap</a></li><li><a href="global.html#serializeToJson">serializeToJson</a></li><li><a href="global.html#ServerConfig">ServerConfig</a></li><li><a href="global.html#setClockCurrentTime">setClockCurrentTime</a></li><li><a href="global.html#shareKeyIndex">shareKeyIndex</a></li><li><a href="global.html#shouldBeUpdated">shouldBeUpdated</a></li><li><a href="global.html#showSelection">showSelection</a></li><li><a href="global.html#sortByFirst">sortByFirst</a></li><li><a href="global.html#sortedIndices">sortedIndices</a></li><li><a href="global.html#splitIntoBatches">splitIntoBatches</a></li><li><a href="global.html#supportsIntervals">supportsIntervals</a></li><li><a href="global.html#supportsWebGL">supportsWebGL</a></li><li><a href="global.html#TerriaViewer">TerriaViewer</a></li><li><a href="global.html#Title">Title</a></li><li><a href="global.html#toArrayOfRows">toArrayOfRows</a></li><li><a href="global.html#Tooltip">Tooltip</a></li><li><a href="global.html#triggerResize">triggerResize</a></li><li><a href="global.html#unionRectangleArray">unionRectangleArray</a></li><li><a href="global.html#unionRectangles">unionRectangles</a></li><li><a href="global.html#units">units</a></li><li><a href="global.html#up">up</a></li><li><a href="global.html#updateApplicationOnHashChange">updateApplicationOnHashChange</a></li><li><a href="global.html#updateFromJson">updateFromJson</a></li><li><a href="global.html#updateRectangleFromRegion">updateRectangleFromRegion</a></li><li><a href="global.html#variableNameLeft">variableNameLeft</a></li><li><a href="global.html#variableNameTop">variableNameTop</a></li><li><a href="global.html#ViewerMode">ViewerMode</a></li><li><a href="global.html#width">width</a></li><li><a href="global.html#yAxisMax">yAxisMax</a></li><li><a href="global.html#yAxisMin">yAxisMin</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Sep 21 2018 12:26:18 GMT+1000 (AUS Eastern Standard Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>