/**
* Cesium - https://github.com/CesiumGS/cesium
*
* Copyright 2011-2020 Cesium Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Columbus View (Pat. Pend.)
*
* Portions licensed separately.
* See https://github.com/CesiumGS/cesium/blob/main/LICENSE.md for full licensing details.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Cesium = {}));
})(this, (function (exports) { 'use strict';
/**
* @function
*
* @param {*} value The object.
* @returns {Boolean} Returns true if the object is defined, returns false otherwise.
*
* @example
* if (Cesium.defined(positions)) {
* doSomething();
* } else {
* doSomethingElse();
* }
*/
function defined(value) {
return value !== undefined && value !== null;
}
/**
* Constructs an exception object that is thrown due to a developer error, e.g., invalid argument,
* argument out of range, etc. This exception should only be thrown during development;
* it usually indicates a bug in the calling code. This exception should never be
* caught; instead the calling code should strive not to generate it.
* Special cases:
*
* On the other hand, a {@link RuntimeError} indicates an exception that may
* be thrown at runtime, e.g., out of memory, that the calling code should be prepared
* to catch.
*
* @alias DeveloperError
* @constructor
* @extends Error
*
* @param {String} [message] The error message for this exception.
*
* @see RuntimeError
*/
function DeveloperError(message) {
/**
* 'DeveloperError' indicating that this exception was thrown due to a developer error.
* @type {String}
* @readonly
*/
this.name = "DeveloperError";
/**
* The explanation for why this exception was thrown.
* @type {String}
* @readonly
*/
this.message = message;
//Browsers such as IE don't have a stack property until you actually throw the error.
let stack;
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
/**
* The stack trace of this exception, if available.
* @type {String}
* @readonly
*/
this.stack = stack;
}
if (defined(Object.create)) {
DeveloperError.prototype = Object.create(Error.prototype);
DeveloperError.prototype.constructor = DeveloperError;
}
DeveloperError.prototype.toString = function () {
let str = `${this.name}: ${this.message}`;
if (defined(this.stack)) {
str += `\n${this.stack.toString()}`;
}
return str;
};
/**
* @private
*/
DeveloperError.throwInstantiationError = function () {
throw new DeveloperError(
"This function defines an interface and should not be called directly."
);
};
/**
* Contains functions for checking that supplied arguments are of a specified type
* or meet specified conditions
* @private
*/
const Check = {};
/**
* Contains type checking functions, all using the typeof operator
*/
Check.typeOf = {};
function getUndefinedErrorMessage(name) {
return `${name} is required, actual value was undefined`;
}
function getFailedTypeErrorMessage(actual, expected, name) {
return `Expected ${name} to be typeof ${expected}, actual typeof was ${actual}`;
}
/**
* Throws if test is not defined
*
* @param {String} name The name of the variable being tested
* @param {*} test The value that is to be checked
* @exception {DeveloperError} test must be defined
*/
Check.defined = function (name, test) {
if (!defined(test)) {
throw new DeveloperError(getUndefinedErrorMessage(name));
}
};
/**
* Throws if test is not typeof 'function'
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @exception {DeveloperError} test must be typeof 'function'
*/
Check.typeOf.func = function (name, test) {
if (typeof test !== "function") {
throw new DeveloperError(
getFailedTypeErrorMessage(typeof test, "function", name)
);
}
};
/**
* Throws if test is not typeof 'string'
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @exception {DeveloperError} test must be typeof 'string'
*/
Check.typeOf.string = function (name, test) {
if (typeof test !== "string") {
throw new DeveloperError(
getFailedTypeErrorMessage(typeof test, "string", name)
);
}
};
/**
* Throws if test is not typeof 'number'
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @exception {DeveloperError} test must be typeof 'number'
*/
Check.typeOf.number = function (name, test) {
if (typeof test !== "number") {
throw new DeveloperError(
getFailedTypeErrorMessage(typeof test, "number", name)
);
}
};
/**
* Throws if test is not typeof 'number' and less than limit
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @param {Number} limit The limit value to compare against
* @exception {DeveloperError} test must be typeof 'number' and less than limit
*/
Check.typeOf.number.lessThan = function (name, test, limit) {
Check.typeOf.number(name, test);
if (test >= limit) {
throw new DeveloperError(
`Expected ${name} to be less than ${limit}, actual value was ${test}`
);
}
};
/**
* Throws if test is not typeof 'number' and less than or equal to limit
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @param {Number} limit The limit value to compare against
* @exception {DeveloperError} test must be typeof 'number' and less than or equal to limit
*/
Check.typeOf.number.lessThanOrEquals = function (name, test, limit) {
Check.typeOf.number(name, test);
if (test > limit) {
throw new DeveloperError(
`Expected ${name} to be less than or equal to ${limit}, actual value was ${test}`
);
}
};
/**
* Throws if test is not typeof 'number' and greater than limit
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @param {Number} limit The limit value to compare against
* @exception {DeveloperError} test must be typeof 'number' and greater than limit
*/
Check.typeOf.number.greaterThan = function (name, test, limit) {
Check.typeOf.number(name, test);
if (test <= limit) {
throw new DeveloperError(
`Expected ${name} to be greater than ${limit}, actual value was ${test}`
);
}
};
/**
* Throws if test is not typeof 'number' and greater than or equal to limit
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @param {Number} limit The limit value to compare against
* @exception {DeveloperError} test must be typeof 'number' and greater than or equal to limit
*/
Check.typeOf.number.greaterThanOrEquals = function (name, test, limit) {
Check.typeOf.number(name, test);
if (test < limit) {
throw new DeveloperError(
`Expected ${name} to be greater than or equal to ${limit}, actual value was ${test}`
);
}
};
/**
* Throws if test is not typeof 'object'
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @exception {DeveloperError} test must be typeof 'object'
*/
Check.typeOf.object = function (name, test) {
if (typeof test !== "object") {
throw new DeveloperError(
getFailedTypeErrorMessage(typeof test, "object", name)
);
}
};
/**
* Throws if test is not typeof 'boolean'
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @exception {DeveloperError} test must be typeof 'boolean'
*/
Check.typeOf.bool = function (name, test) {
if (typeof test !== "boolean") {
throw new DeveloperError(
getFailedTypeErrorMessage(typeof test, "boolean", name)
);
}
};
/**
* Throws if test is not typeof 'bigint'
*
* @param {String} name The name of the variable being tested
* @param {*} test The value to test
* @exception {DeveloperError} test must be typeof 'bigint'
*/
Check.typeOf.bigint = function (name, test) {
if (typeof test !== "bigint") {
throw new DeveloperError(
getFailedTypeErrorMessage(typeof test, "bigint", name)
);
}
};
/**
* Throws if test1 and test2 is not typeof 'number' and not equal in value
*
* @param {String} name1 The name of the first variable being tested
* @param {String} name2 The name of the second variable being tested against
* @param {*} test1 The value to test
* @param {*} test2 The value to test against
* @exception {DeveloperError} test1 and test2 should be type of 'number' and be equal in value
*/
Check.typeOf.number.equals = function (name1, name2, test1, test2) {
Check.typeOf.number(name1, test1);
Check.typeOf.number(name2, test2);
if (test1 !== test2) {
throw new DeveloperError(
`${name1} must be equal to ${name2}, the actual values are ${test1} and ${test2}`
);
}
};
/**
* Returns the first parameter if not undefined, otherwise the second parameter.
* Useful for setting a default value for a parameter.
*
* @function
*
* @param {*} a
* @param {*} b
* @returns {*} Returns the first parameter if not undefined, otherwise the second parameter.
*
* @example
* param = Cesium.defaultValue(param, 'default');
*/
function defaultValue(a, b) {
if (a !== undefined && a !== null) {
return a;
}
return b;
}
/**
* A frozen empty object that can be used as the default value for options passed as
* an object literal.
* @type {Object}
* @memberof defaultValue
*/
defaultValue.EMPTY_OBJECT = Object.freeze({});
/* This file is automatically rebuilt by the Cesium build process. */
/*
https://github.com/banksean wrapped Makoto Matsumoto and Takuji Nishimura's code in a namespace
so it's better encapsulated. Now you can have multiple random number generators
and they won't stomp all over eachother's state.
If you want to use this as a substitute for Math.random(), use the random()
method like so:
var m = new MersenneTwister();
var randomNumber = m.random();
You can also call the other genrand_{foo}() methods on the instance.
If you want to use a specific seed in order to get a repeatable random
sequence, pass an integer into the constructor:
var m = new MersenneTwister(123);
and that will always produce the same random sequence.
Sean McCullough (banksean@gmail.com)
*/
/*
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Before using, initialize the state by using init_seed(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
var MersenneTwister = function(seed) {
if (seed == undefined) {
seed = new Date().getTime();
}
/* Period parameters */
this.N = 624;
this.M = 397;
this.MATRIX_A = 0x9908b0df; /* constant vector a */
this.UPPER_MASK = 0x80000000; /* most significant w-r bits */
this.LOWER_MASK = 0x7fffffff; /* least significant r bits */
this.mt = new Array(this.N); /* the array for the state vector */
this.mti=this.N+1; /* mti==N+1 means mt[N] is not initialized */
if (seed.constructor == Array) {
this.init_by_array(seed, seed.length);
}
else {
this.init_seed(seed);
}
};
/* initializes mt[N] with a seed */
/* origin name init_genrand */
MersenneTwister.prototype.init_seed = function(s) {
this.mt[0] = s >>> 0;
for (this.mti=1; this.mti
*
*
value
.
*/
// eslint-disable-next-line es/no-math-sinh
CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) {
return (Math.exp(value) - Math.exp(-value)) / 2.0;
});
/**
* Returns the hyperbolic cosine of a number.
* The hyperbolic cosine of value is defined to be
* (ex + e-x)/2.0
* where e is Euler's number, approximately 2.71828183.
*
* Special cases: *
value
.
*/
// eslint-disable-next-line es/no-math-cosh
CesiumMath.cosh = defaultValue(Math.cosh, function cosh(value) {
return (Math.exp(value) + Math.exp(-value)) / 2.0;
});
/**
* Computes the linear interpolation of two values.
*
* @param {Number} p The start value to interpolate.
* @param {Number} q The end value to interpolate.
* @param {Number} time The time of interpolation generally in the range [0.0, 1.0]
.
* @returns {Number} The linearly interpolated value.
*
* @example
* const n = Cesium.Math.lerp(0.0, 2.0, 0.5); // returns 1.0
*/
CesiumMath.lerp = function (p, q, time) {
return (1.0 - time) * p + time * q;
};
/**
* pi
*
* @type {Number}
* @constant
*/
CesiumMath.PI = Math.PI;
/**
* 1/pi
*
* @type {Number}
* @constant
*/
CesiumMath.ONE_OVER_PI = 1.0 / Math.PI;
/**
* pi/2
*
* @type {Number}
* @constant
*/
CesiumMath.PI_OVER_TWO = Math.PI / 2.0;
/**
* pi/3
*
* @type {Number}
* @constant
*/
CesiumMath.PI_OVER_THREE = Math.PI / 3.0;
/**
* pi/4
*
* @type {Number}
* @constant
*/
CesiumMath.PI_OVER_FOUR = Math.PI / 4.0;
/**
* pi/6
*
* @type {Number}
* @constant
*/
CesiumMath.PI_OVER_SIX = Math.PI / 6.0;
/**
* 3pi/2
*
* @type {Number}
* @constant
*/
CesiumMath.THREE_PI_OVER_TWO = (3.0 * Math.PI) / 2.0;
/**
* 2pi
*
* @type {Number}
* @constant
*/
CesiumMath.TWO_PI = 2.0 * Math.PI;
/**
* 1/2pi
*
* @type {Number}
* @constant
*/
CesiumMath.ONE_OVER_TWO_PI = 1.0 / (2.0 * Math.PI);
/**
* The number of radians in a degree.
*
* @type {Number}
* @constant
*/
CesiumMath.RADIANS_PER_DEGREE = Math.PI / 180.0;
/**
* The number of degrees in a radian.
*
* @type {Number}
* @constant
*/
CesiumMath.DEGREES_PER_RADIAN = 180.0 / Math.PI;
/**
* The number of radians in an arc second.
*
* @type {Number}
* @constant
*/
CesiumMath.RADIANS_PER_ARCSECOND = CesiumMath.RADIANS_PER_DEGREE / 3600.0;
/**
* Converts degrees to radians.
* @param {Number} degrees The angle to convert in degrees.
* @returns {Number} The corresponding angle in radians.
*/
CesiumMath.toRadians = function (degrees) {
//>>includeStart('debug', pragmas.debug);
if (!defined(degrees)) {
throw new DeveloperError("degrees is required.");
}
//>>includeEnd('debug');
return degrees * CesiumMath.RADIANS_PER_DEGREE;
};
/**
* Converts radians to degrees.
* @param {Number} radians The angle to convert in radians.
* @returns {Number} The corresponding angle in degrees.
*/
CesiumMath.toDegrees = function (radians) {
//>>includeStart('debug', pragmas.debug);
if (!defined(radians)) {
throw new DeveloperError("radians is required.");
}
//>>includeEnd('debug');
return radians * CesiumMath.DEGREES_PER_RADIAN;
};
/**
* Converts a longitude value, in radians, to the range [-Math.PI
, Math.PI
).
*
* @param {Number} angle The longitude value, in radians, to convert to the range [-Math.PI
, Math.PI
).
* @returns {Number} The equivalent longitude value in the range [-Math.PI
, Math.PI
).
*
* @example
* // Convert 270 degrees to -90 degrees longitude
* const longitude = Cesium.Math.convertLongitudeRange(Cesium.Math.toRadians(270.0));
*/
CesiumMath.convertLongitudeRange = function (angle) {
//>>includeStart('debug', pragmas.debug);
if (!defined(angle)) {
throw new DeveloperError("angle is required.");
}
//>>includeEnd('debug');
const twoPi = CesiumMath.TWO_PI;
const simplified = angle - Math.floor(angle / twoPi) * twoPi;
if (simplified < -Math.PI) {
return simplified + twoPi;
}
if (simplified >= Math.PI) {
return simplified - twoPi;
}
return simplified;
};
/**
* Convenience function that clamps a latitude value, in radians, to the range [-Math.PI/2
, Math.PI/2
).
* Useful for sanitizing data before use in objects requiring correct range.
*
* @param {Number} angle The latitude value, in radians, to clamp to the range [-Math.PI/2
, Math.PI/2
).
* @returns {Number} The latitude value clamped to the range [-Math.PI/2
, Math.PI/2
).
*
* @example
* // Clamp 108 degrees latitude to 90 degrees latitude
* const latitude = Cesium.Math.clampToLatitudeRange(Cesium.Math.toRadians(108.0));
*/
CesiumMath.clampToLatitudeRange = function (angle) {
//>>includeStart('debug', pragmas.debug);
if (!defined(angle)) {
throw new DeveloperError("angle is required.");
}
//>>includeEnd('debug');
return CesiumMath.clamp(
angle,
-1 * CesiumMath.PI_OVER_TWO,
CesiumMath.PI_OVER_TWO
);
};
/**
* Produces an angle in the range -Pi <= angle <= Pi which is equivalent to the provided angle.
*
* @param {Number} angle in radians
* @returns {Number} The angle in the range [-CesiumMath.PI
, CesiumMath.PI
].
*/
CesiumMath.negativePiToPi = function (angle) {
//>>includeStart('debug', pragmas.debug);
if (!defined(angle)) {
throw new DeveloperError("angle is required.");
}
//>>includeEnd('debug');
if (angle >= -CesiumMath.PI && angle <= CesiumMath.PI) {
// Early exit if the input is already inside the range. This avoids
// unnecessary math which could introduce floating point error.
return angle;
}
return CesiumMath.zeroToTwoPi(angle + CesiumMath.PI) - CesiumMath.PI;
};
/**
* Produces an angle in the range 0 <= angle <= 2Pi which is equivalent to the provided angle.
*
* @param {Number} angle in radians
* @returns {Number} The angle in the range [0, CesiumMath.TWO_PI
].
*/
CesiumMath.zeroToTwoPi = function (angle) {
//>>includeStart('debug', pragmas.debug);
if (!defined(angle)) {
throw new DeveloperError("angle is required.");
}
//>>includeEnd('debug');
if (angle >= 0 && angle <= CesiumMath.TWO_PI) {
// Early exit if the input is already inside the range. This avoids
// unnecessary math which could introduce floating point error.
return angle;
}
const mod = CesiumMath.mod(angle, CesiumMath.TWO_PI);
if (
Math.abs(mod) < CesiumMath.EPSILON14 &&
Math.abs(angle) > CesiumMath.EPSILON14
) {
return CesiumMath.TWO_PI;
}
return mod;
};
/**
* The modulo operation that also works for negative dividends.
*
* @param {Number} m The dividend.
* @param {Number} n The divisor.
* @returns {Number} The remainder.
*/
CesiumMath.mod = function (m, n) {
//>>includeStart('debug', pragmas.debug);
if (!defined(m)) {
throw new DeveloperError("m is required.");
}
if (!defined(n)) {
throw new DeveloperError("n is required.");
}
if (n === 0.0) {
throw new DeveloperError("divisor cannot be 0.");
}
//>>includeEnd('debug');
if (CesiumMath.sign(m) === CesiumMath.sign(n) && Math.abs(m) < Math.abs(n)) {
// Early exit if the input does not need to be modded. This avoids
// unnecessary math which could introduce floating point error.
return m;
}
return ((m % n) + n) % n;
};
/**
* Determines if two values are equal using an absolute or relative tolerance test. This is useful
* to avoid problems due to roundoff error when comparing floating-point values directly. The values are
* first compared using an absolute tolerance test. If that fails, a relative tolerance test is performed.
* Use this test if you are unsure of the magnitudes of left and right.
*
* @param {Number} left The first value to compare.
* @param {Number} right The other value to compare.
* @param {Number} [relativeEpsilon=0] The maximum inclusive delta between left
and right
for the relative tolerance test.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The maximum inclusive delta between left
and right
for the absolute tolerance test.
* @returns {Boolean} true
if the values are equal within the epsilon; otherwise, false
.
*
* @example
* const a = Cesium.Math.equalsEpsilon(0.0, 0.01, Cesium.Math.EPSILON2); // true
* const b = Cesium.Math.equalsEpsilon(0.0, 0.1, Cesium.Math.EPSILON2); // false
* const c = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON7); // true
* const d = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON9); // false
*/
CesiumMath.equalsEpsilon = function (
left,
right,
relativeEpsilon,
absoluteEpsilon
) {
//>>includeStart('debug', pragmas.debug);
if (!defined(left)) {
throw new DeveloperError("left is required.");
}
if (!defined(right)) {
throw new DeveloperError("right is required.");
}
//>>includeEnd('debug');
relativeEpsilon = defaultValue(relativeEpsilon, 0.0);
absoluteEpsilon = defaultValue(absoluteEpsilon, relativeEpsilon);
const absDiff = Math.abs(left - right);
return (
absDiff <= absoluteEpsilon ||
absDiff <= relativeEpsilon * Math.max(Math.abs(left), Math.abs(right))
);
};
/**
* Determines if the left value is less than the right value. If the two values are within
* absoluteEpsilon
of each other, they are considered equal and this function returns false.
*
* @param {Number} left The first number to compare.
* @param {Number} right The second number to compare.
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
* @returns {Boolean} true
if left
is less than right
by more than
* absoluteEpsilon. false
if left
is greater or if the two
* values are nearly equal.
*/
CesiumMath.lessThan = function (left, right, absoluteEpsilon) {
//>>includeStart('debug', pragmas.debug);
if (!defined(left)) {
throw new DeveloperError("first is required.");
}
if (!defined(right)) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right < -absoluteEpsilon;
};
/**
* Determines if the left value is less than or equal to the right value. If the two values are within
* absoluteEpsilon
of each other, they are considered equal and this function returns true.
*
* @param {Number} left The first number to compare.
* @param {Number} right The second number to compare.
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
* @returns {Boolean} true
if left
is less than right
or if the
* the values are nearly equal.
*/
CesiumMath.lessThanOrEquals = function (left, right, absoluteEpsilon) {
//>>includeStart('debug', pragmas.debug);
if (!defined(left)) {
throw new DeveloperError("first is required.");
}
if (!defined(right)) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right < absoluteEpsilon;
};
/**
* Determines if the left value is greater the right value. If the two values are within
* absoluteEpsilon
of each other, they are considered equal and this function returns false.
*
* @param {Number} left The first number to compare.
* @param {Number} right The second number to compare.
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
* @returns {Boolean} true
if left
is greater than right
by more than
* absoluteEpsilon. false
if left
is less or if the two
* values are nearly equal.
*/
CesiumMath.greaterThan = function (left, right, absoluteEpsilon) {
//>>includeStart('debug', pragmas.debug);
if (!defined(left)) {
throw new DeveloperError("first is required.");
}
if (!defined(right)) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right > absoluteEpsilon;
};
/**
* Determines if the left value is greater than or equal to the right value. If the two values are within
* absoluteEpsilon
of each other, they are considered equal and this function returns true.
*
* @param {Number} left The first number to compare.
* @param {Number} right The second number to compare.
* @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
* @returns {Boolean} true
if left
is greater than right
or if the
* the values are nearly equal.
*/
CesiumMath.greaterThanOrEquals = function (left, right, absoluteEpsilon) {
//>>includeStart('debug', pragmas.debug);
if (!defined(left)) {
throw new DeveloperError("first is required.");
}
if (!defined(right)) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right > -absoluteEpsilon;
};
const factorials = [1];
/**
* Computes the factorial of the provided number.
*
* @param {Number} n The number whose factorial is to be computed.
* @returns {Number} The factorial of the provided number or undefined if the number is less than 0.
*
* @exception {DeveloperError} A number greater than or equal to 0 is required.
*
*
* @example
* //Compute 7!, which is equal to 5040
* const computedFactorial = Cesium.Math.factorial(7);
*
* @see {@link http://en.wikipedia.org/wiki/Factorial|Factorial on Wikipedia}
*/
CesiumMath.factorial = function (n) {
//>>includeStart('debug', pragmas.debug);
if (typeof n !== "number" || n < 0) {
throw new DeveloperError(
"A number greater than or equal to 0 is required."
);
}
//>>includeEnd('debug');
const length = factorials.length;
if (n >= length) {
let sum = factorials[length - 1];
for (let i = length; i <= n; i++) {
const next = sum * i;
factorials.push(next);
sum = next;
}
}
return factorials[n];
};
/**
* Increments a number with a wrapping to a minimum value if the number exceeds the maximum value.
*
* @param {Number} [n] The number to be incremented.
* @param {Number} [maximumValue] The maximum incremented value before rolling over to the minimum value.
* @param {Number} [minimumValue=0.0] The number reset to after the maximum value has been exceeded.
* @returns {Number} The incremented number.
*
* @exception {DeveloperError} Maximum value must be greater than minimum value.
*
* @example
* const n = Cesium.Math.incrementWrap(5, 10, 0); // returns 6
* const m = Cesium.Math.incrementWrap(10, 10, 0); // returns 0
*/
CesiumMath.incrementWrap = function (n, maximumValue, minimumValue) {
minimumValue = defaultValue(minimumValue, 0.0);
//>>includeStart('debug', pragmas.debug);
if (!defined(n)) {
throw new DeveloperError("n is required.");
}
if (maximumValue <= minimumValue) {
throw new DeveloperError("maximumValue must be greater than minimumValue.");
}
//>>includeEnd('debug');
++n;
if (n > maximumValue) {
n = minimumValue;
}
return n;
};
/**
* Determines if a non-negative integer is a power of two.
* The maximum allowed input is (2^32)-1 due to 32-bit bitwise operator limitation in Javascript.
*
* @param {Number} n The integer to test in the range [0, (2^32)-1].
* @returns {Boolean} true
if the number if a power of two; otherwise, false
.
*
* @exception {DeveloperError} A number between 0 and (2^32)-1 is required.
*
* @example
* const t = Cesium.Math.isPowerOfTwo(16); // true
* const f = Cesium.Math.isPowerOfTwo(20); // false
*/
CesiumMath.isPowerOfTwo = function (n) {
//>>includeStart('debug', pragmas.debug);
if (typeof n !== "number" || n < 0 || n > 4294967295) {
throw new DeveloperError("A number between 0 and (2^32)-1 is required.");
}
//>>includeEnd('debug');
return n !== 0 && (n & (n - 1)) === 0;
};
/**
* Computes the next power-of-two integer greater than or equal to the provided non-negative integer.
* The maximum allowed input is 2^31 due to 32-bit bitwise operator limitation in Javascript.
*
* @param {Number} n The integer to test in the range [0, 2^31].
* @returns {Number} The next power-of-two integer.
*
* @exception {DeveloperError} A number between 0 and 2^31 is required.
*
* @example
* const n = Cesium.Math.nextPowerOfTwo(29); // 32
* const m = Cesium.Math.nextPowerOfTwo(32); // 32
*/
CesiumMath.nextPowerOfTwo = function (n) {
//>>includeStart('debug', pragmas.debug);
if (typeof n !== "number" || n < 0 || n > 2147483648) {
throw new DeveloperError("A number between 0 and 2^31 is required.");
}
//>>includeEnd('debug');
// From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
--n;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
++n;
return n;
};
/**
* Computes the previous power-of-two integer less than or equal to the provided non-negative integer.
* The maximum allowed input is (2^32)-1 due to 32-bit bitwise operator limitation in Javascript.
*
* @param {Number} n The integer to test in the range [0, (2^32)-1].
* @returns {Number} The previous power-of-two integer.
*
* @exception {DeveloperError} A number between 0 and (2^32)-1 is required.
*
* @example
* const n = Cesium.Math.previousPowerOfTwo(29); // 16
* const m = Cesium.Math.previousPowerOfTwo(32); // 32
*/
CesiumMath.previousPowerOfTwo = function (n) {
//>>includeStart('debug', pragmas.debug);
if (typeof n !== "number" || n < 0 || n > 4294967295) {
throw new DeveloperError("A number between 0 and (2^32)-1 is required.");
}
//>>includeEnd('debug');
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
// The previous bitwise operations implicitly convert to signed 32-bit. Use `>>>` to convert to unsigned
n = (n >>> 0) - (n >>> 1);
return n;
};
/**
* Constraint a value to lie between two values.
*
* @param {Number} value The value to constrain.
* @param {Number} min The minimum value.
* @param {Number} max The maximum value.
* @returns {Number} The value clamped so that min <= value <= max.
*/
CesiumMath.clamp = function (value, min, max) {
//>>includeStart('debug', pragmas.debug);
if (!defined(value)) {
throw new DeveloperError("value is required");
}
if (!defined(min)) {
throw new DeveloperError("min is required.");
}
if (!defined(max)) {
throw new DeveloperError("max is required.");
}
//>>includeEnd('debug');
return value < min ? min : value > max ? max : value;
};
let randomNumberGenerator$2 = new mersenneTwister();
/**
* Sets the seed used by the random number generator
* in {@link CesiumMath#nextRandomNumber}.
*
* @param {Number} seed An integer used as the seed.
*/
CesiumMath.setRandomNumberSeed = function (seed) {
//>>includeStart('debug', pragmas.debug);
if (!defined(seed)) {
throw new DeveloperError("seed is required.");
}
//>>includeEnd('debug');
randomNumberGenerator$2 = new mersenneTwister(seed);
};
/**
* Generates a random floating point number in the range of [0.0, 1.0)
* using a Mersenne twister.
*
* @returns {Number} A random number in the range of [0.0, 1.0).
*
* @see CesiumMath.setRandomNumberSeed
* @see {@link http://en.wikipedia.org/wiki/Mersenne_twister|Mersenne twister on Wikipedia}
*/
CesiumMath.nextRandomNumber = function () {
return randomNumberGenerator$2.random();
};
/**
* Generates a random number between two numbers.
*
* @param {Number} min The minimum value.
* @param {Number} max The maximum value.
* @returns {Number} A random number between the min and max.
*/
CesiumMath.randomBetween = function (min, max) {
return CesiumMath.nextRandomNumber() * (max - min) + min;
};
/**
* Computes Math.acos(value)
, but first clamps value
to the range [-1.0, 1.0]
* so that the function will never return NaN.
*
* @param {Number} value The value for which to compute acos.
* @returns {Number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0,
* whichever is closer, if the value is outside the range.
*/
CesiumMath.acosClamped = function (value) {
//>>includeStart('debug', pragmas.debug);
if (!defined(value)) {
throw new DeveloperError("value is required.");
}
//>>includeEnd('debug');
return Math.acos(CesiumMath.clamp(value, -1.0, 1.0));
};
/**
* Computes Math.asin(value)
, but first clamps value
to the range [-1.0, 1.0]
* so that the function will never return NaN.
*
* @param {Number} value The value for which to compute asin.
* @returns {Number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0,
* whichever is closer, if the value is outside the range.
*/
CesiumMath.asinClamped = function (value) {
//>>includeStart('debug', pragmas.debug);
if (!defined(value)) {
throw new DeveloperError("value is required.");
}
//>>includeEnd('debug');
return Math.asin(CesiumMath.clamp(value, -1.0, 1.0));
};
/**
* Finds the chord length between two points given the circle's radius and the angle between the points.
*
* @param {Number} angle The angle between the two points.
* @param {Number} radius The radius of the circle.
* @returns {Number} The chord length.
*/
CesiumMath.chordLength = function (angle, radius) {
//>>includeStart('debug', pragmas.debug);
if (!defined(angle)) {
throw new DeveloperError("angle is required.");
}
if (!defined(radius)) {
throw new DeveloperError("radius is required.");
}
//>>includeEnd('debug');
return 2.0 * radius * Math.sin(angle * 0.5);
};
/**
* Finds the logarithm of a number to a base.
*
* @param {Number} number The number.
* @param {Number} base The base.
* @returns {Number} The result.
*/
CesiumMath.logBase = function (number, base) {
//>>includeStart('debug', pragmas.debug);
if (!defined(number)) {
throw new DeveloperError("number is required.");
}
if (!defined(base)) {
throw new DeveloperError("base is required.");
}
//>>includeEnd('debug');
return Math.log(number) / Math.log(base);
};
/**
* Finds the cube root of a number.
* Returns NaN if number
is not provided.
*
* @function
* @param {Number} [number] The number.
* @returns {Number} The result.
*/
// eslint-disable-next-line es/no-math-cbrt
CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) {
const result = Math.pow(Math.abs(number), 1.0 / 3.0);
return number < 0.0 ? -result : result;
});
/**
* Finds the base 2 logarithm of a number.
*
* @function
* @param {Number} number The number.
* @returns {Number} The result.
*/
// eslint-disable-next-line es/no-math-log2
CesiumMath.log2 = defaultValue(Math.log2, function log2(number) {
return Math.log(number) * Math.LOG2E;
});
/**
* @private
*/
CesiumMath.fog = function (distanceToCamera, density) {
const scalar = distanceToCamera * density;
return 1.0 - Math.exp(-(scalar * scalar));
};
/**
* Computes a fast approximation of Atan for input in the range [-1, 1].
*
* Based on Michal Drobot's approximation from ShaderFastLibs,
* which in turn is based on "Efficient approximations for the arctangent function,"
* Rajan, S. Sichun Wang Inkol, R. Joyal, A., May 2006.
* Adapted from ShaderFastLibs under MIT License.
*
* @param {Number} x An input number in the range [-1, 1]
* @returns {Number} An approximation of atan(x)
*/
CesiumMath.fastApproximateAtan = function (x) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("x", x);
//>>includeEnd('debug');
return x * (-0.1784 * Math.abs(x) - 0.0663 * x * x + 1.0301);
};
/**
* Computes a fast approximation of Atan2(x, y) for arbitrary input scalars.
*
* Range reduction math based on nvidia's cg reference implementation: http://developer.download.nvidia.com/cg/atan2.html
*
* @param {Number} x An input number that isn't zero if y is zero.
* @param {Number} y An input number that isn't zero if x is zero.
* @returns {Number} An approximation of atan2(x, y)
*/
CesiumMath.fastApproximateAtan2 = function (x, y) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("x", x);
Check.typeOf.number("y", y);
//>>includeEnd('debug');
// atan approximations are usually only reliable over [-1, 1]
// So reduce the range by flipping whether x or y is on top based on which is bigger.
let opposite;
let t = Math.abs(x); // t used as swap and atan result.
opposite = Math.abs(y);
const adjacent = Math.max(t, opposite);
opposite = Math.min(t, opposite);
const oppositeOverAdjacent = opposite / adjacent;
//>>includeStart('debug', pragmas.debug);
if (isNaN(oppositeOverAdjacent)) {
throw new DeveloperError("either x or y must be nonzero");
}
//>>includeEnd('debug');
t = CesiumMath.fastApproximateAtan(oppositeOverAdjacent);
// Undo range reduction
t = Math.abs(y) > Math.abs(x) ? CesiumMath.PI_OVER_TWO - t : t;
t = x < 0.0 ? CesiumMath.PI - t : t;
t = y < 0.0 ? -t : t;
return t;
};
/**
* A 3D Cartesian point.
* @alias Cartesian3
* @constructor
*
* @param {Number} [x=0.0] The X component.
* @param {Number} [y=0.0] The Y component.
* @param {Number} [z=0.0] The Z component.
*
* @see Cartesian2
* @see Cartesian4
* @see Packable
*/
function Cartesian3(x, y, z) {
/**
* The X component.
* @type {Number}
* @default 0.0
*/
this.x = defaultValue(x, 0.0);
/**
* The Y component.
* @type {Number}
* @default 0.0
*/
this.y = defaultValue(y, 0.0);
/**
* The Z component.
* @type {Number}
* @default 0.0
*/
this.z = defaultValue(z, 0.0);
}
/**
* Converts the provided Spherical into Cartesian3 coordinates.
*
* @param {Spherical} spherical The Spherical to be converted to Cartesian3.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
*/
Cartesian3.fromSpherical = function (spherical, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("spherical", spherical);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Cartesian3();
}
const clock = spherical.clock;
const cone = spherical.cone;
const magnitude = defaultValue(spherical.magnitude, 1.0);
const radial = magnitude * Math.sin(cone);
result.x = radial * Math.cos(clock);
result.y = radial * Math.sin(clock);
result.z = magnitude * Math.cos(cone);
return result;
};
/**
* Creates a Cartesian3 instance from x, y and z coordinates.
*
* @param {Number} x The x coordinate.
* @param {Number} y The y coordinate.
* @param {Number} z The z coordinate.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
*/
Cartesian3.fromElements = function (x, y, z, result) {
if (!defined(result)) {
return new Cartesian3(x, y, z);
}
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Duplicates a Cartesian3 instance.
*
* @param {Cartesian3} cartesian The Cartesian to duplicate.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. (Returns undefined if cartesian is undefined)
*/
Cartesian3.clone = function (cartesian, result) {
if (!defined(cartesian)) {
return undefined;
}
if (!defined(result)) {
return new Cartesian3(cartesian.x, cartesian.y, cartesian.z);
}
result.x = cartesian.x;
result.y = cartesian.y;
result.z = cartesian.z;
return result;
};
/**
* Creates a Cartesian3 instance from an existing Cartesian4. This simply takes the
* x, y, and z properties of the Cartesian4 and drops w.
* @function
*
* @param {Cartesian4} cartesian The Cartesian4 instance to create a Cartesian3 instance from.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
*/
Cartesian3.fromCartesian4 = Cartesian3.clone;
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Cartesian3.packedLength = 3;
/**
* Stores the provided instance into the provided array.
*
* @param {Cartesian3} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Cartesian3.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
array[startingIndex++] = value.x;
array[startingIndex++] = value.y;
array[startingIndex] = value.z;
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Cartesian3} [result] The object into which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
*/
Cartesian3.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new Cartesian3();
}
result.x = array[startingIndex++];
result.y = array[startingIndex++];
result.z = array[startingIndex];
return result;
};
/**
* Flattens an array of Cartesian3s into an array of components.
*
* @param {Cartesian3[]} array The array of cartesians to pack.
* @param {Number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 3 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 3) elements.
* @returns {Number[]} The packed array.
*/
Cartesian3.packArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
const length = array.length;
const resultLength = length * 3;
if (!defined(result)) {
result = new Array(resultLength);
} else if (!Array.isArray(result) && result.length !== resultLength) {
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError(
"If result is a typed array, it must have exactly array.length * 3 elements"
);
//>>includeEnd('debug');
} else if (result.length !== resultLength) {
result.length = resultLength;
}
for (let i = 0; i < length; ++i) {
Cartesian3.pack(array[i], result, i * 3);
}
return result;
};
/**
* Unpacks an array of cartesian components into an array of Cartesian3s.
*
* @param {Number[]} array The array of components to unpack.
* @param {Cartesian3[]} [result] The array onto which to store the result.
* @returns {Cartesian3[]} The unpacked array.
*/
Cartesian3.unpackArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
Check.typeOf.number.greaterThanOrEquals("array.length", array.length, 3);
if (array.length % 3 !== 0) {
throw new DeveloperError("array length must be a multiple of 3.");
}
//>>includeEnd('debug');
const length = array.length;
if (!defined(result)) {
result = new Array(length / 3);
} else {
result.length = length / 3;
}
for (let i = 0; i < length; i += 3) {
const index = i / 3;
result[index] = Cartesian3.unpack(array, i, result[index]);
}
return result;
};
/**
* Creates a Cartesian3 from three consecutive elements in an array.
* @function
*
* @param {Number[]} array The array whose three consecutive elements correspond to the x, y, and z components, respectively.
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
*
* @example
* // Create a Cartesian3 with (1.0, 2.0, 3.0)
* const v = [1.0, 2.0, 3.0];
* const p = Cesium.Cartesian3.fromArray(v);
*
* // Create a Cartesian3 with (1.0, 2.0, 3.0) using an offset into an array
* const v2 = [0.0, 0.0, 1.0, 2.0, 3.0];
* const p2 = Cesium.Cartesian3.fromArray(v2, 2);
*/
Cartesian3.fromArray = Cartesian3.unpack;
/**
* Computes the value of the maximum component for the supplied Cartesian.
*
* @param {Cartesian3} cartesian The cartesian to use.
* @returns {Number} The value of the maximum component.
*/
Cartesian3.maximumComponent = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return Math.max(cartesian.x, cartesian.y, cartesian.z);
};
/**
* Computes the value of the minimum component for the supplied Cartesian.
*
* @param {Cartesian3} cartesian The cartesian to use.
* @returns {Number} The value of the minimum component.
*/
Cartesian3.minimumComponent = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return Math.min(cartesian.x, cartesian.y, cartesian.z);
};
/**
* Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
*
* @param {Cartesian3} first A cartesian to compare.
* @param {Cartesian3} second A cartesian to compare.
* @param {Cartesian3} result The object into which to store the result.
* @returns {Cartesian3} A cartesian with the minimum components.
*/
Cartesian3.minimumByComponent = function (first, second, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("first", first);
Check.typeOf.object("second", second);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.min(first.x, second.x);
result.y = Math.min(first.y, second.y);
result.z = Math.min(first.z, second.z);
return result;
};
/**
* Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
*
* @param {Cartesian3} first A cartesian to compare.
* @param {Cartesian3} second A cartesian to compare.
* @param {Cartesian3} result The object into which to store the result.
* @returns {Cartesian3} A cartesian with the maximum components.
*/
Cartesian3.maximumByComponent = function (first, second, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("first", first);
Check.typeOf.object("second", second);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.max(first.x, second.x);
result.y = Math.max(first.y, second.y);
result.z = Math.max(first.z, second.z);
return result;
};
/**
* Computes the provided Cartesian's squared magnitude.
*
* @param {Cartesian3} cartesian The Cartesian instance whose squared magnitude is to be computed.
* @returns {Number} The squared magnitude.
*/
Cartesian3.magnitudeSquared = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return (
cartesian.x * cartesian.x +
cartesian.y * cartesian.y +
cartesian.z * cartesian.z
);
};
/**
* Computes the Cartesian's magnitude (length).
*
* @param {Cartesian3} cartesian The Cartesian instance whose magnitude is to be computed.
* @returns {Number} The magnitude.
*/
Cartesian3.magnitude = function (cartesian) {
return Math.sqrt(Cartesian3.magnitudeSquared(cartesian));
};
const distanceScratch$3 = new Cartesian3();
/**
* Computes the distance between two points.
*
* @param {Cartesian3} left The first point to compute the distance from.
* @param {Cartesian3} right The second point to compute the distance to.
* @returns {Number} The distance between two points.
*
* @example
* // Returns 1.0
* const d = Cesium.Cartesian3.distance(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(2.0, 0.0, 0.0));
*/
Cartesian3.distance = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian3.subtract(left, right, distanceScratch$3);
return Cartesian3.magnitude(distanceScratch$3);
};
/**
* Computes the squared distance between two points. Comparing squared distances
* using this function is more efficient than comparing distances using {@link Cartesian3#distance}.
*
* @param {Cartesian3} left The first point to compute the distance from.
* @param {Cartesian3} right The second point to compute the distance to.
* @returns {Number} The distance between two points.
*
* @example
* // Returns 4.0, not 2.0
* const d = Cesium.Cartesian3.distanceSquared(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(3.0, 0.0, 0.0));
*/
Cartesian3.distanceSquared = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian3.subtract(left, right, distanceScratch$3);
return Cartesian3.magnitudeSquared(distanceScratch$3);
};
/**
* Computes the normalized form of the supplied Cartesian.
*
* @param {Cartesian3} cartesian The Cartesian to be normalized.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.normalize = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const magnitude = Cartesian3.magnitude(cartesian);
result.x = cartesian.x / magnitude;
result.y = cartesian.y / magnitude;
result.z = cartesian.z / magnitude;
//>>includeStart('debug', pragmas.debug);
if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z)) {
throw new DeveloperError("normalized result is not a number");
}
//>>includeEnd('debug');
return result;
};
/**
* Computes the dot (scalar) product of two Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @returns {Number} The dot product.
*/
Cartesian3.dot = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
return left.x * right.x + left.y * right.y + left.z * right.z;
};
/**
* Computes the componentwise product of two Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.multiplyComponents = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x * right.x;
result.y = left.y * right.y;
result.z = left.z * right.z;
return result;
};
/**
* Computes the componentwise quotient of two Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.divideComponents = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x / right.x;
result.y = left.y / right.y;
result.z = left.z / right.z;
return result;
};
/**
* Computes the componentwise sum of two Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.add = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x + right.x;
result.y = left.y + right.y;
result.z = left.z + right.z;
return result;
};
/**
* Computes the componentwise difference of two Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.subtract = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x - right.x;
result.y = left.y - right.y;
result.z = left.z - right.z;
return result;
};
/**
* Multiplies the provided Cartesian componentwise by the provided scalar.
*
* @param {Cartesian3} cartesian The Cartesian to be scaled.
* @param {Number} scalar The scalar to multiply with.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.multiplyByScalar = function (cartesian, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = cartesian.x * scalar;
result.y = cartesian.y * scalar;
result.z = cartesian.z * scalar;
return result;
};
/**
* Divides the provided Cartesian componentwise by the provided scalar.
*
* @param {Cartesian3} cartesian The Cartesian to be divided.
* @param {Number} scalar The scalar to divide by.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.divideByScalar = function (cartesian, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = cartesian.x / scalar;
result.y = cartesian.y / scalar;
result.z = cartesian.z / scalar;
return result;
};
/**
* Negates the provided Cartesian.
*
* @param {Cartesian3} cartesian The Cartesian to be negated.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.negate = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = -cartesian.x;
result.y = -cartesian.y;
result.z = -cartesian.z;
return result;
};
/**
* Computes the absolute value of the provided Cartesian.
*
* @param {Cartesian3} cartesian The Cartesian whose absolute value is to be computed.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.abs = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.abs(cartesian.x);
result.y = Math.abs(cartesian.y);
result.z = Math.abs(cartesian.z);
return result;
};
const lerpScratch$3 = new Cartesian3();
/**
* Computes the linear interpolation or extrapolation at t using the provided cartesians.
*
* @param {Cartesian3} start The value corresponding to t at 0.0.
* @param {Cartesian3} end The value corresponding to t at 1.0.
* @param {Number} t The point along t at which to interpolate.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Cartesian3.lerp = function (start, end, t, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("start", start);
Check.typeOf.object("end", end);
Check.typeOf.number("t", t);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
Cartesian3.multiplyByScalar(end, t, lerpScratch$3);
result = Cartesian3.multiplyByScalar(start, 1.0 - t, result);
return Cartesian3.add(lerpScratch$3, result, result);
};
const angleBetweenScratch$1 = new Cartesian3();
const angleBetweenScratch2$1 = new Cartesian3();
/**
* Returns the angle, in radians, between the provided Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @returns {Number} The angle between the Cartesians.
*/
Cartesian3.angleBetween = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian3.normalize(left, angleBetweenScratch$1);
Cartesian3.normalize(right, angleBetweenScratch2$1);
const cosine = Cartesian3.dot(angleBetweenScratch$1, angleBetweenScratch2$1);
const sine = Cartesian3.magnitude(
Cartesian3.cross(
angleBetweenScratch$1,
angleBetweenScratch2$1,
angleBetweenScratch$1
)
);
return Math.atan2(sine, cosine);
};
const mostOrthogonalAxisScratch$2 = new Cartesian3();
/**
* Returns the axis that is most orthogonal to the provided Cartesian.
*
* @param {Cartesian3} cartesian The Cartesian on which to find the most orthogonal axis.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The most orthogonal axis.
*/
Cartesian3.mostOrthogonalAxis = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const f = Cartesian3.normalize(cartesian, mostOrthogonalAxisScratch$2);
Cartesian3.abs(f, f);
if (f.x <= f.y) {
if (f.x <= f.z) {
result = Cartesian3.clone(Cartesian3.UNIT_X, result);
} else {
result = Cartesian3.clone(Cartesian3.UNIT_Z, result);
}
} else if (f.y <= f.z) {
result = Cartesian3.clone(Cartesian3.UNIT_Y, result);
} else {
result = Cartesian3.clone(Cartesian3.UNIT_Z, result);
}
return result;
};
/**
* Projects vector a onto vector b
* @param {Cartesian3} a The vector that needs projecting
* @param {Cartesian3} b The vector to project onto
* @param {Cartesian3} result The result cartesian
* @returns {Cartesian3} The modified result parameter
*/
Cartesian3.projectVector = function (a, b, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("a", a);
Check.defined("b", b);
Check.defined("result", result);
//>>includeEnd('debug');
const scalar = Cartesian3.dot(a, b) / Cartesian3.dot(b, b);
return Cartesian3.multiplyByScalar(b, scalar, result);
};
/**
* Compares the provided Cartesians componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartesian3} [left] The first Cartesian.
* @param {Cartesian3} [right] The second Cartesian.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartesian3.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left.x === right.x &&
left.y === right.y &&
left.z === right.z)
);
};
/**
* @private
*/
Cartesian3.equalsArray = function (cartesian, array, offset) {
return (
cartesian.x === array[offset] &&
cartesian.y === array[offset + 1] &&
cartesian.z === array[offset + 2]
);
};
/**
* Compares the provided Cartesians componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Cartesian3} [left] The first Cartesian.
* @param {Cartesian3} [right] The second Cartesian.
* @param {Number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartesian3.equalsEpsilon = function (
left,
right,
relativeEpsilon,
absoluteEpsilon
) {
return (
left === right ||
(defined(left) &&
defined(right) &&
CesiumMath.equalsEpsilon(
left.x,
right.x,
relativeEpsilon,
absoluteEpsilon
) &&
CesiumMath.equalsEpsilon(
left.y,
right.y,
relativeEpsilon,
absoluteEpsilon
) &&
CesiumMath.equalsEpsilon(
left.z,
right.z,
relativeEpsilon,
absoluteEpsilon
))
);
};
/**
* Computes the cross (outer) product of two Cartesians.
*
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The cross product.
*/
Cartesian3.cross = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const leftX = left.x;
const leftY = left.y;
const leftZ = left.z;
const rightX = right.x;
const rightY = right.y;
const rightZ = right.z;
const x = leftY * rightZ - leftZ * rightY;
const y = leftZ * rightX - leftX * rightZ;
const z = leftX * rightY - leftY * rightX;
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Computes the midpoint between the right and left Cartesian.
* @param {Cartesian3} left The first Cartesian.
* @param {Cartesian3} right The second Cartesian.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The midpoint.
*/
Cartesian3.midpoint = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = (left.x + right.x) * 0.5;
result.y = (left.y + right.y) * 0.5;
result.z = (left.z + right.z) * 0.5;
return result;
};
/**
* Returns a Cartesian3 position from longitude and latitude values given in degrees.
*
* @param {Number} longitude The longitude, in degrees
* @param {Number} latitude The latitude, in degrees
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The position
*
* @example
* const position = Cesium.Cartesian3.fromDegrees(-115.0, 37.0);
*/
Cartesian3.fromDegrees = function (
longitude,
latitude,
height,
ellipsoid,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
//>>includeEnd('debug');
longitude = CesiumMath.toRadians(longitude);
latitude = CesiumMath.toRadians(latitude);
return Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result);
};
let scratchN = new Cartesian3();
let scratchK = new Cartesian3();
const wgs84RadiiSquared = new Cartesian3(
6378137.0 * 6378137.0,
6378137.0 * 6378137.0,
6356752.3142451793 * 6356752.3142451793
);
/**
* Returns a Cartesian3 position from longitude and latitude values given in radians.
*
* @param {Number} longitude The longitude, in radians
* @param {Number} latitude The latitude, in radians
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The position
*
* @example
* const position = Cesium.Cartesian3.fromRadians(-2.007, 0.645);
*/
Cartesian3.fromRadians = function (
longitude,
latitude,
height,
ellipsoid,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
//>>includeEnd('debug');
height = defaultValue(height, 0.0);
const radiiSquared = defined(ellipsoid)
? ellipsoid.radiiSquared
: wgs84RadiiSquared;
const cosLatitude = Math.cos(latitude);
scratchN.x = cosLatitude * Math.cos(longitude);
scratchN.y = cosLatitude * Math.sin(longitude);
scratchN.z = Math.sin(latitude);
scratchN = Cartesian3.normalize(scratchN, scratchN);
Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK);
const gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK));
scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);
scratchN = Cartesian3.multiplyByScalar(scratchN, height, scratchN);
if (!defined(result)) {
result = new Cartesian3();
}
return Cartesian3.add(scratchK, scratchN, result);
};
/**
* Returns an array of Cartesian3 positions given an array of longitude and latitude values given in degrees.
*
* @param {Number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...].
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the coordinates lie.
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
* @returns {Cartesian3[]} The array of positions.
*
* @example
* const positions = Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0, -107.0, 33.0]);
*/
Cartesian3.fromDegreesArray = function (coordinates, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("coordinates", coordinates);
if (coordinates.length < 2 || coordinates.length % 2 !== 0) {
throw new DeveloperError(
"the number of coordinates must be a multiple of 2 and at least 2"
);
}
//>>includeEnd('debug');
const length = coordinates.length;
if (!defined(result)) {
result = new Array(length / 2);
} else {
result.length = length / 2;
}
for (let i = 0; i < length; i += 2) {
const longitude = coordinates[i];
const latitude = coordinates[i + 1];
const index = i / 2;
result[index] = Cartesian3.fromDegrees(
longitude,
latitude,
0,
ellipsoid,
result[index]
);
}
return result;
};
/**
* Returns an array of Cartesian3 positions given an array of longitude and latitude values given in radians.
*
* @param {Number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...].
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the coordinates lie.
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
* @returns {Cartesian3[]} The array of positions.
*
* @example
* const positions = Cesium.Cartesian3.fromRadiansArray([-2.007, 0.645, -1.867, .575]);
*/
Cartesian3.fromRadiansArray = function (coordinates, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("coordinates", coordinates);
if (coordinates.length < 2 || coordinates.length % 2 !== 0) {
throw new DeveloperError(
"the number of coordinates must be a multiple of 2 and at least 2"
);
}
//>>includeEnd('debug');
const length = coordinates.length;
if (!defined(result)) {
result = new Array(length / 2);
} else {
result.length = length / 2;
}
for (let i = 0; i < length; i += 2) {
const longitude = coordinates[i];
const latitude = coordinates[i + 1];
const index = i / 2;
result[index] = Cartesian3.fromRadians(
longitude,
latitude,
0,
ellipsoid,
result[index]
);
}
return result;
};
/**
* Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in degrees.
*
* @param {Number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...].
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
* @returns {Cartesian3[]} The array of positions.
*
* @example
* const positions = Cesium.Cartesian3.fromDegreesArrayHeights([-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0]);
*/
Cartesian3.fromDegreesArrayHeights = function (coordinates, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("coordinates", coordinates);
if (coordinates.length < 3 || coordinates.length % 3 !== 0) {
throw new DeveloperError(
"the number of coordinates must be a multiple of 3 and at least 3"
);
}
//>>includeEnd('debug');
const length = coordinates.length;
if (!defined(result)) {
result = new Array(length / 3);
} else {
result.length = length / 3;
}
for (let i = 0; i < length; i += 3) {
const longitude = coordinates[i];
const latitude = coordinates[i + 1];
const height = coordinates[i + 2];
const index = i / 3;
result[index] = Cartesian3.fromDegrees(
longitude,
latitude,
height,
ellipsoid,
result[index]
);
}
return result;
};
/**
* Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in radians.
*
* @param {Number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...].
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result.
* @returns {Cartesian3[]} The array of positions.
*
* @example
* const positions = Cesium.Cartesian3.fromRadiansArrayHeights([-2.007, 0.645, 100000.0, -1.867, .575, 150000.0]);
*/
Cartesian3.fromRadiansArrayHeights = function (coordinates, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("coordinates", coordinates);
if (coordinates.length < 3 || coordinates.length % 3 !== 0) {
throw new DeveloperError(
"the number of coordinates must be a multiple of 3 and at least 3"
);
}
//>>includeEnd('debug');
const length = coordinates.length;
if (!defined(result)) {
result = new Array(length / 3);
} else {
result.length = length / 3;
}
for (let i = 0; i < length; i += 3) {
const longitude = coordinates[i];
const latitude = coordinates[i + 1];
const height = coordinates[i + 2];
const index = i / 3;
result[index] = Cartesian3.fromRadians(
longitude,
latitude,
height,
ellipsoid,
result[index]
);
}
return result;
};
/**
* An immutable Cartesian3 instance initialized to (0.0, 0.0, 0.0).
*
* @type {Cartesian3}
* @constant
*/
Cartesian3.ZERO = Object.freeze(new Cartesian3(0.0, 0.0, 0.0));
/**
* An immutable Cartesian3 instance initialized to (1.0, 1.0, 1.0).
*
* @type {Cartesian3}
* @constant
*/
Cartesian3.ONE = Object.freeze(new Cartesian3(1.0, 1.0, 1.0));
/**
* An immutable Cartesian3 instance initialized to (1.0, 0.0, 0.0).
*
* @type {Cartesian3}
* @constant
*/
Cartesian3.UNIT_X = Object.freeze(new Cartesian3(1.0, 0.0, 0.0));
/**
* An immutable Cartesian3 instance initialized to (0.0, 1.0, 0.0).
*
* @type {Cartesian3}
* @constant
*/
Cartesian3.UNIT_Y = Object.freeze(new Cartesian3(0.0, 1.0, 0.0));
/**
* An immutable Cartesian3 instance initialized to (0.0, 0.0, 1.0).
*
* @type {Cartesian3}
* @constant
*/
Cartesian3.UNIT_Z = Object.freeze(new Cartesian3(0.0, 0.0, 1.0));
/**
* Duplicates this Cartesian3 instance.
*
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided.
*/
Cartesian3.prototype.clone = function (result) {
return Cartesian3.clone(this, result);
};
/**
* Compares this Cartesian against the provided Cartesian componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartesian3} [right] The right hand side Cartesian.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
Cartesian3.prototype.equals = function (right) {
return Cartesian3.equals(this, right);
};
/**
* Compares this Cartesian against the provided Cartesian componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Cartesian3} [right] The right hand side Cartesian.
* @param {Number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if they are within the provided epsilon, false
otherwise.
*/
Cartesian3.prototype.equalsEpsilon = function (
right,
relativeEpsilon,
absoluteEpsilon
) {
return Cartesian3.equalsEpsilon(
this,
right,
relativeEpsilon,
absoluteEpsilon
);
};
/**
* Creates a string representing this Cartesian in the format '(x, y, z)'.
*
* @returns {String} A string representing this Cartesian in the format '(x, y, z)'.
*/
Cartesian3.prototype.toString = function () {
return `(${this.x}, ${this.y}, ${this.z})`;
};
const scaleToGeodeticSurfaceIntersection = new Cartesian3();
const scaleToGeodeticSurfaceGradient = new Cartesian3();
/**
* Scales the provided Cartesian position along the geodetic surface normal
* so that it is on the surface of this ellipsoid. If the position is
* at the center of the ellipsoid, this function returns undefined.
*
* @param {Cartesian3} cartesian The Cartesian position to scale.
* @param {Cartesian3} oneOverRadii One over radii of the ellipsoid.
* @param {Cartesian3} oneOverRadiiSquared One over radii squared of the ellipsoid.
* @param {Number} centerToleranceSquared Tolerance for closeness to the center.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
*
* @function scaleToGeodeticSurface
*
* @private
*/
function scaleToGeodeticSurface(
cartesian,
oneOverRadii,
oneOverRadiiSquared,
centerToleranceSquared,
result
) {
//>>includeStart('debug', pragmas.debug);
if (!defined(cartesian)) {
throw new DeveloperError("cartesian is required.");
}
if (!defined(oneOverRadii)) {
throw new DeveloperError("oneOverRadii is required.");
}
if (!defined(oneOverRadiiSquared)) {
throw new DeveloperError("oneOverRadiiSquared is required.");
}
if (!defined(centerToleranceSquared)) {
throw new DeveloperError("centerToleranceSquared is required.");
}
//>>includeEnd('debug');
const positionX = cartesian.x;
const positionY = cartesian.y;
const positionZ = cartesian.z;
const oneOverRadiiX = oneOverRadii.x;
const oneOverRadiiY = oneOverRadii.y;
const oneOverRadiiZ = oneOverRadii.z;
const x2 = positionX * positionX * oneOverRadiiX * oneOverRadiiX;
const y2 = positionY * positionY * oneOverRadiiY * oneOverRadiiY;
const z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ;
// Compute the squared ellipsoid norm.
const squaredNorm = x2 + y2 + z2;
const ratio = Math.sqrt(1.0 / squaredNorm);
// As an initial approximation, assume that the radial intersection is the projection point.
const intersection = Cartesian3.multiplyByScalar(
cartesian,
ratio,
scaleToGeodeticSurfaceIntersection
);
// If the position is near the center, the iteration will not converge.
if (squaredNorm < centerToleranceSquared) {
return !isFinite(ratio)
? undefined
: Cartesian3.clone(intersection, result);
}
const oneOverRadiiSquaredX = oneOverRadiiSquared.x;
const oneOverRadiiSquaredY = oneOverRadiiSquared.y;
const oneOverRadiiSquaredZ = oneOverRadiiSquared.z;
// Use the gradient at the intersection point in place of the true unit normal.
// The difference in magnitude will be absorbed in the multiplier.
const gradient = scaleToGeodeticSurfaceGradient;
gradient.x = intersection.x * oneOverRadiiSquaredX * 2.0;
gradient.y = intersection.y * oneOverRadiiSquaredY * 2.0;
gradient.z = intersection.z * oneOverRadiiSquaredZ * 2.0;
// Compute the initial guess at the normal vector multiplier, lambda.
let lambda =
((1.0 - ratio) * Cartesian3.magnitude(cartesian)) /
(0.5 * Cartesian3.magnitude(gradient));
let correction = 0.0;
let func;
let denominator;
let xMultiplier;
let yMultiplier;
let zMultiplier;
let xMultiplier2;
let yMultiplier2;
let zMultiplier2;
let xMultiplier3;
let yMultiplier3;
let zMultiplier3;
do {
lambda -= correction;
xMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredX);
yMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredY);
zMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredZ);
xMultiplier2 = xMultiplier * xMultiplier;
yMultiplier2 = yMultiplier * yMultiplier;
zMultiplier2 = zMultiplier * zMultiplier;
xMultiplier3 = xMultiplier2 * xMultiplier;
yMultiplier3 = yMultiplier2 * yMultiplier;
zMultiplier3 = zMultiplier2 * zMultiplier;
func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1.0;
// "denominator" here refers to the use of this expression in the velocity and acceleration
// computations in the sections to follow.
denominator =
x2 * xMultiplier3 * oneOverRadiiSquaredX +
y2 * yMultiplier3 * oneOverRadiiSquaredY +
z2 * zMultiplier3 * oneOverRadiiSquaredZ;
const derivative = -2.0 * denominator;
correction = func / derivative;
} while (Math.abs(func) > CesiumMath.EPSILON12);
if (!defined(result)) {
return new Cartesian3(
positionX * xMultiplier,
positionY * yMultiplier,
positionZ * zMultiplier
);
}
result.x = positionX * xMultiplier;
result.y = positionY * yMultiplier;
result.z = positionZ * zMultiplier;
return result;
}
/**
* A position defined by longitude, latitude, and height.
* @alias Cartographic
* @constructor
*
* @param {Number} [longitude=0.0] The longitude, in radians.
* @param {Number} [latitude=0.0] The latitude, in radians.
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
*
* @see Ellipsoid
*/
function Cartographic(longitude, latitude, height) {
/**
* The longitude, in radians.
* @type {Number}
* @default 0.0
*/
this.longitude = defaultValue(longitude, 0.0);
/**
* The latitude, in radians.
* @type {Number}
* @default 0.0
*/
this.latitude = defaultValue(latitude, 0.0);
/**
* The height, in meters, above the ellipsoid.
* @type {Number}
* @default 0.0
*/
this.height = defaultValue(height, 0.0);
}
/**
* Creates a new Cartographic instance from longitude and latitude
* specified in radians.
*
* @param {Number} longitude The longitude, in radians.
* @param {Number} latitude The latitude, in radians.
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
*/
Cartographic.fromRadians = function (longitude, latitude, height, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
//>>includeEnd('debug');
height = defaultValue(height, 0.0);
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
};
/**
* Creates a new Cartographic instance from longitude and latitude
* specified in degrees. The values in the resulting object will
* be in radians.
*
* @param {Number} longitude The longitude, in degrees.
* @param {Number} latitude The latitude, in degrees.
* @param {Number} [height=0.0] The height, in meters, above the ellipsoid.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
*/
Cartographic.fromDegrees = function (longitude, latitude, height, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
//>>includeEnd('debug');
longitude = CesiumMath.toRadians(longitude);
latitude = CesiumMath.toRadians(latitude);
return Cartographic.fromRadians(longitude, latitude, height, result);
};
const cartesianToCartographicN$1 = new Cartesian3();
const cartesianToCartographicP$1 = new Cartesian3();
const cartesianToCartographicH$1 = new Cartesian3();
const wgs84OneOverRadii = new Cartesian3(
1.0 / 6378137.0,
1.0 / 6378137.0,
1.0 / 6356752.3142451793
);
const wgs84OneOverRadiiSquared = new Cartesian3(
1.0 / (6378137.0 * 6378137.0),
1.0 / (6378137.0 * 6378137.0),
1.0 / (6356752.3142451793 * 6356752.3142451793)
);
const wgs84CenterToleranceSquared = CesiumMath.EPSILON1;
/**
* Creates a new Cartographic instance from a Cartesian position. The values in the
* resulting object will be in radians.
*
* @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
*/
Cartographic.fromCartesian = function (cartesian, ellipsoid, result) {
const oneOverRadii = defined(ellipsoid)
? ellipsoid.oneOverRadii
: wgs84OneOverRadii;
const oneOverRadiiSquared = defined(ellipsoid)
? ellipsoid.oneOverRadiiSquared
: wgs84OneOverRadiiSquared;
const centerToleranceSquared = defined(ellipsoid)
? ellipsoid._centerToleranceSquared
: wgs84CenterToleranceSquared;
//`cartesian is required.` is thrown from scaleToGeodeticSurface
const p = scaleToGeodeticSurface(
cartesian,
oneOverRadii,
oneOverRadiiSquared,
centerToleranceSquared,
cartesianToCartographicP$1
);
if (!defined(p)) {
return undefined;
}
let n = Cartesian3.multiplyComponents(
p,
oneOverRadiiSquared,
cartesianToCartographicN$1
);
n = Cartesian3.normalize(n, n);
const h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH$1);
const longitude = Math.atan2(n.y, n.x);
const latitude = Math.asin(n.z);
const height =
CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
};
/**
* Creates a new Cartesian3 instance from a Cartographic input. The values in the inputted
* object should be in radians.
*
* @param {Cartographic} cartographic Input to be converted into a Cartesian3 output.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the position lies.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The position
*/
Cartographic.toCartesian = function (cartographic, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("cartographic", cartographic);
//>>includeEnd('debug');
return Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
cartographic.height,
ellipsoid,
result
);
};
/**
* Duplicates a Cartographic instance.
*
* @param {Cartographic} cartographic The cartographic to duplicate.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. (Returns undefined if cartographic is undefined)
*/
Cartographic.clone = function (cartographic, result) {
if (!defined(cartographic)) {
return undefined;
}
if (!defined(result)) {
return new Cartographic(
cartographic.longitude,
cartographic.latitude,
cartographic.height
);
}
result.longitude = cartographic.longitude;
result.latitude = cartographic.latitude;
result.height = cartographic.height;
return result;
};
/**
* Compares the provided cartographics componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartographic} [left] The first cartographic.
* @param {Cartographic} [right] The second cartographic.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartographic.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left.longitude === right.longitude &&
left.latitude === right.latitude &&
left.height === right.height)
);
};
/**
* Compares the provided cartographics componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Cartographic} [left] The first cartographic.
* @param {Cartographic} [right] The second cartographic.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartographic.equalsEpsilon = function (left, right, epsilon) {
epsilon = defaultValue(epsilon, 0);
return (
left === right ||
(defined(left) &&
defined(right) &&
Math.abs(left.longitude - right.longitude) <= epsilon &&
Math.abs(left.latitude - right.latitude) <= epsilon &&
Math.abs(left.height - right.height) <= epsilon)
);
};
/**
* An immutable Cartographic instance initialized to (0.0, 0.0, 0.0).
*
* @type {Cartographic}
* @constant
*/
Cartographic.ZERO = Object.freeze(new Cartographic(0.0, 0.0, 0.0));
/**
* Duplicates this instance.
*
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided.
*/
Cartographic.prototype.clone = function (result) {
return Cartographic.clone(this, result);
};
/**
* Compares the provided against this cartographic componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartographic} [right] The second cartographic.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartographic.prototype.equals = function (right) {
return Cartographic.equals(this, right);
};
/**
* Compares the provided against this cartographic componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Cartographic} [right] The second cartographic.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartographic.prototype.equalsEpsilon = function (right, epsilon) {
return Cartographic.equalsEpsilon(this, right, epsilon);
};
/**
* Creates a string representing this cartographic in the format '(longitude, latitude, height)'.
*
* @returns {String} A string representing the provided cartographic in the format '(longitude, latitude, height)'.
*/
Cartographic.prototype.toString = function () {
return `(${this.longitude}, ${this.latitude}, ${this.height})`;
};
function initialize$e(ellipsoid, x, y, z) {
x = defaultValue(x, 0.0);
y = defaultValue(y, 0.0);
z = defaultValue(z, 0.0);
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("x", x, 0.0);
Check.typeOf.number.greaterThanOrEquals("y", y, 0.0);
Check.typeOf.number.greaterThanOrEquals("z", z, 0.0);
//>>includeEnd('debug');
ellipsoid._radii = new Cartesian3(x, y, z);
ellipsoid._radiiSquared = new Cartesian3(x * x, y * y, z * z);
ellipsoid._radiiToTheFourth = new Cartesian3(
x * x * x * x,
y * y * y * y,
z * z * z * z
);
ellipsoid._oneOverRadii = new Cartesian3(
x === 0.0 ? 0.0 : 1.0 / x,
y === 0.0 ? 0.0 : 1.0 / y,
z === 0.0 ? 0.0 : 1.0 / z
);
ellipsoid._oneOverRadiiSquared = new Cartesian3(
x === 0.0 ? 0.0 : 1.0 / (x * x),
y === 0.0 ? 0.0 : 1.0 / (y * y),
z === 0.0 ? 0.0 : 1.0 / (z * z)
);
ellipsoid._minimumRadius = Math.min(x, y, z);
ellipsoid._maximumRadius = Math.max(x, y, z);
ellipsoid._centerToleranceSquared = CesiumMath.EPSILON1;
if (ellipsoid._radiiSquared.z !== 0) {
ellipsoid._squaredXOverSquaredZ =
ellipsoid._radiiSquared.x / ellipsoid._radiiSquared.z;
}
}
/**
* A quadratic surface defined in Cartesian coordinates by the equation
* (x / a)^2 + (y / b)^2 + (z / c)^2 = 1
. Primarily used
* by Cesium to represent the shape of planetary bodies.
*
* Rather than constructing this object directly, one of the provided
* constants is normally used.
* @alias Ellipsoid
* @constructor
*
* @param {Number} [x=0] The radius in the x direction.
* @param {Number} [y=0] The radius in the y direction.
* @param {Number} [z=0] The radius in the z direction.
*
* @exception {DeveloperError} All radii components must be greater than or equal to zero.
*
* @see Ellipsoid.fromCartesian3
* @see Ellipsoid.WGS84
* @see Ellipsoid.UNIT_SPHERE
*/
function Ellipsoid(x, y, z) {
this._radii = undefined;
this._radiiSquared = undefined;
this._radiiToTheFourth = undefined;
this._oneOverRadii = undefined;
this._oneOverRadiiSquared = undefined;
this._minimumRadius = undefined;
this._maximumRadius = undefined;
this._centerToleranceSquared = undefined;
this._squaredXOverSquaredZ = undefined;
initialize$e(this, x, y, z);
}
Object.defineProperties(Ellipsoid.prototype, {
/**
* Gets the radii of the ellipsoid.
* @memberof Ellipsoid.prototype
* @type {Cartesian3}
* @readonly
*/
radii: {
get: function () {
return this._radii;
},
},
/**
* Gets the squared radii of the ellipsoid.
* @memberof Ellipsoid.prototype
* @type {Cartesian3}
* @readonly
*/
radiiSquared: {
get: function () {
return this._radiiSquared;
},
},
/**
* Gets the radii of the ellipsoid raise to the fourth power.
* @memberof Ellipsoid.prototype
* @type {Cartesian3}
* @readonly
*/
radiiToTheFourth: {
get: function () {
return this._radiiToTheFourth;
},
},
/**
* Gets one over the radii of the ellipsoid.
* @memberof Ellipsoid.prototype
* @type {Cartesian3}
* @readonly
*/
oneOverRadii: {
get: function () {
return this._oneOverRadii;
},
},
/**
* Gets one over the squared radii of the ellipsoid.
* @memberof Ellipsoid.prototype
* @type {Cartesian3}
* @readonly
*/
oneOverRadiiSquared: {
get: function () {
return this._oneOverRadiiSquared;
},
},
/**
* Gets the minimum radius of the ellipsoid.
* @memberof Ellipsoid.prototype
* @type {Number}
* @readonly
*/
minimumRadius: {
get: function () {
return this._minimumRadius;
},
},
/**
* Gets the maximum radius of the ellipsoid.
* @memberof Ellipsoid.prototype
* @type {Number}
* @readonly
*/
maximumRadius: {
get: function () {
return this._maximumRadius;
},
},
});
/**
* Duplicates an Ellipsoid instance.
*
* @param {Ellipsoid} ellipsoid The ellipsoid to duplicate.
* @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
* instance should be created.
* @returns {Ellipsoid} The cloned Ellipsoid. (Returns undefined if ellipsoid is undefined)
*/
Ellipsoid.clone = function (ellipsoid, result) {
if (!defined(ellipsoid)) {
return undefined;
}
const radii = ellipsoid._radii;
if (!defined(result)) {
return new Ellipsoid(radii.x, radii.y, radii.z);
}
Cartesian3.clone(radii, result._radii);
Cartesian3.clone(ellipsoid._radiiSquared, result._radiiSquared);
Cartesian3.clone(ellipsoid._radiiToTheFourth, result._radiiToTheFourth);
Cartesian3.clone(ellipsoid._oneOverRadii, result._oneOverRadii);
Cartesian3.clone(ellipsoid._oneOverRadiiSquared, result._oneOverRadiiSquared);
result._minimumRadius = ellipsoid._minimumRadius;
result._maximumRadius = ellipsoid._maximumRadius;
result._centerToleranceSquared = ellipsoid._centerToleranceSquared;
return result;
};
/**
* Computes an Ellipsoid from a Cartesian specifying the radii in x, y, and z directions.
*
* @param {Cartesian3} [cartesian=Cartesian3.ZERO] The ellipsoid's radius in the x, y, and z directions.
* @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
* instance should be created.
* @returns {Ellipsoid} A new Ellipsoid instance.
*
* @exception {DeveloperError} All radii components must be greater than or equal to zero.
*
* @see Ellipsoid.WGS84
* @see Ellipsoid.UNIT_SPHERE
*/
Ellipsoid.fromCartesian3 = function (cartesian, result) {
if (!defined(result)) {
result = new Ellipsoid();
}
if (!defined(cartesian)) {
return result;
}
initialize$e(result, cartesian.x, cartesian.y, cartesian.z);
return result;
};
/**
* An Ellipsoid instance initialized to the WGS84 standard.
*
* @type {Ellipsoid}
* @constant
*/
Ellipsoid.WGS84 = Object.freeze(
new Ellipsoid(6378137.0, 6378137.0, 6356752.3142451793)
);
/**
* An Ellipsoid instance initialized to radii of (1.0, 1.0, 1.0).
*
* @type {Ellipsoid}
* @constant
*/
Ellipsoid.UNIT_SPHERE = Object.freeze(new Ellipsoid(1.0, 1.0, 1.0));
/**
* An Ellipsoid instance initialized to a sphere with the lunar radius.
*
* @type {Ellipsoid}
* @constant
*/
Ellipsoid.MOON = Object.freeze(
new Ellipsoid(
CesiumMath.LUNAR_RADIUS,
CesiumMath.LUNAR_RADIUS,
CesiumMath.LUNAR_RADIUS
)
);
/**
* Duplicates an Ellipsoid instance.
*
* @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
* instance should be created.
* @returns {Ellipsoid} The cloned Ellipsoid.
*/
Ellipsoid.prototype.clone = function (result) {
return Ellipsoid.clone(this, result);
};
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Ellipsoid.packedLength = Cartesian3.packedLength;
/**
* Stores the provided instance into the provided array.
*
* @param {Ellipsoid} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Ellipsoid.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
Cartesian3.pack(value._radii, array, startingIndex);
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Ellipsoid} [result] The object into which to store the result.
* @returns {Ellipsoid} The modified result parameter or a new Ellipsoid instance if one was not provided.
*/
Ellipsoid.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
const radii = Cartesian3.unpack(array, startingIndex);
return Ellipsoid.fromCartesian3(radii, result);
};
/**
* Computes the unit vector directed from the center of this ellipsoid toward the provided Cartesian position.
* @function
*
* @param {Cartesian3} cartesian The Cartesian for which to to determine the geocentric normal.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
*/
Ellipsoid.prototype.geocentricSurfaceNormal = Cartesian3.normalize;
/**
* Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position.
*
* @param {Cartographic} cartographic The cartographic position for which to to determine the geodetic normal.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
*/
Ellipsoid.prototype.geodeticSurfaceNormalCartographic = function (
cartographic,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartographic", cartographic);
//>>includeEnd('debug');
const longitude = cartographic.longitude;
const latitude = cartographic.latitude;
const cosLatitude = Math.cos(latitude);
const x = cosLatitude * Math.cos(longitude);
const y = cosLatitude * Math.sin(longitude);
const z = Math.sin(latitude);
if (!defined(result)) {
result = new Cartesian3();
}
result.x = x;
result.y = y;
result.z = z;
return Cartesian3.normalize(result, result);
};
/**
* Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position.
*
* @param {Cartesian3} cartesian The Cartesian position for which to to determine the surface normal.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided, or undefined if a normal cannot be found.
*/
Ellipsoid.prototype.geodeticSurfaceNormal = function (cartesian, result) {
if (
Cartesian3.equalsEpsilon(cartesian, Cartesian3.ZERO, CesiumMath.EPSILON14)
) {
return undefined;
}
if (!defined(result)) {
result = new Cartesian3();
}
result = Cartesian3.multiplyComponents(
cartesian,
this._oneOverRadiiSquared,
result
);
return Cartesian3.normalize(result, result);
};
const cartographicToCartesianNormal = new Cartesian3();
const cartographicToCartesianK = new Cartesian3();
/**
* Converts the provided cartographic to Cartesian representation.
*
* @param {Cartographic} cartographic The cartographic position.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
*
* @example
* //Create a Cartographic and determine it's Cartesian representation on a WGS84 ellipsoid.
* const position = new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 5000);
* const cartesianPosition = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position);
*/
Ellipsoid.prototype.cartographicToCartesian = function (cartographic, result) {
//`cartographic is required` is thrown from geodeticSurfaceNormalCartographic.
const n = cartographicToCartesianNormal;
const k = cartographicToCartesianK;
this.geodeticSurfaceNormalCartographic(cartographic, n);
Cartesian3.multiplyComponents(this._radiiSquared, n, k);
const gamma = Math.sqrt(Cartesian3.dot(n, k));
Cartesian3.divideByScalar(k, gamma, k);
Cartesian3.multiplyByScalar(n, cartographic.height, n);
if (!defined(result)) {
result = new Cartesian3();
}
return Cartesian3.add(k, n, result);
};
/**
* Converts the provided array of cartographics to an array of Cartesians.
*
* @param {Cartographic[]} cartographics An array of cartographic positions.
* @param {Cartesian3[]} [result] The object onto which to store the result.
* @returns {Cartesian3[]} The modified result parameter or a new Array instance if none was provided.
*
* @example
* //Convert an array of Cartographics and determine their Cartesian representation on a WGS84 ellipsoid.
* const positions = [new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 0),
* new Cesium.Cartographic(Cesium.Math.toRadians(21.321), Cesium.Math.toRadians(78.123), 100),
* new Cesium.Cartographic(Cesium.Math.toRadians(21.645), Cesium.Math.toRadians(78.456), 250)];
* const cartesianPositions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(positions);
*/
Ellipsoid.prototype.cartographicArrayToCartesianArray = function (
cartographics,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("cartographics", cartographics);
//>>includeEnd('debug')
const length = cartographics.length;
if (!defined(result)) {
result = new Array(length);
} else {
result.length = length;
}
for (let i = 0; i < length; i++) {
result[i] = this.cartographicToCartesian(cartographics[i], result[i]);
}
return result;
};
const cartesianToCartographicN = new Cartesian3();
const cartesianToCartographicP = new Cartesian3();
const cartesianToCartographicH = new Cartesian3();
/**
* Converts the provided cartesian to cartographic representation.
* The cartesian is undefined at the center of the ellipsoid.
*
* @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation.
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid.
*
* @example
* //Create a Cartesian and determine it's Cartographic representation on a WGS84 ellipsoid.
* const position = new Cesium.Cartesian3(17832.12, 83234.52, 952313.73);
* const cartographicPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
*/
Ellipsoid.prototype.cartesianToCartographic = function (cartesian, result) {
//`cartesian is required.` is thrown from scaleToGeodeticSurface
const p = this.scaleToGeodeticSurface(cartesian, cartesianToCartographicP);
if (!defined(p)) {
return undefined;
}
const n = this.geodeticSurfaceNormal(p, cartesianToCartographicN);
const h = Cartesian3.subtract(cartesian, p, cartesianToCartographicH);
const longitude = Math.atan2(n.y, n.x);
const latitude = Math.asin(n.z);
const height =
CesiumMath.sign(Cartesian3.dot(h, cartesian)) * Cartesian3.magnitude(h);
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
};
/**
* Converts the provided array of cartesians to an array of cartographics.
*
* @param {Cartesian3[]} cartesians An array of Cartesian positions.
* @param {Cartographic[]} [result] The object onto which to store the result.
* @returns {Cartographic[]} The modified result parameter or a new Array instance if none was provided.
*
* @example
* //Create an array of Cartesians and determine their Cartographic representation on a WGS84 ellipsoid.
* const positions = [new Cesium.Cartesian3(17832.12, 83234.52, 952313.73),
* new Cesium.Cartesian3(17832.13, 83234.53, 952313.73),
* new Cesium.Cartesian3(17832.14, 83234.54, 952313.73)]
* const cartographicPositions = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions);
*/
Ellipsoid.prototype.cartesianArrayToCartographicArray = function (
cartesians,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("cartesians", cartesians);
//>>includeEnd('debug');
const length = cartesians.length;
if (!defined(result)) {
result = new Array(length);
} else {
result.length = length;
}
for (let i = 0; i < length; ++i) {
result[i] = this.cartesianToCartographic(cartesians[i], result[i]);
}
return result;
};
/**
* Scales the provided Cartesian position along the geodetic surface normal
* so that it is on the surface of this ellipsoid. If the position is
* at the center of the ellipsoid, this function returns undefined.
*
* @param {Cartesian3} cartesian The Cartesian position to scale.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
*/
Ellipsoid.prototype.scaleToGeodeticSurface = function (cartesian, result) {
return scaleToGeodeticSurface(
cartesian,
this._oneOverRadii,
this._oneOverRadiiSquared,
this._centerToleranceSquared,
result
);
};
/**
* Scales the provided Cartesian position along the geocentric surface normal
* so that it is on the surface of this ellipsoid.
*
* @param {Cartesian3} cartesian The Cartesian position to scale.
* @param {Cartesian3} [result] The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
*/
Ellipsoid.prototype.scaleToGeocentricSurface = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Cartesian3();
}
const positionX = cartesian.x;
const positionY = cartesian.y;
const positionZ = cartesian.z;
const oneOverRadiiSquared = this._oneOverRadiiSquared;
const beta =
1.0 /
Math.sqrt(
positionX * positionX * oneOverRadiiSquared.x +
positionY * positionY * oneOverRadiiSquared.y +
positionZ * positionZ * oneOverRadiiSquared.z
);
return Cartesian3.multiplyByScalar(cartesian, beta, result);
};
/**
* Transforms a Cartesian X, Y, Z position to the ellipsoid-scaled space by multiplying
* its components by the result of {@link Ellipsoid#oneOverRadii}.
*
* @param {Cartesian3} position The position to transform.
* @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and
* return a new instance.
* @returns {Cartesian3} The position expressed in the scaled space. The returned instance is the
* one passed as the result parameter if it is not undefined, or a new instance of it is.
*/
Ellipsoid.prototype.transformPositionToScaledSpace = function (
position,
result
) {
if (!defined(result)) {
result = new Cartesian3();
}
return Cartesian3.multiplyComponents(position, this._oneOverRadii, result);
};
/**
* Transforms a Cartesian X, Y, Z position from the ellipsoid-scaled space by multiplying
* its components by the result of {@link Ellipsoid#radii}.
*
* @param {Cartesian3} position The position to transform.
* @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and
* return a new instance.
* @returns {Cartesian3} The position expressed in the unscaled space. The returned instance is the
* one passed as the result parameter if it is not undefined, or a new instance of it is.
*/
Ellipsoid.prototype.transformPositionFromScaledSpace = function (
position,
result
) {
if (!defined(result)) {
result = new Cartesian3();
}
return Cartesian3.multiplyComponents(position, this._radii, result);
};
/**
* Compares this Ellipsoid against the provided Ellipsoid componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Ellipsoid} [right] The other Ellipsoid.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
Ellipsoid.prototype.equals = function (right) {
return (
this === right ||
(defined(right) && Cartesian3.equals(this._radii, right._radii))
);
};
/**
* Creates a string representing this Ellipsoid in the format '(radii.x, radii.y, radii.z)'.
*
* @returns {String} A string representing this ellipsoid in the format '(radii.x, radii.y, radii.z)'.
*/
Ellipsoid.prototype.toString = function () {
return this._radii.toString();
};
/**
* Computes a point which is the intersection of the surface normal with the z-axis.
*
* @param {Cartesian3} position the position. must be on the surface of the ellipsoid.
* @param {Number} [buffer = 0.0] A buffer to subtract from the ellipsoid size when checking if the point is inside the ellipsoid.
* In earth case, with common earth datums, there is no need for this buffer since the intersection point is always (relatively) very close to the center.
* In WGS84 datum, intersection point is at max z = +-42841.31151331382 (0.673% of z-axis).
* Intersection point could be outside the ellipsoid if the ratio of MajorAxis / AxisOfRotation is bigger than the square root of 2
* @param {Cartesian3} [result] The cartesian to which to copy the result, or undefined to create and
* return a new instance.
* @returns {Cartesian3 | undefined} the intersection point if it's inside the ellipsoid, undefined otherwise
*
* @exception {DeveloperError} position is required.
* @exception {DeveloperError} Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y).
* @exception {DeveloperError} Ellipsoid.radii.z must be greater than 0.
*/
Ellipsoid.prototype.getSurfaceNormalIntersectionWithZAxis = function (
position,
buffer,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("position", position);
if (
!CesiumMath.equalsEpsilon(
this._radii.x,
this._radii.y,
CesiumMath.EPSILON15
)
) {
throw new DeveloperError(
"Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)"
);
}
Check.typeOf.number.greaterThan("Ellipsoid.radii.z", this._radii.z, 0);
//>>includeEnd('debug');
buffer = defaultValue(buffer, 0.0);
const squaredXOverSquaredZ = this._squaredXOverSquaredZ;
if (!defined(result)) {
result = new Cartesian3();
}
result.x = 0.0;
result.y = 0.0;
result.z = position.z * (1 - squaredXOverSquaredZ);
if (Math.abs(result.z) >= this._radii.z - buffer) {
return undefined;
}
return result;
};
const abscissas = [
0.14887433898163,
0.43339539412925,
0.67940956829902,
0.86506336668898,
0.97390652851717,
0.0,
];
const weights = [
0.29552422471475,
0.26926671930999,
0.21908636251598,
0.14945134915058,
0.066671344308684,
0.0,
];
/**
* Compute the 10th order Gauss-Legendre Quadrature of the given definite integral.
*
* @param {Number} a The lower bound for the integration.
* @param {Number} b The upper bound for the integration.
* @param {Ellipsoid~RealValuedScalarFunction} func The function to integrate.
* @returns {Number} The value of the integral of the given function over the given domain.
*
* @private
*/
function gaussLegendreQuadrature(a, b, func) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("a", a);
Check.typeOf.number("b", b);
Check.typeOf.func("func", func);
//>>includeEnd('debug');
// The range is half of the normal range since the five weights add to one (ten weights add to two).
// The values of the abscissas are multiplied by two to account for this.
const xMean = 0.5 * (b + a);
const xRange = 0.5 * (b - a);
let sum = 0.0;
for (let i = 0; i < 5; i++) {
const dx = xRange * abscissas[i];
sum += weights[i] * (func(xMean + dx) + func(xMean - dx));
}
// Scale the sum to the range of x.
sum *= xRange;
return sum;
}
/**
* A real valued scalar function.
* @callback Ellipsoid~RealValuedScalarFunction
*
* @param {Number} x The value used to evaluate the function.
* @returns {Number} The value of the function at x.
*
* @private
*/
/**
* Computes an approximation of the surface area of a rectangle on the surface of an ellipsoid using
* Gauss-Legendre 10th order quadrature.
*
* @param {Rectangle} rectangle The rectangle used for computing the surface area.
* @returns {Number} The approximate area of the rectangle on the surface of this ellipsoid.
*/
Ellipsoid.prototype.surfaceArea = function (rectangle) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
const minLongitude = rectangle.west;
let maxLongitude = rectangle.east;
const minLatitude = rectangle.south;
const maxLatitude = rectangle.north;
while (maxLongitude < minLongitude) {
maxLongitude += CesiumMath.TWO_PI;
}
const radiiSquared = this._radiiSquared;
const a2 = radiiSquared.x;
const b2 = radiiSquared.y;
const c2 = radiiSquared.z;
const a2b2 = a2 * b2;
return gaussLegendreQuadrature(minLatitude, maxLatitude, function (lat) {
// phi represents the angle measured from the north pole
// sin(phi) = sin(pi / 2 - lat) = cos(lat), cos(phi) is similar
const sinPhi = Math.cos(lat);
const cosPhi = Math.sin(lat);
return (
Math.cos(lat) *
gaussLegendreQuadrature(minLongitude, maxLongitude, function (lon) {
const cosTheta = Math.cos(lon);
const sinTheta = Math.sin(lon);
return Math.sqrt(
a2b2 * cosPhi * cosPhi +
c2 *
(b2 * cosTheta * cosTheta + a2 * sinTheta * sinTheta) *
sinPhi *
sinPhi
);
})
);
});
};
/**
* A simple map projection where longitude and latitude are linearly mapped to X and Y by multiplying
* them by the {@link Ellipsoid#maximumRadius}. This projection
* is commonly known as geographic, equirectangular, equidistant cylindrical, or plate carrée. It
* is also known as EPSG:4326.
*
* @alias GeographicProjection
* @constructor
*
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid.
*
* @see WebMercatorProjection
*/
function GeographicProjection(ellipsoid) {
this._ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
this._semimajorAxis = this._ellipsoid.maximumRadius;
this._oneOverSemimajorAxis = 1.0 / this._semimajorAxis;
}
Object.defineProperties(GeographicProjection.prototype, {
/**
* Gets the {@link Ellipsoid}.
*
* @memberof GeographicProjection.prototype
*
* @type {Ellipsoid}
* @readonly
*/
ellipsoid: {
get: function () {
return this._ellipsoid;
},
},
});
/**
* Projects a set of {@link Cartographic} coordinates, in radians, to map coordinates, in meters.
* X and Y are the longitude and latitude, respectively, multiplied by the maximum radius of the
* ellipsoid. Z is the unmodified height.
*
* @param {Cartographic} cartographic The coordinates to project.
* @param {Cartesian3} [result] An instance into which to copy the result. If this parameter is
* undefined, a new instance is created and returned.
* @returns {Cartesian3} The projected coordinates. If the result parameter is not undefined, the
* coordinates are copied there and that instance is returned. Otherwise, a new instance is
* created and returned.
*/
GeographicProjection.prototype.project = function (cartographic, result) {
// Actually this is the special case of equidistant cylindrical called the plate carree
const semimajorAxis = this._semimajorAxis;
const x = cartographic.longitude * semimajorAxis;
const y = cartographic.latitude * semimajorAxis;
const z = cartographic.height;
if (!defined(result)) {
return new Cartesian3(x, y, z);
}
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Unprojects a set of projected {@link Cartesian3} coordinates, in meters, to {@link Cartographic}
* coordinates, in radians. Longitude and Latitude are the X and Y coordinates, respectively,
* divided by the maximum radius of the ellipsoid. Height is the unmodified Z coordinate.
*
* @param {Cartesian3} cartesian The Cartesian position to unproject with height (z) in meters.
* @param {Cartographic} [result] An instance into which to copy the result. If this parameter is
* undefined, a new instance is created and returned.
* @returns {Cartographic} The unprojected coordinates. If the result parameter is not undefined, the
* coordinates are copied there and that instance is returned. Otherwise, a new instance is
* created and returned.
*/
GeographicProjection.prototype.unproject = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
if (!defined(cartesian)) {
throw new DeveloperError("cartesian is required");
}
//>>includeEnd('debug');
const oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis;
const longitude = cartesian.x * oneOverEarthSemimajorAxis;
const latitude = cartesian.y * oneOverEarthSemimajorAxis;
const height = cartesian.z;
if (!defined(result)) {
return new Cartographic(longitude, latitude, height);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = height;
return result;
};
/**
* This enumerated type is used in determining where, relative to the frustum, an
* object is located. The object can either be fully contained within the frustum (INSIDE),
* partially inside the frustum and partially outside (INTERSECTING), or somewhere entirely
* outside of the frustum's 6 planes (OUTSIDE).
*
* @enum {Number}
*/
const Intersect = {
/**
* Represents that an object is not contained within the frustum.
*
* @type {Number}
* @constant
*/
OUTSIDE: -1,
/**
* Represents that an object intersects one of the frustum's planes.
*
* @type {Number}
* @constant
*/
INTERSECTING: 0,
/**
* Represents that an object is fully within the frustum.
*
* @type {Number}
* @constant
*/
INSIDE: 1,
};
var Intersect$1 = Object.freeze(Intersect);
/**
* Represents the closed interval [start, stop].
* @alias Interval
* @constructor
*
* @param {Number} [start=0.0] The beginning of the interval.
* @param {Number} [stop=0.0] The end of the interval.
*/
function Interval(start, stop) {
/**
* The beginning of the interval.
* @type {Number}
* @default 0.0
*/
this.start = defaultValue(start, 0.0);
/**
* The end of the interval.
* @type {Number}
* @default 0.0
*/
this.stop = defaultValue(stop, 0.0);
}
/**
* A 3x3 matrix, indexable as a column-major order array.
* Constructor parameters are in row-major order for code readability.
* @alias Matrix3
* @constructor
* @implements {ArrayLike}
*
* @param {Number} [column0Row0=0.0] The value for column 0, row 0.
* @param {Number} [column1Row0=0.0] The value for column 1, row 0.
* @param {Number} [column2Row0=0.0] The value for column 2, row 0.
* @param {Number} [column0Row1=0.0] The value for column 0, row 1.
* @param {Number} [column1Row1=0.0] The value for column 1, row 1.
* @param {Number} [column2Row1=0.0] The value for column 2, row 1.
* @param {Number} [column0Row2=0.0] The value for column 0, row 2.
* @param {Number} [column1Row2=0.0] The value for column 1, row 2.
* @param {Number} [column2Row2=0.0] The value for column 2, row 2.
*
* @see Matrix3.fromArray
* @see Matrix3.fromColumnMajorArray
* @see Matrix3.fromRowMajorArray
* @see Matrix3.fromQuaternion
* @see Matrix3.fromHeadingPitchRoll
* @see Matrix3.fromScale
* @see Matrix3.fromUniformScale
* @see Matrix3.fromCrossProduct
* @see Matrix3.fromRotationX
* @see Matrix3.fromRotationY
* @see Matrix3.fromRotationZ
* @see Matrix2
* @see Matrix4
*/
function Matrix3(
column0Row0,
column1Row0,
column2Row0,
column0Row1,
column1Row1,
column2Row1,
column0Row2,
column1Row2,
column2Row2
) {
this[0] = defaultValue(column0Row0, 0.0);
this[1] = defaultValue(column0Row1, 0.0);
this[2] = defaultValue(column0Row2, 0.0);
this[3] = defaultValue(column1Row0, 0.0);
this[4] = defaultValue(column1Row1, 0.0);
this[5] = defaultValue(column1Row2, 0.0);
this[6] = defaultValue(column2Row0, 0.0);
this[7] = defaultValue(column2Row1, 0.0);
this[8] = defaultValue(column2Row2, 0.0);
}
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Matrix3.packedLength = 9;
/**
* Stores the provided instance into the provided array.
*
* @param {Matrix3} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Matrix3.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
array[startingIndex++] = value[0];
array[startingIndex++] = value[1];
array[startingIndex++] = value[2];
array[startingIndex++] = value[3];
array[startingIndex++] = value[4];
array[startingIndex++] = value[5];
array[startingIndex++] = value[6];
array[startingIndex++] = value[7];
array[startingIndex++] = value[8];
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Matrix3} [result] The object into which to store the result.
* @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided.
*/
Matrix3.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new Matrix3();
}
result[0] = array[startingIndex++];
result[1] = array[startingIndex++];
result[2] = array[startingIndex++];
result[3] = array[startingIndex++];
result[4] = array[startingIndex++];
result[5] = array[startingIndex++];
result[6] = array[startingIndex++];
result[7] = array[startingIndex++];
result[8] = array[startingIndex++];
return result;
};
/**
* Flattens an array of Matrix3s into an array of components. The components
* are stored in column-major order.
*
* @param {Matrix3[]} array The array of matrices to pack.
* @param {Number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 9 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 9) elements.
* @returns {Number[]} The packed array.
*/
Matrix3.packArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
const length = array.length;
const resultLength = length * 9;
if (!defined(result)) {
result = new Array(resultLength);
} else if (!Array.isArray(result) && result.length !== resultLength) {
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError(
"If result is a typed array, it must have exactly array.length * 9 elements"
);
//>>includeEnd('debug');
} else if (result.length !== resultLength) {
result.length = resultLength;
}
for (let i = 0; i < length; ++i) {
Matrix3.pack(array[i], result, i * 9);
}
return result;
};
/**
* Unpacks an array of column-major matrix components into an array of Matrix3s.
*
* @param {Number[]} array The array of components to unpack.
* @param {Matrix3[]} [result] The array onto which to store the result.
* @returns {Matrix3[]} The unpacked array.
*/
Matrix3.unpackArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
Check.typeOf.number.greaterThanOrEquals("array.length", array.length, 9);
if (array.length % 9 !== 0) {
throw new DeveloperError("array length must be a multiple of 9.");
}
//>>includeEnd('debug');
const length = array.length;
if (!defined(result)) {
result = new Array(length / 9);
} else {
result.length = length / 9;
}
for (let i = 0; i < length; i += 9) {
const index = i / 9;
result[index] = Matrix3.unpack(array, i, result[index]);
}
return result;
};
/**
* Duplicates a Matrix3 instance.
*
* @param {Matrix3} matrix The matrix to duplicate.
* @param {Matrix3} [result] The object onto which to store the result.
* @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided. (Returns undefined if matrix is undefined)
*/
Matrix3.clone = function (matrix, result) {
if (!defined(matrix)) {
return undefined;
}
if (!defined(result)) {
return new Matrix3(
matrix[0],
matrix[3],
matrix[6],
matrix[1],
matrix[4],
matrix[7],
matrix[2],
matrix[5],
matrix[8]
);
}
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
return result;
};
/**
* Creates a Matrix3 from 9 consecutive elements in an array.
*
* @param {Number[]} array The array whose 9 consecutive elements correspond to the positions of the matrix. Assumes column-major order.
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to first column first row position in the matrix.
* @param {Matrix3} [result] The object onto which to store the result.
* @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided.
*
* @example
* // Create the Matrix3:
* // [1.0, 2.0, 3.0]
* // [1.0, 2.0, 3.0]
* // [1.0, 2.0, 3.0]
*
* const v = [1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0];
* const m = Cesium.Matrix3.fromArray(v);
*
* // Create same Matrix3 with using an offset into an array
* const v2 = [0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0];
* const m2 = Cesium.Matrix3.fromArray(v2, 2);
*/
Matrix3.fromArray = Matrix3.unpack;
/**
* Creates a Matrix3 instance from a column-major order array.
*
* @param {Number[]} values The column-major order array.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*/
Matrix3.fromColumnMajorArray = function (values, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("values", values);
//>>includeEnd('debug');
return Matrix3.clone(values, result);
};
/**
* Creates a Matrix3 instance from a row-major order array.
* The resulting matrix will be in column-major order.
*
* @param {Number[]} values The row-major order array.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*/
Matrix3.fromRowMajorArray = function (values, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("values", values);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix3(
values[0],
values[1],
values[2],
values[3],
values[4],
values[5],
values[6],
values[7],
values[8]
);
}
result[0] = values[0];
result[1] = values[3];
result[2] = values[6];
result[3] = values[1];
result[4] = values[4];
result[5] = values[7];
result[6] = values[2];
result[7] = values[5];
result[8] = values[8];
return result;
};
/**
* Computes a 3x3 rotation matrix from the provided quaternion.
*
* @param {Quaternion} quaternion the quaternion to use.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The 3x3 rotation matrix from this quaternion.
*/
Matrix3.fromQuaternion = function (quaternion, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("quaternion", quaternion);
//>>includeEnd('debug');
const x2 = quaternion.x * quaternion.x;
const xy = quaternion.x * quaternion.y;
const xz = quaternion.x * quaternion.z;
const xw = quaternion.x * quaternion.w;
const y2 = quaternion.y * quaternion.y;
const yz = quaternion.y * quaternion.z;
const yw = quaternion.y * quaternion.w;
const z2 = quaternion.z * quaternion.z;
const zw = quaternion.z * quaternion.w;
const w2 = quaternion.w * quaternion.w;
const m00 = x2 - y2 - z2 + w2;
const m01 = 2.0 * (xy - zw);
const m02 = 2.0 * (xz + yw);
const m10 = 2.0 * (xy + zw);
const m11 = -x2 + y2 - z2 + w2;
const m12 = 2.0 * (yz - xw);
const m20 = 2.0 * (xz - yw);
const m21 = 2.0 * (yz + xw);
const m22 = -x2 - y2 + z2 + w2;
if (!defined(result)) {
return new Matrix3(m00, m01, m02, m10, m11, m12, m20, m21, m22);
}
result[0] = m00;
result[1] = m10;
result[2] = m20;
result[3] = m01;
result[4] = m11;
result[5] = m21;
result[6] = m02;
result[7] = m12;
result[8] = m22;
return result;
};
/**
* Computes a 3x3 rotation matrix from the provided headingPitchRoll. (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles )
*
* @param {HeadingPitchRoll} headingPitchRoll the headingPitchRoll to use.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The 3x3 rotation matrix from this headingPitchRoll.
*/
Matrix3.fromHeadingPitchRoll = function (headingPitchRoll, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("headingPitchRoll", headingPitchRoll);
//>>includeEnd('debug');
const cosTheta = Math.cos(-headingPitchRoll.pitch);
const cosPsi = Math.cos(-headingPitchRoll.heading);
const cosPhi = Math.cos(headingPitchRoll.roll);
const sinTheta = Math.sin(-headingPitchRoll.pitch);
const sinPsi = Math.sin(-headingPitchRoll.heading);
const sinPhi = Math.sin(headingPitchRoll.roll);
const m00 = cosTheta * cosPsi;
const m01 = -cosPhi * sinPsi + sinPhi * sinTheta * cosPsi;
const m02 = sinPhi * sinPsi + cosPhi * sinTheta * cosPsi;
const m10 = cosTheta * sinPsi;
const m11 = cosPhi * cosPsi + sinPhi * sinTheta * sinPsi;
const m12 = -sinPhi * cosPsi + cosPhi * sinTheta * sinPsi;
const m20 = -sinTheta;
const m21 = sinPhi * cosTheta;
const m22 = cosPhi * cosTheta;
if (!defined(result)) {
return new Matrix3(m00, m01, m02, m10, m11, m12, m20, m21, m22);
}
result[0] = m00;
result[1] = m10;
result[2] = m20;
result[3] = m01;
result[4] = m11;
result[5] = m21;
result[6] = m02;
result[7] = m12;
result[8] = m22;
return result;
};
/**
* Computes a Matrix3 instance representing a non-uniform scale.
*
* @param {Cartesian3} scale The x, y, and z scale factors.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*
* @example
* // Creates
* // [7.0, 0.0, 0.0]
* // [0.0, 8.0, 0.0]
* // [0.0, 0.0, 9.0]
* const m = Cesium.Matrix3.fromScale(new Cesium.Cartesian3(7.0, 8.0, 9.0));
*/
Matrix3.fromScale = function (scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("scale", scale);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix3(scale.x, 0.0, 0.0, 0.0, scale.y, 0.0, 0.0, 0.0, scale.z);
}
result[0] = scale.x;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = scale.y;
result[5] = 0.0;
result[6] = 0.0;
result[7] = 0.0;
result[8] = scale.z;
return result;
};
/**
* Computes a Matrix3 instance representing a uniform scale.
*
* @param {Number} scale The uniform scale factor.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*
* @example
* // Creates
* // [2.0, 0.0, 0.0]
* // [0.0, 2.0, 0.0]
* // [0.0, 0.0, 2.0]
* const m = Cesium.Matrix3.fromUniformScale(2.0);
*/
Matrix3.fromUniformScale = function (scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("scale", scale);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix3(scale, 0.0, 0.0, 0.0, scale, 0.0, 0.0, 0.0, scale);
}
result[0] = scale;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = scale;
result[5] = 0.0;
result[6] = 0.0;
result[7] = 0.0;
result[8] = scale;
return result;
};
/**
* Computes a Matrix3 instance representing the cross product equivalent matrix of a Cartesian3 vector.
*
* @param {Cartesian3} vector the vector on the left hand side of the cross product operation.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*
* @example
* // Creates
* // [0.0, -9.0, 8.0]
* // [9.0, 0.0, -7.0]
* // [-8.0, 7.0, 0.0]
* const m = Cesium.Matrix3.fromCrossProduct(new Cesium.Cartesian3(7.0, 8.0, 9.0));
*/
Matrix3.fromCrossProduct = function (vector, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("vector", vector);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix3(
0.0,
-vector.z,
vector.y,
vector.z,
0.0,
-vector.x,
-vector.y,
vector.x,
0.0
);
}
result[0] = 0.0;
result[1] = vector.z;
result[2] = -vector.y;
result[3] = -vector.z;
result[4] = 0.0;
result[5] = vector.x;
result[6] = vector.y;
result[7] = -vector.x;
result[8] = 0.0;
return result;
};
/**
* Creates a rotation matrix around the x-axis.
*
* @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*
* @example
* // Rotate a point 45 degrees counterclockwise around the x-axis.
* const p = new Cesium.Cartesian3(5, 6, 7);
* const m = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(45.0));
* const rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3());
*/
Matrix3.fromRotationX = function (angle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("angle", angle);
//>>includeEnd('debug');
const cosAngle = Math.cos(angle);
const sinAngle = Math.sin(angle);
if (!defined(result)) {
return new Matrix3(
1.0,
0.0,
0.0,
0.0,
cosAngle,
-sinAngle,
0.0,
sinAngle,
cosAngle
);
}
result[0] = 1.0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = cosAngle;
result[5] = sinAngle;
result[6] = 0.0;
result[7] = -sinAngle;
result[8] = cosAngle;
return result;
};
/**
* Creates a rotation matrix around the y-axis.
*
* @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*
* @example
* // Rotate a point 45 degrees counterclockwise around the y-axis.
* const p = new Cesium.Cartesian3(5, 6, 7);
* const m = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(45.0));
* const rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3());
*/
Matrix3.fromRotationY = function (angle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("angle", angle);
//>>includeEnd('debug');
const cosAngle = Math.cos(angle);
const sinAngle = Math.sin(angle);
if (!defined(result)) {
return new Matrix3(
cosAngle,
0.0,
sinAngle,
0.0,
1.0,
0.0,
-sinAngle,
0.0,
cosAngle
);
}
result[0] = cosAngle;
result[1] = 0.0;
result[2] = -sinAngle;
result[3] = 0.0;
result[4] = 1.0;
result[5] = 0.0;
result[6] = sinAngle;
result[7] = 0.0;
result[8] = cosAngle;
return result;
};
/**
* Creates a rotation matrix around the z-axis.
*
* @param {Number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise.
* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided.
*
* @example
* // Rotate a point 45 degrees counterclockwise around the z-axis.
* const p = new Cesium.Cartesian3(5, 6, 7);
* const m = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(45.0));
* const rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3());
*/
Matrix3.fromRotationZ = function (angle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("angle", angle);
//>>includeEnd('debug');
const cosAngle = Math.cos(angle);
const sinAngle = Math.sin(angle);
if (!defined(result)) {
return new Matrix3(
cosAngle,
-sinAngle,
0.0,
sinAngle,
cosAngle,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = cosAngle;
result[1] = sinAngle;
result[2] = 0.0;
result[3] = -sinAngle;
result[4] = cosAngle;
result[5] = 0.0;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 1.0;
return result;
};
/**
* Creates an Array from the provided Matrix3 instance.
* The array will be in column-major order.
*
* @param {Matrix3} matrix The matrix to use..
* @param {Number[]} [result] The Array onto which to store the result.
* @returns {Number[]} The modified Array parameter or a new Array instance if one was not provided.
*/
Matrix3.toArray = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
//>>includeEnd('debug');
if (!defined(result)) {
return [
matrix[0],
matrix[1],
matrix[2],
matrix[3],
matrix[4],
matrix[5],
matrix[6],
matrix[7],
matrix[8],
];
}
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
return result;
};
/**
* Computes the array index of the element at the provided row and column.
*
* @param {Number} column The zero-based index of the column.
* @param {Number} row The zero-based index of the row.
* @returns {Number} The index of the element at the provided row and column.
*
* @exception {DeveloperError} row must be 0, 1, or 2.
* @exception {DeveloperError} column must be 0, 1, or 2.
*
* @example
* const myMatrix = new Cesium.Matrix3();
* const column1Row0Index = Cesium.Matrix3.getElementIndex(1, 0);
* const column1Row0 = myMatrix[column1Row0Index]
* myMatrix[column1Row0Index] = 10.0;
*/
Matrix3.getElementIndex = function (column, row) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("row", row, 0);
Check.typeOf.number.lessThanOrEquals("row", row, 2);
Check.typeOf.number.greaterThanOrEquals("column", column, 0);
Check.typeOf.number.lessThanOrEquals("column", column, 2);
//>>includeEnd('debug');
return column * 3 + row;
};
/**
* Retrieves a copy of the matrix column at the provided index as a Cartesian3 instance.
*
* @param {Matrix3} matrix The matrix to use.
* @param {Number} index The zero-based index of the column to retrieve.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, or 2.
*/
Matrix3.getColumn = function (matrix, index, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 2);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const startIndex = index * 3;
const x = matrix[startIndex];
const y = matrix[startIndex + 1];
const z = matrix[startIndex + 2];
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian3 instance.
*
* @param {Matrix3} matrix The matrix to use.
* @param {Number} index The zero-based index of the column to set.
* @param {Cartesian3} cartesian The Cartesian whose values will be assigned to the specified column.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, or 2.
*/
Matrix3.setColumn = function (matrix, index, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 2);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result = Matrix3.clone(matrix, result);
const startIndex = index * 3;
result[startIndex] = cartesian.x;
result[startIndex + 1] = cartesian.y;
result[startIndex + 2] = cartesian.z;
return result;
};
/**
* Retrieves a copy of the matrix row at the provided index as a Cartesian3 instance.
*
* @param {Matrix3} matrix The matrix to use.
* @param {Number} index The zero-based index of the row to retrieve.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, or 2.
*/
Matrix3.getRow = function (matrix, index, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 2);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const x = matrix[index];
const y = matrix[index + 3];
const z = matrix[index + 6];
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian3 instance.
*
* @param {Matrix3} matrix The matrix to use.
* @param {Number} index The zero-based index of the row to set.
* @param {Cartesian3} cartesian The Cartesian whose values will be assigned to the specified row.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, or 2.
*/
Matrix3.setRow = function (matrix, index, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 2);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result = Matrix3.clone(matrix, result);
result[index] = cartesian.x;
result[index + 3] = cartesian.y;
result[index + 6] = cartesian.z;
return result;
};
const scaleScratch1$2 = new Cartesian3();
/**
* Computes a new matrix that replaces the scale with the provided scale.
* This assumes the matrix is an affine transformation.
*
* @param {Matrix3} matrix The matrix to use.
* @param {Cartesian3} scale The scale that replaces the scale of the provided matrix.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @see Matrix3.setUniformScale
* @see Matrix3.fromScale
* @see Matrix3.fromUniformScale
* @see Matrix3.multiplyByScale
* @see Matrix3.multiplyByUniformScale
* @see Matrix3.getScale
*/
Matrix3.setScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const existingScale = Matrix3.getScale(matrix, scaleScratch1$2);
const scaleRatioX = scale.x / existingScale.x;
const scaleRatioY = scale.y / existingScale.y;
const scaleRatioZ = scale.z / existingScale.z;
result[0] = matrix[0] * scaleRatioX;
result[1] = matrix[1] * scaleRatioX;
result[2] = matrix[2] * scaleRatioX;
result[3] = matrix[3] * scaleRatioY;
result[4] = matrix[4] * scaleRatioY;
result[5] = matrix[5] * scaleRatioY;
result[6] = matrix[6] * scaleRatioZ;
result[7] = matrix[7] * scaleRatioZ;
result[8] = matrix[8] * scaleRatioZ;
return result;
};
const scaleScratch2$2 = new Cartesian3();
/**
* Computes a new matrix that replaces the scale with the provided uniform scale.
* This assumes the matrix is an affine transformation.
*
* @param {Matrix3} matrix The matrix to use.
* @param {Number} scale The uniform scale that replaces the scale of the provided matrix.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @see Matrix3.setScale
* @see Matrix3.fromScale
* @see Matrix3.fromUniformScale
* @see Matrix3.multiplyByScale
* @see Matrix3.multiplyByUniformScale
* @see Matrix3.getScale
*/
Matrix3.setUniformScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const existingScale = Matrix3.getScale(matrix, scaleScratch2$2);
const scaleRatioX = scale / existingScale.x;
const scaleRatioY = scale / existingScale.y;
const scaleRatioZ = scale / existingScale.z;
result[0] = matrix[0] * scaleRatioX;
result[1] = matrix[1] * scaleRatioX;
result[2] = matrix[2] * scaleRatioX;
result[3] = matrix[3] * scaleRatioY;
result[4] = matrix[4] * scaleRatioY;
result[5] = matrix[5] * scaleRatioY;
result[6] = matrix[6] * scaleRatioZ;
result[7] = matrix[7] * scaleRatioZ;
result[8] = matrix[8] * scaleRatioZ;
return result;
};
const scratchColumn$2 = new Cartesian3();
/**
* Extracts the non-uniform scale assuming the matrix is an affine transformation.
*
* @param {Matrix3} matrix The matrix.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*
* @see Matrix3.multiplyByScale
* @see Matrix3.multiplyByUniformScale
* @see Matrix3.fromScale
* @see Matrix3.fromUniformScale
* @see Matrix3.setScale
* @see Matrix3.setUniformScale
*/
Matrix3.getScale = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Cartesian3.magnitude(
Cartesian3.fromElements(matrix[0], matrix[1], matrix[2], scratchColumn$2)
);
result.y = Cartesian3.magnitude(
Cartesian3.fromElements(matrix[3], matrix[4], matrix[5], scratchColumn$2)
);
result.z = Cartesian3.magnitude(
Cartesian3.fromElements(matrix[6], matrix[7], matrix[8], scratchColumn$2)
);
return result;
};
const scaleScratch3$2 = new Cartesian3();
/**
* Computes the maximum scale assuming the matrix is an affine transformation.
* The maximum scale is the maximum length of the column vectors.
*
* @param {Matrix3} matrix The matrix.
* @returns {Number} The maximum scale.
*/
Matrix3.getMaximumScale = function (matrix) {
Matrix3.getScale(matrix, scaleScratch3$2);
return Cartesian3.maximumComponent(scaleScratch3$2);
};
const scaleScratch4$2 = new Cartesian3();
/**
* Sets the rotation assuming the matrix is an affine transformation.
*
* @param {Matrix3} matrix The matrix.
* @param {Matrix3} rotation The rotation matrix.
* @returns {Matrix3} The modified result parameter.
*
* @see Matrix3.getRotation
*/
Matrix3.setRotation = function (matrix, rotation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const scale = Matrix3.getScale(matrix, scaleScratch4$2);
result[0] = rotation[0] * scale.x;
result[1] = rotation[1] * scale.x;
result[2] = rotation[2] * scale.x;
result[3] = rotation[3] * scale.y;
result[4] = rotation[4] * scale.y;
result[5] = rotation[5] * scale.y;
result[6] = rotation[6] * scale.z;
result[7] = rotation[7] * scale.z;
result[8] = rotation[8] * scale.z;
return result;
};
const scaleScratch5$2 = new Cartesian3();
/**
* Extracts the rotation matrix assuming the matrix is an affine transformation.
*
* @param {Matrix3} matrix The matrix.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @see Matrix3.setRotation
*/
Matrix3.getRotation = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const scale = Matrix3.getScale(matrix, scaleScratch5$2);
result[0] = matrix[0] / scale.x;
result[1] = matrix[1] / scale.x;
result[2] = matrix[2] / scale.x;
result[3] = matrix[3] / scale.y;
result[4] = matrix[4] / scale.y;
result[5] = matrix[5] / scale.y;
result[6] = matrix[6] / scale.z;
result[7] = matrix[7] / scale.z;
result[8] = matrix[8] / scale.z;
return result;
};
/**
* Computes the product of two matrices.
*
* @param {Matrix3} left The first matrix.
* @param {Matrix3} right The second matrix.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.multiply = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const column0Row0 =
left[0] * right[0] + left[3] * right[1] + left[6] * right[2];
const column0Row1 =
left[1] * right[0] + left[4] * right[1] + left[7] * right[2];
const column0Row2 =
left[2] * right[0] + left[5] * right[1] + left[8] * right[2];
const column1Row0 =
left[0] * right[3] + left[3] * right[4] + left[6] * right[5];
const column1Row1 =
left[1] * right[3] + left[4] * right[4] + left[7] * right[5];
const column1Row2 =
left[2] * right[3] + left[5] * right[4] + left[8] * right[5];
const column2Row0 =
left[0] * right[6] + left[3] * right[7] + left[6] * right[8];
const column2Row1 =
left[1] * right[6] + left[4] * right[7] + left[7] * right[8];
const column2Row2 =
left[2] * right[6] + left[5] * right[7] + left[8] * right[8];
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = column1Row0;
result[4] = column1Row1;
result[5] = column1Row2;
result[6] = column2Row0;
result[7] = column2Row1;
result[8] = column2Row2;
return result;
};
/**
* Computes the sum of two matrices.
*
* @param {Matrix3} left The first matrix.
* @param {Matrix3} right The second matrix.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.add = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = left[0] + right[0];
result[1] = left[1] + right[1];
result[2] = left[2] + right[2];
result[3] = left[3] + right[3];
result[4] = left[4] + right[4];
result[5] = left[5] + right[5];
result[6] = left[6] + right[6];
result[7] = left[7] + right[7];
result[8] = left[8] + right[8];
return result;
};
/**
* Computes the difference of two matrices.
*
* @param {Matrix3} left The first matrix.
* @param {Matrix3} right The second matrix.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.subtract = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = left[0] - right[0];
result[1] = left[1] - right[1];
result[2] = left[2] - right[2];
result[3] = left[3] - right[3];
result[4] = left[4] - right[4];
result[5] = left[5] - right[5];
result[6] = left[6] - right[6];
result[7] = left[7] - right[7];
result[8] = left[8] - right[8];
return result;
};
/**
* Computes the product of a matrix and a column vector.
*
* @param {Matrix3} matrix The matrix.
* @param {Cartesian3} cartesian The column.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Matrix3.multiplyByVector = function (matrix, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[3] * vY + matrix[6] * vZ;
const y = matrix[1] * vX + matrix[4] * vY + matrix[7] * vZ;
const z = matrix[2] * vX + matrix[5] * vY + matrix[8] * vZ;
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Computes the product of a matrix and a scalar.
*
* @param {Matrix3} matrix The matrix.
* @param {Number} scalar The number to multiply by.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.multiplyByScalar = function (matrix, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0] * scalar;
result[1] = matrix[1] * scalar;
result[2] = matrix[2] * scalar;
result[3] = matrix[3] * scalar;
result[4] = matrix[4] * scalar;
result[5] = matrix[5] * scalar;
result[6] = matrix[6] * scalar;
result[7] = matrix[7] * scalar;
result[8] = matrix[8] * scalar;
return result;
};
/**
* Computes the product of a matrix times a (non-uniform) scale, as if the scale were a scale matrix.
*
* @param {Matrix3} matrix The matrix on the left-hand side.
* @param {Number} scale The non-uniform scale on the right-hand side.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
*
* @example
* // Instead of Cesium.Matrix3.multiply(m, Cesium.Matrix3.fromScale(scale), m);
* Cesium.Matrix3.multiplyByScale(m, scale, m);
*
* @see Matrix3.multiplyByUniformScale
* @see Matrix3.fromScale
* @see Matrix3.fromUniformScale
* @see Matrix3.setScale
* @see Matrix3.setUniformScale
* @see Matrix3.getScale
*/
Matrix3.multiplyByScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0] * scale.x;
result[1] = matrix[1] * scale.x;
result[2] = matrix[2] * scale.x;
result[3] = matrix[3] * scale.y;
result[4] = matrix[4] * scale.y;
result[5] = matrix[5] * scale.y;
result[6] = matrix[6] * scale.z;
result[7] = matrix[7] * scale.z;
result[8] = matrix[8] * scale.z;
return result;
};
/**
* Computes the product of a matrix times a uniform scale, as if the scale were a scale matrix.
*
* @param {Matrix3} matrix The matrix on the left-hand side.
* @param {Number} scale The uniform scale on the right-hand side.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @example
* // Instead of Cesium.Matrix3.multiply(m, Cesium.Matrix3.fromUniformScale(scale), m);
* Cesium.Matrix3.multiplyByUniformScale(m, scale, m);
*
* @see Matrix3.multiplyByScale
* @see Matrix3.fromScale
* @see Matrix3.fromUniformScale
* @see Matrix3.setScale
* @see Matrix3.setUniformScale
* @see Matrix3.getScale
*/
Matrix3.multiplyByUniformScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0] * scale;
result[1] = matrix[1] * scale;
result[2] = matrix[2] * scale;
result[3] = matrix[3] * scale;
result[4] = matrix[4] * scale;
result[5] = matrix[5] * scale;
result[6] = matrix[6] * scale;
result[7] = matrix[7] * scale;
result[8] = matrix[8] * scale;
return result;
};
/**
* Creates a negated copy of the provided matrix.
*
* @param {Matrix3} matrix The matrix to negate.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.negate = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = -matrix[0];
result[1] = -matrix[1];
result[2] = -matrix[2];
result[3] = -matrix[3];
result[4] = -matrix[4];
result[5] = -matrix[5];
result[6] = -matrix[6];
result[7] = -matrix[7];
result[8] = -matrix[8];
return result;
};
/**
* Computes the transpose of the provided matrix.
*
* @param {Matrix3} matrix The matrix to transpose.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.transpose = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const column0Row0 = matrix[0];
const column0Row1 = matrix[3];
const column0Row2 = matrix[6];
const column1Row0 = matrix[1];
const column1Row1 = matrix[4];
const column1Row2 = matrix[7];
const column2Row0 = matrix[2];
const column2Row1 = matrix[5];
const column2Row2 = matrix[8];
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = column1Row0;
result[4] = column1Row1;
result[5] = column1Row2;
result[6] = column2Row0;
result[7] = column2Row1;
result[8] = column2Row2;
return result;
};
function computeFrobeniusNorm(matrix) {
let norm = 0.0;
for (let i = 0; i < 9; ++i) {
const temp = matrix[i];
norm += temp * temp;
}
return Math.sqrt(norm);
}
const rowVal = [1, 0, 0];
const colVal = [2, 2, 1];
function offDiagonalFrobeniusNorm(matrix) {
// Computes the "off-diagonal" Frobenius norm.
// Assumes matrix is symmetric.
let norm = 0.0;
for (let i = 0; i < 3; ++i) {
const temp = matrix[Matrix3.getElementIndex(colVal[i], rowVal[i])];
norm += 2.0 * temp * temp;
}
return Math.sqrt(norm);
}
function shurDecomposition(matrix, result) {
// This routine was created based upon Matrix Computations, 3rd ed., by Golub and Van Loan,
// section 8.4.2 The 2by2 Symmetric Schur Decomposition.
//
// The routine takes a matrix, which is assumed to be symmetric, and
// finds the largest off-diagonal term, and then creates
// a matrix (result) which can be used to help reduce it
const tolerance = CesiumMath.EPSILON15;
let maxDiagonal = 0.0;
let rotAxis = 1;
// find pivot (rotAxis) based on max diagonal of matrix
for (let i = 0; i < 3; ++i) {
const temp = Math.abs(
matrix[Matrix3.getElementIndex(colVal[i], rowVal[i])]
);
if (temp > maxDiagonal) {
rotAxis = i;
maxDiagonal = temp;
}
}
let c = 1.0;
let s = 0.0;
const p = rowVal[rotAxis];
const q = colVal[rotAxis];
if (Math.abs(matrix[Matrix3.getElementIndex(q, p)]) > tolerance) {
const qq = matrix[Matrix3.getElementIndex(q, q)];
const pp = matrix[Matrix3.getElementIndex(p, p)];
const qp = matrix[Matrix3.getElementIndex(q, p)];
const tau = (qq - pp) / 2.0 / qp;
let t;
if (tau < 0.0) {
t = -1.0 / (-tau + Math.sqrt(1.0 + tau * tau));
} else {
t = 1.0 / (tau + Math.sqrt(1.0 + tau * tau));
}
c = 1.0 / Math.sqrt(1.0 + t * t);
s = t * c;
}
result = Matrix3.clone(Matrix3.IDENTITY, result);
result[Matrix3.getElementIndex(p, p)] = result[
Matrix3.getElementIndex(q, q)
] = c;
result[Matrix3.getElementIndex(q, p)] = s;
result[Matrix3.getElementIndex(p, q)] = -s;
return result;
}
const jMatrix = new Matrix3();
const jMatrixTranspose = new Matrix3();
/**
* Computes the eigenvectors and eigenvalues of a symmetric matrix.
*
* Returns a diagonal matrix and unitary matrix such that:
* matrix = unitary matrix * diagonal matrix * transpose(unitary matrix)
*
*
* The values along the diagonal of the diagonal matrix are the eigenvalues. The columns
* of the unitary matrix are the corresponding eigenvectors.
*
*
* @param {Matrix3} matrix The matrix to decompose into diagonal and unitary matrix. Expected to be symmetric.
* @param {Object} [result] An object with unitary and diagonal properties which are matrices onto which to store the result.
* @returns {Object} An object with unitary and diagonal properties which are the unitary and diagonal matrices, respectively.
*
* @example
* const a = //... symetric matrix
* const result = {
* unitary : new Cesium.Matrix3(),
* diagonal : new Cesium.Matrix3()
* };
* Cesium.Matrix3.computeEigenDecomposition(a, result);
*
* const unitaryTranspose = Cesium.Matrix3.transpose(result.unitary, new Cesium.Matrix3());
* const b = Cesium.Matrix3.multiply(result.unitary, result.diagonal, new Cesium.Matrix3());
* Cesium.Matrix3.multiply(b, unitaryTranspose, b); // b is now equal to a
*
* const lambda = Cesium.Matrix3.getColumn(result.diagonal, 0, new Cesium.Cartesian3()).x; // first eigenvalue
* const v = Cesium.Matrix3.getColumn(result.unitary, 0, new Cesium.Cartesian3()); // first eigenvector
* const c = Cesium.Cartesian3.multiplyByScalar(v, lambda, new Cesium.Cartesian3()); // equal to Cesium.Matrix3.multiplyByVector(a, v)
*/
Matrix3.computeEigenDecomposition = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
//>>includeEnd('debug');
// This routine was created based upon Matrix Computations, 3rd ed., by Golub and Van Loan,
// section 8.4.3 The Classical Jacobi Algorithm
const tolerance = CesiumMath.EPSILON20;
const maxSweeps = 10;
let count = 0;
let sweep = 0;
if (!defined(result)) {
result = {};
}
const unitaryMatrix = (result.unitary = Matrix3.clone(
Matrix3.IDENTITY,
result.unitary
));
const diagMatrix = (result.diagonal = Matrix3.clone(matrix, result.diagonal));
const epsilon = tolerance * computeFrobeniusNorm(diagMatrix);
while (sweep < maxSweeps && offDiagonalFrobeniusNorm(diagMatrix) > epsilon) {
shurDecomposition(diagMatrix, jMatrix);
Matrix3.transpose(jMatrix, jMatrixTranspose);
Matrix3.multiply(diagMatrix, jMatrix, diagMatrix);
Matrix3.multiply(jMatrixTranspose, diagMatrix, diagMatrix);
Matrix3.multiply(unitaryMatrix, jMatrix, unitaryMatrix);
if (++count > 2) {
++sweep;
count = 0;
}
}
return result;
};
/**
* Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements.
*
* @param {Matrix3} matrix The matrix with signed elements.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.abs = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = Math.abs(matrix[0]);
result[1] = Math.abs(matrix[1]);
result[2] = Math.abs(matrix[2]);
result[3] = Math.abs(matrix[3]);
result[4] = Math.abs(matrix[4]);
result[5] = Math.abs(matrix[5]);
result[6] = Math.abs(matrix[6]);
result[7] = Math.abs(matrix[7]);
result[8] = Math.abs(matrix[8]);
return result;
};
/**
* Computes the determinant of the provided matrix.
*
* @param {Matrix3} matrix The matrix to use.
* @returns {Number} The value of the determinant of the matrix.
*/
Matrix3.determinant = function (matrix) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
//>>includeEnd('debug');
const m11 = matrix[0];
const m21 = matrix[3];
const m31 = matrix[6];
const m12 = matrix[1];
const m22 = matrix[4];
const m32 = matrix[7];
const m13 = matrix[2];
const m23 = matrix[5];
const m33 = matrix[8];
return (
m11 * (m22 * m33 - m23 * m32) +
m12 * (m23 * m31 - m21 * m33) +
m13 * (m21 * m32 - m22 * m31)
);
};
/**
* Computes the inverse of the provided matrix.
*
* @param {Matrix3} matrix The matrix to invert.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @exception {DeveloperError} matrix is not invertible.
*/
Matrix3.inverse = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const m11 = matrix[0];
const m21 = matrix[1];
const m31 = matrix[2];
const m12 = matrix[3];
const m22 = matrix[4];
const m32 = matrix[5];
const m13 = matrix[6];
const m23 = matrix[7];
const m33 = matrix[8];
const determinant = Matrix3.determinant(matrix);
//>>includeStart('debug', pragmas.debug);
if (Math.abs(determinant) <= CesiumMath.EPSILON15) {
throw new DeveloperError("matrix is not invertible");
}
//>>includeEnd('debug');
result[0] = m22 * m33 - m23 * m32;
result[1] = m23 * m31 - m21 * m33;
result[2] = m21 * m32 - m22 * m31;
result[3] = m13 * m32 - m12 * m33;
result[4] = m11 * m33 - m13 * m31;
result[5] = m12 * m31 - m11 * m32;
result[6] = m12 * m23 - m13 * m22;
result[7] = m13 * m21 - m11 * m23;
result[8] = m11 * m22 - m12 * m21;
const scale = 1.0 / determinant;
return Matrix3.multiplyByScalar(result, scale, result);
};
const scratchTransposeMatrix$1 = new Matrix3();
/**
* Computes the inverse transpose of a matrix.
*
* @param {Matrix3} matrix The matrix to transpose and invert.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.inverseTranspose = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
return Matrix3.inverse(
Matrix3.transpose(matrix, scratchTransposeMatrix$1),
result
);
};
/**
* Compares the provided matrices componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Matrix3} [left] The first matrix.
* @param {Matrix3} [right] The second matrix.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Matrix3.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left[0] === right[0] &&
left[1] === right[1] &&
left[2] === right[2] &&
left[3] === right[3] &&
left[4] === right[4] &&
left[5] === right[5] &&
left[6] === right[6] &&
left[7] === right[7] &&
left[8] === right[8])
);
};
/**
* Compares the provided matrices componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Matrix3} [left] The first matrix.
* @param {Matrix3} [right] The second matrix.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Matrix3.equalsEpsilon = function (left, right, epsilon) {
epsilon = defaultValue(epsilon, 0);
return (
left === right ||
(defined(left) &&
defined(right) &&
Math.abs(left[0] - right[0]) <= epsilon &&
Math.abs(left[1] - right[1]) <= epsilon &&
Math.abs(left[2] - right[2]) <= epsilon &&
Math.abs(left[3] - right[3]) <= epsilon &&
Math.abs(left[4] - right[4]) <= epsilon &&
Math.abs(left[5] - right[5]) <= epsilon &&
Math.abs(left[6] - right[6]) <= epsilon &&
Math.abs(left[7] - right[7]) <= epsilon &&
Math.abs(left[8] - right[8]) <= epsilon)
);
};
/**
* An immutable Matrix3 instance initialized to the identity matrix.
*
* @type {Matrix3}
* @constant
*/
Matrix3.IDENTITY = Object.freeze(
new Matrix3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
);
/**
* An immutable Matrix3 instance initialized to the zero matrix.
*
* @type {Matrix3}
* @constant
*/
Matrix3.ZERO = Object.freeze(
new Matrix3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
);
/**
* The index into Matrix3 for column 0, row 0.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN0ROW0 = 0;
/**
* The index into Matrix3 for column 0, row 1.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN0ROW1 = 1;
/**
* The index into Matrix3 for column 0, row 2.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN0ROW2 = 2;
/**
* The index into Matrix3 for column 1, row 0.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN1ROW0 = 3;
/**
* The index into Matrix3 for column 1, row 1.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN1ROW1 = 4;
/**
* The index into Matrix3 for column 1, row 2.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN1ROW2 = 5;
/**
* The index into Matrix3 for column 2, row 0.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN2ROW0 = 6;
/**
* The index into Matrix3 for column 2, row 1.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN2ROW1 = 7;
/**
* The index into Matrix3 for column 2, row 2.
*
* @type {Number}
* @constant
*/
Matrix3.COLUMN2ROW2 = 8;
Object.defineProperties(Matrix3.prototype, {
/**
* Gets the number of items in the collection.
* @memberof Matrix3.prototype
*
* @type {Number}
*/
length: {
get: function () {
return Matrix3.packedLength;
},
},
});
/**
* Duplicates the provided Matrix3 instance.
*
* @param {Matrix3} [result] The object onto which to store the result.
* @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided.
*/
Matrix3.prototype.clone = function (result) {
return Matrix3.clone(this, result);
};
/**
* Compares this matrix to the provided matrix componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Matrix3} [right] The right hand side matrix.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
Matrix3.prototype.equals = function (right) {
return Matrix3.equals(this, right);
};
/**
* @private
*/
Matrix3.equalsArray = function (matrix, array, offset) {
return (
matrix[0] === array[offset] &&
matrix[1] === array[offset + 1] &&
matrix[2] === array[offset + 2] &&
matrix[3] === array[offset + 3] &&
matrix[4] === array[offset + 4] &&
matrix[5] === array[offset + 5] &&
matrix[6] === array[offset + 6] &&
matrix[7] === array[offset + 7] &&
matrix[8] === array[offset + 8]
);
};
/**
* Compares this matrix to the provided matrix componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Matrix3} [right] The right hand side matrix.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if they are within the provided epsilon, false
otherwise.
*/
Matrix3.prototype.equalsEpsilon = function (right, epsilon) {
return Matrix3.equalsEpsilon(this, right, epsilon);
};
/**
* Creates a string representing this Matrix with each row being
* on a separate line and in the format '(column0, column1, column2)'.
*
* @returns {String} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1, column2)'.
*/
Matrix3.prototype.toString = function () {
return (
`(${this[0]}, ${this[3]}, ${this[6]})\n` +
`(${this[1]}, ${this[4]}, ${this[7]})\n` +
`(${this[2]}, ${this[5]}, ${this[8]})`
);
};
/**
* A 4D Cartesian point.
* @alias Cartesian4
* @constructor
*
* @param {Number} [x=0.0] The X component.
* @param {Number} [y=0.0] The Y component.
* @param {Number} [z=0.0] The Z component.
* @param {Number} [w=0.0] The W component.
*
* @see Cartesian2
* @see Cartesian3
* @see Packable
*/
function Cartesian4(x, y, z, w) {
/**
* The X component.
* @type {Number}
* @default 0.0
*/
this.x = defaultValue(x, 0.0);
/**
* The Y component.
* @type {Number}
* @default 0.0
*/
this.y = defaultValue(y, 0.0);
/**
* The Z component.
* @type {Number}
* @default 0.0
*/
this.z = defaultValue(z, 0.0);
/**
* The W component.
* @type {Number}
* @default 0.0
*/
this.w = defaultValue(w, 0.0);
}
/**
* Creates a Cartesian4 instance from x, y, z and w coordinates.
*
* @param {Number} x The x coordinate.
* @param {Number} y The y coordinate.
* @param {Number} z The z coordinate.
* @param {Number} w The w coordinate.
* @param {Cartesian4} [result] The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
*/
Cartesian4.fromElements = function (x, y, z, w, result) {
if (!defined(result)) {
return new Cartesian4(x, y, z, w);
}
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
};
/**
* Creates a Cartesian4 instance from a {@link Color}. red
, green
, blue
,
* and alpha
map to x
, y
, z
, and w
, respectively.
*
* @param {Color} color The source color.
* @param {Cartesian4} [result] The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
*/
Cartesian4.fromColor = function (color, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("color", color);
//>>includeEnd('debug');
if (!defined(result)) {
return new Cartesian4(color.red, color.green, color.blue, color.alpha);
}
result.x = color.red;
result.y = color.green;
result.z = color.blue;
result.w = color.alpha;
return result;
};
/**
* Duplicates a Cartesian4 instance.
*
* @param {Cartesian4} cartesian The Cartesian to duplicate.
* @param {Cartesian4} [result] The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. (Returns undefined if cartesian is undefined)
*/
Cartesian4.clone = function (cartesian, result) {
if (!defined(cartesian)) {
return undefined;
}
if (!defined(result)) {
return new Cartesian4(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
}
result.x = cartesian.x;
result.y = cartesian.y;
result.z = cartesian.z;
result.w = cartesian.w;
return result;
};
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Cartesian4.packedLength = 4;
/**
* Stores the provided instance into the provided array.
*
* @param {Cartesian4} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Cartesian4.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
array[startingIndex++] = value.x;
array[startingIndex++] = value.y;
array[startingIndex++] = value.z;
array[startingIndex] = value.w;
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Cartesian4} [result] The object into which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
*/
Cartesian4.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new Cartesian4();
}
result.x = array[startingIndex++];
result.y = array[startingIndex++];
result.z = array[startingIndex++];
result.w = array[startingIndex];
return result;
};
/**
* Flattens an array of Cartesian4s into an array of components.
*
* @param {Cartesian4[]} array The array of cartesians to pack.
* @param {Number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 4 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 4) elements.
* @returns {Number[]} The packed array.
*/
Cartesian4.packArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
const length = array.length;
const resultLength = length * 4;
if (!defined(result)) {
result = new Array(resultLength);
} else if (!Array.isArray(result) && result.length !== resultLength) {
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError(
"If result is a typed array, it must have exactly array.length * 4 elements"
);
//>>includeEnd('debug');
} else if (result.length !== resultLength) {
result.length = resultLength;
}
for (let i = 0; i < length; ++i) {
Cartesian4.pack(array[i], result, i * 4);
}
return result;
};
/**
* Unpacks an array of cartesian components into an array of Cartesian4s.
*
* @param {Number[]} array The array of components to unpack.
* @param {Cartesian4[]} [result] The array onto which to store the result.
* @returns {Cartesian4[]} The unpacked array.
*/
Cartesian4.unpackArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
Check.typeOf.number.greaterThanOrEquals("array.length", array.length, 4);
if (array.length % 4 !== 0) {
throw new DeveloperError("array length must be a multiple of 4.");
}
//>>includeEnd('debug');
const length = array.length;
if (!defined(result)) {
result = new Array(length / 4);
} else {
result.length = length / 4;
}
for (let i = 0; i < length; i += 4) {
const index = i / 4;
result[index] = Cartesian4.unpack(array, i, result[index]);
}
return result;
};
/**
* Creates a Cartesian4 from four consecutive elements in an array.
* @function
*
* @param {Number[]} array The array whose four consecutive elements correspond to the x, y, z, and w components, respectively.
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
* @param {Cartesian4} [result] The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
*
* @example
* // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0)
* const v = [1.0, 2.0, 3.0, 4.0];
* const p = Cesium.Cartesian4.fromArray(v);
*
* // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0) using an offset into an array
* const v2 = [0.0, 0.0, 1.0, 2.0, 3.0, 4.0];
* const p2 = Cesium.Cartesian4.fromArray(v2, 2);
*/
Cartesian4.fromArray = Cartesian4.unpack;
/**
* Computes the value of the maximum component for the supplied Cartesian.
*
* @param {Cartesian4} cartesian The cartesian to use.
* @returns {Number} The value of the maximum component.
*/
Cartesian4.maximumComponent = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return Math.max(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
};
/**
* Computes the value of the minimum component for the supplied Cartesian.
*
* @param {Cartesian4} cartesian The cartesian to use.
* @returns {Number} The value of the minimum component.
*/
Cartesian4.minimumComponent = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return Math.min(cartesian.x, cartesian.y, cartesian.z, cartesian.w);
};
/**
* Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
*
* @param {Cartesian4} first A cartesian to compare.
* @param {Cartesian4} second A cartesian to compare.
* @param {Cartesian4} result The object into which to store the result.
* @returns {Cartesian4} A cartesian with the minimum components.
*/
Cartesian4.minimumByComponent = function (first, second, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("first", first);
Check.typeOf.object("second", second);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.min(first.x, second.x);
result.y = Math.min(first.y, second.y);
result.z = Math.min(first.z, second.z);
result.w = Math.min(first.w, second.w);
return result;
};
/**
* Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
*
* @param {Cartesian4} first A cartesian to compare.
* @param {Cartesian4} second A cartesian to compare.
* @param {Cartesian4} result The object into which to store the result.
* @returns {Cartesian4} A cartesian with the maximum components.
*/
Cartesian4.maximumByComponent = function (first, second, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("first", first);
Check.typeOf.object("second", second);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.max(first.x, second.x);
result.y = Math.max(first.y, second.y);
result.z = Math.max(first.z, second.z);
result.w = Math.max(first.w, second.w);
return result;
};
/**
* Computes the provided Cartesian's squared magnitude.
*
* @param {Cartesian4} cartesian The Cartesian instance whose squared magnitude is to be computed.
* @returns {Number} The squared magnitude.
*/
Cartesian4.magnitudeSquared = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return (
cartesian.x * cartesian.x +
cartesian.y * cartesian.y +
cartesian.z * cartesian.z +
cartesian.w * cartesian.w
);
};
/**
* Computes the Cartesian's magnitude (length).
*
* @param {Cartesian4} cartesian The Cartesian instance whose magnitude is to be computed.
* @returns {Number} The magnitude.
*/
Cartesian4.magnitude = function (cartesian) {
return Math.sqrt(Cartesian4.magnitudeSquared(cartesian));
};
const distanceScratch$2 = new Cartesian4();
/**
* Computes the 4-space distance between two points.
*
* @param {Cartesian4} left The first point to compute the distance from.
* @param {Cartesian4} right The second point to compute the distance to.
* @returns {Number} The distance between two points.
*
* @example
* // Returns 1.0
* const d = Cesium.Cartesian4.distance(
* new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0),
* new Cesium.Cartesian4(2.0, 0.0, 0.0, 0.0));
*/
Cartesian4.distance = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian4.subtract(left, right, distanceScratch$2);
return Cartesian4.magnitude(distanceScratch$2);
};
/**
* Computes the squared distance between two points. Comparing squared distances
* using this function is more efficient than comparing distances using {@link Cartesian4#distance}.
*
* @param {Cartesian4} left The first point to compute the distance from.
* @param {Cartesian4} right The second point to compute the distance to.
* @returns {Number} The distance between two points.
*
* @example
* // Returns 4.0, not 2.0
* const d = Cesium.Cartesian4.distance(
* new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0),
* new Cesium.Cartesian4(3.0, 0.0, 0.0, 0.0));
*/
Cartesian4.distanceSquared = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian4.subtract(left, right, distanceScratch$2);
return Cartesian4.magnitudeSquared(distanceScratch$2);
};
/**
* Computes the normalized form of the supplied Cartesian.
*
* @param {Cartesian4} cartesian The Cartesian to be normalized.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.normalize = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const magnitude = Cartesian4.magnitude(cartesian);
result.x = cartesian.x / magnitude;
result.y = cartesian.y / magnitude;
result.z = cartesian.z / magnitude;
result.w = cartesian.w / magnitude;
//>>includeStart('debug', pragmas.debug);
if (
isNaN(result.x) ||
isNaN(result.y) ||
isNaN(result.z) ||
isNaN(result.w)
) {
throw new DeveloperError("normalized result is not a number");
}
//>>includeEnd('debug');
return result;
};
/**
* Computes the dot (scalar) product of two Cartesians.
*
* @param {Cartesian4} left The first Cartesian.
* @param {Cartesian4} right The second Cartesian.
* @returns {Number} The dot product.
*/
Cartesian4.dot = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
return (
left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w
);
};
/**
* Computes the componentwise product of two Cartesians.
*
* @param {Cartesian4} left The first Cartesian.
* @param {Cartesian4} right The second Cartesian.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.multiplyComponents = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x * right.x;
result.y = left.y * right.y;
result.z = left.z * right.z;
result.w = left.w * right.w;
return result;
};
/**
* Computes the componentwise quotient of two Cartesians.
*
* @param {Cartesian4} left The first Cartesian.
* @param {Cartesian4} right The second Cartesian.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.divideComponents = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x / right.x;
result.y = left.y / right.y;
result.z = left.z / right.z;
result.w = left.w / right.w;
return result;
};
/**
* Computes the componentwise sum of two Cartesians.
*
* @param {Cartesian4} left The first Cartesian.
* @param {Cartesian4} right The second Cartesian.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.add = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x + right.x;
result.y = left.y + right.y;
result.z = left.z + right.z;
result.w = left.w + right.w;
return result;
};
/**
* Computes the componentwise difference of two Cartesians.
*
* @param {Cartesian4} left The first Cartesian.
* @param {Cartesian4} right The second Cartesian.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.subtract = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x - right.x;
result.y = left.y - right.y;
result.z = left.z - right.z;
result.w = left.w - right.w;
return result;
};
/**
* Multiplies the provided Cartesian componentwise by the provided scalar.
*
* @param {Cartesian4} cartesian The Cartesian to be scaled.
* @param {Number} scalar The scalar to multiply with.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.multiplyByScalar = function (cartesian, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = cartesian.x * scalar;
result.y = cartesian.y * scalar;
result.z = cartesian.z * scalar;
result.w = cartesian.w * scalar;
return result;
};
/**
* Divides the provided Cartesian componentwise by the provided scalar.
*
* @param {Cartesian4} cartesian The Cartesian to be divided.
* @param {Number} scalar The scalar to divide by.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.divideByScalar = function (cartesian, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = cartesian.x / scalar;
result.y = cartesian.y / scalar;
result.z = cartesian.z / scalar;
result.w = cartesian.w / scalar;
return result;
};
/**
* Negates the provided Cartesian.
*
* @param {Cartesian4} cartesian The Cartesian to be negated.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.negate = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = -cartesian.x;
result.y = -cartesian.y;
result.z = -cartesian.z;
result.w = -cartesian.w;
return result;
};
/**
* Computes the absolute value of the provided Cartesian.
*
* @param {Cartesian4} cartesian The Cartesian whose absolute value is to be computed.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.abs = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.abs(cartesian.x);
result.y = Math.abs(cartesian.y);
result.z = Math.abs(cartesian.z);
result.w = Math.abs(cartesian.w);
return result;
};
const lerpScratch$2 = new Cartesian4();
/**
* Computes the linear interpolation or extrapolation at t using the provided cartesians.
*
* @param {Cartesian4} start The value corresponding to t at 0.0.
* @param {Cartesian4}end The value corresponding to t at 1.0.
* @param {Number} t The point along t at which to interpolate.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Cartesian4.lerp = function (start, end, t, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("start", start);
Check.typeOf.object("end", end);
Check.typeOf.number("t", t);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
Cartesian4.multiplyByScalar(end, t, lerpScratch$2);
result = Cartesian4.multiplyByScalar(start, 1.0 - t, result);
return Cartesian4.add(lerpScratch$2, result, result);
};
const mostOrthogonalAxisScratch$1 = new Cartesian4();
/**
* Returns the axis that is most orthogonal to the provided Cartesian.
*
* @param {Cartesian4} cartesian The Cartesian on which to find the most orthogonal axis.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The most orthogonal axis.
*/
Cartesian4.mostOrthogonalAxis = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const f = Cartesian4.normalize(cartesian, mostOrthogonalAxisScratch$1);
Cartesian4.abs(f, f);
if (f.x <= f.y) {
if (f.x <= f.z) {
if (f.x <= f.w) {
result = Cartesian4.clone(Cartesian4.UNIT_X, result);
} else {
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
}
} else if (f.z <= f.w) {
result = Cartesian4.clone(Cartesian4.UNIT_Z, result);
} else {
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
}
} else if (f.y <= f.z) {
if (f.y <= f.w) {
result = Cartesian4.clone(Cartesian4.UNIT_Y, result);
} else {
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
}
} else if (f.z <= f.w) {
result = Cartesian4.clone(Cartesian4.UNIT_Z, result);
} else {
result = Cartesian4.clone(Cartesian4.UNIT_W, result);
}
return result;
};
/**
* Compares the provided Cartesians componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartesian4} [left] The first Cartesian.
* @param {Cartesian4} [right] The second Cartesian.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartesian4.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left.x === right.x &&
left.y === right.y &&
left.z === right.z &&
left.w === right.w)
);
};
/**
* @private
*/
Cartesian4.equalsArray = function (cartesian, array, offset) {
return (
cartesian.x === array[offset] &&
cartesian.y === array[offset + 1] &&
cartesian.z === array[offset + 2] &&
cartesian.w === array[offset + 3]
);
};
/**
* Compares the provided Cartesians componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Cartesian4} [left] The first Cartesian.
* @param {Cartesian4} [right] The second Cartesian.
* @param {Number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartesian4.equalsEpsilon = function (
left,
right,
relativeEpsilon,
absoluteEpsilon
) {
return (
left === right ||
(defined(left) &&
defined(right) &&
CesiumMath.equalsEpsilon(
left.x,
right.x,
relativeEpsilon,
absoluteEpsilon
) &&
CesiumMath.equalsEpsilon(
left.y,
right.y,
relativeEpsilon,
absoluteEpsilon
) &&
CesiumMath.equalsEpsilon(
left.z,
right.z,
relativeEpsilon,
absoluteEpsilon
) &&
CesiumMath.equalsEpsilon(
left.w,
right.w,
relativeEpsilon,
absoluteEpsilon
))
);
};
/**
* An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 0.0).
*
* @type {Cartesian4}
* @constant
*/
Cartesian4.ZERO = Object.freeze(new Cartesian4(0.0, 0.0, 0.0, 0.0));
/**
* An immutable Cartesian4 instance initialized to (1.0, 1.0, 1.0, 1.0).
*
* @type {Cartesian4}
* @constant
*/
Cartesian4.ONE = Object.freeze(new Cartesian4(1.0, 1.0, 1.0, 1.0));
/**
* An immutable Cartesian4 instance initialized to (1.0, 0.0, 0.0, 0.0).
*
* @type {Cartesian4}
* @constant
*/
Cartesian4.UNIT_X = Object.freeze(new Cartesian4(1.0, 0.0, 0.0, 0.0));
/**
* An immutable Cartesian4 instance initialized to (0.0, 1.0, 0.0, 0.0).
*
* @type {Cartesian4}
* @constant
*/
Cartesian4.UNIT_Y = Object.freeze(new Cartesian4(0.0, 1.0, 0.0, 0.0));
/**
* An immutable Cartesian4 instance initialized to (0.0, 0.0, 1.0, 0.0).
*
* @type {Cartesian4}
* @constant
*/
Cartesian4.UNIT_Z = Object.freeze(new Cartesian4(0.0, 0.0, 1.0, 0.0));
/**
* An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 1.0).
*
* @type {Cartesian4}
* @constant
*/
Cartesian4.UNIT_W = Object.freeze(new Cartesian4(0.0, 0.0, 0.0, 1.0));
/**
* Duplicates this Cartesian4 instance.
*
* @param {Cartesian4} [result] The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
*/
Cartesian4.prototype.clone = function (result) {
return Cartesian4.clone(this, result);
};
/**
* Compares this Cartesian against the provided Cartesian componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartesian4} [right] The right hand side Cartesian.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
Cartesian4.prototype.equals = function (right) {
return Cartesian4.equals(this, right);
};
/**
* Compares this Cartesian against the provided Cartesian componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Cartesian4} [right] The right hand side Cartesian.
* @param {Number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if they are within the provided epsilon, false
otherwise.
*/
Cartesian4.prototype.equalsEpsilon = function (
right,
relativeEpsilon,
absoluteEpsilon
) {
return Cartesian4.equalsEpsilon(
this,
right,
relativeEpsilon,
absoluteEpsilon
);
};
/**
* Creates a string representing this Cartesian in the format '(x, y, z, w)'.
*
* @returns {String} A string representing the provided Cartesian in the format '(x, y, z, w)'.
*/
Cartesian4.prototype.toString = function () {
return `(${this.x}, ${this.y}, ${this.z}, ${this.w})`;
};
// scratchU8Array and scratchF32Array are views into the same buffer
const scratchF32Array = new Float32Array(1);
const scratchU8Array = new Uint8Array(scratchF32Array.buffer);
const testU32 = new Uint32Array([0x11223344]);
const testU8 = new Uint8Array(testU32.buffer);
const littleEndian = testU8[0] === 0x44;
/**
* Packs an arbitrary floating point value to 4 values representable using uint8.
*
* @param {Number} value A floating point number.
* @param {Cartesian4} [result] The Cartesian4 that will contain the packed float.
* @returns {Cartesian4} A Cartesian4 representing the float packed to values in x, y, z, and w.
*/
Cartesian4.packFloat = function (value, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("value", value);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Cartesian4();
}
// scratchU8Array and scratchF32Array are views into the same buffer
scratchF32Array[0] = value;
if (littleEndian) {
result.x = scratchU8Array[0];
result.y = scratchU8Array[1];
result.z = scratchU8Array[2];
result.w = scratchU8Array[3];
} else {
// convert from big-endian to little-endian
result.x = scratchU8Array[3];
result.y = scratchU8Array[2];
result.z = scratchU8Array[1];
result.w = scratchU8Array[0];
}
return result;
};
/**
* Unpacks a float packed using Cartesian4.packFloat.
*
* @param {Cartesian4} packedFloat A Cartesian4 containing a float packed to 4 values representable using uint8.
* @returns {Number} The unpacked float.
* @private
*/
Cartesian4.unpackFloat = function (packedFloat) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("packedFloat", packedFloat);
//>>includeEnd('debug');
// scratchU8Array and scratchF32Array are views into the same buffer
if (littleEndian) {
scratchU8Array[0] = packedFloat.x;
scratchU8Array[1] = packedFloat.y;
scratchU8Array[2] = packedFloat.z;
scratchU8Array[3] = packedFloat.w;
} else {
// convert from little-endian to big-endian
scratchU8Array[0] = packedFloat.w;
scratchU8Array[1] = packedFloat.z;
scratchU8Array[2] = packedFloat.y;
scratchU8Array[3] = packedFloat.x;
}
return scratchF32Array[0];
};
/**
* Constructs an exception object that is thrown due to an error that can occur at runtime, e.g.,
* out of memory, could not compile shader, etc. If a function may throw this
* exception, the calling code should be prepared to catch it.
*
* On the other hand, a {@link DeveloperError} indicates an exception due
* to a developer error, e.g., invalid argument, that usually indicates a bug in the
* calling code.
*
* @alias RuntimeError
* @constructor
* @extends Error
*
* @param {String} [message] The error message for this exception.
*
* @see DeveloperError
*/
function RuntimeError(message) {
/**
* 'RuntimeError' indicating that this exception was thrown due to a runtime error.
* @type {String}
* @readonly
*/
this.name = "RuntimeError";
/**
* The explanation for why this exception was thrown.
* @type {String}
* @readonly
*/
this.message = message;
//Browsers such as IE don't have a stack property until you actually throw the error.
let stack;
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
/**
* The stack trace of this exception, if available.
* @type {String}
* @readonly
*/
this.stack = stack;
}
if (defined(Object.create)) {
RuntimeError.prototype = Object.create(Error.prototype);
RuntimeError.prototype.constructor = RuntimeError;
}
RuntimeError.prototype.toString = function () {
let str = `${this.name}: ${this.message}`;
if (defined(this.stack)) {
str += `\n${this.stack.toString()}`;
}
return str;
};
/**
* A 4x4 matrix, indexable as a column-major order array.
* Constructor parameters are in row-major order for code readability.
* @alias Matrix4
* @constructor
* @implements {ArrayLike}
*
* @param {Number} [column0Row0=0.0] The value for column 0, row 0.
* @param {Number} [column1Row0=0.0] The value for column 1, row 0.
* @param {Number} [column2Row0=0.0] The value for column 2, row 0.
* @param {Number} [column3Row0=0.0] The value for column 3, row 0.
* @param {Number} [column0Row1=0.0] The value for column 0, row 1.
* @param {Number} [column1Row1=0.0] The value for column 1, row 1.
* @param {Number} [column2Row1=0.0] The value for column 2, row 1.
* @param {Number} [column3Row1=0.0] The value for column 3, row 1.
* @param {Number} [column0Row2=0.0] The value for column 0, row 2.
* @param {Number} [column1Row2=0.0] The value for column 1, row 2.
* @param {Number} [column2Row2=0.0] The value for column 2, row 2.
* @param {Number} [column3Row2=0.0] The value for column 3, row 2.
* @param {Number} [column0Row3=0.0] The value for column 0, row 3.
* @param {Number} [column1Row3=0.0] The value for column 1, row 3.
* @param {Number} [column2Row3=0.0] The value for column 2, row 3.
* @param {Number} [column3Row3=0.0] The value for column 3, row 3.
*
* @see Matrix4.fromArray
* @see Matrix4.fromColumnMajorArray
* @see Matrix4.fromRowMajorArray
* @see Matrix4.fromRotationTranslation
* @see Matrix4.fromTranslationQuaternionRotationScale
* @see Matrix4.fromTranslationRotationScale
* @see Matrix4.fromTranslation
* @see Matrix4.fromScale
* @see Matrix4.fromUniformScale
* @see Matrix4.fromRotation
* @see Matrix4.fromCamera
* @see Matrix4.computePerspectiveFieldOfView
* @see Matrix4.computeOrthographicOffCenter
* @see Matrix4.computePerspectiveOffCenter
* @see Matrix4.computeInfinitePerspectiveOffCenter
* @see Matrix4.computeViewportTransformation
* @see Matrix4.computeView
* @see Matrix2
* @see Matrix3
* @see Packable
*/
function Matrix4(
column0Row0,
column1Row0,
column2Row0,
column3Row0,
column0Row1,
column1Row1,
column2Row1,
column3Row1,
column0Row2,
column1Row2,
column2Row2,
column3Row2,
column0Row3,
column1Row3,
column2Row3,
column3Row3
) {
this[0] = defaultValue(column0Row0, 0.0);
this[1] = defaultValue(column0Row1, 0.0);
this[2] = defaultValue(column0Row2, 0.0);
this[3] = defaultValue(column0Row3, 0.0);
this[4] = defaultValue(column1Row0, 0.0);
this[5] = defaultValue(column1Row1, 0.0);
this[6] = defaultValue(column1Row2, 0.0);
this[7] = defaultValue(column1Row3, 0.0);
this[8] = defaultValue(column2Row0, 0.0);
this[9] = defaultValue(column2Row1, 0.0);
this[10] = defaultValue(column2Row2, 0.0);
this[11] = defaultValue(column2Row3, 0.0);
this[12] = defaultValue(column3Row0, 0.0);
this[13] = defaultValue(column3Row1, 0.0);
this[14] = defaultValue(column3Row2, 0.0);
this[15] = defaultValue(column3Row3, 0.0);
}
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Matrix4.packedLength = 16;
/**
* Stores the provided instance into the provided array.
*
* @param {Matrix4} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Matrix4.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
array[startingIndex++] = value[0];
array[startingIndex++] = value[1];
array[startingIndex++] = value[2];
array[startingIndex++] = value[3];
array[startingIndex++] = value[4];
array[startingIndex++] = value[5];
array[startingIndex++] = value[6];
array[startingIndex++] = value[7];
array[startingIndex++] = value[8];
array[startingIndex++] = value[9];
array[startingIndex++] = value[10];
array[startingIndex++] = value[11];
array[startingIndex++] = value[12];
array[startingIndex++] = value[13];
array[startingIndex++] = value[14];
array[startingIndex] = value[15];
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Matrix4} [result] The object into which to store the result.
* @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided.
*/
Matrix4.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new Matrix4();
}
result[0] = array[startingIndex++];
result[1] = array[startingIndex++];
result[2] = array[startingIndex++];
result[3] = array[startingIndex++];
result[4] = array[startingIndex++];
result[5] = array[startingIndex++];
result[6] = array[startingIndex++];
result[7] = array[startingIndex++];
result[8] = array[startingIndex++];
result[9] = array[startingIndex++];
result[10] = array[startingIndex++];
result[11] = array[startingIndex++];
result[12] = array[startingIndex++];
result[13] = array[startingIndex++];
result[14] = array[startingIndex++];
result[15] = array[startingIndex];
return result;
};
/**
* Flattens an array of Matrix4s into an array of components. The components
* are stored in column-major order.
*
* @param {Matrix4[]} array The array of matrices to pack.
* @param {Number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 16 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 16) elements.
* @returns {Number[]} The packed array.
*/
Matrix4.packArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
const length = array.length;
const resultLength = length * 16;
if (!defined(result)) {
result = new Array(resultLength);
} else if (!Array.isArray(result) && result.length !== resultLength) {
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError(
"If result is a typed array, it must have exactly array.length * 16 elements"
);
//>>includeEnd('debug');
} else if (result.length !== resultLength) {
result.length = resultLength;
}
for (let i = 0; i < length; ++i) {
Matrix4.pack(array[i], result, i * 16);
}
return result;
};
/**
* Unpacks an array of column-major matrix components into an array of Matrix4s.
*
* @param {Number[]} array The array of components to unpack.
* @param {Matrix4[]} [result] The array onto which to store the result.
* @returns {Matrix4[]} The unpacked array.
*/
Matrix4.unpackArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
Check.typeOf.number.greaterThanOrEquals("array.length", array.length, 16);
if (array.length % 16 !== 0) {
throw new DeveloperError("array length must be a multiple of 16.");
}
//>>includeEnd('debug');
const length = array.length;
if (!defined(result)) {
result = new Array(length / 16);
} else {
result.length = length / 16;
}
for (let i = 0; i < length; i += 16) {
const index = i / 16;
result[index] = Matrix4.unpack(array, i, result[index]);
}
return result;
};
/**
* Duplicates a Matrix4 instance.
*
* @param {Matrix4} matrix The matrix to duplicate.
* @param {Matrix4} [result] The object onto which to store the result.
* @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. (Returns undefined if matrix is undefined)
*/
Matrix4.clone = function (matrix, result) {
if (!defined(matrix)) {
return undefined;
}
if (!defined(result)) {
return new Matrix4(
matrix[0],
matrix[4],
matrix[8],
matrix[12],
matrix[1],
matrix[5],
matrix[9],
matrix[13],
matrix[2],
matrix[6],
matrix[10],
matrix[14],
matrix[3],
matrix[7],
matrix[11],
matrix[15]
);
}
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
/**
* Creates a Matrix4 from 16 consecutive elements in an array.
* @function
*
* @param {Number[]} array The array whose 16 consecutive elements correspond to the positions of the matrix. Assumes column-major order.
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to first column first row position in the matrix.
* @param {Matrix4} [result] The object onto which to store the result.
* @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided.
*
* @example
* // Create the Matrix4:
* // [1.0, 2.0, 3.0, 4.0]
* // [1.0, 2.0, 3.0, 4.0]
* // [1.0, 2.0, 3.0, 4.0]
* // [1.0, 2.0, 3.0, 4.0]
*
* const v = [1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0];
* const m = Cesium.Matrix4.fromArray(v);
*
* // Create same Matrix4 with using an offset into an array
* const v2 = [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0];
* const m2 = Cesium.Matrix4.fromArray(v2, 2);
*/
Matrix4.fromArray = Matrix4.unpack;
/**
* Computes a Matrix4 instance from a column-major order array.
*
* @param {Number[]} values The column-major order array.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromColumnMajorArray = function (values, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("values", values);
//>>includeEnd('debug');
return Matrix4.clone(values, result);
};
/**
* Computes a Matrix4 instance from a row-major order array.
* The resulting matrix will be in column-major order.
*
* @param {Number[]} values The row-major order array.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromRowMajorArray = function (values, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("values", values);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix4(
values[0],
values[1],
values[2],
values[3],
values[4],
values[5],
values[6],
values[7],
values[8],
values[9],
values[10],
values[11],
values[12],
values[13],
values[14],
values[15]
);
}
result[0] = values[0];
result[1] = values[4];
result[2] = values[8];
result[3] = values[12];
result[4] = values[1];
result[5] = values[5];
result[6] = values[9];
result[7] = values[13];
result[8] = values[2];
result[9] = values[6];
result[10] = values[10];
result[11] = values[14];
result[12] = values[3];
result[13] = values[7];
result[14] = values[11];
result[15] = values[15];
return result;
};
/**
* Computes a Matrix4 instance from a Matrix3 representing the rotation
* and a Cartesian3 representing the translation.
*
* @param {Matrix3} rotation The upper left portion of the matrix representing the rotation.
* @param {Cartesian3} [translation=Cartesian3.ZERO] The upper right portion of the matrix representing the translation.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromRotationTranslation = function (rotation, translation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rotation", rotation);
//>>includeEnd('debug');
translation = defaultValue(translation, Cartesian3.ZERO);
if (!defined(result)) {
return new Matrix4(
rotation[0],
rotation[3],
rotation[6],
translation.x,
rotation[1],
rotation[4],
rotation[7],
translation.y,
rotation[2],
rotation[5],
rotation[8],
translation.z,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = rotation[0];
result[1] = rotation[1];
result[2] = rotation[2];
result[3] = 0.0;
result[4] = rotation[3];
result[5] = rotation[4];
result[6] = rotation[5];
result[7] = 0.0;
result[8] = rotation[6];
result[9] = rotation[7];
result[10] = rotation[8];
result[11] = 0.0;
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = 1.0;
return result;
};
/**
* Computes a Matrix4 instance from a translation, rotation, and scale (TRS)
* representation with the rotation represented as a quaternion.
*
* @param {Cartesian3} translation The translation transformation.
* @param {Quaternion} rotation The rotation transformation.
* @param {Cartesian3} scale The non-uniform scale transformation.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*
* @example
* const result = Cesium.Matrix4.fromTranslationQuaternionRotationScale(
* new Cesium.Cartesian3(1.0, 2.0, 3.0), // translation
* Cesium.Quaternion.IDENTITY, // rotation
* new Cesium.Cartesian3(7.0, 8.0, 9.0), // scale
* result);
*/
Matrix4.fromTranslationQuaternionRotationScale = function (
translation,
rotation,
scale,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("translation", translation);
Check.typeOf.object("rotation", rotation);
Check.typeOf.object("scale", scale);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Matrix4();
}
const scaleX = scale.x;
const scaleY = scale.y;
const scaleZ = scale.z;
const x2 = rotation.x * rotation.x;
const xy = rotation.x * rotation.y;
const xz = rotation.x * rotation.z;
const xw = rotation.x * rotation.w;
const y2 = rotation.y * rotation.y;
const yz = rotation.y * rotation.z;
const yw = rotation.y * rotation.w;
const z2 = rotation.z * rotation.z;
const zw = rotation.z * rotation.w;
const w2 = rotation.w * rotation.w;
const m00 = x2 - y2 - z2 + w2;
const m01 = 2.0 * (xy - zw);
const m02 = 2.0 * (xz + yw);
const m10 = 2.0 * (xy + zw);
const m11 = -x2 + y2 - z2 + w2;
const m12 = 2.0 * (yz - xw);
const m20 = 2.0 * (xz - yw);
const m21 = 2.0 * (yz + xw);
const m22 = -x2 - y2 + z2 + w2;
result[0] = m00 * scaleX;
result[1] = m10 * scaleX;
result[2] = m20 * scaleX;
result[3] = 0.0;
result[4] = m01 * scaleY;
result[5] = m11 * scaleY;
result[6] = m21 * scaleY;
result[7] = 0.0;
result[8] = m02 * scaleZ;
result[9] = m12 * scaleZ;
result[10] = m22 * scaleZ;
result[11] = 0.0;
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = 1.0;
return result;
};
/**
* Creates a Matrix4 instance from a {@link TranslationRotationScale} instance.
*
* @param {TranslationRotationScale} translationRotationScale The instance.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromTranslationRotationScale = function (
translationRotationScale,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("translationRotationScale", translationRotationScale);
//>>includeEnd('debug');
return Matrix4.fromTranslationQuaternionRotationScale(
translationRotationScale.translation,
translationRotationScale.rotation,
translationRotationScale.scale,
result
);
};
/**
* Creates a Matrix4 instance from a Cartesian3 representing the translation.
*
* @param {Cartesian3} translation The upper right portion of the matrix representing the translation.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*
* @see Matrix4.multiplyByTranslation
*/
Matrix4.fromTranslation = function (translation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("translation", translation);
//>>includeEnd('debug');
return Matrix4.fromRotationTranslation(Matrix3.IDENTITY, translation, result);
};
/**
* Computes a Matrix4 instance representing a non-uniform scale.
*
* @param {Cartesian3} scale The x, y, and z scale factors.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*
* @example
* // Creates
* // [7.0, 0.0, 0.0, 0.0]
* // [0.0, 8.0, 0.0, 0.0]
* // [0.0, 0.0, 9.0, 0.0]
* // [0.0, 0.0, 0.0, 1.0]
* const m = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(7.0, 8.0, 9.0));
*/
Matrix4.fromScale = function (scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("scale", scale);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix4(
scale.x,
0.0,
0.0,
0.0,
0.0,
scale.y,
0.0,
0.0,
0.0,
0.0,
scale.z,
0.0,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = scale.x;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = scale.y;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = scale.z;
result[11] = 0.0;
result[12] = 0.0;
result[13] = 0.0;
result[14] = 0.0;
result[15] = 1.0;
return result;
};
/**
* Computes a Matrix4 instance representing a uniform scale.
*
* @param {Number} scale The uniform scale factor.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*
* @example
* // Creates
* // [2.0, 0.0, 0.0, 0.0]
* // [0.0, 2.0, 0.0, 0.0]
* // [0.0, 0.0, 2.0, 0.0]
* // [0.0, 0.0, 0.0, 1.0]
* const m = Cesium.Matrix4.fromUniformScale(2.0);
*/
Matrix4.fromUniformScale = function (scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("scale", scale);
//>>includeEnd('debug');
if (!defined(result)) {
return new Matrix4(
scale,
0.0,
0.0,
0.0,
0.0,
scale,
0.0,
0.0,
0.0,
0.0,
scale,
0.0,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = scale;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = scale;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = scale;
result[11] = 0.0;
result[12] = 0.0;
result[13] = 0.0;
result[14] = 0.0;
result[15] = 1.0;
return result;
};
/**
* Creates a rotation matrix.
*
* @param {Matrix3} rotation The rotation matrix.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromRotation = function (rotation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rotation", rotation);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Matrix4();
}
result[0] = rotation[0];
result[1] = rotation[1];
result[2] = rotation[2];
result[3] = 0.0;
result[4] = rotation[3];
result[5] = rotation[4];
result[6] = rotation[5];
result[7] = 0.0;
result[8] = rotation[6];
result[9] = rotation[7];
result[10] = rotation[8];
result[11] = 0.0;
result[12] = 0.0;
result[13] = 0.0;
result[14] = 0.0;
result[15] = 1.0;
return result;
};
const fromCameraF = new Cartesian3();
const fromCameraR = new Cartesian3();
const fromCameraU = new Cartesian3();
/**
* Computes a Matrix4 instance from a Camera.
*
* @param {Camera} camera The camera to use.
* @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created.
* @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided.
*/
Matrix4.fromCamera = function (camera, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("camera", camera);
//>>includeEnd('debug');
const position = camera.position;
const direction = camera.direction;
const up = camera.up;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("camera.position", position);
Check.typeOf.object("camera.direction", direction);
Check.typeOf.object("camera.up", up);
//>>includeEnd('debug');
Cartesian3.normalize(direction, fromCameraF);
Cartesian3.normalize(
Cartesian3.cross(fromCameraF, up, fromCameraR),
fromCameraR
);
Cartesian3.normalize(
Cartesian3.cross(fromCameraR, fromCameraF, fromCameraU),
fromCameraU
);
const sX = fromCameraR.x;
const sY = fromCameraR.y;
const sZ = fromCameraR.z;
const fX = fromCameraF.x;
const fY = fromCameraF.y;
const fZ = fromCameraF.z;
const uX = fromCameraU.x;
const uY = fromCameraU.y;
const uZ = fromCameraU.z;
const positionX = position.x;
const positionY = position.y;
const positionZ = position.z;
const t0 = sX * -positionX + sY * -positionY + sZ * -positionZ;
const t1 = uX * -positionX + uY * -positionY + uZ * -positionZ;
const t2 = fX * positionX + fY * positionY + fZ * positionZ;
// The code below this comment is an optimized
// version of the commented lines.
// Rather that create two matrices and then multiply,
// we just bake in the multiplcation as part of creation.
// const rotation = new Matrix4(
// sX, sY, sZ, 0.0,
// uX, uY, uZ, 0.0,
// -fX, -fY, -fZ, 0.0,
// 0.0, 0.0, 0.0, 1.0);
// const translation = new Matrix4(
// 1.0, 0.0, 0.0, -position.x,
// 0.0, 1.0, 0.0, -position.y,
// 0.0, 0.0, 1.0, -position.z,
// 0.0, 0.0, 0.0, 1.0);
// return rotation.multiply(translation);
if (!defined(result)) {
return new Matrix4(
sX,
sY,
sZ,
t0,
uX,
uY,
uZ,
t1,
-fX,
-fY,
-fZ,
t2,
0.0,
0.0,
0.0,
1.0
);
}
result[0] = sX;
result[1] = uX;
result[2] = -fX;
result[3] = 0.0;
result[4] = sY;
result[5] = uY;
result[6] = -fY;
result[7] = 0.0;
result[8] = sZ;
result[9] = uZ;
result[10] = -fZ;
result[11] = 0.0;
result[12] = t0;
result[13] = t1;
result[14] = t2;
result[15] = 1.0;
return result;
};
/**
* Computes a Matrix4 instance representing a perspective transformation matrix.
*
* @param {Number} fovY The field of view along the Y axis in radians.
* @param {Number} aspectRatio The aspect ratio.
* @param {Number} near The distance to the near plane in meters.
* @param {Number} far The distance to the far plane in meters.
* @param {Matrix4} result The object in which the result will be stored.
* @returns {Matrix4} The modified result parameter.
*
* @exception {DeveloperError} fovY must be in (0, PI].
* @exception {DeveloperError} aspectRatio must be greater than zero.
* @exception {DeveloperError} near must be greater than zero.
* @exception {DeveloperError} far must be greater than zero.
*/
Matrix4.computePerspectiveFieldOfView = function (
fovY,
aspectRatio,
near,
far,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThan("fovY", fovY, 0.0);
Check.typeOf.number.lessThan("fovY", fovY, Math.PI);
Check.typeOf.number.greaterThan("near", near, 0.0);
Check.typeOf.number.greaterThan("far", far, 0.0);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const bottom = Math.tan(fovY * 0.5);
const column1Row1 = 1.0 / bottom;
const column0Row0 = column1Row1 / aspectRatio;
const column2Row2 = (far + near) / (near - far);
const column3Row2 = (2.0 * far * near) / (near - far);
result[0] = column0Row0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = column1Row1;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = column2Row2;
result[11] = -1.0;
result[12] = 0.0;
result[13] = 0.0;
result[14] = column3Row2;
result[15] = 0.0;
return result;
};
/**
* Computes a Matrix4 instance representing an orthographic transformation matrix.
*
* @param {Number} left The number of meters to the left of the camera that will be in view.
* @param {Number} right The number of meters to the right of the camera that will be in view.
* @param {Number} bottom The number of meters below of the camera that will be in view.
* @param {Number} top The number of meters above of the camera that will be in view.
* @param {Number} near The distance to the near plane in meters.
* @param {Number} far The distance to the far plane in meters.
* @param {Matrix4} result The object in which the result will be stored.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.computeOrthographicOffCenter = function (
left,
right,
bottom,
top,
near,
far,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("left", left);
Check.typeOf.number("right", right);
Check.typeOf.number("bottom", bottom);
Check.typeOf.number("top", top);
Check.typeOf.number("near", near);
Check.typeOf.number("far", far);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
let a = 1.0 / (right - left);
let b = 1.0 / (top - bottom);
let c = 1.0 / (far - near);
const tx = -(right + left) * a;
const ty = -(top + bottom) * b;
const tz = -(far + near) * c;
a *= 2.0;
b *= 2.0;
c *= -2.0;
result[0] = a;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = b;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = c;
result[11] = 0.0;
result[12] = tx;
result[13] = ty;
result[14] = tz;
result[15] = 1.0;
return result;
};
/**
* Computes a Matrix4 instance representing an off center perspective transformation.
*
* @param {Number} left The number of meters to the left of the camera that will be in view.
* @param {Number} right The number of meters to the right of the camera that will be in view.
* @param {Number} bottom The number of meters below of the camera that will be in view.
* @param {Number} top The number of meters above of the camera that will be in view.
* @param {Number} near The distance to the near plane in meters.
* @param {Number} far The distance to the far plane in meters.
* @param {Matrix4} result The object in which the result will be stored.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.computePerspectiveOffCenter = function (
left,
right,
bottom,
top,
near,
far,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("left", left);
Check.typeOf.number("right", right);
Check.typeOf.number("bottom", bottom);
Check.typeOf.number("top", top);
Check.typeOf.number("near", near);
Check.typeOf.number("far", far);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const column0Row0 = (2.0 * near) / (right - left);
const column1Row1 = (2.0 * near) / (top - bottom);
const column2Row0 = (right + left) / (right - left);
const column2Row1 = (top + bottom) / (top - bottom);
const column2Row2 = -(far + near) / (far - near);
const column2Row3 = -1.0;
const column3Row2 = (-2.0 * far * near) / (far - near);
result[0] = column0Row0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = column1Row1;
result[6] = 0.0;
result[7] = 0.0;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = column2Row3;
result[12] = 0.0;
result[13] = 0.0;
result[14] = column3Row2;
result[15] = 0.0;
return result;
};
/**
* Computes a Matrix4 instance representing an infinite off center perspective transformation.
*
* @param {Number} left The number of meters to the left of the camera that will be in view.
* @param {Number} right The number of meters to the right of the camera that will be in view.
* @param {Number} bottom The number of meters below of the camera that will be in view.
* @param {Number} top The number of meters above of the camera that will be in view.
* @param {Number} near The distance to the near plane in meters.
* @param {Matrix4} result The object in which the result will be stored.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.computeInfinitePerspectiveOffCenter = function (
left,
right,
bottom,
top,
near,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number("left", left);
Check.typeOf.number("right", right);
Check.typeOf.number("bottom", bottom);
Check.typeOf.number("top", top);
Check.typeOf.number("near", near);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const column0Row0 = (2.0 * near) / (right - left);
const column1Row1 = (2.0 * near) / (top - bottom);
const column2Row0 = (right + left) / (right - left);
const column2Row1 = (top + bottom) / (top - bottom);
const column2Row2 = -1.0;
const column2Row3 = -1.0;
const column3Row2 = -2.0 * near;
result[0] = column0Row0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = column1Row1;
result[6] = 0.0;
result[7] = 0.0;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = column2Row3;
result[12] = 0.0;
result[13] = 0.0;
result[14] = column3Row2;
result[15] = 0.0;
return result;
};
/**
* Computes a Matrix4 instance that transforms from normalized device coordinates to window coordinates.
*
* @param {Object} [viewport = { x : 0.0, y : 0.0, width : 0.0, height : 0.0 }] The viewport's corners as shown in Example 1.
* @param {Number} [nearDepthRange=0.0] The near plane distance in window coordinates.
* @param {Number} [farDepthRange=1.0] The far plane distance in window coordinates.
* @param {Matrix4} [result] The object in which the result will be stored.
* @returns {Matrix4} The modified result parameter.
*
* @example
* // Create viewport transformation using an explicit viewport and depth range.
* const m = Cesium.Matrix4.computeViewportTransformation({
* x : 0.0,
* y : 0.0,
* width : 1024.0,
* height : 768.0
* }, 0.0, 1.0, new Cesium.Matrix4());
*/
Matrix4.computeViewportTransformation = function (
viewport,
nearDepthRange,
farDepthRange,
result
) {
if (!defined(result)) {
result = new Matrix4();
}
viewport = defaultValue(viewport, defaultValue.EMPTY_OBJECT);
const x = defaultValue(viewport.x, 0.0);
const y = defaultValue(viewport.y, 0.0);
const width = defaultValue(viewport.width, 0.0);
const height = defaultValue(viewport.height, 0.0);
nearDepthRange = defaultValue(nearDepthRange, 0.0);
farDepthRange = defaultValue(farDepthRange, 1.0);
const halfWidth = width * 0.5;
const halfHeight = height * 0.5;
const halfDepth = (farDepthRange - nearDepthRange) * 0.5;
const column0Row0 = halfWidth;
const column1Row1 = halfHeight;
const column2Row2 = halfDepth;
const column3Row0 = x + halfWidth;
const column3Row1 = y + halfHeight;
const column3Row2 = nearDepthRange + halfDepth;
const column3Row3 = 1.0;
result[0] = column0Row0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = column1Row1;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = column2Row2;
result[11] = 0.0;
result[12] = column3Row0;
result[13] = column3Row1;
result[14] = column3Row2;
result[15] = column3Row3;
return result;
};
/**
* Computes a Matrix4 instance that transforms from world space to view space.
*
* @param {Cartesian3} position The position of the camera.
* @param {Cartesian3} direction The forward direction.
* @param {Cartesian3} up The up direction.
* @param {Cartesian3} right The right direction.
* @param {Matrix4} result The object in which the result will be stored.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.computeView = function (position, direction, up, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("position", position);
Check.typeOf.object("direction", direction);
Check.typeOf.object("up", up);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = right.x;
result[1] = up.x;
result[2] = -direction.x;
result[3] = 0.0;
result[4] = right.y;
result[5] = up.y;
result[6] = -direction.y;
result[7] = 0.0;
result[8] = right.z;
result[9] = up.z;
result[10] = -direction.z;
result[11] = 0.0;
result[12] = -Cartesian3.dot(right, position);
result[13] = -Cartesian3.dot(up, position);
result[14] = Cartesian3.dot(direction, position);
result[15] = 1.0;
return result;
};
/**
* Computes an Array from the provided Matrix4 instance.
* The array will be in column-major order.
*
* @param {Matrix4} matrix The matrix to use..
* @param {Number[]} [result] The Array onto which to store the result.
* @returns {Number[]} The modified Array parameter or a new Array instance if one was not provided.
*
* @example
* //create an array from an instance of Matrix4
* // m = [10.0, 14.0, 18.0, 22.0]
* // [11.0, 15.0, 19.0, 23.0]
* // [12.0, 16.0, 20.0, 24.0]
* // [13.0, 17.0, 21.0, 25.0]
* const a = Cesium.Matrix4.toArray(m);
*
* // m remains the same
* //creates a = [10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0]
*/
Matrix4.toArray = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
//>>includeEnd('debug');
if (!defined(result)) {
return [
matrix[0],
matrix[1],
matrix[2],
matrix[3],
matrix[4],
matrix[5],
matrix[6],
matrix[7],
matrix[8],
matrix[9],
matrix[10],
matrix[11],
matrix[12],
matrix[13],
matrix[14],
matrix[15],
];
}
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
/**
* Computes the array index of the element at the provided row and column.
*
* @param {Number} row The zero-based index of the row.
* @param {Number} column The zero-based index of the column.
* @returns {Number} The index of the element at the provided row and column.
*
* @exception {DeveloperError} row must be 0, 1, 2, or 3.
* @exception {DeveloperError} column must be 0, 1, 2, or 3.
*
* @example
* const myMatrix = new Cesium.Matrix4();
* const column1Row0Index = Cesium.Matrix4.getElementIndex(1, 0);
* const column1Row0 = myMatrix[column1Row0Index];
* myMatrix[column1Row0Index] = 10.0;
*/
Matrix4.getElementIndex = function (column, row) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("row", row, 0);
Check.typeOf.number.lessThanOrEquals("row", row, 3);
Check.typeOf.number.greaterThanOrEquals("column", column, 0);
Check.typeOf.number.lessThanOrEquals("column", column, 3);
//>>includeEnd('debug');
return column * 4 + row;
};
/**
* Retrieves a copy of the matrix column at the provided index as a Cartesian4 instance.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Number} index The zero-based index of the column to retrieve.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, 2, or 3.
*
* @example
* //returns a Cartesian4 instance with values from the specified column
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* //Example 1: Creates an instance of Cartesian
* const a = Cesium.Matrix4.getColumn(m, 2, new Cesium.Cartesian4());
*
* @example
* //Example 2: Sets values for Cartesian instance
* const a = new Cesium.Cartesian4();
* Cesium.Matrix4.getColumn(m, 2, a);
*
* // a.x = 12.0; a.y = 16.0; a.z = 20.0; a.w = 24.0;
*/
Matrix4.getColumn = function (matrix, index, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 3);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const startIndex = index * 4;
const x = matrix[startIndex];
const y = matrix[startIndex + 1];
const z = matrix[startIndex + 2];
const w = matrix[startIndex + 3];
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
};
/**
* Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian4 instance.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Number} index The zero-based index of the column to set.
* @param {Cartesian4} cartesian The Cartesian whose values will be assigned to the specified column.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, 2, or 3.
*
* @example
* //creates a new Matrix4 instance with new column values from the Cartesian4 instance
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* const a = Cesium.Matrix4.setColumn(m, 2, new Cesium.Cartesian4(99.0, 98.0, 97.0, 96.0), new Cesium.Matrix4());
*
* // m remains the same
* // a = [10.0, 11.0, 99.0, 13.0]
* // [14.0, 15.0, 98.0, 17.0]
* // [18.0, 19.0, 97.0, 21.0]
* // [22.0, 23.0, 96.0, 25.0]
*/
Matrix4.setColumn = function (matrix, index, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 3);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result = Matrix4.clone(matrix, result);
const startIndex = index * 4;
result[startIndex] = cartesian.x;
result[startIndex + 1] = cartesian.y;
result[startIndex + 2] = cartesian.z;
result[startIndex + 3] = cartesian.w;
return result;
};
/**
* Retrieves a copy of the matrix row at the provided index as a Cartesian4 instance.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Number} index The zero-based index of the row to retrieve.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, 2, or 3.
*
* @example
* //returns a Cartesian4 instance with values from the specified column
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* //Example 1: Returns an instance of Cartesian
* const a = Cesium.Matrix4.getRow(m, 2, new Cesium.Cartesian4());
*
* @example
* //Example 2: Sets values for a Cartesian instance
* const a = new Cesium.Cartesian4();
* Cesium.Matrix4.getRow(m, 2, a);
*
* // a.x = 18.0; a.y = 19.0; a.z = 20.0; a.w = 21.0;
*/
Matrix4.getRow = function (matrix, index, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 3);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const x = matrix[index];
const y = matrix[index + 4];
const z = matrix[index + 8];
const w = matrix[index + 12];
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
};
/**
* Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian4 instance.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Number} index The zero-based index of the row to set.
* @param {Cartesian4} cartesian The Cartesian whose values will be assigned to the specified row.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @exception {DeveloperError} index must be 0, 1, 2, or 3.
*
* @example
* //create a new Matrix4 instance with new row values from the Cartesian4 instance
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* const a = Cesium.Matrix4.setRow(m, 2, new Cesium.Cartesian4(99.0, 98.0, 97.0, 96.0), new Cesium.Matrix4());
*
* // m remains the same
* // a = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [99.0, 98.0, 97.0, 96.0]
* // [22.0, 23.0, 24.0, 25.0]
*/
Matrix4.setRow = function (matrix, index, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.lessThanOrEquals("index", index, 3);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result = Matrix4.clone(matrix, result);
result[index] = cartesian.x;
result[index + 4] = cartesian.y;
result[index + 8] = cartesian.z;
result[index + 12] = cartesian.w;
return result;
};
/**
* Computes a new matrix that replaces the translation in the rightmost column of the provided
* matrix with the provided translation. This assumes the matrix is an affine transformation.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Cartesian3} translation The translation that replaces the translation of the provided matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.setTranslation = function (matrix, translation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("translation", translation);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = matrix[15];
return result;
};
const scaleScratch1$1 = new Cartesian3();
/**
* Computes a new matrix that replaces the scale with the provided scale.
* This assumes the matrix is an affine transformation.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Cartesian3} scale The scale that replaces the scale of the provided matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @see Matrix4.setUniformScale
* @see Matrix4.fromScale
* @see Matrix4.fromUniformScale
* @see Matrix4.multiplyByScale
* @see Matrix4.multiplyByUniformScale
* @see Matrix4.getScale
*/
Matrix4.setScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const existingScale = Matrix4.getScale(matrix, scaleScratch1$1);
const scaleRatioX = scale.x / existingScale.x;
const scaleRatioY = scale.y / existingScale.y;
const scaleRatioZ = scale.z / existingScale.y;
result[0] = matrix[0] * scaleRatioX;
result[1] = matrix[1] * scaleRatioX;
result[2] = matrix[2] * scaleRatioX;
result[3] = matrix[3];
result[4] = matrix[4] * scaleRatioY;
result[5] = matrix[5] * scaleRatioY;
result[6] = matrix[6] * scaleRatioY;
result[7] = matrix[7];
result[8] = matrix[8] * scaleRatioZ;
result[9] = matrix[9] * scaleRatioZ;
result[10] = matrix[10] * scaleRatioZ;
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
const scaleScratch2$1 = new Cartesian3();
/**
* Computes a new matrix that replaces the scale with the provided uniform scale.
* This assumes the matrix is an affine transformation.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Number} scale The uniform scale that replaces the scale of the provided matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @see Matrix4.setScale
* @see Matrix4.fromScale
* @see Matrix4.fromUniformScale
* @see Matrix4.multiplyByScale
* @see Matrix4.multiplyByUniformScale
* @see Matrix4.getScale
*/
Matrix4.setUniformScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const existingScale = Matrix4.getScale(matrix, scaleScratch2$1);
const scaleRatioX = scale / existingScale.x;
const scaleRatioY = scale / existingScale.y;
const scaleRatioZ = scale / existingScale.z;
result[0] = matrix[0] * scaleRatioX;
result[1] = matrix[1] * scaleRatioX;
result[2] = matrix[2] * scaleRatioX;
result[3] = matrix[3];
result[4] = matrix[4] * scaleRatioY;
result[5] = matrix[5] * scaleRatioY;
result[6] = matrix[6] * scaleRatioY;
result[7] = matrix[7];
result[8] = matrix[8] * scaleRatioZ;
result[9] = matrix[9] * scaleRatioZ;
result[10] = matrix[10] * scaleRatioZ;
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
const scratchColumn$1 = new Cartesian3();
/**
* Extracts the non-uniform scale assuming the matrix is an affine transformation.
*
* @param {Matrix4} matrix The matrix.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter
*
* @see Matrix4.multiplyByScale
* @see Matrix4.multiplyByUniformScale
* @see Matrix4.fromScale
* @see Matrix4.fromUniformScale
* @see Matrix4.setScale
* @see Matrix4.setUniformScale
*/
Matrix4.getScale = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Cartesian3.magnitude(
Cartesian3.fromElements(matrix[0], matrix[1], matrix[2], scratchColumn$1)
);
result.y = Cartesian3.magnitude(
Cartesian3.fromElements(matrix[4], matrix[5], matrix[6], scratchColumn$1)
);
result.z = Cartesian3.magnitude(
Cartesian3.fromElements(matrix[8], matrix[9], matrix[10], scratchColumn$1)
);
return result;
};
const scaleScratch3$1 = new Cartesian3();
/**
* Computes the maximum scale assuming the matrix is an affine transformation.
* The maximum scale is the maximum length of the column vectors in the upper-left
* 3x3 matrix.
*
* @param {Matrix4} matrix The matrix.
* @returns {Number} The maximum scale.
*/
Matrix4.getMaximumScale = function (matrix) {
Matrix4.getScale(matrix, scaleScratch3$1);
return Cartesian3.maximumComponent(scaleScratch3$1);
};
const scaleScratch4$1 = new Cartesian3();
/**
* Sets the rotation assuming the matrix is an affine transformation.
*
* @param {Matrix4} matrix The matrix.
* @param {Matrix4} rotation The rotation matrix.
* @returns {Matrix4} The modified result parameter.
*
* @see Matrix4.fromRotation
* @see Matrix4.getRotation
*/
Matrix4.setRotation = function (matrix, rotation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const scale = Matrix4.getScale(matrix, scaleScratch4$1);
result[0] = rotation[0] * scale.x;
result[1] = rotation[1] * scale.x;
result[2] = rotation[2] * scale.x;
result[3] = matrix[3];
result[4] = rotation[3] * scale.y;
result[5] = rotation[4] * scale.y;
result[6] = rotation[5] * scale.y;
result[7] = matrix[7];
result[8] = rotation[6] * scale.z;
result[9] = rotation[7] * scale.z;
result[10] = rotation[8] * scale.z;
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
const scaleScratch5$1 = new Cartesian3();
/**
* Extracts the rotation matrix assuming the matrix is an affine transformation.
*
* @param {Matrix4} matrix The matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @see Matrix4.setRotation
* @see Matrix4.fromRotation
*/
Matrix4.getRotation = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const scale = Matrix4.getScale(matrix, scaleScratch5$1);
result[0] = matrix[0] / scale.x;
result[1] = matrix[1] / scale.x;
result[2] = matrix[2] / scale.x;
result[3] = matrix[4] / scale.y;
result[4] = matrix[5] / scale.y;
result[5] = matrix[6] / scale.y;
result[6] = matrix[8] / scale.z;
result[7] = matrix[9] / scale.z;
result[8] = matrix[10] / scale.z;
return result;
};
/**
* Computes the product of two matrices.
*
* @param {Matrix4} left The first matrix.
* @param {Matrix4} right The second matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.multiply = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const left0 = left[0];
const left1 = left[1];
const left2 = left[2];
const left3 = left[3];
const left4 = left[4];
const left5 = left[5];
const left6 = left[6];
const left7 = left[7];
const left8 = left[8];
const left9 = left[9];
const left10 = left[10];
const left11 = left[11];
const left12 = left[12];
const left13 = left[13];
const left14 = left[14];
const left15 = left[15];
const right0 = right[0];
const right1 = right[1];
const right2 = right[2];
const right3 = right[3];
const right4 = right[4];
const right5 = right[5];
const right6 = right[6];
const right7 = right[7];
const right8 = right[8];
const right9 = right[9];
const right10 = right[10];
const right11 = right[11];
const right12 = right[12];
const right13 = right[13];
const right14 = right[14];
const right15 = right[15];
const column0Row0 =
left0 * right0 + left4 * right1 + left8 * right2 + left12 * right3;
const column0Row1 =
left1 * right0 + left5 * right1 + left9 * right2 + left13 * right3;
const column0Row2 =
left2 * right0 + left6 * right1 + left10 * right2 + left14 * right3;
const column0Row3 =
left3 * right0 + left7 * right1 + left11 * right2 + left15 * right3;
const column1Row0 =
left0 * right4 + left4 * right5 + left8 * right6 + left12 * right7;
const column1Row1 =
left1 * right4 + left5 * right5 + left9 * right6 + left13 * right7;
const column1Row2 =
left2 * right4 + left6 * right5 + left10 * right6 + left14 * right7;
const column1Row3 =
left3 * right4 + left7 * right5 + left11 * right6 + left15 * right7;
const column2Row0 =
left0 * right8 + left4 * right9 + left8 * right10 + left12 * right11;
const column2Row1 =
left1 * right8 + left5 * right9 + left9 * right10 + left13 * right11;
const column2Row2 =
left2 * right8 + left6 * right9 + left10 * right10 + left14 * right11;
const column2Row3 =
left3 * right8 + left7 * right9 + left11 * right10 + left15 * right11;
const column3Row0 =
left0 * right12 + left4 * right13 + left8 * right14 + left12 * right15;
const column3Row1 =
left1 * right12 + left5 * right13 + left9 * right14 + left13 * right15;
const column3Row2 =
left2 * right12 + left6 * right13 + left10 * right14 + left14 * right15;
const column3Row3 =
left3 * right12 + left7 * right13 + left11 * right14 + left15 * right15;
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = column0Row3;
result[4] = column1Row0;
result[5] = column1Row1;
result[6] = column1Row2;
result[7] = column1Row3;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = column2Row3;
result[12] = column3Row0;
result[13] = column3Row1;
result[14] = column3Row2;
result[15] = column3Row3;
return result;
};
/**
* Computes the sum of two matrices.
*
* @param {Matrix4} left The first matrix.
* @param {Matrix4} right The second matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.add = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = left[0] + right[0];
result[1] = left[1] + right[1];
result[2] = left[2] + right[2];
result[3] = left[3] + right[3];
result[4] = left[4] + right[4];
result[5] = left[5] + right[5];
result[6] = left[6] + right[6];
result[7] = left[7] + right[7];
result[8] = left[8] + right[8];
result[9] = left[9] + right[9];
result[10] = left[10] + right[10];
result[11] = left[11] + right[11];
result[12] = left[12] + right[12];
result[13] = left[13] + right[13];
result[14] = left[14] + right[14];
result[15] = left[15] + right[15];
return result;
};
/**
* Computes the difference of two matrices.
*
* @param {Matrix4} left The first matrix.
* @param {Matrix4} right The second matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.subtract = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = left[0] - right[0];
result[1] = left[1] - right[1];
result[2] = left[2] - right[2];
result[3] = left[3] - right[3];
result[4] = left[4] - right[4];
result[5] = left[5] - right[5];
result[6] = left[6] - right[6];
result[7] = left[7] - right[7];
result[8] = left[8] - right[8];
result[9] = left[9] - right[9];
result[10] = left[10] - right[10];
result[11] = left[11] - right[11];
result[12] = left[12] - right[12];
result[13] = left[13] - right[13];
result[14] = left[14] - right[14];
result[15] = left[15] - right[15];
return result;
};
/**
* Computes the product of two matrices assuming the matrices are affine transformation matrices,
* where the upper left 3x3 elements are any matrix, and
* the upper three elements in the fourth column are the translation.
* The bottom row is assumed to be [0, 0, 0, 1].
* The matrix is not verified to be in the proper form.
* This method is faster than computing the product for general 4x4
* matrices using {@link Matrix4.multiply}.
*
* @param {Matrix4} left The first matrix.
* @param {Matrix4} right The second matrix.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* const m1 = new Cesium.Matrix4(1.0, 6.0, 7.0, 0.0, 2.0, 5.0, 8.0, 0.0, 3.0, 4.0, 9.0, 0.0, 0.0, 0.0, 0.0, 1.0);
* const m2 = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3(1.0, 1.0, 1.0));
* const m3 = Cesium.Matrix4.multiplyTransformation(m1, m2, new Cesium.Matrix4());
*/
Matrix4.multiplyTransformation = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const left0 = left[0];
const left1 = left[1];
const left2 = left[2];
const left4 = left[4];
const left5 = left[5];
const left6 = left[6];
const left8 = left[8];
const left9 = left[9];
const left10 = left[10];
const left12 = left[12];
const left13 = left[13];
const left14 = left[14];
const right0 = right[0];
const right1 = right[1];
const right2 = right[2];
const right4 = right[4];
const right5 = right[5];
const right6 = right[6];
const right8 = right[8];
const right9 = right[9];
const right10 = right[10];
const right12 = right[12];
const right13 = right[13];
const right14 = right[14];
const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2;
const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2;
const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2;
const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6;
const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6;
const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6;
const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10;
const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10;
const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10;
const column3Row0 =
left0 * right12 + left4 * right13 + left8 * right14 + left12;
const column3Row1 =
left1 * right12 + left5 * right13 + left9 * right14 + left13;
const column3Row2 =
left2 * right12 + left6 * right13 + left10 * right14 + left14;
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = 0.0;
result[4] = column1Row0;
result[5] = column1Row1;
result[6] = column1Row2;
result[7] = 0.0;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = 0.0;
result[12] = column3Row0;
result[13] = column3Row1;
result[14] = column3Row2;
result[15] = 1.0;
return result;
};
/**
* Multiplies a transformation matrix (with a bottom row of [0.0, 0.0, 0.0, 1.0]
)
* by a 3x3 rotation matrix. This is an optimization
* for Matrix4.multiply(m, Matrix4.fromRotationTranslation(rotation), m);
with less allocations and arithmetic operations.
*
* @param {Matrix4} matrix The matrix on the left-hand side.
* @param {Matrix3} rotation The 3x3 rotation matrix on the right-hand side.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromRotationTranslation(rotation), m);
* Cesium.Matrix4.multiplyByMatrix3(m, rotation, m);
*/
Matrix4.multiplyByMatrix3 = function (matrix, rotation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("rotation", rotation);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const left0 = matrix[0];
const left1 = matrix[1];
const left2 = matrix[2];
const left4 = matrix[4];
const left5 = matrix[5];
const left6 = matrix[6];
const left8 = matrix[8];
const left9 = matrix[9];
const left10 = matrix[10];
const right0 = rotation[0];
const right1 = rotation[1];
const right2 = rotation[2];
const right4 = rotation[3];
const right5 = rotation[4];
const right6 = rotation[5];
const right8 = rotation[6];
const right9 = rotation[7];
const right10 = rotation[8];
const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2;
const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2;
const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2;
const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6;
const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6;
const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6;
const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10;
const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10;
const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10;
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = 0.0;
result[4] = column1Row0;
result[5] = column1Row1;
result[6] = column1Row2;
result[7] = 0.0;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = 0.0;
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
/**
* Multiplies a transformation matrix (with a bottom row of [0.0, 0.0, 0.0, 1.0]
)
* by an implicit translation matrix defined by a {@link Cartesian3}. This is an optimization
* for Matrix4.multiply(m, Matrix4.fromTranslation(position), m);
with less allocations and arithmetic operations.
*
* @param {Matrix4} matrix The matrix on the left-hand side.
* @param {Cartesian3} translation The translation on the right-hand side.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromTranslation(position), m);
* Cesium.Matrix4.multiplyByTranslation(m, position, m);
*/
Matrix4.multiplyByTranslation = function (matrix, translation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("translation", translation);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const x = translation.x;
const y = translation.y;
const z = translation.z;
const tx = x * matrix[0] + y * matrix[4] + z * matrix[8] + matrix[12];
const ty = x * matrix[1] + y * matrix[5] + z * matrix[9] + matrix[13];
const tz = x * matrix[2] + y * matrix[6] + z * matrix[10] + matrix[14];
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = tx;
result[13] = ty;
result[14] = tz;
result[15] = matrix[15];
return result;
};
/**
* Multiplies an affine transformation matrix (with a bottom row of [0.0, 0.0, 0.0, 1.0]
)
* by an implicit non-uniform scale matrix. This is an optimization
* for Matrix4.multiply(m, Matrix4.fromUniformScale(scale), m);
, where
* m
must be an affine matrix.
* This function performs fewer allocations and arithmetic operations.
*
* @param {Matrix4} matrix The affine matrix on the left-hand side.
* @param {Cartesian3} scale The non-uniform scale on the right-hand side.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
*
* @example
* // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromScale(scale), m);
* Cesium.Matrix4.multiplyByScale(m, scale, m);
*
* @see Matrix4.multiplyByUniformScale
* @see Matrix4.fromScale
* @see Matrix4.fromUniformScale
* @see Matrix4.setScale
* @see Matrix4.setUniformScale
* @see Matrix4.getScale
*/
Matrix4.multiplyByScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const scaleX = scale.x;
const scaleY = scale.y;
const scaleZ = scale.z;
// Faster than Cartesian3.equals
if (scaleX === 1.0 && scaleY === 1.0 && scaleZ === 1.0) {
return Matrix4.clone(matrix, result);
}
result[0] = scaleX * matrix[0];
result[1] = scaleX * matrix[1];
result[2] = scaleX * matrix[2];
result[3] = matrix[3];
result[4] = scaleY * matrix[4];
result[5] = scaleY * matrix[5];
result[6] = scaleY * matrix[6];
result[7] = matrix[7];
result[8] = scaleZ * matrix[8];
result[9] = scaleZ * matrix[9];
result[10] = scaleZ * matrix[10];
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
/**
* Computes the product of a matrix times a uniform scale, as if the scale were a scale matrix.
*
* @param {Matrix4} matrix The matrix on the left-hand side.
* @param {Number} scale The uniform scale on the right-hand side.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromUniformScale(scale), m);
* Cesium.Matrix4.multiplyByUniformScale(m, scale, m);
*
* @see Matrix4.multiplyByScale
* @see Matrix4.fromScale
* @see Matrix4.fromUniformScale
* @see Matrix4.setScale
* @see Matrix4.setUniformScale
* @see Matrix4.getScale
*/
Matrix4.multiplyByUniformScale = function (matrix, scale, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number("scale", scale);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0] * scale;
result[1] = matrix[1] * scale;
result[2] = matrix[2] * scale;
result[3] = matrix[3];
result[4] = matrix[4] * scale;
result[5] = matrix[5] * scale;
result[6] = matrix[6] * scale;
result[7] = matrix[7];
result[8] = matrix[8] * scale;
result[9] = matrix[9] * scale;
result[10] = matrix[10] * scale;
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
};
/**
* Computes the product of a matrix and a column vector.
*
* @param {Matrix4} matrix The matrix.
* @param {Cartesian4} cartesian The vector.
* @param {Cartesian4} result The object onto which to store the result.
* @returns {Cartesian4} The modified result parameter.
*/
Matrix4.multiplyByVector = function (matrix, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const vW = cartesian.w;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12] * vW;
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13] * vW;
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14] * vW;
const w = matrix[3] * vX + matrix[7] * vY + matrix[11] * vZ + matrix[15] * vW;
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
};
/**
* Computes the product of a matrix and a {@link Cartesian3}. This is equivalent to calling {@link Matrix4.multiplyByVector}
* with a {@link Cartesian4} with a w
component of zero.
*
* @param {Matrix4} matrix The matrix.
* @param {Cartesian3} cartesian The point.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*
* @example
* const p = new Cesium.Cartesian3(1.0, 2.0, 3.0);
* const result = Cesium.Matrix4.multiplyByPointAsVector(matrix, p, new Cesium.Cartesian3());
* // A shortcut for
* // Cartesian3 p = ...
* // Cesium.Matrix4.multiplyByVector(matrix, new Cesium.Cartesian4(p.x, p.y, p.z, 0.0), result);
*/
Matrix4.multiplyByPointAsVector = function (matrix, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ;
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ;
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ;
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Computes the product of a matrix and a {@link Cartesian3}. This is equivalent to calling {@link Matrix4.multiplyByVector}
* with a {@link Cartesian4} with a w
component of 1, but returns a {@link Cartesian3} instead of a {@link Cartesian4}.
*
* @param {Matrix4} matrix The matrix.
* @param {Cartesian3} cartesian The point.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*
* @example
* const p = new Cesium.Cartesian3(1.0, 2.0, 3.0);
* const result = Cesium.Matrix4.multiplyByPoint(matrix, p, new Cesium.Cartesian3());
*/
Matrix4.multiplyByPoint = function (matrix, cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12];
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13];
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14];
result.x = x;
result.y = y;
result.z = z;
return result;
};
/**
* Computes the product of a matrix and a scalar.
*
* @param {Matrix4} matrix The matrix.
* @param {Number} scalar The number to multiply by.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* //create a Matrix4 instance which is a scaled version of the supplied Matrix4
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* const a = Cesium.Matrix4.multiplyByScalar(m, -2, new Cesium.Matrix4());
*
* // m remains the same
* // a = [-20.0, -22.0, -24.0, -26.0]
* // [-28.0, -30.0, -32.0, -34.0]
* // [-36.0, -38.0, -40.0, -42.0]
* // [-44.0, -46.0, -48.0, -50.0]
*/
Matrix4.multiplyByScalar = function (matrix, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0] * scalar;
result[1] = matrix[1] * scalar;
result[2] = matrix[2] * scalar;
result[3] = matrix[3] * scalar;
result[4] = matrix[4] * scalar;
result[5] = matrix[5] * scalar;
result[6] = matrix[6] * scalar;
result[7] = matrix[7] * scalar;
result[8] = matrix[8] * scalar;
result[9] = matrix[9] * scalar;
result[10] = matrix[10] * scalar;
result[11] = matrix[11] * scalar;
result[12] = matrix[12] * scalar;
result[13] = matrix[13] * scalar;
result[14] = matrix[14] * scalar;
result[15] = matrix[15] * scalar;
return result;
};
/**
* Computes a negated copy of the provided matrix.
*
* @param {Matrix4} matrix The matrix to negate.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* //create a new Matrix4 instance which is a negation of a Matrix4
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* const a = Cesium.Matrix4.negate(m, new Cesium.Matrix4());
*
* // m remains the same
* // a = [-10.0, -11.0, -12.0, -13.0]
* // [-14.0, -15.0, -16.0, -17.0]
* // [-18.0, -19.0, -20.0, -21.0]
* // [-22.0, -23.0, -24.0, -25.0]
*/
Matrix4.negate = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = -matrix[0];
result[1] = -matrix[1];
result[2] = -matrix[2];
result[3] = -matrix[3];
result[4] = -matrix[4];
result[5] = -matrix[5];
result[6] = -matrix[6];
result[7] = -matrix[7];
result[8] = -matrix[8];
result[9] = -matrix[9];
result[10] = -matrix[10];
result[11] = -matrix[11];
result[12] = -matrix[12];
result[13] = -matrix[13];
result[14] = -matrix[14];
result[15] = -matrix[15];
return result;
};
/**
* Computes the transpose of the provided matrix.
*
* @param {Matrix4} matrix The matrix to transpose.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @example
* //returns transpose of a Matrix4
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* const a = Cesium.Matrix4.transpose(m, new Cesium.Matrix4());
*
* // m remains the same
* // a = [10.0, 14.0, 18.0, 22.0]
* // [11.0, 15.0, 19.0, 23.0]
* // [12.0, 16.0, 20.0, 24.0]
* // [13.0, 17.0, 21.0, 25.0]
*/
Matrix4.transpose = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const matrix1 = matrix[1];
const matrix2 = matrix[2];
const matrix3 = matrix[3];
const matrix6 = matrix[6];
const matrix7 = matrix[7];
const matrix11 = matrix[11];
result[0] = matrix[0];
result[1] = matrix[4];
result[2] = matrix[8];
result[3] = matrix[12];
result[4] = matrix1;
result[5] = matrix[5];
result[6] = matrix[9];
result[7] = matrix[13];
result[8] = matrix2;
result[9] = matrix6;
result[10] = matrix[10];
result[11] = matrix[14];
result[12] = matrix3;
result[13] = matrix7;
result[14] = matrix11;
result[15] = matrix[15];
return result;
};
/**
* Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements.
*
* @param {Matrix4} matrix The matrix with signed elements.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.abs = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = Math.abs(matrix[0]);
result[1] = Math.abs(matrix[1]);
result[2] = Math.abs(matrix[2]);
result[3] = Math.abs(matrix[3]);
result[4] = Math.abs(matrix[4]);
result[5] = Math.abs(matrix[5]);
result[6] = Math.abs(matrix[6]);
result[7] = Math.abs(matrix[7]);
result[8] = Math.abs(matrix[8]);
result[9] = Math.abs(matrix[9]);
result[10] = Math.abs(matrix[10]);
result[11] = Math.abs(matrix[11]);
result[12] = Math.abs(matrix[12]);
result[13] = Math.abs(matrix[13]);
result[14] = Math.abs(matrix[14]);
result[15] = Math.abs(matrix[15]);
return result;
};
/**
* Compares the provided matrices componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Matrix4} [left] The first matrix.
* @param {Matrix4} [right] The second matrix.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*
* @example
* //compares two Matrix4 instances
*
* // a = [10.0, 14.0, 18.0, 22.0]
* // [11.0, 15.0, 19.0, 23.0]
* // [12.0, 16.0, 20.0, 24.0]
* // [13.0, 17.0, 21.0, 25.0]
*
* // b = [10.0, 14.0, 18.0, 22.0]
* // [11.0, 15.0, 19.0, 23.0]
* // [12.0, 16.0, 20.0, 24.0]
* // [13.0, 17.0, 21.0, 25.0]
*
* if(Cesium.Matrix4.equals(a,b)) {
* console.log("Both matrices are equal");
* } else {
* console.log("They are not equal");
* }
*
* //Prints "Both matrices are equal" on the console
*/
Matrix4.equals = function (left, right) {
// Given that most matrices will be transformation matrices, the elements
// are tested in order such that the test is likely to fail as early
// as possible. I _think_ this is just as friendly to the L1 cache
// as testing in index order. It is certainty faster in practice.
return (
left === right ||
(defined(left) &&
defined(right) &&
// Translation
left[12] === right[12] &&
left[13] === right[13] &&
left[14] === right[14] &&
// Rotation/scale
left[0] === right[0] &&
left[1] === right[1] &&
left[2] === right[2] &&
left[4] === right[4] &&
left[5] === right[5] &&
left[6] === right[6] &&
left[8] === right[8] &&
left[9] === right[9] &&
left[10] === right[10] &&
// Bottom row
left[3] === right[3] &&
left[7] === right[7] &&
left[11] === right[11] &&
left[15] === right[15])
);
};
/**
* Compares the provided matrices componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Matrix4} [left] The first matrix.
* @param {Matrix4} [right] The second matrix.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*
* @example
* //compares two Matrix4 instances
*
* // a = [10.5, 14.5, 18.5, 22.5]
* // [11.5, 15.5, 19.5, 23.5]
* // [12.5, 16.5, 20.5, 24.5]
* // [13.5, 17.5, 21.5, 25.5]
*
* // b = [10.0, 14.0, 18.0, 22.0]
* // [11.0, 15.0, 19.0, 23.0]
* // [12.0, 16.0, 20.0, 24.0]
* // [13.0, 17.0, 21.0, 25.0]
*
* if(Cesium.Matrix4.equalsEpsilon(a,b,0.1)){
* console.log("Difference between both the matrices is less than 0.1");
* } else {
* console.log("Difference between both the matrices is not less than 0.1");
* }
*
* //Prints "Difference between both the matrices is not less than 0.1" on the console
*/
Matrix4.equalsEpsilon = function (left, right, epsilon) {
epsilon = defaultValue(epsilon, 0);
return (
left === right ||
(defined(left) &&
defined(right) &&
Math.abs(left[0] - right[0]) <= epsilon &&
Math.abs(left[1] - right[1]) <= epsilon &&
Math.abs(left[2] - right[2]) <= epsilon &&
Math.abs(left[3] - right[3]) <= epsilon &&
Math.abs(left[4] - right[4]) <= epsilon &&
Math.abs(left[5] - right[5]) <= epsilon &&
Math.abs(left[6] - right[6]) <= epsilon &&
Math.abs(left[7] - right[7]) <= epsilon &&
Math.abs(left[8] - right[8]) <= epsilon &&
Math.abs(left[9] - right[9]) <= epsilon &&
Math.abs(left[10] - right[10]) <= epsilon &&
Math.abs(left[11] - right[11]) <= epsilon &&
Math.abs(left[12] - right[12]) <= epsilon &&
Math.abs(left[13] - right[13]) <= epsilon &&
Math.abs(left[14] - right[14]) <= epsilon &&
Math.abs(left[15] - right[15]) <= epsilon)
);
};
/**
* Gets the translation portion of the provided matrix, assuming the matrix is an affine transformation matrix.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Cartesian3} result The object onto which to store the result.
* @returns {Cartesian3} The modified result parameter.
*/
Matrix4.getTranslation = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = matrix[12];
result.y = matrix[13];
result.z = matrix[14];
return result;
};
/**
* Gets the upper left 3x3 matrix of the provided matrix.
*
* @param {Matrix4} matrix The matrix to use.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*
* @example
* // returns a Matrix3 instance from a Matrix4 instance
*
* // m = [10.0, 14.0, 18.0, 22.0]
* // [11.0, 15.0, 19.0, 23.0]
* // [12.0, 16.0, 20.0, 24.0]
* // [13.0, 17.0, 21.0, 25.0]
*
* const b = new Cesium.Matrix3();
* Cesium.Matrix4.getMatrix3(m,b);
*
* // b = [10.0, 14.0, 18.0]
* // [11.0, 15.0, 19.0]
* // [12.0, 16.0, 20.0]
*/
Matrix4.getMatrix3 = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[4];
result[4] = matrix[5];
result[5] = matrix[6];
result[6] = matrix[8];
result[7] = matrix[9];
result[8] = matrix[10];
return result;
};
const scratchInverseRotation = new Matrix3();
const scratchMatrix3Zero = new Matrix3();
const scratchBottomRow = new Cartesian4();
const scratchExpectedBottomRow = new Cartesian4(0.0, 0.0, 0.0, 1.0);
/**
* Computes the inverse of the provided matrix using Cramers Rule.
* If the determinant is zero, the matrix can not be inverted, and an exception is thrown.
* If the matrix is a proper rigid transformation, it is more efficient
* to invert it with {@link Matrix4.inverseTransformation}.
*
* @param {Matrix4} matrix The matrix to invert.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*
* @exception {RuntimeError} matrix is not invertible because its determinate is zero.
*/
Matrix4.inverse = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
//
// Ported from:
// ftp://download.intel.com/design/PentiumIII/sml/24504301.pdf
//
const src0 = matrix[0];
const src1 = matrix[4];
const src2 = matrix[8];
const src3 = matrix[12];
const src4 = matrix[1];
const src5 = matrix[5];
const src6 = matrix[9];
const src7 = matrix[13];
const src8 = matrix[2];
const src9 = matrix[6];
const src10 = matrix[10];
const src11 = matrix[14];
const src12 = matrix[3];
const src13 = matrix[7];
const src14 = matrix[11];
const src15 = matrix[15];
// calculate pairs for first 8 elements (cofactors)
let tmp0 = src10 * src15;
let tmp1 = src11 * src14;
let tmp2 = src9 * src15;
let tmp3 = src11 * src13;
let tmp4 = src9 * src14;
let tmp5 = src10 * src13;
let tmp6 = src8 * src15;
let tmp7 = src11 * src12;
let tmp8 = src8 * src14;
let tmp9 = src10 * src12;
let tmp10 = src8 * src13;
let tmp11 = src9 * src12;
// calculate first 8 elements (cofactors)
const dst0 =
tmp0 * src5 +
tmp3 * src6 +
tmp4 * src7 -
(tmp1 * src5 + tmp2 * src6 + tmp5 * src7);
const dst1 =
tmp1 * src4 +
tmp6 * src6 +
tmp9 * src7 -
(tmp0 * src4 + tmp7 * src6 + tmp8 * src7);
const dst2 =
tmp2 * src4 +
tmp7 * src5 +
tmp10 * src7 -
(tmp3 * src4 + tmp6 * src5 + tmp11 * src7);
const dst3 =
tmp5 * src4 +
tmp8 * src5 +
tmp11 * src6 -
(tmp4 * src4 + tmp9 * src5 + tmp10 * src6);
const dst4 =
tmp1 * src1 +
tmp2 * src2 +
tmp5 * src3 -
(tmp0 * src1 + tmp3 * src2 + tmp4 * src3);
const dst5 =
tmp0 * src0 +
tmp7 * src2 +
tmp8 * src3 -
(tmp1 * src0 + tmp6 * src2 + tmp9 * src3);
const dst6 =
tmp3 * src0 +
tmp6 * src1 +
tmp11 * src3 -
(tmp2 * src0 + tmp7 * src1 + tmp10 * src3);
const dst7 =
tmp4 * src0 +
tmp9 * src1 +
tmp10 * src2 -
(tmp5 * src0 + tmp8 * src1 + tmp11 * src2);
// calculate pairs for second 8 elements (cofactors)
tmp0 = src2 * src7;
tmp1 = src3 * src6;
tmp2 = src1 * src7;
tmp3 = src3 * src5;
tmp4 = src1 * src6;
tmp5 = src2 * src5;
tmp6 = src0 * src7;
tmp7 = src3 * src4;
tmp8 = src0 * src6;
tmp9 = src2 * src4;
tmp10 = src0 * src5;
tmp11 = src1 * src4;
// calculate second 8 elements (cofactors)
const dst8 =
tmp0 * src13 +
tmp3 * src14 +
tmp4 * src15 -
(tmp1 * src13 + tmp2 * src14 + tmp5 * src15);
const dst9 =
tmp1 * src12 +
tmp6 * src14 +
tmp9 * src15 -
(tmp0 * src12 + tmp7 * src14 + tmp8 * src15);
const dst10 =
tmp2 * src12 +
tmp7 * src13 +
tmp10 * src15 -
(tmp3 * src12 + tmp6 * src13 + tmp11 * src15);
const dst11 =
tmp5 * src12 +
tmp8 * src13 +
tmp11 * src14 -
(tmp4 * src12 + tmp9 * src13 + tmp10 * src14);
const dst12 =
tmp2 * src10 +
tmp5 * src11 +
tmp1 * src9 -
(tmp4 * src11 + tmp0 * src9 + tmp3 * src10);
const dst13 =
tmp8 * src11 +
tmp0 * src8 +
tmp7 * src10 -
(tmp6 * src10 + tmp9 * src11 + tmp1 * src8);
const dst14 =
tmp6 * src9 +
tmp11 * src11 +
tmp3 * src8 -
(tmp10 * src11 + tmp2 * src8 + tmp7 * src9);
const dst15 =
tmp10 * src10 +
tmp4 * src8 +
tmp9 * src9 -
(tmp8 * src9 + tmp11 * src10 + tmp5 * src8);
// calculate determinant
let det = src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3;
if (Math.abs(det) < CesiumMath.EPSILON21) {
// Special case for a zero scale matrix that can occur, for example,
// when a model's node has a [0, 0, 0] scale.
if (
Matrix3.equalsEpsilon(
Matrix4.getMatrix3(matrix, scratchInverseRotation),
scratchMatrix3Zero,
CesiumMath.EPSILON7
) &&
Cartesian4.equals(
Matrix4.getRow(matrix, 3, scratchBottomRow),
scratchExpectedBottomRow
)
) {
result[0] = 0.0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = 0.0;
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = 0.0;
result[11] = 0.0;
result[12] = -matrix[12];
result[13] = -matrix[13];
result[14] = -matrix[14];
result[15] = 1.0;
return result;
}
throw new RuntimeError(
"matrix is not invertible because its determinate is zero."
);
}
// calculate matrix inverse
det = 1.0 / det;
result[0] = dst0 * det;
result[1] = dst1 * det;
result[2] = dst2 * det;
result[3] = dst3 * det;
result[4] = dst4 * det;
result[5] = dst5 * det;
result[6] = dst6 * det;
result[7] = dst7 * det;
result[8] = dst8 * det;
result[9] = dst9 * det;
result[10] = dst10 * det;
result[11] = dst11 * det;
result[12] = dst12 * det;
result[13] = dst13 * det;
result[14] = dst14 * det;
result[15] = dst15 * det;
return result;
};
/**
* Computes the inverse of the provided matrix assuming it is a proper rigid matrix,
* where the upper left 3x3 elements are a rotation matrix,
* and the upper three elements in the fourth column are the translation.
* The bottom row is assumed to be [0, 0, 0, 1].
* The matrix is not verified to be in the proper form.
* This method is faster than computing the inverse for a general 4x4
* matrix using {@link Matrix4.inverse}.
*
* @param {Matrix4} matrix The matrix to invert.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.inverseTransformation = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
//This function is an optimized version of the below 4 lines.
//const rT = Matrix3.transpose(Matrix4.getMatrix3(matrix));
//const rTN = Matrix3.negate(rT);
//const rTT = Matrix3.multiplyByVector(rTN, Matrix4.getTranslation(matrix));
//return Matrix4.fromRotationTranslation(rT, rTT, result);
const matrix0 = matrix[0];
const matrix1 = matrix[1];
const matrix2 = matrix[2];
const matrix4 = matrix[4];
const matrix5 = matrix[5];
const matrix6 = matrix[6];
const matrix8 = matrix[8];
const matrix9 = matrix[9];
const matrix10 = matrix[10];
const vX = matrix[12];
const vY = matrix[13];
const vZ = matrix[14];
const x = -matrix0 * vX - matrix1 * vY - matrix2 * vZ;
const y = -matrix4 * vX - matrix5 * vY - matrix6 * vZ;
const z = -matrix8 * vX - matrix9 * vY - matrix10 * vZ;
result[0] = matrix0;
result[1] = matrix4;
result[2] = matrix8;
result[3] = 0.0;
result[4] = matrix1;
result[5] = matrix5;
result[6] = matrix9;
result[7] = 0.0;
result[8] = matrix2;
result[9] = matrix6;
result[10] = matrix10;
result[11] = 0.0;
result[12] = x;
result[13] = y;
result[14] = z;
result[15] = 1.0;
return result;
};
const scratchTransposeMatrix = new Matrix4();
/**
* Computes the inverse transpose of a matrix.
*
* @param {Matrix4} matrix The matrix to transpose and invert.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.inverseTranspose = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
return Matrix4.inverse(
Matrix4.transpose(matrix, scratchTransposeMatrix),
result
);
};
/**
* An immutable Matrix4 instance initialized to the identity matrix.
*
* @type {Matrix4}
* @constant
*/
Matrix4.IDENTITY = Object.freeze(
new Matrix4(
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0
)
);
/**
* An immutable Matrix4 instance initialized to the zero matrix.
*
* @type {Matrix4}
* @constant
*/
Matrix4.ZERO = Object.freeze(
new Matrix4(
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
)
);
/**
* The index into Matrix4 for column 0, row 0.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN0ROW0 = 0;
/**
* The index into Matrix4 for column 0, row 1.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN0ROW1 = 1;
/**
* The index into Matrix4 for column 0, row 2.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN0ROW2 = 2;
/**
* The index into Matrix4 for column 0, row 3.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN0ROW3 = 3;
/**
* The index into Matrix4 for column 1, row 0.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN1ROW0 = 4;
/**
* The index into Matrix4 for column 1, row 1.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN1ROW1 = 5;
/**
* The index into Matrix4 for column 1, row 2.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN1ROW2 = 6;
/**
* The index into Matrix4 for column 1, row 3.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN1ROW3 = 7;
/**
* The index into Matrix4 for column 2, row 0.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN2ROW0 = 8;
/**
* The index into Matrix4 for column 2, row 1.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN2ROW1 = 9;
/**
* The index into Matrix4 for column 2, row 2.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN2ROW2 = 10;
/**
* The index into Matrix4 for column 2, row 3.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN2ROW3 = 11;
/**
* The index into Matrix4 for column 3, row 0.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN3ROW0 = 12;
/**
* The index into Matrix4 for column 3, row 1.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN3ROW1 = 13;
/**
* The index into Matrix4 for column 3, row 2.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN3ROW2 = 14;
/**
* The index into Matrix4 for column 3, row 3.
*
* @type {Number}
* @constant
*/
Matrix4.COLUMN3ROW3 = 15;
Object.defineProperties(Matrix4.prototype, {
/**
* Gets the number of items in the collection.
* @memberof Matrix4.prototype
*
* @type {Number}
*/
length: {
get: function () {
return Matrix4.packedLength;
},
},
});
/**
* Duplicates the provided Matrix4 instance.
*
* @param {Matrix4} [result] The object onto which to store the result.
* @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided.
*/
Matrix4.prototype.clone = function (result) {
return Matrix4.clone(this, result);
};
/**
* Compares this matrix to the provided matrix componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Matrix4} [right] The right hand side matrix.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
Matrix4.prototype.equals = function (right) {
return Matrix4.equals(this, right);
};
/**
* @private
*/
Matrix4.equalsArray = function (matrix, array, offset) {
return (
matrix[0] === array[offset] &&
matrix[1] === array[offset + 1] &&
matrix[2] === array[offset + 2] &&
matrix[3] === array[offset + 3] &&
matrix[4] === array[offset + 4] &&
matrix[5] === array[offset + 5] &&
matrix[6] === array[offset + 6] &&
matrix[7] === array[offset + 7] &&
matrix[8] === array[offset + 8] &&
matrix[9] === array[offset + 9] &&
matrix[10] === array[offset + 10] &&
matrix[11] === array[offset + 11] &&
matrix[12] === array[offset + 12] &&
matrix[13] === array[offset + 13] &&
matrix[14] === array[offset + 14] &&
matrix[15] === array[offset + 15]
);
};
/**
* Compares this matrix to the provided matrix componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Matrix4} [right] The right hand side matrix.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if they are within the provided epsilon, false
otherwise.
*/
Matrix4.prototype.equalsEpsilon = function (right, epsilon) {
return Matrix4.equalsEpsilon(this, right, epsilon);
};
/**
* Computes a string representing this Matrix with each row being
* on a separate line and in the format '(column0, column1, column2, column3)'.
*
* @returns {String} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1, column2, column3)'.
*/
Matrix4.prototype.toString = function () {
return (
`(${this[0]}, ${this[4]}, ${this[8]}, ${this[12]})\n` +
`(${this[1]}, ${this[5]}, ${this[9]}, ${this[13]})\n` +
`(${this[2]}, ${this[6]}, ${this[10]}, ${this[14]})\n` +
`(${this[3]}, ${this[7]}, ${this[11]}, ${this[15]})`
);
};
/**
* A two dimensional region specified as longitude and latitude coordinates.
*
* @alias Rectangle
* @constructor
*
* @param {Number} [west=0.0] The westernmost longitude, in radians, in the range [-Pi, Pi].
* @param {Number} [south=0.0] The southernmost latitude, in radians, in the range [-Pi/2, Pi/2].
* @param {Number} [east=0.0] The easternmost longitude, in radians, in the range [-Pi, Pi].
* @param {Number} [north=0.0] The northernmost latitude, in radians, in the range [-Pi/2, Pi/2].
*
* @see Packable
*/
function Rectangle(west, south, east, north) {
/**
* The westernmost longitude in radians in the range [-Pi, Pi].
*
* @type {Number}
* @default 0.0
*/
this.west = defaultValue(west, 0.0);
/**
* The southernmost latitude in radians in the range [-Pi/2, Pi/2].
*
* @type {Number}
* @default 0.0
*/
this.south = defaultValue(south, 0.0);
/**
* The easternmost longitude in radians in the range [-Pi, Pi].
*
* @type {Number}
* @default 0.0
*/
this.east = defaultValue(east, 0.0);
/**
* The northernmost latitude in radians in the range [-Pi/2, Pi/2].
*
* @type {Number}
* @default 0.0
*/
this.north = defaultValue(north, 0.0);
}
Object.defineProperties(Rectangle.prototype, {
/**
* Gets the width of the rectangle in radians.
* @memberof Rectangle.prototype
* @type {Number}
* @readonly
*/
width: {
get: function () {
return Rectangle.computeWidth(this);
},
},
/**
* Gets the height of the rectangle in radians.
* @memberof Rectangle.prototype
* @type {Number}
* @readonly
*/
height: {
get: function () {
return Rectangle.computeHeight(this);
},
},
});
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Rectangle.packedLength = 4;
/**
* Stores the provided instance into the provided array.
*
* @param {Rectangle} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Rectangle.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
array[startingIndex++] = value.west;
array[startingIndex++] = value.south;
array[startingIndex++] = value.east;
array[startingIndex] = value.north;
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Rectangle} [result] The object into which to store the result.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided.
*/
Rectangle.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new Rectangle();
}
result.west = array[startingIndex++];
result.south = array[startingIndex++];
result.east = array[startingIndex++];
result.north = array[startingIndex];
return result;
};
/**
* Computes the width of a rectangle in radians.
* @param {Rectangle} rectangle The rectangle to compute the width of.
* @returns {Number} The width.
*/
Rectangle.computeWidth = function (rectangle) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
let east = rectangle.east;
const west = rectangle.west;
if (east < west) {
east += CesiumMath.TWO_PI;
}
return east - west;
};
/**
* Computes the height of a rectangle in radians.
* @param {Rectangle} rectangle The rectangle to compute the height of.
* @returns {Number} The height.
*/
Rectangle.computeHeight = function (rectangle) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
return rectangle.north - rectangle.south;
};
/**
* Creates a rectangle given the boundary longitude and latitude in degrees.
*
* @param {Number} [west=0.0] The westernmost longitude in degrees in the range [-180.0, 180.0].
* @param {Number} [south=0.0] The southernmost latitude in degrees in the range [-90.0, 90.0].
* @param {Number} [east=0.0] The easternmost longitude in degrees in the range [-180.0, 180.0].
* @param {Number} [north=0.0] The northernmost latitude in degrees in the range [-90.0, 90.0].
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*
* @example
* const rectangle = Cesium.Rectangle.fromDegrees(0.0, 20.0, 10.0, 30.0);
*/
Rectangle.fromDegrees = function (west, south, east, north, result) {
west = CesiumMath.toRadians(defaultValue(west, 0.0));
south = CesiumMath.toRadians(defaultValue(south, 0.0));
east = CesiumMath.toRadians(defaultValue(east, 0.0));
north = CesiumMath.toRadians(defaultValue(north, 0.0));
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Creates a rectangle given the boundary longitude and latitude in radians.
*
* @param {Number} [west=0.0] The westernmost longitude in radians in the range [-Math.PI, Math.PI].
* @param {Number} [south=0.0] The southernmost latitude in radians in the range [-Math.PI/2, Math.PI/2].
* @param {Number} [east=0.0] The easternmost longitude in radians in the range [-Math.PI, Math.PI].
* @param {Number} [north=0.0] The northernmost latitude in radians in the range [-Math.PI/2, Math.PI/2].
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*
* @example
* const rectangle = Cesium.Rectangle.fromRadians(0.0, Math.PI/4, Math.PI/8, 3*Math.PI/4);
*/
Rectangle.fromRadians = function (west, south, east, north, result) {
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = defaultValue(west, 0.0);
result.south = defaultValue(south, 0.0);
result.east = defaultValue(east, 0.0);
result.north = defaultValue(north, 0.0);
return result;
};
/**
* Creates the smallest possible Rectangle that encloses all positions in the provided array.
*
* @param {Cartographic[]} cartographics The list of Cartographic instances.
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*/
Rectangle.fromCartographicArray = function (cartographics, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("cartographics", cartographics);
//>>includeEnd('debug');
let west = Number.MAX_VALUE;
let east = -Number.MAX_VALUE;
let westOverIDL = Number.MAX_VALUE;
let eastOverIDL = -Number.MAX_VALUE;
let south = Number.MAX_VALUE;
let north = -Number.MAX_VALUE;
for (let i = 0, len = cartographics.length; i < len; i++) {
const position = cartographics[i];
west = Math.min(west, position.longitude);
east = Math.max(east, position.longitude);
south = Math.min(south, position.latitude);
north = Math.max(north, position.latitude);
const lonAdjusted =
position.longitude >= 0
? position.longitude
: position.longitude + CesiumMath.TWO_PI;
westOverIDL = Math.min(westOverIDL, lonAdjusted);
eastOverIDL = Math.max(eastOverIDL, lonAdjusted);
}
if (east - west > eastOverIDL - westOverIDL) {
west = westOverIDL;
east = eastOverIDL;
if (east > CesiumMath.PI) {
east = east - CesiumMath.TWO_PI;
}
if (west > CesiumMath.PI) {
west = west - CesiumMath.TWO_PI;
}
}
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Creates the smallest possible Rectangle that encloses all positions in the provided array.
*
* @param {Cartesian3[]} cartesians The list of Cartesian instances.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid the cartesians are on.
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*/
Rectangle.fromCartesianArray = function (cartesians, ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("cartesians", cartesians);
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
let west = Number.MAX_VALUE;
let east = -Number.MAX_VALUE;
let westOverIDL = Number.MAX_VALUE;
let eastOverIDL = -Number.MAX_VALUE;
let south = Number.MAX_VALUE;
let north = -Number.MAX_VALUE;
for (let i = 0, len = cartesians.length; i < len; i++) {
const position = ellipsoid.cartesianToCartographic(cartesians[i]);
west = Math.min(west, position.longitude);
east = Math.max(east, position.longitude);
south = Math.min(south, position.latitude);
north = Math.max(north, position.latitude);
const lonAdjusted =
position.longitude >= 0
? position.longitude
: position.longitude + CesiumMath.TWO_PI;
westOverIDL = Math.min(westOverIDL, lonAdjusted);
eastOverIDL = Math.max(eastOverIDL, lonAdjusted);
}
if (east - west > eastOverIDL - westOverIDL) {
west = westOverIDL;
east = eastOverIDL;
if (east > CesiumMath.PI) {
east = east - CesiumMath.TWO_PI;
}
if (west > CesiumMath.PI) {
west = west - CesiumMath.TWO_PI;
}
}
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Duplicates a Rectangle.
*
* @param {Rectangle} rectangle The rectangle to clone.
* @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. (Returns undefined if rectangle is undefined)
*/
Rectangle.clone = function (rectangle, result) {
if (!defined(rectangle)) {
return undefined;
}
if (!defined(result)) {
return new Rectangle(
rectangle.west,
rectangle.south,
rectangle.east,
rectangle.north
);
}
result.west = rectangle.west;
result.south = rectangle.south;
result.east = rectangle.east;
result.north = rectangle.north;
return result;
};
/**
* Compares the provided Rectangles componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Rectangle} [left] The first Rectangle.
* @param {Rectangle} [right] The second Rectangle.
* @param {Number} [absoluteEpsilon=0] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Rectangle.equalsEpsilon = function (left, right, absoluteEpsilon) {
absoluteEpsilon = defaultValue(absoluteEpsilon, 0);
return (
left === right ||
(defined(left) &&
defined(right) &&
Math.abs(left.west - right.west) <= absoluteEpsilon &&
Math.abs(left.south - right.south) <= absoluteEpsilon &&
Math.abs(left.east - right.east) <= absoluteEpsilon &&
Math.abs(left.north - right.north) <= absoluteEpsilon)
);
};
/**
* Duplicates this Rectangle.
*
* @param {Rectangle} [result] The object onto which to store the result.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*/
Rectangle.prototype.clone = function (result) {
return Rectangle.clone(this, result);
};
/**
* Compares the provided Rectangle with this Rectangle componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Rectangle} [other] The Rectangle to compare.
* @returns {Boolean} true
if the Rectangles are equal, false
otherwise.
*/
Rectangle.prototype.equals = function (other) {
return Rectangle.equals(this, other);
};
/**
* Compares the provided rectangles and returns true
if they are equal,
* false
otherwise.
*
* @param {Rectangle} [left] The first Rectangle.
* @param {Rectangle} [right] The second Rectangle.
* @returns {Boolean} true
if left and right are equal; otherwise false
.
*/
Rectangle.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left.west === right.west &&
left.south === right.south &&
left.east === right.east &&
left.north === right.north)
);
};
/**
* Compares the provided Rectangle with this Rectangle componentwise and returns
* true
if they are within the provided epsilon,
* false
otherwise.
*
* @param {Rectangle} [other] The Rectangle to compare.
* @param {Number} [epsilon=0] The epsilon to use for equality testing.
* @returns {Boolean} true
if the Rectangles are within the provided epsilon, false
otherwise.
*/
Rectangle.prototype.equalsEpsilon = function (other, epsilon) {
return Rectangle.equalsEpsilon(this, other, epsilon);
};
/**
* Checks a Rectangle's properties and throws if they are not in valid ranges.
*
* @param {Rectangle} rectangle The rectangle to validate
*
* @exception {DeveloperError} north
must be in the interval [-Pi/2
, Pi/2
].
* @exception {DeveloperError} south
must be in the interval [-Pi/2
, Pi/2
].
* @exception {DeveloperError} east
must be in the interval [-Pi
, Pi
].
* @exception {DeveloperError} west
must be in the interval [-Pi
, Pi
].
*/
Rectangle.validate = function (rectangle) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
const north = rectangle.north;
Check.typeOf.number.greaterThanOrEquals(
"north",
north,
-CesiumMath.PI_OVER_TWO
);
Check.typeOf.number.lessThanOrEquals("north", north, CesiumMath.PI_OVER_TWO);
const south = rectangle.south;
Check.typeOf.number.greaterThanOrEquals(
"south",
south,
-CesiumMath.PI_OVER_TWO
);
Check.typeOf.number.lessThanOrEquals("south", south, CesiumMath.PI_OVER_TWO);
const west = rectangle.west;
Check.typeOf.number.greaterThanOrEquals("west", west, -Math.PI);
Check.typeOf.number.lessThanOrEquals("west", west, Math.PI);
const east = rectangle.east;
Check.typeOf.number.greaterThanOrEquals("east", east, -Math.PI);
Check.typeOf.number.lessThanOrEquals("east", east, Math.PI);
//>>includeEnd('debug');
};
/**
* Computes the southwest corner of a rectangle.
*
* @param {Rectangle} rectangle The rectangle for which to find the corner
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
*/
Rectangle.southwest = function (rectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
if (!defined(result)) {
return new Cartographic(rectangle.west, rectangle.south);
}
result.longitude = rectangle.west;
result.latitude = rectangle.south;
result.height = 0.0;
return result;
};
/**
* Computes the northwest corner of a rectangle.
*
* @param {Rectangle} rectangle The rectangle for which to find the corner
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
*/
Rectangle.northwest = function (rectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
if (!defined(result)) {
return new Cartographic(rectangle.west, rectangle.north);
}
result.longitude = rectangle.west;
result.latitude = rectangle.north;
result.height = 0.0;
return result;
};
/**
* Computes the northeast corner of a rectangle.
*
* @param {Rectangle} rectangle The rectangle for which to find the corner
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
*/
Rectangle.northeast = function (rectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
if (!defined(result)) {
return new Cartographic(rectangle.east, rectangle.north);
}
result.longitude = rectangle.east;
result.latitude = rectangle.north;
result.height = 0.0;
return result;
};
/**
* Computes the southeast corner of a rectangle.
*
* @param {Rectangle} rectangle The rectangle for which to find the corner
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
*/
Rectangle.southeast = function (rectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
if (!defined(result)) {
return new Cartographic(rectangle.east, rectangle.south);
}
result.longitude = rectangle.east;
result.latitude = rectangle.south;
result.height = 0.0;
return result;
};
/**
* Computes the center of a rectangle.
*
* @param {Rectangle} rectangle The rectangle for which to find the center
* @param {Cartographic} [result] The object onto which to store the result.
* @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided.
*/
Rectangle.center = function (rectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
let east = rectangle.east;
const west = rectangle.west;
if (east < west) {
east += CesiumMath.TWO_PI;
}
const longitude = CesiumMath.negativePiToPi((west + east) * 0.5);
const latitude = (rectangle.south + rectangle.north) * 0.5;
if (!defined(result)) {
return new Cartographic(longitude, latitude);
}
result.longitude = longitude;
result.latitude = latitude;
result.height = 0.0;
return result;
};
/**
* Computes the intersection of two rectangles. This function assumes that the rectangle's coordinates are
* latitude and longitude in radians and produces a correct intersection, taking into account the fact that
* the same angle can be represented with multiple values as well as the wrapping of longitude at the
* anti-meridian. For a simple intersection that ignores these factors and can be used with projected
* coordinates, see {@link Rectangle.simpleIntersection}.
*
* @param {Rectangle} rectangle On rectangle to find an intersection
* @param {Rectangle} otherRectangle Another rectangle to find an intersection
* @param {Rectangle} [result] The object onto which to store the result.
* @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection.
*/
Rectangle.intersection = function (rectangle, otherRectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
Check.typeOf.object("otherRectangle", otherRectangle);
//>>includeEnd('debug');
let rectangleEast = rectangle.east;
let rectangleWest = rectangle.west;
let otherRectangleEast = otherRectangle.east;
let otherRectangleWest = otherRectangle.west;
if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
rectangleEast += CesiumMath.TWO_PI;
} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
otherRectangleEast += CesiumMath.TWO_PI;
}
if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
otherRectangleWest += CesiumMath.TWO_PI;
} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
rectangleWest += CesiumMath.TWO_PI;
}
const west = CesiumMath.negativePiToPi(
Math.max(rectangleWest, otherRectangleWest)
);
const east = CesiumMath.negativePiToPi(
Math.min(rectangleEast, otherRectangleEast)
);
if (
(rectangle.west < rectangle.east ||
otherRectangle.west < otherRectangle.east) &&
east <= west
) {
return undefined;
}
const south = Math.max(rectangle.south, otherRectangle.south);
const north = Math.min(rectangle.north, otherRectangle.north);
if (south >= north) {
return undefined;
}
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Computes a simple intersection of two rectangles. Unlike {@link Rectangle.intersection}, this function
* does not attempt to put the angular coordinates into a consistent range or to account for crossing the
* anti-meridian. As such, it can be used for rectangles where the coordinates are not simply latitude
* and longitude (i.e. projected coordinates).
*
* @param {Rectangle} rectangle On rectangle to find an intersection
* @param {Rectangle} otherRectangle Another rectangle to find an intersection
* @param {Rectangle} [result] The object onto which to store the result.
* @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection.
*/
Rectangle.simpleIntersection = function (rectangle, otherRectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
Check.typeOf.object("otherRectangle", otherRectangle);
//>>includeEnd('debug');
const west = Math.max(rectangle.west, otherRectangle.west);
const south = Math.max(rectangle.south, otherRectangle.south);
const east = Math.min(rectangle.east, otherRectangle.east);
const north = Math.min(rectangle.north, otherRectangle.north);
if (south >= north || west >= east) {
return undefined;
}
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Computes a rectangle that is the union of two rectangles.
*
* @param {Rectangle} rectangle A rectangle to enclose in rectangle.
* @param {Rectangle} otherRectangle A rectangle to enclose in a rectangle.
* @param {Rectangle} [result] The object onto which to store the result.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*/
Rectangle.union = function (rectangle, otherRectangle, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
Check.typeOf.object("otherRectangle", otherRectangle);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Rectangle();
}
let rectangleEast = rectangle.east;
let rectangleWest = rectangle.west;
let otherRectangleEast = otherRectangle.east;
let otherRectangleWest = otherRectangle.west;
if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
rectangleEast += CesiumMath.TWO_PI;
} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
otherRectangleEast += CesiumMath.TWO_PI;
}
if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
otherRectangleWest += CesiumMath.TWO_PI;
} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
rectangleWest += CesiumMath.TWO_PI;
}
const west = CesiumMath.negativePiToPi(
Math.min(rectangleWest, otherRectangleWest)
);
const east = CesiumMath.negativePiToPi(
Math.max(rectangleEast, otherRectangleEast)
);
result.west = west;
result.south = Math.min(rectangle.south, otherRectangle.south);
result.east = east;
result.north = Math.max(rectangle.north, otherRectangle.north);
return result;
};
/**
* Computes a rectangle by enlarging the provided rectangle until it contains the provided cartographic.
*
* @param {Rectangle} rectangle A rectangle to expand.
* @param {Cartographic} cartographic A cartographic to enclose in a rectangle.
* @param {Rectangle} [result] The object onto which to store the result.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided.
*/
Rectangle.expand = function (rectangle, cartographic, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
Check.typeOf.object("cartographic", cartographic);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Rectangle();
}
result.west = Math.min(rectangle.west, cartographic.longitude);
result.south = Math.min(rectangle.south, cartographic.latitude);
result.east = Math.max(rectangle.east, cartographic.longitude);
result.north = Math.max(rectangle.north, cartographic.latitude);
return result;
};
/**
* Returns true if the cartographic is on or inside the rectangle, false otherwise.
*
* @param {Rectangle} rectangle The rectangle
* @param {Cartographic} cartographic The cartographic to test.
* @returns {Boolean} true if the provided cartographic is inside the rectangle, false otherwise.
*/
Rectangle.contains = function (rectangle, cartographic) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
Check.typeOf.object("cartographic", cartographic);
//>>includeEnd('debug');
let longitude = cartographic.longitude;
const latitude = cartographic.latitude;
const west = rectangle.west;
let east = rectangle.east;
if (east < west) {
east += CesiumMath.TWO_PI;
if (longitude < 0.0) {
longitude += CesiumMath.TWO_PI;
}
}
return (
(longitude > west ||
CesiumMath.equalsEpsilon(longitude, west, CesiumMath.EPSILON14)) &&
(longitude < east ||
CesiumMath.equalsEpsilon(longitude, east, CesiumMath.EPSILON14)) &&
latitude >= rectangle.south &&
latitude <= rectangle.north
);
};
const subsampleLlaScratch = new Cartographic();
/**
* Samples a rectangle so that it includes a list of Cartesian points suitable for passing to
* {@link BoundingSphere#fromPoints}. Sampling is necessary to account
* for rectangles that cover the poles or cross the equator.
*
* @param {Rectangle} rectangle The rectangle to subsample.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
* @param {Number} [surfaceHeight=0.0] The height of the rectangle above the ellipsoid.
* @param {Cartesian3[]} [result] The array of Cartesians onto which to store the result.
* @returns {Cartesian3[]} The modified result parameter or a new Array of Cartesians instances if none was provided.
*/
Rectangle.subsample = function (rectangle, ellipsoid, surfaceHeight, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
surfaceHeight = defaultValue(surfaceHeight, 0.0);
if (!defined(result)) {
result = [];
}
let length = 0;
const north = rectangle.north;
const south = rectangle.south;
const east = rectangle.east;
const west = rectangle.west;
const lla = subsampleLlaScratch;
lla.height = surfaceHeight;
lla.longitude = west;
lla.latitude = north;
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
lla.longitude = east;
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
lla.latitude = south;
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
lla.longitude = west;
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
if (north < 0.0) {
lla.latitude = north;
} else if (south > 0.0) {
lla.latitude = south;
} else {
lla.latitude = 0.0;
}
for (let i = 1; i < 8; ++i) {
lla.longitude = -Math.PI + i * CesiumMath.PI_OVER_TWO;
if (Rectangle.contains(rectangle, lla)) {
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
}
}
if (lla.latitude === 0.0) {
lla.longitude = west;
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
lla.longitude = east;
result[length] = ellipsoid.cartographicToCartesian(lla, result[length]);
length++;
}
result.length = length;
return result;
};
/**
* Computes a subsection of a rectangle from normalized coordinates in the range [0.0, 1.0].
*
* @param {Rectangle} rectangle The rectangle to subsection.
* @param {Number} westLerp The west interpolation factor in the range [0.0, 1.0]. Must be less than or equal to eastLerp.
* @param {Number} southLerp The south interpolation factor in the range [0.0, 1.0]. Must be less than or equal to northLerp.
* @param {Number} eastLerp The east interpolation factor in the range [0.0, 1.0]. Must be greater than or equal to westLerp.
* @param {Number} northLerp The north interpolation factor in the range [0.0, 1.0]. Must be greater than or equal to southLerp.
* @param {Rectangle} [result] The object onto which to store the result.
* @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided.
*/
Rectangle.subsection = function (
rectangle,
westLerp,
southLerp,
eastLerp,
northLerp,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("rectangle", rectangle);
Check.typeOf.number.greaterThanOrEquals("westLerp", westLerp, 0.0);
Check.typeOf.number.lessThanOrEquals("westLerp", westLerp, 1.0);
Check.typeOf.number.greaterThanOrEquals("southLerp", southLerp, 0.0);
Check.typeOf.number.lessThanOrEquals("southLerp", southLerp, 1.0);
Check.typeOf.number.greaterThanOrEquals("eastLerp", eastLerp, 0.0);
Check.typeOf.number.lessThanOrEquals("eastLerp", eastLerp, 1.0);
Check.typeOf.number.greaterThanOrEquals("northLerp", northLerp, 0.0);
Check.typeOf.number.lessThanOrEquals("northLerp", northLerp, 1.0);
Check.typeOf.number.lessThanOrEquals("westLerp", westLerp, eastLerp);
Check.typeOf.number.lessThanOrEquals("southLerp", southLerp, northLerp);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Rectangle();
}
// This function doesn't use CesiumMath.lerp because it has floating point precision problems
// when the start and end values are the same but the t changes.
if (rectangle.west <= rectangle.east) {
const width = rectangle.east - rectangle.west;
result.west = rectangle.west + westLerp * width;
result.east = rectangle.west + eastLerp * width;
} else {
const width = CesiumMath.TWO_PI + rectangle.east - rectangle.west;
result.west = CesiumMath.negativePiToPi(rectangle.west + westLerp * width);
result.east = CesiumMath.negativePiToPi(rectangle.west + eastLerp * width);
}
const height = rectangle.north - rectangle.south;
result.south = rectangle.south + southLerp * height;
result.north = rectangle.south + northLerp * height;
// Fix floating point precision problems when t = 1
if (westLerp === 1.0) {
result.west = rectangle.east;
}
if (eastLerp === 1.0) {
result.east = rectangle.east;
}
if (southLerp === 1.0) {
result.south = rectangle.north;
}
if (northLerp === 1.0) {
result.north = rectangle.north;
}
return result;
};
/**
* The largest possible rectangle.
*
* @type {Rectangle}
* @constant
*/
Rectangle.MAX_VALUE = Object.freeze(
new Rectangle(
-Math.PI,
-CesiumMath.PI_OVER_TWO,
Math.PI,
CesiumMath.PI_OVER_TWO
)
);
/**
* A bounding sphere with a center and a radius.
* @alias BoundingSphere
* @constructor
*
* @param {Cartesian3} [center=Cartesian3.ZERO] The center of the bounding sphere.
* @param {Number} [radius=0.0] The radius of the bounding sphere.
*
* @see AxisAlignedBoundingBox
* @see BoundingRectangle
* @see Packable
*/
function BoundingSphere(center, radius) {
/**
* The center point of the sphere.
* @type {Cartesian3}
* @default {@link Cartesian3.ZERO}
*/
this.center = Cartesian3.clone(defaultValue(center, Cartesian3.ZERO));
/**
* The radius of the sphere.
* @type {Number}
* @default 0.0
*/
this.radius = defaultValue(radius, 0.0);
}
const fromPointsXMin = new Cartesian3();
const fromPointsYMin = new Cartesian3();
const fromPointsZMin = new Cartesian3();
const fromPointsXMax = new Cartesian3();
const fromPointsYMax = new Cartesian3();
const fromPointsZMax = new Cartesian3();
const fromPointsCurrentPos = new Cartesian3();
const fromPointsScratch = new Cartesian3();
const fromPointsRitterCenter = new Cartesian3();
const fromPointsMinBoxPt = new Cartesian3();
const fromPointsMaxBoxPt = new Cartesian3();
const fromPointsNaiveCenterScratch = new Cartesian3();
const volumeConstant = (4.0 / 3.0) * CesiumMath.PI;
/**
* Computes a tight-fitting bounding sphere enclosing a list of 3D Cartesian points.
* The bounding sphere is computed by running two algorithms, a naive algorithm and
* Ritter's algorithm. The smaller of the two spheres is used to ensure a tight fit.
*
* @param {Cartesian3[]} [positions] An array of points that the bounding sphere will enclose. Each point must have x
, y
, and z
properties.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
*
* @see {@link http://help.agi.com/AGIComponents/html/BlogBoundingSphere.htm|Bounding Sphere computation article}
*/
BoundingSphere.fromPoints = function (positions, result) {
if (!defined(result)) {
result = new BoundingSphere();
}
if (!defined(positions) || positions.length === 0) {
result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = 0.0;
return result;
}
const currentPos = Cartesian3.clone(positions[0], fromPointsCurrentPos);
const xMin = Cartesian3.clone(currentPos, fromPointsXMin);
const yMin = Cartesian3.clone(currentPos, fromPointsYMin);
const zMin = Cartesian3.clone(currentPos, fromPointsZMin);
const xMax = Cartesian3.clone(currentPos, fromPointsXMax);
const yMax = Cartesian3.clone(currentPos, fromPointsYMax);
const zMax = Cartesian3.clone(currentPos, fromPointsZMax);
const numPositions = positions.length;
let i;
for (i = 1; i < numPositions; i++) {
Cartesian3.clone(positions[i], currentPos);
const x = currentPos.x;
const y = currentPos.y;
const z = currentPos.z;
// Store points containing the the smallest and largest components
if (x < xMin.x) {
Cartesian3.clone(currentPos, xMin);
}
if (x > xMax.x) {
Cartesian3.clone(currentPos, xMax);
}
if (y < yMin.y) {
Cartesian3.clone(currentPos, yMin);
}
if (y > yMax.y) {
Cartesian3.clone(currentPos, yMax);
}
if (z < zMin.z) {
Cartesian3.clone(currentPos, zMin);
}
if (z > zMax.z) {
Cartesian3.clone(currentPos, zMax);
}
}
// Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
const xSpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(xMax, xMin, fromPointsScratch)
);
const ySpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(yMax, yMin, fromPointsScratch)
);
const zSpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(zMax, zMin, fromPointsScratch)
);
// Set the diameter endpoints to the largest span.
let diameter1 = xMin;
let diameter2 = xMax;
let maxSpan = xSpan;
if (ySpan > maxSpan) {
maxSpan = ySpan;
diameter1 = yMin;
diameter2 = yMax;
}
if (zSpan > maxSpan) {
maxSpan = zSpan;
diameter1 = zMin;
diameter2 = zMax;
}
// Calculate the center of the initial sphere found by Ritter's algorithm
const ritterCenter = fromPointsRitterCenter;
ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
// Calculate the radius of the initial sphere found by Ritter's algorithm
let radiusSquared = Cartesian3.magnitudeSquared(
Cartesian3.subtract(diameter2, ritterCenter, fromPointsScratch)
);
let ritterRadius = Math.sqrt(radiusSquared);
// Find the center of the sphere found using the Naive method.
const minBoxPt = fromPointsMinBoxPt;
minBoxPt.x = xMin.x;
minBoxPt.y = yMin.y;
minBoxPt.z = zMin.z;
const maxBoxPt = fromPointsMaxBoxPt;
maxBoxPt.x = xMax.x;
maxBoxPt.y = yMax.y;
maxBoxPt.z = zMax.z;
const naiveCenter = Cartesian3.midpoint(
minBoxPt,
maxBoxPt,
fromPointsNaiveCenterScratch
);
// Begin 2nd pass to find naive radius and modify the ritter sphere.
let naiveRadius = 0;
for (i = 0; i < numPositions; i++) {
Cartesian3.clone(positions[i], currentPos);
// Find the furthest point from the naive center to calculate the naive radius.
const r = Cartesian3.magnitude(
Cartesian3.subtract(currentPos, naiveCenter, fromPointsScratch)
);
if (r > naiveRadius) {
naiveRadius = r;
}
// Make adjustments to the Ritter Sphere to include all points.
const oldCenterToPointSquared = Cartesian3.magnitudeSquared(
Cartesian3.subtract(currentPos, ritterCenter, fromPointsScratch)
);
if (oldCenterToPointSquared > radiusSquared) {
const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
// Calculate new radius to include the point that lies outside
ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
radiusSquared = ritterRadius * ritterRadius;
// Calculate center of new Ritter sphere
const oldToNew = oldCenterToPoint - ritterRadius;
ritterCenter.x =
(ritterRadius * ritterCenter.x + oldToNew * currentPos.x) /
oldCenterToPoint;
ritterCenter.y =
(ritterRadius * ritterCenter.y + oldToNew * currentPos.y) /
oldCenterToPoint;
ritterCenter.z =
(ritterRadius * ritterCenter.z + oldToNew * currentPos.z) /
oldCenterToPoint;
}
}
if (ritterRadius < naiveRadius) {
Cartesian3.clone(ritterCenter, result.center);
result.radius = ritterRadius;
} else {
Cartesian3.clone(naiveCenter, result.center);
result.radius = naiveRadius;
}
return result;
};
const defaultProjection$1 = new GeographicProjection();
const fromRectangle2DLowerLeft = new Cartesian3();
const fromRectangle2DUpperRight = new Cartesian3();
const fromRectangle2DSouthwest = new Cartographic();
const fromRectangle2DNortheast = new Cartographic();
/**
* Computes a bounding sphere from a rectangle projected in 2D.
*
* @param {Rectangle} [rectangle] The rectangle around which to create a bounding sphere.
* @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.fromRectangle2D = function (rectangle, projection, result) {
return BoundingSphere.fromRectangleWithHeights2D(
rectangle,
projection,
0.0,
0.0,
result
);
};
/**
* Computes a bounding sphere from a rectangle projected in 2D. The bounding sphere accounts for the
* object's minimum and maximum heights over the rectangle.
*
* @param {Rectangle} [rectangle] The rectangle around which to create a bounding sphere.
* @param {Object} [projection=GeographicProjection] The projection used to project the rectangle into 2D.
* @param {Number} [minimumHeight=0.0] The minimum height over the rectangle.
* @param {Number} [maximumHeight=0.0] The maximum height over the rectangle.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.fromRectangleWithHeights2D = function (
rectangle,
projection,
minimumHeight,
maximumHeight,
result
) {
if (!defined(result)) {
result = new BoundingSphere();
}
if (!defined(rectangle)) {
result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = 0.0;
return result;
}
projection = defaultValue(projection, defaultProjection$1);
Rectangle.southwest(rectangle, fromRectangle2DSouthwest);
fromRectangle2DSouthwest.height = minimumHeight;
Rectangle.northeast(rectangle, fromRectangle2DNortheast);
fromRectangle2DNortheast.height = maximumHeight;
const lowerLeft = projection.project(
fromRectangle2DSouthwest,
fromRectangle2DLowerLeft
);
const upperRight = projection.project(
fromRectangle2DNortheast,
fromRectangle2DUpperRight
);
const width = upperRight.x - lowerLeft.x;
const height = upperRight.y - lowerLeft.y;
const elevation = upperRight.z - lowerLeft.z;
result.radius =
Math.sqrt(width * width + height * height + elevation * elevation) * 0.5;
const center = result.center;
center.x = lowerLeft.x + width * 0.5;
center.y = lowerLeft.y + height * 0.5;
center.z = lowerLeft.z + elevation * 0.5;
return result;
};
const fromRectangle3DScratch = [];
/**
* Computes a bounding sphere from a rectangle in 3D. The bounding sphere is created using a subsample of points
* on the ellipsoid and contained in the rectangle. It may not be accurate for all rectangles on all types of ellipsoids.
*
* @param {Rectangle} [rectangle] The valid rectangle used to create a bounding sphere.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid used to determine positions of the rectangle.
* @param {Number} [surfaceHeight=0.0] The height above the surface of the ellipsoid.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.fromRectangle3D = function (
rectangle,
ellipsoid,
surfaceHeight,
result
) {
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
surfaceHeight = defaultValue(surfaceHeight, 0.0);
if (!defined(result)) {
result = new BoundingSphere();
}
if (!defined(rectangle)) {
result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = 0.0;
return result;
}
const positions = Rectangle.subsample(
rectangle,
ellipsoid,
surfaceHeight,
fromRectangle3DScratch
);
return BoundingSphere.fromPoints(positions, result);
};
/**
* Computes a tight-fitting bounding sphere enclosing a list of 3D points, where the points are
* stored in a flat array in X, Y, Z, order. The bounding sphere is computed by running two
* algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to
* ensure a tight fit.
*
* @param {Number[]} [positions] An array of points that the bounding sphere will enclose. Each point
* is formed from three elements in the array in the order X, Y, Z.
* @param {Cartesian3} [center=Cartesian3.ZERO] The position to which the positions are relative, which need not be the
* origin of the coordinate system. This is useful when the positions are to be used for
* relative-to-center (RTC) rendering.
* @param {Number} [stride=3] The number of array elements per vertex. It must be at least 3, but it may
* be higher. Regardless of the value of this parameter, the X coordinate of the first position
* is at array index 0, the Y coordinate is at array index 1, and the Z coordinate is at array index
* 2. When stride is 3, the X coordinate of the next position then begins at array index 3. If
* the stride is 5, however, two array elements are skipped and the next position begins at array
* index 5.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
*
* @example
* // Compute the bounding sphere from 3 positions, each specified relative to a center.
* // In addition to the X, Y, and Z coordinates, the points array contains two additional
* // elements per point which are ignored for the purpose of computing the bounding sphere.
* const center = new Cesium.Cartesian3(1.0, 2.0, 3.0);
* const points = [1.0, 2.0, 3.0, 0.1, 0.2,
* 4.0, 5.0, 6.0, 0.1, 0.2,
* 7.0, 8.0, 9.0, 0.1, 0.2];
* const sphere = Cesium.BoundingSphere.fromVertices(points, center, 5);
*
* @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article}
*/
BoundingSphere.fromVertices = function (positions, center, stride, result) {
if (!defined(result)) {
result = new BoundingSphere();
}
if (!defined(positions) || positions.length === 0) {
result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = 0.0;
return result;
}
center = defaultValue(center, Cartesian3.ZERO);
stride = defaultValue(stride, 3);
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("stride", stride, 3);
//>>includeEnd('debug');
const currentPos = fromPointsCurrentPos;
currentPos.x = positions[0] + center.x;
currentPos.y = positions[1] + center.y;
currentPos.z = positions[2] + center.z;
const xMin = Cartesian3.clone(currentPos, fromPointsXMin);
const yMin = Cartesian3.clone(currentPos, fromPointsYMin);
const zMin = Cartesian3.clone(currentPos, fromPointsZMin);
const xMax = Cartesian3.clone(currentPos, fromPointsXMax);
const yMax = Cartesian3.clone(currentPos, fromPointsYMax);
const zMax = Cartesian3.clone(currentPos, fromPointsZMax);
const numElements = positions.length;
let i;
for (i = 0; i < numElements; i += stride) {
const x = positions[i] + center.x;
const y = positions[i + 1] + center.y;
const z = positions[i + 2] + center.z;
currentPos.x = x;
currentPos.y = y;
currentPos.z = z;
// Store points containing the the smallest and largest components
if (x < xMin.x) {
Cartesian3.clone(currentPos, xMin);
}
if (x > xMax.x) {
Cartesian3.clone(currentPos, xMax);
}
if (y < yMin.y) {
Cartesian3.clone(currentPos, yMin);
}
if (y > yMax.y) {
Cartesian3.clone(currentPos, yMax);
}
if (z < zMin.z) {
Cartesian3.clone(currentPos, zMin);
}
if (z > zMax.z) {
Cartesian3.clone(currentPos, zMax);
}
}
// Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
const xSpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(xMax, xMin, fromPointsScratch)
);
const ySpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(yMax, yMin, fromPointsScratch)
);
const zSpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(zMax, zMin, fromPointsScratch)
);
// Set the diameter endpoints to the largest span.
let diameter1 = xMin;
let diameter2 = xMax;
let maxSpan = xSpan;
if (ySpan > maxSpan) {
maxSpan = ySpan;
diameter1 = yMin;
diameter2 = yMax;
}
if (zSpan > maxSpan) {
maxSpan = zSpan;
diameter1 = zMin;
diameter2 = zMax;
}
// Calculate the center of the initial sphere found by Ritter's algorithm
const ritterCenter = fromPointsRitterCenter;
ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
// Calculate the radius of the initial sphere found by Ritter's algorithm
let radiusSquared = Cartesian3.magnitudeSquared(
Cartesian3.subtract(diameter2, ritterCenter, fromPointsScratch)
);
let ritterRadius = Math.sqrt(radiusSquared);
// Find the center of the sphere found using the Naive method.
const minBoxPt = fromPointsMinBoxPt;
minBoxPt.x = xMin.x;
minBoxPt.y = yMin.y;
minBoxPt.z = zMin.z;
const maxBoxPt = fromPointsMaxBoxPt;
maxBoxPt.x = xMax.x;
maxBoxPt.y = yMax.y;
maxBoxPt.z = zMax.z;
const naiveCenter = Cartesian3.midpoint(
minBoxPt,
maxBoxPt,
fromPointsNaiveCenterScratch
);
// Begin 2nd pass to find naive radius and modify the ritter sphere.
let naiveRadius = 0;
for (i = 0; i < numElements; i += stride) {
currentPos.x = positions[i] + center.x;
currentPos.y = positions[i + 1] + center.y;
currentPos.z = positions[i + 2] + center.z;
// Find the furthest point from the naive center to calculate the naive radius.
const r = Cartesian3.magnitude(
Cartesian3.subtract(currentPos, naiveCenter, fromPointsScratch)
);
if (r > naiveRadius) {
naiveRadius = r;
}
// Make adjustments to the Ritter Sphere to include all points.
const oldCenterToPointSquared = Cartesian3.magnitudeSquared(
Cartesian3.subtract(currentPos, ritterCenter, fromPointsScratch)
);
if (oldCenterToPointSquared > radiusSquared) {
const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
// Calculate new radius to include the point that lies outside
ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
radiusSquared = ritterRadius * ritterRadius;
// Calculate center of new Ritter sphere
const oldToNew = oldCenterToPoint - ritterRadius;
ritterCenter.x =
(ritterRadius * ritterCenter.x + oldToNew * currentPos.x) /
oldCenterToPoint;
ritterCenter.y =
(ritterRadius * ritterCenter.y + oldToNew * currentPos.y) /
oldCenterToPoint;
ritterCenter.z =
(ritterRadius * ritterCenter.z + oldToNew * currentPos.z) /
oldCenterToPoint;
}
}
if (ritterRadius < naiveRadius) {
Cartesian3.clone(ritterCenter, result.center);
result.radius = ritterRadius;
} else {
Cartesian3.clone(naiveCenter, result.center);
result.radius = naiveRadius;
}
return result;
};
/**
* Computes a tight-fitting bounding sphere enclosing a list of EncodedCartesian3s, where the points are
* stored in parallel flat arrays in X, Y, Z, order. The bounding sphere is computed by running two
* algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to
* ensure a tight fit.
*
* @param {Number[]} [positionsHigh] An array of high bits of the encoded cartesians that the bounding sphere will enclose. Each point
* is formed from three elements in the array in the order X, Y, Z.
* @param {Number[]} [positionsLow] An array of low bits of the encoded cartesians that the bounding sphere will enclose. Each point
* is formed from three elements in the array in the order X, Y, Z.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
*
* @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article}
*/
BoundingSphere.fromEncodedCartesianVertices = function (
positionsHigh,
positionsLow,
result
) {
if (!defined(result)) {
result = new BoundingSphere();
}
if (
!defined(positionsHigh) ||
!defined(positionsLow) ||
positionsHigh.length !== positionsLow.length ||
positionsHigh.length === 0
) {
result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = 0.0;
return result;
}
const currentPos = fromPointsCurrentPos;
currentPos.x = positionsHigh[0] + positionsLow[0];
currentPos.y = positionsHigh[1] + positionsLow[1];
currentPos.z = positionsHigh[2] + positionsLow[2];
const xMin = Cartesian3.clone(currentPos, fromPointsXMin);
const yMin = Cartesian3.clone(currentPos, fromPointsYMin);
const zMin = Cartesian3.clone(currentPos, fromPointsZMin);
const xMax = Cartesian3.clone(currentPos, fromPointsXMax);
const yMax = Cartesian3.clone(currentPos, fromPointsYMax);
const zMax = Cartesian3.clone(currentPos, fromPointsZMax);
const numElements = positionsHigh.length;
let i;
for (i = 0; i < numElements; i += 3) {
const x = positionsHigh[i] + positionsLow[i];
const y = positionsHigh[i + 1] + positionsLow[i + 1];
const z = positionsHigh[i + 2] + positionsLow[i + 2];
currentPos.x = x;
currentPos.y = y;
currentPos.z = z;
// Store points containing the the smallest and largest components
if (x < xMin.x) {
Cartesian3.clone(currentPos, xMin);
}
if (x > xMax.x) {
Cartesian3.clone(currentPos, xMax);
}
if (y < yMin.y) {
Cartesian3.clone(currentPos, yMin);
}
if (y > yMax.y) {
Cartesian3.clone(currentPos, yMax);
}
if (z < zMin.z) {
Cartesian3.clone(currentPos, zMin);
}
if (z > zMax.z) {
Cartesian3.clone(currentPos, zMax);
}
}
// Compute x-, y-, and z-spans (Squared distances b/n each component's min. and max.).
const xSpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(xMax, xMin, fromPointsScratch)
);
const ySpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(yMax, yMin, fromPointsScratch)
);
const zSpan = Cartesian3.magnitudeSquared(
Cartesian3.subtract(zMax, zMin, fromPointsScratch)
);
// Set the diameter endpoints to the largest span.
let diameter1 = xMin;
let diameter2 = xMax;
let maxSpan = xSpan;
if (ySpan > maxSpan) {
maxSpan = ySpan;
diameter1 = yMin;
diameter2 = yMax;
}
if (zSpan > maxSpan) {
maxSpan = zSpan;
diameter1 = zMin;
diameter2 = zMax;
}
// Calculate the center of the initial sphere found by Ritter's algorithm
const ritterCenter = fromPointsRitterCenter;
ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
// Calculate the radius of the initial sphere found by Ritter's algorithm
let radiusSquared = Cartesian3.magnitudeSquared(
Cartesian3.subtract(diameter2, ritterCenter, fromPointsScratch)
);
let ritterRadius = Math.sqrt(radiusSquared);
// Find the center of the sphere found using the Naive method.
const minBoxPt = fromPointsMinBoxPt;
minBoxPt.x = xMin.x;
minBoxPt.y = yMin.y;
minBoxPt.z = zMin.z;
const maxBoxPt = fromPointsMaxBoxPt;
maxBoxPt.x = xMax.x;
maxBoxPt.y = yMax.y;
maxBoxPt.z = zMax.z;
const naiveCenter = Cartesian3.midpoint(
minBoxPt,
maxBoxPt,
fromPointsNaiveCenterScratch
);
// Begin 2nd pass to find naive radius and modify the ritter sphere.
let naiveRadius = 0;
for (i = 0; i < numElements; i += 3) {
currentPos.x = positionsHigh[i] + positionsLow[i];
currentPos.y = positionsHigh[i + 1] + positionsLow[i + 1];
currentPos.z = positionsHigh[i + 2] + positionsLow[i + 2];
// Find the furthest point from the naive center to calculate the naive radius.
const r = Cartesian3.magnitude(
Cartesian3.subtract(currentPos, naiveCenter, fromPointsScratch)
);
if (r > naiveRadius) {
naiveRadius = r;
}
// Make adjustments to the Ritter Sphere to include all points.
const oldCenterToPointSquared = Cartesian3.magnitudeSquared(
Cartesian3.subtract(currentPos, ritterCenter, fromPointsScratch)
);
if (oldCenterToPointSquared > radiusSquared) {
const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
// Calculate new radius to include the point that lies outside
ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
radiusSquared = ritterRadius * ritterRadius;
// Calculate center of new Ritter sphere
const oldToNew = oldCenterToPoint - ritterRadius;
ritterCenter.x =
(ritterRadius * ritterCenter.x + oldToNew * currentPos.x) /
oldCenterToPoint;
ritterCenter.y =
(ritterRadius * ritterCenter.y + oldToNew * currentPos.y) /
oldCenterToPoint;
ritterCenter.z =
(ritterRadius * ritterCenter.z + oldToNew * currentPos.z) /
oldCenterToPoint;
}
}
if (ritterRadius < naiveRadius) {
Cartesian3.clone(ritterCenter, result.center);
result.radius = ritterRadius;
} else {
Cartesian3.clone(naiveCenter, result.center);
result.radius = naiveRadius;
}
return result;
};
/**
* Computes a bounding sphere from the corner points of an axis-aligned bounding box. The sphere
* tighly and fully encompases the box.
*
* @param {Cartesian3} [corner] The minimum height over the rectangle.
* @param {Cartesian3} [oppositeCorner] The maximum height over the rectangle.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*
* @example
* // Create a bounding sphere around the unit cube
* const sphere = Cesium.BoundingSphere.fromCornerPoints(new Cesium.Cartesian3(-0.5, -0.5, -0.5), new Cesium.Cartesian3(0.5, 0.5, 0.5));
*/
BoundingSphere.fromCornerPoints = function (corner, oppositeCorner, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("corner", corner);
Check.typeOf.object("oppositeCorner", oppositeCorner);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
const center = Cartesian3.midpoint(corner, oppositeCorner, result.center);
result.radius = Cartesian3.distance(center, oppositeCorner);
return result;
};
/**
* Creates a bounding sphere encompassing an ellipsoid.
*
* @param {Ellipsoid} ellipsoid The ellipsoid around which to create a bounding sphere.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*
* @example
* const boundingSphere = Cesium.BoundingSphere.fromEllipsoid(ellipsoid);
*/
BoundingSphere.fromEllipsoid = function (ellipsoid, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("ellipsoid", ellipsoid);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = ellipsoid.maximumRadius;
return result;
};
const fromBoundingSpheresScratch = new Cartesian3();
/**
* Computes a tight-fitting bounding sphere enclosing the provided array of bounding spheres.
*
* @param {BoundingSphere[]} [boundingSpheres] The array of bounding spheres.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.fromBoundingSpheres = function (boundingSpheres, result) {
if (!defined(result)) {
result = new BoundingSphere();
}
if (!defined(boundingSpheres) || boundingSpheres.length === 0) {
result.center = Cartesian3.clone(Cartesian3.ZERO, result.center);
result.radius = 0.0;
return result;
}
const length = boundingSpheres.length;
if (length === 1) {
return BoundingSphere.clone(boundingSpheres[0], result);
}
if (length === 2) {
return BoundingSphere.union(boundingSpheres[0], boundingSpheres[1], result);
}
const positions = [];
let i;
for (i = 0; i < length; i++) {
positions.push(boundingSpheres[i].center);
}
result = BoundingSphere.fromPoints(positions, result);
const center = result.center;
let radius = result.radius;
for (i = 0; i < length; i++) {
const tmp = boundingSpheres[i];
radius = Math.max(
radius,
Cartesian3.distance(center, tmp.center, fromBoundingSpheresScratch) +
tmp.radius
);
}
result.radius = radius;
return result;
};
const fromOrientedBoundingBoxScratchU = new Cartesian3();
const fromOrientedBoundingBoxScratchV = new Cartesian3();
const fromOrientedBoundingBoxScratchW = new Cartesian3();
/**
* Computes a tight-fitting bounding sphere enclosing the provided oriented bounding box.
*
* @param {OrientedBoundingBox} orientedBoundingBox The oriented bounding box.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.fromOrientedBoundingBox = function (
orientedBoundingBox,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("orientedBoundingBox", orientedBoundingBox);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
const halfAxes = orientedBoundingBox.halfAxes;
const u = Matrix3.getColumn(halfAxes, 0, fromOrientedBoundingBoxScratchU);
const v = Matrix3.getColumn(halfAxes, 1, fromOrientedBoundingBoxScratchV);
const w = Matrix3.getColumn(halfAxes, 2, fromOrientedBoundingBoxScratchW);
Cartesian3.add(u, v, u);
Cartesian3.add(u, w, u);
result.center = Cartesian3.clone(orientedBoundingBox.center, result.center);
result.radius = Cartesian3.magnitude(u);
return result;
};
const scratchFromTransformationCenter = new Cartesian3();
const scratchFromTransformationScale = new Cartesian3();
/**
* Computes a tight-fitting bounding sphere enclosing the provided affine transformation.
*
* @param {Matrix4} transformation The affine transformation.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.fromTransformation = function (transformation, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("transformation", transformation);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
const center = Matrix4.getTranslation(
transformation,
scratchFromTransformationCenter
);
const scale = Matrix4.getScale(
transformation,
scratchFromTransformationScale
);
const radius = 0.5 * Cartesian3.magnitude(scale);
result.center = Cartesian3.clone(center, result.center);
result.radius = radius;
return result;
};
/**
* Duplicates a BoundingSphere instance.
*
* @param {BoundingSphere} sphere The bounding sphere to duplicate.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. (Returns undefined if sphere is undefined)
*/
BoundingSphere.clone = function (sphere, result) {
if (!defined(sphere)) {
return undefined;
}
if (!defined(result)) {
return new BoundingSphere(sphere.center, sphere.radius);
}
result.center = Cartesian3.clone(sphere.center, result.center);
result.radius = sphere.radius;
return result;
};
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
BoundingSphere.packedLength = 4;
/**
* Stores the provided instance into the provided array.
*
* @param {BoundingSphere} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
BoundingSphere.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
const center = value.center;
array[startingIndex++] = center.x;
array[startingIndex++] = center.y;
array[startingIndex++] = center.z;
array[startingIndex] = value.radius;
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {BoundingSphere} [result] The object into which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided.
*/
BoundingSphere.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new BoundingSphere();
}
const center = result.center;
center.x = array[startingIndex++];
center.y = array[startingIndex++];
center.z = array[startingIndex++];
result.radius = array[startingIndex];
return result;
};
const unionScratch = new Cartesian3();
const unionScratchCenter = new Cartesian3();
/**
* Computes a bounding sphere that contains both the left and right bounding spheres.
*
* @param {BoundingSphere} left A sphere to enclose in a bounding sphere.
* @param {BoundingSphere} right A sphere to enclose in a bounding sphere.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.union = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
const leftCenter = left.center;
const leftRadius = left.radius;
const rightCenter = right.center;
const rightRadius = right.radius;
const toRightCenter = Cartesian3.subtract(
rightCenter,
leftCenter,
unionScratch
);
const centerSeparation = Cartesian3.magnitude(toRightCenter);
if (leftRadius >= centerSeparation + rightRadius) {
// Left sphere wins.
left.clone(result);
return result;
}
if (rightRadius >= centerSeparation + leftRadius) {
// Right sphere wins.
right.clone(result);
return result;
}
// There are two tangent points, one on far side of each sphere.
const halfDistanceBetweenTangentPoints =
(leftRadius + centerSeparation + rightRadius) * 0.5;
// Compute the center point halfway between the two tangent points.
const center = Cartesian3.multiplyByScalar(
toRightCenter,
(-leftRadius + halfDistanceBetweenTangentPoints) / centerSeparation,
unionScratchCenter
);
Cartesian3.add(center, leftCenter, center);
Cartesian3.clone(center, result.center);
result.radius = halfDistanceBetweenTangentPoints;
return result;
};
const expandScratch = new Cartesian3();
/**
* Computes a bounding sphere by enlarging the provided sphere to contain the provided point.
*
* @param {BoundingSphere} sphere A sphere to expand.
* @param {Cartesian3} point A point to enclose in a bounding sphere.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.expand = function (sphere, point, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("point", point);
//>>includeEnd('debug');
result = BoundingSphere.clone(sphere, result);
const radius = Cartesian3.magnitude(
Cartesian3.subtract(point, result.center, expandScratch)
);
if (radius > result.radius) {
result.radius = radius;
}
return result;
};
/**
* Determines which side of a plane a sphere is located.
*
* @param {BoundingSphere} sphere The bounding sphere to test.
* @param {Plane} plane The plane to test against.
* @returns {Intersect} {@link Intersect.INSIDE} if the entire sphere is on the side of the plane
* the normal is pointing, {@link Intersect.OUTSIDE} if the entire sphere is
* on the opposite side, and {@link Intersect.INTERSECTING} if the sphere
* intersects the plane.
*/
BoundingSphere.intersectPlane = function (sphere, plane) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("plane", plane);
//>>includeEnd('debug');
const center = sphere.center;
const radius = sphere.radius;
const normal = plane.normal;
const distanceToPlane = Cartesian3.dot(normal, center) + plane.distance;
if (distanceToPlane < -radius) {
// The center point is negative side of the plane normal
return Intersect$1.OUTSIDE;
} else if (distanceToPlane < radius) {
// The center point is positive side of the plane, but radius extends beyond it; partial overlap
return Intersect$1.INTERSECTING;
}
return Intersect$1.INSIDE;
};
/**
* Applies a 4x4 affine transformation matrix to a bounding sphere.
*
* @param {BoundingSphere} sphere The bounding sphere to apply the transformation to.
* @param {Matrix4} transform The transformation matrix to apply to the bounding sphere.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.transform = function (sphere, transform, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("transform", transform);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
result.center = Matrix4.multiplyByPoint(
transform,
sphere.center,
result.center
);
result.radius = Matrix4.getMaximumScale(transform) * sphere.radius;
return result;
};
const distanceSquaredToScratch = new Cartesian3();
/**
* Computes the estimated distance squared from the closest point on a bounding sphere to a point.
*
* @param {BoundingSphere} sphere The sphere.
* @param {Cartesian3} cartesian The point
* @returns {Number} The distance squared from the bounding sphere to the point. Returns 0 if the point is inside the sphere.
*
* @example
* // Sort bounding spheres from back to front
* spheres.sort(function(a, b) {
* return Cesium.BoundingSphere.distanceSquaredTo(b, camera.positionWC) - Cesium.BoundingSphere.distanceSquaredTo(a, camera.positionWC);
* });
*/
BoundingSphere.distanceSquaredTo = function (sphere, cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
const diff = Cartesian3.subtract(
sphere.center,
cartesian,
distanceSquaredToScratch
);
const distance = Cartesian3.magnitude(diff) - sphere.radius;
if (distance <= 0.0) {
return 0.0;
}
return distance * distance;
};
/**
* Applies a 4x4 affine transformation matrix to a bounding sphere where there is no scale
* The transformation matrix is not verified to have a uniform scale of 1.
* This method is faster than computing the general bounding sphere transform using {@link BoundingSphere.transform}.
*
* @param {BoundingSphere} sphere The bounding sphere to apply the transformation to.
* @param {Matrix4} transform The transformation matrix to apply to the bounding sphere.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*
* @example
* const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid);
* const boundingSphere = new Cesium.BoundingSphere();
* const newBoundingSphere = Cesium.BoundingSphere.transformWithoutScale(boundingSphere, modelMatrix);
*/
BoundingSphere.transformWithoutScale = function (sphere, transform, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("transform", transform);
//>>includeEnd('debug');
if (!defined(result)) {
result = new BoundingSphere();
}
result.center = Matrix4.multiplyByPoint(
transform,
sphere.center,
result.center
);
result.radius = sphere.radius;
return result;
};
const scratchCartesian3$d = new Cartesian3();
/**
* The distances calculated by the vector from the center of the bounding sphere to position projected onto direction
* plus/minus the radius of the bounding sphere.
*
* If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
* closest and farthest planes from position that intersect the bounding sphere.
*
* @param {BoundingSphere} sphere The bounding sphere to calculate the distance to.
* @param {Cartesian3} position The position to calculate the distance from.
* @param {Cartesian3} direction The direction from position.
* @param {Interval} [result] A Interval to store the nearest and farthest distances.
* @returns {Interval} The nearest and farthest distances on the bounding sphere from position in direction.
*/
BoundingSphere.computePlaneDistances = function (
sphere,
position,
direction,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("position", position);
Check.typeOf.object("direction", direction);
//>>includeEnd('debug');
if (!defined(result)) {
result = new Interval();
}
const toCenter = Cartesian3.subtract(
sphere.center,
position,
scratchCartesian3$d
);
const mag = Cartesian3.dot(direction, toCenter);
result.start = mag - sphere.radius;
result.stop = mag + sphere.radius;
return result;
};
const projectTo2DNormalScratch = new Cartesian3();
const projectTo2DEastScratch = new Cartesian3();
const projectTo2DNorthScratch = new Cartesian3();
const projectTo2DWestScratch = new Cartesian3();
const projectTo2DSouthScratch = new Cartesian3();
const projectTo2DCartographicScratch = new Cartographic();
const projectTo2DPositionsScratch = new Array(8);
for (let n = 0; n < 8; ++n) {
projectTo2DPositionsScratch[n] = new Cartesian3();
}
const projectTo2DProjection = new GeographicProjection();
/**
* Creates a bounding sphere in 2D from a bounding sphere in 3D world coordinates.
*
* @param {BoundingSphere} sphere The bounding sphere to transform to 2D.
* @param {Object} [projection=GeographicProjection] The projection to 2D.
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.projectTo2D = function (sphere, projection, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
//>>includeEnd('debug');
projection = defaultValue(projection, projectTo2DProjection);
const ellipsoid = projection.ellipsoid;
let center = sphere.center;
const radius = sphere.radius;
let normal;
if (Cartesian3.equals(center, Cartesian3.ZERO)) {
// Bounding sphere is at the center. The geodetic surface normal is not
// defined here so pick the x-axis as a fallback.
normal = Cartesian3.clone(Cartesian3.UNIT_X, projectTo2DNormalScratch);
} else {
normal = ellipsoid.geodeticSurfaceNormal(center, projectTo2DNormalScratch);
}
const east = Cartesian3.cross(
Cartesian3.UNIT_Z,
normal,
projectTo2DEastScratch
);
Cartesian3.normalize(east, east);
const north = Cartesian3.cross(normal, east, projectTo2DNorthScratch);
Cartesian3.normalize(north, north);
Cartesian3.multiplyByScalar(normal, radius, normal);
Cartesian3.multiplyByScalar(north, radius, north);
Cartesian3.multiplyByScalar(east, radius, east);
const south = Cartesian3.negate(north, projectTo2DSouthScratch);
const west = Cartesian3.negate(east, projectTo2DWestScratch);
const positions = projectTo2DPositionsScratch;
// top NE corner
let corner = positions[0];
Cartesian3.add(normal, north, corner);
Cartesian3.add(corner, east, corner);
// top NW corner
corner = positions[1];
Cartesian3.add(normal, north, corner);
Cartesian3.add(corner, west, corner);
// top SW corner
corner = positions[2];
Cartesian3.add(normal, south, corner);
Cartesian3.add(corner, west, corner);
// top SE corner
corner = positions[3];
Cartesian3.add(normal, south, corner);
Cartesian3.add(corner, east, corner);
Cartesian3.negate(normal, normal);
// bottom NE corner
corner = positions[4];
Cartesian3.add(normal, north, corner);
Cartesian3.add(corner, east, corner);
// bottom NW corner
corner = positions[5];
Cartesian3.add(normal, north, corner);
Cartesian3.add(corner, west, corner);
// bottom SW corner
corner = positions[6];
Cartesian3.add(normal, south, corner);
Cartesian3.add(corner, west, corner);
// bottom SE corner
corner = positions[7];
Cartesian3.add(normal, south, corner);
Cartesian3.add(corner, east, corner);
const length = positions.length;
for (let i = 0; i < length; ++i) {
const position = positions[i];
Cartesian3.add(center, position, position);
const cartographic = ellipsoid.cartesianToCartographic(
position,
projectTo2DCartographicScratch
);
projection.project(cartographic, position);
}
result = BoundingSphere.fromPoints(positions, result);
// swizzle center components
center = result.center;
const x = center.x;
const y = center.y;
const z = center.z;
center.x = z;
center.y = x;
center.z = y;
return result;
};
/**
* Determines whether or not a sphere is hidden from view by the occluder.
*
* @param {BoundingSphere} sphere The bounding sphere surrounding the occludee object.
* @param {Occluder} occluder The occluder.
* @returns {Boolean} true
if the sphere is not visible; otherwise false
.
*/
BoundingSphere.isOccluded = function (sphere, occluder) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("sphere", sphere);
Check.typeOf.object("occluder", occluder);
//>>includeEnd('debug');
return !occluder.isBoundingSphereVisible(sphere);
};
/**
* Compares the provided BoundingSphere componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {BoundingSphere} [left] The first BoundingSphere.
* @param {BoundingSphere} [right] The second BoundingSphere.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
BoundingSphere.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
Cartesian3.equals(left.center, right.center) &&
left.radius === right.radius)
);
};
/**
* Determines which side of a plane the sphere is located.
*
* @param {Plane} plane The plane to test against.
* @returns {Intersect} {@link Intersect.INSIDE} if the entire sphere is on the side of the plane
* the normal is pointing, {@link Intersect.OUTSIDE} if the entire sphere is
* on the opposite side, and {@link Intersect.INTERSECTING} if the sphere
* intersects the plane.
*/
BoundingSphere.prototype.intersectPlane = function (plane) {
return BoundingSphere.intersectPlane(this, plane);
};
/**
* Computes the estimated distance squared from the closest point on a bounding sphere to a point.
*
* @param {Cartesian3} cartesian The point
* @returns {Number} The estimated distance squared from the bounding sphere to the point.
*
* @example
* // Sort bounding spheres from back to front
* spheres.sort(function(a, b) {
* return b.distanceSquaredTo(camera.positionWC) - a.distanceSquaredTo(camera.positionWC);
* });
*/
BoundingSphere.prototype.distanceSquaredTo = function (cartesian) {
return BoundingSphere.distanceSquaredTo(this, cartesian);
};
/**
* The distances calculated by the vector from the center of the bounding sphere to position projected onto direction
* plus/minus the radius of the bounding sphere.
*
* If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the
* closest and farthest planes from position that intersect the bounding sphere.
*
* @param {Cartesian3} position The position to calculate the distance from.
* @param {Cartesian3} direction The direction from position.
* @param {Interval} [result] A Interval to store the nearest and farthest distances.
* @returns {Interval} The nearest and farthest distances on the bounding sphere from position in direction.
*/
BoundingSphere.prototype.computePlaneDistances = function (
position,
direction,
result
) {
return BoundingSphere.computePlaneDistances(
this,
position,
direction,
result
);
};
/**
* Determines whether or not a sphere is hidden from view by the occluder.
*
* @param {Occluder} occluder The occluder.
* @returns {Boolean} true
if the sphere is not visible; otherwise false
.
*/
BoundingSphere.prototype.isOccluded = function (occluder) {
return BoundingSphere.isOccluded(this, occluder);
};
/**
* Compares this BoundingSphere against the provided BoundingSphere componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {BoundingSphere} [right] The right hand side BoundingSphere.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
BoundingSphere.prototype.equals = function (right) {
return BoundingSphere.equals(this, right);
};
/**
* Duplicates this BoundingSphere instance.
*
* @param {BoundingSphere} [result] The object onto which to store the result.
* @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided.
*/
BoundingSphere.prototype.clone = function (result) {
return BoundingSphere.clone(this, result);
};
/**
* Computes the radius of the BoundingSphere.
* @returns {Number} The radius of the BoundingSphere.
*/
BoundingSphere.prototype.volume = function () {
const radius = this.radius;
return volumeConstant * radius * radius * radius;
};
/* This file is automatically rebuilt by the Cesium build process. */
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, basedir, module) {
return module = {
path: basedir,
exports: {},
require: function (path, base) {
return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
}
}, fn(module, module.exports), module.exports;
}
function commonjsRequire () {
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
}
/* This file is automatically rebuilt by the Cesium build process. */
var punycode = createCommonjsModule(function (module, exports) {
(function(root) {
/** Detect free variables */
var freeExports = exports &&
!exports.nodeType && exports;
var freeModule = module &&
!module.nodeType && module;
var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal;
if (
freeGlobal.global === freeGlobal ||
freeGlobal.window === freeGlobal ||
freeGlobal.self === freeGlobal
) {
root = freeGlobal;
}
/**
* The `punycode` object.
* @name punycode
* @type Object
*/
var punycode,
/** Highest positive signed 32-bit float value */
maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
/** Bootstring parameters */
base = 36,
tMin = 1,
tMax = 26,
skew = 38,
damp = 700,
initialBias = 72,
initialN = 128, // 0x80
delimiter = '-', // '\x2D'
/** Regular expressions */
regexPunycode = /^xn--/,
regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
/** Error messages */
errors = {
'overflow': 'Overflow: input needs wider integers to process',
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
'invalid-input': 'Invalid input'
},
/** Convenience shortcuts */
baseMinusTMin = base - tMin,
floor = Math.floor,
stringFromCharCode = String.fromCharCode,
/** Temporary variable */
key;
/*--------------------------------------------------------------------------*/
/**
* A generic error utility function.
* @private
* @param {String} type The error type.
* @returns {Error} Throws a `RangeError` with the applicable error message.
*/
function error(type) {
throw new RangeError(errors[type]);
}
/**
* A generic `Array#map` utility function.
* @private
* @param {Array} array The array to iterate over.
* @param {Function} callback The function that gets called for every array
* item.
* @returns {Array} A new array of values returned by the callback function.
*/
function map(array, fn) {
var length = array.length;
var result = [];
while (length--) {
result[length] = fn(array[length]);
}
return result;
}
/**
* A simple `Array#map`-like wrapper to work with domain name strings or email
* addresses.
* @private
* @param {String} domain The domain name or email address.
* @param {Function} callback The function that gets called for every
* character.
* @returns {Array} A new string of characters returned by the callback
* function.
*/
function mapDomain(string, fn) {
var parts = string.split('@');
var result = '';
if (parts.length > 1) {
// In email addresses, only the domain name should be punycoded. Leave
// the local part (i.e. everything up to `@`) intact.
result = parts[0] + '@';
string = parts[1];
}
// Avoid `split(regex)` for IE8 compatibility. See #17.
string = string.replace(regexSeparators, '\x2E');
var labels = string.split('.');
var encoded = map(labels, fn).join('.');
return result + encoded;
}
/**
* Creates an array containing the numeric code points of each Unicode
* character in the string. While JavaScript uses UCS-2 internally,
* this function will convert a pair of surrogate halves (each of which
* UCS-2 exposes as separate characters) into a single code point,
* matching UTF-16.
* @see `punycode.ucs2.encode`
* @see
* @memberOf punycode.ucs2
* @name decode
* @param {String} string The Unicode input string (UCS-2).
* @returns {Array} The new array of code points.
*/
function ucs2decode(string) {
var output = [],
counter = 0,
length = string.length,
value,
extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
// high surrogate, and there is a next character
extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
} else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
output.push(value);
counter--;
}
} else {
output.push(value);
}
}
return output;
}
/**
* Creates a string based on an array of numeric code points.
* @see `punycode.ucs2.decode`
* @memberOf punycode.ucs2
* @name encode
* @param {Array} codePoints The array of numeric code points.
* @returns {String} The new Unicode string (UCS-2).
*/
function ucs2encode(array) {
return map(array, function(value) {
var output = '';
if (value > 0xFFFF) {
value -= 0x10000;
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
value = 0xDC00 | value & 0x3FF;
}
output += stringFromCharCode(value);
return output;
}).join('');
}
/**
* Converts a basic code point into a digit/integer.
* @see `digitToBasic()`
* @private
* @param {Number} codePoint The basic numeric code point value.
* @returns {Number} The numeric value of a basic code point (for use in
* representing integers) in the range `0` to `base - 1`, or `base` if
* the code point does not represent a value.
*/
function basicToDigit(codePoint) {
if (codePoint - 48 < 10) {
return codePoint - 22;
}
if (codePoint - 65 < 26) {
return codePoint - 65;
}
if (codePoint - 97 < 26) {
return codePoint - 97;
}
return base;
}
/**
* Converts a digit/integer into a basic code point.
* @see `basicToDigit()`
* @private
* @param {Number} digit The numeric value of a basic code point.
* @returns {Number} The basic code point whose value (when used for
* representing integers) is `digit`, which needs to be in the range
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
* used; else, the lowercase form is used. The behavior is undefined
* if `flag` is non-zero and `digit` has no uppercase form.
*/
function digitToBasic(digit, flag) {
// 0..25 map to ASCII a..z or A..Z
// 26..35 map to ASCII 0..9
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
}
/**
* Bias adaptation function as per section 3.4 of RFC 3492.
* https://tools.ietf.org/html/rfc3492#section-3.4
* @private
*/
function adapt(delta, numPoints, firstTime) {
var k = 0;
delta = firstTime ? floor(delta / damp) : delta >> 1;
delta += floor(delta / numPoints);
for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
delta = floor(delta / baseMinusTMin);
}
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
}
/**
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
* symbols.
* @memberOf punycode
* @param {String} input The Punycode string of ASCII-only symbols.
* @returns {String} The resulting string of Unicode symbols.
*/
function decode(input) {
// Don't use UCS-2
var output = [],
inputLength = input.length,
out,
i = 0,
n = initialN,
bias = initialBias,
basic,
j,
index,
oldi,
w,
k,
digit,
t,
/** Cached calculation results */
baseMinusT;
// Handle the basic code points: let `basic` be the number of input code
// points before the last delimiter, or `0` if there is none, then copy
// the first basic code points to the output.
basic = input.lastIndexOf(delimiter);
if (basic < 0) {
basic = 0;
}
for (j = 0; j < basic; ++j) {
// if it's not a basic code point
if (input.charCodeAt(j) >= 0x80) {
error('not-basic');
}
output.push(input.charCodeAt(j));
}
// Main decoding loop: start just after the last delimiter if any basic code
// points were copied; start at the beginning otherwise.
for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
// `index` is the index of the next character to be consumed.
// Decode a generalized variable-length integer into `delta`,
// which gets added to `i`. The overflow checking is easier
// if we increase `i` as we go, then subtract off its starting
// value at the end to obtain `delta`.
for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
if (index >= inputLength) {
error('invalid-input');
}
digit = basicToDigit(input.charCodeAt(index++));
if (digit >= base || digit > floor((maxInt - i) / w)) {
error('overflow');
}
i += digit * w;
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
if (digit < t) {
break;
}
baseMinusT = base - t;
if (w > floor(maxInt / baseMinusT)) {
error('overflow');
}
w *= baseMinusT;
}
out = output.length + 1;
bias = adapt(i - oldi, out, oldi == 0);
// `i` was supposed to wrap around from `out` to `0`,
// incrementing `n` each time, so we'll fix that now:
if (floor(i / out) > maxInt - n) {
error('overflow');
}
n += floor(i / out);
i %= out;
// Insert `n` at position `i` of the output
output.splice(i++, 0, n);
}
return ucs2encode(output);
}
/**
* Converts a string of Unicode symbols (e.g. a domain name label) to a
* Punycode string of ASCII-only symbols.
* @memberOf punycode
* @param {String} input The string of Unicode symbols.
* @returns {String} The resulting Punycode string of ASCII-only symbols.
*/
function encode(input) {
var n,
delta,
handledCPCount,
basicLength,
bias,
j,
m,
q,
k,
t,
currentValue,
output = [],
/** `inputLength` will hold the number of code points in `input`. */
inputLength,
/** Cached calculation results */
handledCPCountPlusOne,
baseMinusT,
qMinusT;
// Convert the input in UCS-2 to Unicode
input = ucs2decode(input);
// Cache the length
inputLength = input.length;
// Initialize the state
n = initialN;
delta = 0;
bias = initialBias;
// Handle the basic code points
for (j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue < 0x80) {
output.push(stringFromCharCode(currentValue));
}
}
handledCPCount = basicLength = output.length;
// `handledCPCount` is the number of code points that have been handled;
// `basicLength` is the number of basic code points.
// Finish the basic string - if it is not empty - with a delimiter
if (basicLength) {
output.push(delimiter);
}
// Main encoding loop:
while (handledCPCount < inputLength) {
// All non-basic code points < n have been handled already. Find the next
// larger one:
for (m = maxInt, j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue >= n && currentValue < m) {
m = currentValue;
}
}
// Increase `delta` enough to advance the decoder's state to ,
// but guard against overflow
handledCPCountPlusOne = handledCPCount + 1;
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
error('overflow');
}
delta += (m - n) * handledCPCountPlusOne;
n = m;
for (j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue < n && ++delta > maxInt) {
error('overflow');
}
if (currentValue == n) {
// Represent delta as a generalized variable-length integer
for (q = delta, k = base; /* no condition */; k += base) {
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
if (q < t) {
break;
}
qMinusT = q - t;
baseMinusT = base - t;
output.push(
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
);
q = floor(qMinusT / baseMinusT);
}
output.push(stringFromCharCode(digitToBasic(q, 0)));
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
delta = 0;
++handledCPCount;
}
}
++delta;
++n;
}
return output.join('');
}
/**
* Converts a Punycode string representing a domain name or an email address
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
* it doesn't matter if you call it on a string that has already been
* converted to Unicode.
* @memberOf punycode
* @param {String} input The Punycoded domain name or email address to
* convert to Unicode.
* @returns {String} The Unicode representation of the given Punycode
* string.
*/
function toUnicode(input) {
return mapDomain(input, function(string) {
return regexPunycode.test(string)
? decode(string.slice(4).toLowerCase())
: string;
});
}
/**
* Converts a Unicode string representing a domain name or an email address to
* Punycode. Only the non-ASCII parts of the domain name will be converted,
* i.e. it doesn't matter if you call it with a domain that's already in
* ASCII.
* @memberOf punycode
* @param {String} input The domain name or email address to convert, as a
* Unicode string.
* @returns {String} The Punycode representation of the given domain name or
* email address.
*/
function toASCII(input) {
return mapDomain(input, function(string) {
return regexNonASCII.test(string)
? 'xn--' + encode(string)
: string;
});
}
/*--------------------------------------------------------------------------*/
/** Define the public API */
punycode = {
/**
* A string representing the current Punycode.js version number.
* @memberOf punycode
* @type String
*/
'version': '1.3.2',
/**
* An object of methods to convert from JavaScript's internal character
* representation (UCS-2) to Unicode code points, and back.
* @see
* @memberOf punycode
* @type Object
*/
'ucs2': {
'decode': ucs2decode,
'encode': ucs2encode
},
'decode': decode,
'encode': encode,
'toASCII': toASCII,
'toUnicode': toUnicode
};
/** Expose `punycode` */
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (freeExports && freeModule) {
if (module.exports == freeExports) {
// in Node.js, io.js, or RingoJS v0.8.0+
freeModule.exports = punycode;
} else {
// in Narwhal or RingoJS v0.7.0-
for (key in punycode) {
punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
}
}
} else {
// in Rhino or a web browser
root.punycode = punycode;
}
}(commonjsGlobal));
});
var IPv6 = createCommonjsModule(function (module) {
/*!
* URI.js - Mutating URLs
* IPv6 Support
*
* Version: 1.19.8
*
* Author: Rodney Rehm
* Web: http://medialize.github.io/URI.js/
*
* Licensed under
* MIT License http://www.opensource.org/licenses/mit-license
*
*/
(function (root, factory) {
// https://github.com/umdjs/umd/blob/master/returnExports.js
if (module.exports) {
// Node
module.exports = factory();
} else {
// Browser globals (root is window)
root.IPv6 = factory(root);
}
}(commonjsGlobal, function (root) {
/*
var _in = "fe80:0000:0000:0000:0204:61ff:fe9d:f156";
var _out = IPv6.best(_in);
var _expected = "fe80::204:61ff:fe9d:f156";
console.log(_in, _out, _expected, _out === _expected);
*/
// save current IPv6 variable, if any
var _IPv6 = root && root.IPv6;
function bestPresentation(address) {
// based on:
// Javascript to test an IPv6 address for proper format, and to
// present the "best text representation" according to IETF Draft RFC at
// http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04
// 8 Feb 2010 Rich Brown, Dartware, LLC
// Please feel free to use this code as long as you provide a link to
// http://www.intermapper.com
// http://intermapper.com/support/tools/IPV6-Validator.aspx
// http://download.dartware.com/thirdparty/ipv6validator.js
var _address = address.toLowerCase();
var segments = _address.split(':');
var length = segments.length;
var total = 8;
// trim colons (:: or ::a:b:c… or …a:b:c::)
if (segments[0] === '' && segments[1] === '' && segments[2] === '') {
// must have been ::
// remove first two items
segments.shift();
segments.shift();
} else if (segments[0] === '' && segments[1] === '') {
// must have been ::xxxx
// remove the first item
segments.shift();
} else if (segments[length - 1] === '' && segments[length - 2] === '') {
// must have been xxxx::
segments.pop();
}
length = segments.length;
// adjust total segments for IPv4 trailer
if (segments[length - 1].indexOf('.') !== -1) {
// found a "." which means IPv4
total = 7;
}
// fill empty segments them with "0000"
var pos;
for (pos = 0; pos < length; pos++) {
if (segments[pos] === '') {
break;
}
}
if (pos < total) {
segments.splice(pos, 1, '0000');
while (segments.length < total) {
segments.splice(pos, 0, '0000');
}
}
// strip leading zeros
var _segments;
for (var i = 0; i < total; i++) {
_segments = segments[i].split('');
for (var j = 0; j < 3 ; j++) {
if (_segments[0] === '0' && _segments.length > 1) {
_segments.splice(0,1);
} else {
break;
}
}
segments[i] = _segments.join('');
}
// find longest sequence of zeroes and coalesce them into one segment
var best = -1;
var _best = 0;
var _current = 0;
var current = -1;
var inzeroes = false;
// i; already declared
for (i = 0; i < total; i++) {
if (inzeroes) {
if (segments[i] === '0') {
_current += 1;
} else {
inzeroes = false;
if (_current > _best) {
best = current;
_best = _current;
}
}
} else {
if (segments[i] === '0') {
inzeroes = true;
current = i;
_current = 1;
}
}
}
if (_current > _best) {
best = current;
_best = _current;
}
if (_best > 1) {
segments.splice(best, _best, '');
}
length = segments.length;
// assemble remaining segments
var result = '';
if (segments[0] === '') {
result = ':';
}
for (i = 0; i < length; i++) {
result += segments[i];
if (i === length - 1) {
break;
}
result += ':';
}
if (segments[length - 1] === '') {
result += ':';
}
return result;
}
function noConflict() {
/*jshint validthis: true */
if (root.IPv6 === this) {
root.IPv6 = _IPv6;
}
return this;
}
return {
best: bestPresentation,
noConflict: noConflict
};
}));
});
var SecondLevelDomains = createCommonjsModule(function (module) {
/*!
* URI.js - Mutating URLs
* Second Level Domain (SLD) Support
*
* Version: 1.19.8
*
* Author: Rodney Rehm
* Web: http://medialize.github.io/URI.js/
*
* Licensed under
* MIT License http://www.opensource.org/licenses/mit-license
*
*/
(function (root, factory) {
// https://github.com/umdjs/umd/blob/master/returnExports.js
if (module.exports) {
// Node
module.exports = factory();
} else {
// Browser globals (root is window)
root.SecondLevelDomains = factory(root);
}
}(commonjsGlobal, function (root) {
// save current SecondLevelDomains variable, if any
var _SecondLevelDomains = root && root.SecondLevelDomains;
var SLD = {
// list of known Second Level Domains
// converted list of SLDs from https://github.com/gavingmiller/second-level-domains
// ----
// publicsuffix.org is more current and actually used by a couple of browsers internally.
// downside is it also contains domains like "dyndns.org" - which is fine for the security
// issues browser have to deal with (SOP for cookies, etc) - but is way overboard for URI.js
// ----
list: {
'ac':' com gov mil net org ',
'ae':' ac co gov mil name net org pro sch ',
'af':' com edu gov net org ',
'al':' com edu gov mil net org ',
'ao':' co ed gv it og pb ',
'ar':' com edu gob gov int mil net org tur ',
'at':' ac co gv or ',
'au':' asn com csiro edu gov id net org ',
'ba':' co com edu gov mil net org rs unbi unmo unsa untz unze ',
'bb':' biz co com edu gov info net org store tv ',
'bh':' biz cc com edu gov info net org ',
'bn':' com edu gov net org ',
'bo':' com edu gob gov int mil net org tv ',
'br':' adm adv agr am arq art ato b bio blog bmd cim cng cnt com coop ecn edu eng esp etc eti far flog fm fnd fot fst g12 ggf gov imb ind inf jor jus lel mat med mil mus net nom not ntr odo org ppg pro psc psi qsl rec slg srv tmp trd tur tv vet vlog wiki zlg ',
'bs':' com edu gov net org ',
'bz':' du et om ov rg ',
'ca':' ab bc mb nb nf nl ns nt nu on pe qc sk yk ',
'ck':' biz co edu gen gov info net org ',
'cn':' ac ah bj com cq edu fj gd gov gs gx gz ha hb he hi hl hn jl js jx ln mil net nm nx org qh sc sd sh sn sx tj tw xj xz yn zj ',
'co':' com edu gov mil net nom org ',
'cr':' ac c co ed fi go or sa ',
'cy':' ac biz com ekloges gov ltd name net org parliament press pro tm ',
'do':' art com edu gob gov mil net org sld web ',
'dz':' art asso com edu gov net org pol ',
'ec':' com edu fin gov info med mil net org pro ',
'eg':' com edu eun gov mil name net org sci ',
'er':' com edu gov ind mil net org rochest w ',
'es':' com edu gob nom org ',
'et':' biz com edu gov info name net org ',
'fj':' ac biz com info mil name net org pro ',
'fk':' ac co gov net nom org ',
'fr':' asso com f gouv nom prd presse tm ',
'gg':' co net org ',
'gh':' com edu gov mil org ',
'gn':' ac com gov net org ',
'gr':' com edu gov mil net org ',
'gt':' com edu gob ind mil net org ',
'gu':' com edu gov net org ',
'hk':' com edu gov idv net org ',
'hu':' 2000 agrar bolt casino city co erotica erotika film forum games hotel info ingatlan jogasz konyvelo lakas media news org priv reklam sex shop sport suli szex tm tozsde utazas video ',
'id':' ac co go mil net or sch web ',
'il':' ac co gov idf k12 muni net org ',
'in':' ac co edu ernet firm gen gov i ind mil net nic org res ',
'iq':' com edu gov i mil net org ',
'ir':' ac co dnssec gov i id net org sch ',
'it':' edu gov ',
'je':' co net org ',
'jo':' com edu gov mil name net org sch ',
'jp':' ac ad co ed go gr lg ne or ',
'ke':' ac co go info me mobi ne or sc ',
'kh':' com edu gov mil net org per ',
'ki':' biz com de edu gov info mob net org tel ',
'km':' asso com coop edu gouv k medecin mil nom notaires pharmaciens presse tm veterinaire ',
'kn':' edu gov net org ',
'kr':' ac busan chungbuk chungnam co daegu daejeon es gangwon go gwangju gyeongbuk gyeonggi gyeongnam hs incheon jeju jeonbuk jeonnam k kg mil ms ne or pe re sc seoul ulsan ',
'kw':' com edu gov net org ',
'ky':' com edu gov net org ',
'kz':' com edu gov mil net org ',
'lb':' com edu gov net org ',
'lk':' assn com edu gov grp hotel int ltd net ngo org sch soc web ',
'lr':' com edu gov net org ',
'lv':' asn com conf edu gov id mil net org ',
'ly':' com edu gov id med net org plc sch ',
'ma':' ac co gov m net org press ',
'mc':' asso tm ',
'me':' ac co edu gov its net org priv ',
'mg':' com edu gov mil nom org prd tm ',
'mk':' com edu gov inf name net org pro ',
'ml':' com edu gov net org presse ',
'mn':' edu gov org ',
'mo':' com edu gov net org ',
'mt':' com edu gov net org ',
'mv':' aero biz com coop edu gov info int mil museum name net org pro ',
'mw':' ac co com coop edu gov int museum net org ',
'mx':' com edu gob net org ',
'my':' com edu gov mil name net org sch ',
'nf':' arts com firm info net other per rec store web ',
'ng':' biz com edu gov mil mobi name net org sch ',
'ni':' ac co com edu gob mil net nom org ',
'np':' com edu gov mil net org ',
'nr':' biz com edu gov info net org ',
'om':' ac biz co com edu gov med mil museum net org pro sch ',
'pe':' com edu gob mil net nom org sld ',
'ph':' com edu gov i mil net ngo org ',
'pk':' biz com edu fam gob gok gon gop gos gov net org web ',
'pl':' art bialystok biz com edu gda gdansk gorzow gov info katowice krakow lodz lublin mil net ngo olsztyn org poznan pwr radom slupsk szczecin torun warszawa waw wroc wroclaw zgora ',
'pr':' ac biz com edu est gov info isla name net org pro prof ',
'ps':' com edu gov net org plo sec ',
'pw':' belau co ed go ne or ',
'ro':' arts com firm info nom nt org rec store tm www ',
'rs':' ac co edu gov in org ',
'sb':' com edu gov net org ',
'sc':' com edu gov net org ',
'sh':' co com edu gov net nom org ',
'sl':' com edu gov net org ',
'st':' co com consulado edu embaixada gov mil net org principe saotome store ',
'sv':' com edu gob org red ',
'sz':' ac co org ',
'tr':' av bbs bel biz com dr edu gen gov info k12 name net org pol tel tsk tv web ',
'tt':' aero biz cat co com coop edu gov info int jobs mil mobi museum name net org pro tel travel ',
'tw':' club com ebiz edu game gov idv mil net org ',
'mu':' ac co com gov net or org ',
'mz':' ac co edu gov org ',
'na':' co com ',
'nz':' ac co cri geek gen govt health iwi maori mil net org parliament school ',
'pa':' abo ac com edu gob ing med net nom org sld ',
'pt':' com edu gov int net nome org publ ',
'py':' com edu gov mil net org ',
'qa':' com edu gov mil net org ',
're':' asso com nom ',
'ru':' ac adygeya altai amur arkhangelsk astrakhan bashkiria belgorod bir bryansk buryatia cbg chel chelyabinsk chita chukotka chuvashia com dagestan e-burg edu gov grozny int irkutsk ivanovo izhevsk jar joshkar-ola kalmykia kaluga kamchatka karelia kazan kchr kemerovo khabarovsk khakassia khv kirov koenig komi kostroma kranoyarsk kuban kurgan kursk lipetsk magadan mari mari-el marine mil mordovia mosreg msk murmansk nalchik net nnov nov novosibirsk nsk omsk orenburg org oryol penza perm pp pskov ptz rnd ryazan sakhalin samara saratov simbirsk smolensk spb stavropol stv surgut tambov tatarstan tom tomsk tsaritsyn tsk tula tuva tver tyumen udm udmurtia ulan-ude vladikavkaz vladimir vladivostok volgograd vologda voronezh vrn vyatka yakutia yamal yekaterinburg yuzhno-sakhalinsk ',
'rw':' ac co com edu gouv gov int mil net ',
'sa':' com edu gov med net org pub sch ',
'sd':' com edu gov info med net org tv ',
'se':' a ac b bd c d e f g h i k l m n o org p parti pp press r s t tm u w x y z ',
'sg':' com edu gov idn net org per ',
'sn':' art com edu gouv org perso univ ',
'sy':' com edu gov mil net news org ',
'th':' ac co go in mi net or ',
'tj':' ac biz co com edu go gov info int mil name net nic org test web ',
'tn':' agrinet com defense edunet ens fin gov ind info intl mincom nat net org perso rnrt rns rnu tourism ',
'tz':' ac co go ne or ',
'ua':' biz cherkassy chernigov chernovtsy ck cn co com crimea cv dn dnepropetrovsk donetsk dp edu gov if in ivano-frankivsk kh kharkov kherson khmelnitskiy kiev kirovograd km kr ks kv lg lugansk lutsk lviv me mk net nikolaev od odessa org pl poltava pp rovno rv sebastopol sumy te ternopil uzhgorod vinnica vn zaporizhzhe zhitomir zp zt ',
'ug':' ac co go ne or org sc ',
'uk':' ac bl british-library co cym gov govt icnet jet lea ltd me mil mod national-library-scotland nel net nhs nic nls org orgn parliament plc police sch scot soc ',
'us':' dni fed isa kids nsn ',
'uy':' com edu gub mil net org ',
've':' co com edu gob info mil net org web ',
'vi':' co com k12 net org ',
'vn':' ac biz com edu gov health info int name net org pro ',
'ye':' co com gov ltd me net org plc ',
'yu':' ac co edu gov org ',
'za':' ac agric alt bourse city co cybernet db edu gov grondar iaccess imt inca landesign law mil net ngo nis nom olivetti org pix school tm web ',
'zm':' ac co com edu gov net org sch ',
// https://en.wikipedia.org/wiki/CentralNic#Second-level_domains
'com': 'ar br cn de eu gb gr hu jpn kr no qc ru sa se uk us uy za ',
'net': 'gb jp se uk ',
'org': 'ae',
'de': 'com '
},
// gorhill 2013-10-25: Using indexOf() instead Regexp(). Significant boost
// in both performance and memory footprint. No initialization required.
// http://jsperf.com/uri-js-sld-regex-vs-binary-search/4
// Following methods use lastIndexOf() rather than array.split() in order
// to avoid any memory allocations.
has: function(domain) {
var tldOffset = domain.lastIndexOf('.');
if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {
return false;
}
var sldOffset = domain.lastIndexOf('.', tldOffset-1);
if (sldOffset <= 0 || sldOffset >= (tldOffset-1)) {
return false;
}
var sldList = SLD.list[domain.slice(tldOffset+1)];
if (!sldList) {
return false;
}
return sldList.indexOf(' ' + domain.slice(sldOffset+1, tldOffset) + ' ') >= 0;
},
is: function(domain) {
var tldOffset = domain.lastIndexOf('.');
if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {
return false;
}
var sldOffset = domain.lastIndexOf('.', tldOffset-1);
if (sldOffset >= 0) {
return false;
}
var sldList = SLD.list[domain.slice(tldOffset+1)];
if (!sldList) {
return false;
}
return sldList.indexOf(' ' + domain.slice(0, tldOffset) + ' ') >= 0;
},
get: function(domain) {
var tldOffset = domain.lastIndexOf('.');
if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {
return null;
}
var sldOffset = domain.lastIndexOf('.', tldOffset-1);
if (sldOffset <= 0 || sldOffset >= (tldOffset-1)) {
return null;
}
var sldList = SLD.list[domain.slice(tldOffset+1)];
if (!sldList) {
return null;
}
if (sldList.indexOf(' ' + domain.slice(sldOffset+1, tldOffset) + ' ') < 0) {
return null;
}
return domain.slice(sldOffset+1);
},
noConflict: function(){
if (root.SecondLevelDomains === this) {
root.SecondLevelDomains = _SecondLevelDomains;
}
return this;
}
};
return SLD;
}));
});
var URI = createCommonjsModule(function (module) {
/*!
* URI.js - Mutating URLs
*
* Version: 1.19.8
*
* Author: Rodney Rehm
* Web: http://medialize.github.io/URI.js/
*
* Licensed under
* MIT License http://www.opensource.org/licenses/mit-license
*
*/
(function (root, factory) {
// https://github.com/umdjs/umd/blob/master/returnExports.js
if (module.exports) {
// Node
module.exports = factory(punycode, IPv6, SecondLevelDomains);
} else {
// Browser globals (root is window)
root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root);
}
}(commonjsGlobal, function (punycode, IPv6, SLD, root) {
/*global location, escape, unescape */
// FIXME: v2.0.0 renamce non-camelCase properties to uppercase
/*jshint camelcase: false */
// save current URI variable, if any
var _URI = root && root.URI;
function URI(url, base) {
var _urlSupplied = arguments.length >= 1;
var _baseSupplied = arguments.length >= 2;
// Allow instantiation without the 'new' keyword
if (!(this instanceof URI)) {
if (_urlSupplied) {
if (_baseSupplied) {
return new URI(url, base);
}
return new URI(url);
}
return new URI();
}
if (url === undefined) {
if (_urlSupplied) {
throw new TypeError('undefined is not a valid argument for URI');
}
if (typeof location !== 'undefined') {
url = location.href + '';
} else {
url = '';
}
}
if (url === null) {
if (_urlSupplied) {
throw new TypeError('null is not a valid argument for URI');
}
}
this.href(url);
// resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor
if (base !== undefined) {
return this.absoluteTo(base);
}
return this;
}
function isInteger(value) {
return /^[0-9]+$/.test(value);
}
URI.version = '1.19.8';
var p = URI.prototype;
var hasOwn = Object.prototype.hasOwnProperty;
function escapeRegEx(string) {
// https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}
function getType(value) {
// IE8 doesn't return [Object Undefined] but [Object Object] for undefined value
if (value === undefined) {
return 'Undefined';
}
return String(Object.prototype.toString.call(value)).slice(8, -1);
}
function isArray(obj) {
return getType(obj) === 'Array';
}
function filterArrayValues(data, value) {
var lookup = {};
var i, length;
if (getType(value) === 'RegExp') {
lookup = null;
} else if (isArray(value)) {
for (i = 0, length = value.length; i < length; i++) {
lookup[value[i]] = true;
}
} else {
lookup[value] = true;
}
for (i = 0, length = data.length; i < length; i++) {
/*jshint laxbreak: true */
var _match = lookup && lookup[data[i]] !== undefined
|| !lookup && value.test(data[i]);
/*jshint laxbreak: false */
if (_match) {
data.splice(i, 1);
length--;
i--;
}
}
return data;
}
function arrayContains(list, value) {
var i, length;
// value may be string, number, array, regexp
if (isArray(value)) {
// Note: this can be optimized to O(n) (instead of current O(m * n))
for (i = 0, length = value.length; i < length; i++) {
if (!arrayContains(list, value[i])) {
return false;
}
}
return true;
}
var _type = getType(value);
for (i = 0, length = list.length; i < length; i++) {
if (_type === 'RegExp') {
if (typeof list[i] === 'string' && list[i].match(value)) {
return true;
}
} else if (list[i] === value) {
return true;
}
}
return false;
}
function arraysEqual(one, two) {
if (!isArray(one) || !isArray(two)) {
return false;
}
// arrays can't be equal if they have different amount of content
if (one.length !== two.length) {
return false;
}
one.sort();
two.sort();
for (var i = 0, l = one.length; i < l; i++) {
if (one[i] !== two[i]) {
return false;
}
}
return true;
}
function trimSlashes(text) {
var trim_expression = /^\/+|\/+$/g;
return text.replace(trim_expression, '');
}
URI._parts = function() {
return {
protocol: null,
username: null,
password: null,
hostname: null,
urn: null,
port: null,
path: null,
query: null,
fragment: null,
// state
preventInvalidHostname: URI.preventInvalidHostname,
duplicateQueryParameters: URI.duplicateQueryParameters,
escapeQuerySpace: URI.escapeQuerySpace
};
};
// state: throw on invalid hostname
// see https://github.com/medialize/URI.js/pull/345
// and https://github.com/medialize/URI.js/issues/354
URI.preventInvalidHostname = false;
// state: allow duplicate query parameters (a=1&a=1)
URI.duplicateQueryParameters = false;
// state: replaces + with %20 (space in query strings)
URI.escapeQuerySpace = true;
// static properties
URI.protocol_expression = /^[a-z][a-z0-9.+-]*$/i;
URI.idn_expression = /[^a-z0-9\._-]/i;
URI.punycode_expression = /(xn--)/i;
// well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care?
URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
// credits to Rich Brown
// source: http://forums.intermapper.com/viewtopic.php?p=1096#1096
// specification: http://www.ietf.org/rfc/rfc4291.txt
URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
// expression used is "gruber revised" (@gruber v2) determined to be the
// best solution in a regex-golf we did a couple of ages ago at
// * http://mathiasbynens.be/demo/url-regex
// * http://rodneyrehm.de/t/url-regex.html
URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig;
URI.findUri = {
// valid "scheme://" or "www."
start: /\b(?:([a-z][a-z0-9.+-]*:\/\/)|www\.)/gi,
// everything up to the next whitespace
end: /[\s\r\n]|$/,
// trim trailing punctuation captured by end RegExp
trim: /[`!()\[\]{};:'".,<>?«»“”„‘’]+$/,
// balanced parens inclusion (), [], {}, <>
parens: /(\([^\)]*\)|\[[^\]]*\]|\{[^}]*\}|<[^>]*>)/g,
};
// http://www.iana.org/assignments/uri-schemes.html
// http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports
URI.defaultPorts = {
http: '80',
https: '443',
ftp: '21',
gopher: '70',
ws: '80',
wss: '443'
};
// list of protocols which always require a hostname
URI.hostProtocols = [
'http',
'https'
];
// allowed hostname characters according to RFC 3986
// ALPHA DIGIT "-" "." "_" "~" "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "=" %encoded
// I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . - _
URI.invalid_hostname_characters = /[^a-zA-Z0-9\.\-:_]/;
// map DOM Elements to their URI attribute
URI.domAttributes = {
'a': 'href',
'blockquote': 'cite',
'link': 'href',
'base': 'href',
'script': 'src',
'form': 'action',
'img': 'src',
'area': 'href',
'iframe': 'src',
'embed': 'src',
'source': 'src',
'track': 'src',
'input': 'src', // but only if type="image"
'audio': 'src',
'video': 'src'
};
URI.getDomAttribute = function(node) {
if (!node || !node.nodeName) {
return undefined;
}
var nodeName = node.nodeName.toLowerCase();
// should only expose src for type="image"
if (nodeName === 'input' && node.type !== 'image') {
return undefined;
}
return URI.domAttributes[nodeName];
};
function escapeForDumbFirefox36(value) {
// https://github.com/medialize/URI.js/issues/91
return escape(value);
}
// encoding / decoding according to RFC3986
function strictEncodeURIComponent(string) {
// see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent
return encodeURIComponent(string)
.replace(/[!'()*]/g, escapeForDumbFirefox36)
.replace(/\*/g, '%2A');
}
URI.encode = strictEncodeURIComponent;
URI.decode = decodeURIComponent;
URI.iso8859 = function() {
URI.encode = escape;
URI.decode = unescape;
};
URI.unicode = function() {
URI.encode = strictEncodeURIComponent;
URI.decode = decodeURIComponent;
};
URI.characters = {
pathname: {
encode: {
// RFC3986 2.1: For consistency, URI producers and normalizers should
// use uppercase hexadecimal digits for all percent-encodings.
expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig,
map: {
// -._~!'()*
'%24': '$',
'%26': '&',
'%2B': '+',
'%2C': ',',
'%3B': ';',
'%3D': '=',
'%3A': ':',
'%40': '@'
}
},
decode: {
expression: /[\/\?#]/g,
map: {
'/': '%2F',
'?': '%3F',
'#': '%23'
}
}
},
reserved: {
encode: {
// RFC3986 2.1: For consistency, URI producers and normalizers should
// use uppercase hexadecimal digits for all percent-encodings.
expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,
map: {
// gen-delims
'%3A': ':',
'%2F': '/',
'%3F': '?',
'%23': '#',
'%5B': '[',
'%5D': ']',
'%40': '@',
// sub-delims
'%21': '!',
'%24': '$',
'%26': '&',
'%27': '\'',
'%28': '(',
'%29': ')',
'%2A': '*',
'%2B': '+',
'%2C': ',',
'%3B': ';',
'%3D': '='
}
}
},
urnpath: {
// The characters under `encode` are the characters called out by RFC 2141 as being acceptable
// for usage in a URN. RFC2141 also calls out "-", ".", and "_" as acceptable characters, but
// these aren't encoded by encodeURIComponent, so we don't have to call them out here. Also
// note that the colon character is not featured in the encoding map; this is because URI.js
// gives the colons in URNs semantic meaning as the delimiters of path segements, and so it
// should not appear unencoded in a segment itself.
// See also the note above about RFC3986 and capitalalized hex digits.
encode: {
expression: /%(21|24|27|28|29|2A|2B|2C|3B|3D|40)/ig,
map: {
'%21': '!',
'%24': '$',
'%27': '\'',
'%28': '(',
'%29': ')',
'%2A': '*',
'%2B': '+',
'%2C': ',',
'%3B': ';',
'%3D': '=',
'%40': '@'
}
},
// These characters are the characters called out by RFC2141 as "reserved" characters that
// should never appear in a URN, plus the colon character (see note above).
decode: {
expression: /[\/\?#:]/g,
map: {
'/': '%2F',
'?': '%3F',
'#': '%23',
':': '%3A'
}
}
}
};
URI.encodeQuery = function(string, escapeQuerySpace) {
var escaped = URI.encode(string + '');
if (escapeQuerySpace === undefined) {
escapeQuerySpace = URI.escapeQuerySpace;
}
return escapeQuerySpace ? escaped.replace(/%20/g, '+') : escaped;
};
URI.decodeQuery = function(string, escapeQuerySpace) {
string += '';
if (escapeQuerySpace === undefined) {
escapeQuerySpace = URI.escapeQuerySpace;
}
try {
return URI.decode(escapeQuerySpace ? string.replace(/\+/g, '%20') : string);
} catch(e) {
// we're not going to mess with weird encodings,
// give up and return the undecoded original string
// see https://github.com/medialize/URI.js/issues/87
// see https://github.com/medialize/URI.js/issues/92
return string;
}
};
// generate encode/decode path functions
var _parts = {'encode':'encode', 'decode':'decode'};
var _part;
var generateAccessor = function(_group, _part) {
return function(string) {
try {
return URI[_part](string + '').replace(URI.characters[_group][_part].expression, function(c) {
return URI.characters[_group][_part].map[c];
});
} catch (e) {
// we're not going to mess with weird encodings,
// give up and return the undecoded original string
// see https://github.com/medialize/URI.js/issues/87
// see https://github.com/medialize/URI.js/issues/92
return string;
}
};
};
for (_part in _parts) {
URI[_part + 'PathSegment'] = generateAccessor('pathname', _parts[_part]);
URI[_part + 'UrnPathSegment'] = generateAccessor('urnpath', _parts[_part]);
}
var generateSegmentedPathFunction = function(_sep, _codingFuncName, _innerCodingFuncName) {
return function(string) {
// Why pass in names of functions, rather than the function objects themselves? The
// definitions of some functions (but in particular, URI.decode) will occasionally change due
// to URI.js having ISO8859 and Unicode modes. Passing in the name and getting it will ensure
// that the functions we use here are "fresh".
var actualCodingFunc;
if (!_innerCodingFuncName) {
actualCodingFunc = URI[_codingFuncName];
} else {
actualCodingFunc = function(string) {
return URI[_codingFuncName](URI[_innerCodingFuncName](string));
};
}
var segments = (string + '').split(_sep);
for (var i = 0, length = segments.length; i < length; i++) {
segments[i] = actualCodingFunc(segments[i]);
}
return segments.join(_sep);
};
};
// This takes place outside the above loop because we don't want, e.g., encodeUrnPath functions.
URI.decodePath = generateSegmentedPathFunction('/', 'decodePathSegment');
URI.decodeUrnPath = generateSegmentedPathFunction(':', 'decodeUrnPathSegment');
URI.recodePath = generateSegmentedPathFunction('/', 'encodePathSegment', 'decode');
URI.recodeUrnPath = generateSegmentedPathFunction(':', 'encodeUrnPathSegment', 'decode');
URI.encodeReserved = generateAccessor('reserved', 'encode');
URI.parse = function(string, parts) {
var pos;
if (!parts) {
parts = {
preventInvalidHostname: URI.preventInvalidHostname
};
}
// [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment]
// extract fragment
pos = string.indexOf('#');
if (pos > -1) {
// escaping?
parts.fragment = string.substring(pos + 1) || null;
string = string.substring(0, pos);
}
// extract query
pos = string.indexOf('?');
if (pos > -1) {
// escaping?
parts.query = string.substring(pos + 1) || null;
string = string.substring(0, pos);
}
// slashes and backslashes have lost all meaning for the web protocols (https, http, wss, ws)
string = string.replace(/^(https?|ftp|wss?)?:[/\\]*/i, '$1://');
// extract protocol
if (string.substring(0, 2) === '//') {
// relative-scheme
parts.protocol = null;
string = string.substring(2);
// extract "user:pass@host:port"
string = URI.parseAuthority(string, parts);
} else {
pos = string.indexOf(':');
if (pos > -1) {
parts.protocol = string.substring(0, pos) || null;
if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {
// : may be within the path
parts.protocol = undefined;
} else if (string.substring(pos + 1, pos + 3).replace(/\\/g, '/') === '//') {
string = string.substring(pos + 3);
// extract "user:pass@host:port"
string = URI.parseAuthority(string, parts);
} else {
string = string.substring(pos + 1);
parts.urn = true;
}
}
}
// what's left must be the path
parts.path = string;
// and we're done
return parts;
};
URI.parseHost = function(string, parts) {
if (!string) {
string = '';
}
// Copy chrome, IE, opera backslash-handling behavior.
// Back slashes before the query string get converted to forward slashes
// See: https://github.com/joyent/node/blob/386fd24f49b0e9d1a8a076592a404168faeecc34/lib/url.js#L115-L124
// See: https://code.google.com/p/chromium/issues/detail?id=25916
// https://github.com/medialize/URI.js/pull/233
string = string.replace(/\\/g, '/');
// extract host:port
var pos = string.indexOf('/');
var bracketPos;
var t;
if (pos === -1) {
pos = string.length;
}
if (string.charAt(0) === '[') {
// IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6
// I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts
// IPv6+port in the format [2001:db8::1]:80 (for the time being)
bracketPos = string.indexOf(']');
parts.hostname = string.substring(1, bracketPos) || null;
parts.port = string.substring(bracketPos + 2, pos) || null;
if (parts.port === '/') {
parts.port = null;
}
} else {
var firstColon = string.indexOf(':');
var firstSlash = string.indexOf('/');
var nextColon = string.indexOf(':', firstColon + 1);
if (nextColon !== -1 && (firstSlash === -1 || nextColon < firstSlash)) {
// IPv6 host contains multiple colons - but no port
// this notation is actually not allowed by RFC 3986, but we're a liberal parser
parts.hostname = string.substring(0, pos) || null;
parts.port = null;
} else {
t = string.substring(0, pos).split(':');
parts.hostname = t[0] || null;
parts.port = t[1] || null;
}
}
if (parts.hostname && string.substring(pos).charAt(0) !== '/') {
pos++;
string = '/' + string;
}
if (parts.preventInvalidHostname) {
URI.ensureValidHostname(parts.hostname, parts.protocol);
}
if (parts.port) {
URI.ensureValidPort(parts.port);
}
return string.substring(pos) || '/';
};
URI.parseAuthority = function(string, parts) {
string = URI.parseUserinfo(string, parts);
return URI.parseHost(string, parts);
};
URI.parseUserinfo = function(string, parts) {
// extract username:password
var _string = string;
var firstBackSlash = string.indexOf('\\');
if (firstBackSlash !== -1) {
string = string.replace(/\\/g, '/');
}
var firstSlash = string.indexOf('/');
var pos = string.lastIndexOf('@', firstSlash > -1 ? firstSlash : string.length - 1);
var t;
// authority@ must come before /path or \path
if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) {
t = string.substring(0, pos).split(':');
parts.username = t[0] ? URI.decode(t[0]) : null;
t.shift();
parts.password = t[0] ? URI.decode(t.join(':')) : null;
string = _string.substring(pos + 1);
} else {
parts.username = null;
parts.password = null;
}
return string;
};
URI.parseQuery = function(string, escapeQuerySpace) {
if (!string) {
return {};
}
// throw out the funky business - "?"[name"="value"&"]+
string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, '');
if (!string) {
return {};
}
var items = {};
var splits = string.split('&');
var length = splits.length;
var v, name, value;
for (var i = 0; i < length; i++) {
v = splits[i].split('=');
name = URI.decodeQuery(v.shift(), escapeQuerySpace);
// no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters
value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null;
if (name === '__proto__') {
// ignore attempt at exploiting JavaScript internals
continue;
} else if (hasOwn.call(items, name)) {
if (typeof items[name] === 'string' || items[name] === null) {
items[name] = [items[name]];
}
items[name].push(value);
} else {
items[name] = value;
}
}
return items;
};
URI.build = function(parts) {
var t = '';
var requireAbsolutePath = false;
if (parts.protocol) {
t += parts.protocol + ':';
}
if (!parts.urn && (t || parts.hostname)) {
t += '//';
requireAbsolutePath = true;
}
t += (URI.buildAuthority(parts) || '');
if (typeof parts.path === 'string') {
if (parts.path.charAt(0) !== '/' && requireAbsolutePath) {
t += '/';
}
t += parts.path;
}
if (typeof parts.query === 'string' && parts.query) {
t += '?' + parts.query;
}
if (typeof parts.fragment === 'string' && parts.fragment) {
t += '#' + parts.fragment;
}
return t;
};
URI.buildHost = function(parts) {
var t = '';
if (!parts.hostname) {
return '';
} else if (URI.ip6_expression.test(parts.hostname)) {
t += '[' + parts.hostname + ']';
} else {
t += parts.hostname;
}
if (parts.port) {
t += ':' + parts.port;
}
return t;
};
URI.buildAuthority = function(parts) {
return URI.buildUserinfo(parts) + URI.buildHost(parts);
};
URI.buildUserinfo = function(parts) {
var t = '';
if (parts.username) {
t += URI.encode(parts.username);
}
if (parts.password) {
t += ':' + URI.encode(parts.password);
}
if (t) {
t += '@';
}
return t;
};
URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) {
// according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html
// being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed
// the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax!
// URI.js treats the query string as being application/x-www-form-urlencoded
// see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type
var t = '';
var unique, key, i, length;
for (key in data) {
if (key === '__proto__') {
// ignore attempt at exploiting JavaScript internals
continue;
} else if (hasOwn.call(data, key)) {
if (isArray(data[key])) {
unique = {};
for (i = 0, length = data[key].length; i < length; i++) {
if (data[key][i] !== undefined && unique[data[key][i] + ''] === undefined) {
t += '&' + URI.buildQueryParameter(key, data[key][i], escapeQuerySpace);
if (duplicateQueryParameters !== true) {
unique[data[key][i] + ''] = true;
}
}
}
} else if (data[key] !== undefined) {
t += '&' + URI.buildQueryParameter(key, data[key], escapeQuerySpace);
}
}
}
return t.substring(1);
};
URI.buildQueryParameter = function(name, value, escapeQuerySpace) {
// http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded
// don't append "=" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization
return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ? '=' + URI.encodeQuery(value, escapeQuerySpace) : '');
};
URI.addQuery = function(data, name, value) {
if (typeof name === 'object') {
for (var key in name) {
if (hasOwn.call(name, key)) {
URI.addQuery(data, key, name[key]);
}
}
} else if (typeof name === 'string') {
if (data[name] === undefined) {
data[name] = value;
return;
} else if (typeof data[name] === 'string') {
data[name] = [data[name]];
}
if (!isArray(value)) {
value = [value];
}
data[name] = (data[name] || []).concat(value);
} else {
throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');
}
};
URI.setQuery = function(data, name, value) {
if (typeof name === 'object') {
for (var key in name) {
if (hasOwn.call(name, key)) {
URI.setQuery(data, key, name[key]);
}
}
} else if (typeof name === 'string') {
data[name] = value === undefined ? null : value;
} else {
throw new TypeError('URI.setQuery() accepts an object, string as the name parameter');
}
};
URI.removeQuery = function(data, name, value) {
var i, length, key;
if (isArray(name)) {
for (i = 0, length = name.length; i < length; i++) {
data[name[i]] = undefined;
}
} else if (getType(name) === 'RegExp') {
for (key in data) {
if (name.test(key)) {
data[key] = undefined;
}
}
} else if (typeof name === 'object') {
for (key in name) {
if (hasOwn.call(name, key)) {
URI.removeQuery(data, key, name[key]);
}
}
} else if (typeof name === 'string') {
if (value !== undefined) {
if (getType(value) === 'RegExp') {
if (!isArray(data[name]) && value.test(data[name])) {
data[name] = undefined;
} else {
data[name] = filterArrayValues(data[name], value);
}
} else if (data[name] === String(value) && (!isArray(value) || value.length === 1)) {
data[name] = undefined;
} else if (isArray(data[name])) {
data[name] = filterArrayValues(data[name], value);
}
} else {
data[name] = undefined;
}
} else {
throw new TypeError('URI.removeQuery() accepts an object, string, RegExp as the first parameter');
}
};
URI.hasQuery = function(data, name, value, withinArray) {
switch (getType(name)) {
case 'String':
// Nothing to do here
break;
case 'RegExp':
for (var key in data) {
if (hasOwn.call(data, key)) {
if (name.test(key) && (value === undefined || URI.hasQuery(data, key, value))) {
return true;
}
}
}
return false;
case 'Object':
for (var _key in name) {
if (hasOwn.call(name, _key)) {
if (!URI.hasQuery(data, _key, name[_key])) {
return false;
}
}
}
return true;
default:
throw new TypeError('URI.hasQuery() accepts a string, regular expression or object as the name parameter');
}
switch (getType(value)) {
case 'Undefined':
// true if exists (but may be empty)
return name in data; // data[name] !== undefined;
case 'Boolean':
// true if exists and non-empty
var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);
return value === _booly;
case 'Function':
// allow complex comparison
return !!value(data[name], name, data);
case 'Array':
if (!isArray(data[name])) {
return false;
}
var op = withinArray ? arrayContains : arraysEqual;
return op(data[name], value);
case 'RegExp':
if (!isArray(data[name])) {
return Boolean(data[name] && data[name].match(value));
}
if (!withinArray) {
return false;
}
return arrayContains(data[name], value);
case 'Number':
value = String(value);
/* falls through */
case 'String':
if (!isArray(data[name])) {
return data[name] === value;
}
if (!withinArray) {
return false;
}
return arrayContains(data[name], value);
default:
throw new TypeError('URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter');
}
};
URI.joinPaths = function() {
var input = [];
var segments = [];
var nonEmptySegments = 0;
for (var i = 0; i < arguments.length; i++) {
var url = new URI(arguments[i]);
input.push(url);
var _segments = url.segment();
for (var s = 0; s < _segments.length; s++) {
if (typeof _segments[s] === 'string') {
segments.push(_segments[s]);
}
if (_segments[s]) {
nonEmptySegments++;
}
}
}
if (!segments.length || !nonEmptySegments) {
return new URI('');
}
var uri = new URI('').segment(segments);
if (input[0].path() === '' || input[0].path().slice(0, 1) === '/') {
uri.path('/' + uri.path());
}
return uri.normalize();
};
URI.commonPath = function(one, two) {
var length = Math.min(one.length, two.length);
var pos;
// find first non-matching character
for (pos = 0; pos < length; pos++) {
if (one.charAt(pos) !== two.charAt(pos)) {
pos--;
break;
}
}
if (pos < 1) {
return one.charAt(0) === two.charAt(0) && one.charAt(0) === '/' ? '/' : '';
}
// revert to last /
if (one.charAt(pos) !== '/' || two.charAt(pos) !== '/') {
pos = one.substring(0, pos).lastIndexOf('/');
}
return one.substring(0, pos + 1);
};
URI.withinString = function(string, callback, options) {
options || (options = {});
var _start = options.start || URI.findUri.start;
var _end = options.end || URI.findUri.end;
var _trim = options.trim || URI.findUri.trim;
var _parens = options.parens || URI.findUri.parens;
var _attributeOpen = /[a-z0-9-]=["']?$/i;
_start.lastIndex = 0;
while (true) {
var match = _start.exec(string);
if (!match) {
break;
}
var start = match.index;
if (options.ignoreHtml) {
// attribut(e=["']?$)
var attributeOpen = string.slice(Math.max(start - 3, 0), start);
if (attributeOpen && _attributeOpen.test(attributeOpen)) {
continue;
}
}
var end = start + string.slice(start).search(_end);
var slice = string.slice(start, end);
// make sure we include well balanced parens
var parensEnd = -1;
while (true) {
var parensMatch = _parens.exec(slice);
if (!parensMatch) {
break;
}
var parensMatchEnd = parensMatch.index + parensMatch[0].length;
parensEnd = Math.max(parensEnd, parensMatchEnd);
}
if (parensEnd > -1) {
slice = slice.slice(0, parensEnd) + slice.slice(parensEnd).replace(_trim, '');
} else {
slice = slice.replace(_trim, '');
}
if (slice.length <= match[0].length) {
// the extract only contains the starting marker of a URI,
// e.g. "www" or "http://"
continue;
}
if (options.ignore && options.ignore.test(slice)) {
continue;
}
end = start + slice.length;
var result = callback(slice, start, end, string);
if (result === undefined) {
_start.lastIndex = end;
continue;
}
result = String(result);
string = string.slice(0, start) + result + string.slice(end);
_start.lastIndex = start + result.length;
}
_start.lastIndex = 0;
return string;
};
URI.ensureValidHostname = function(v, protocol) {
// Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986)
// they are not part of DNS and therefore ignored by URI.js
var hasHostname = !!v; // not null and not an empty string
var hasProtocol = !!protocol;
var rejectEmptyHostname = false;
if (hasProtocol) {
rejectEmptyHostname = arrayContains(URI.hostProtocols, protocol);
}
if (rejectEmptyHostname && !hasHostname) {
throw new TypeError('Hostname cannot be empty, if protocol is ' + protocol);
} else if (v && v.match(URI.invalid_hostname_characters)) {
// test punycode
if (!punycode) {
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-:_] and Punycode.js is not available');
}
if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) {
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-:_]');
}
}
};
URI.ensureValidPort = function (v) {
if (!v) {
return;
}
var port = Number(v);
if (isInteger(port) && (port > 0) && (port < 65536)) {
return;
}
throw new TypeError('Port "' + v + '" is not a valid port');
};
// noConflict
URI.noConflict = function(removeAll) {
if (removeAll) {
var unconflicted = {
URI: this.noConflict()
};
if (root.URITemplate && typeof root.URITemplate.noConflict === 'function') {
unconflicted.URITemplate = root.URITemplate.noConflict();
}
if (root.IPv6 && typeof root.IPv6.noConflict === 'function') {
unconflicted.IPv6 = root.IPv6.noConflict();
}
if (root.SecondLevelDomains && typeof root.SecondLevelDomains.noConflict === 'function') {
unconflicted.SecondLevelDomains = root.SecondLevelDomains.noConflict();
}
return unconflicted;
} else if (root.URI === this) {
root.URI = _URI;
}
return this;
};
p.build = function(deferBuild) {
if (deferBuild === true) {
this._deferred_build = true;
} else if (deferBuild === undefined || this._deferred_build) {
this._string = URI.build(this._parts);
this._deferred_build = false;
}
return this;
};
p.clone = function() {
return new URI(this);
};
p.valueOf = p.toString = function() {
return this.build(false)._string;
};
function generateSimpleAccessor(_part){
return function(v, build) {
if (v === undefined) {
return this._parts[_part] || '';
} else {
this._parts[_part] = v || null;
this.build(!build);
return this;
}
};
}
function generatePrefixAccessor(_part, _key){
return function(v, build) {
if (v === undefined) {
return this._parts[_part] || '';
} else {
if (v !== null) {
v = v + '';
if (v.charAt(0) === _key) {
v = v.substring(1);
}
}
this._parts[_part] = v;
this.build(!build);
return this;
}
};
}
p.protocol = generateSimpleAccessor('protocol');
p.username = generateSimpleAccessor('username');
p.password = generateSimpleAccessor('password');
p.hostname = generateSimpleAccessor('hostname');
p.port = generateSimpleAccessor('port');
p.query = generatePrefixAccessor('query', '?');
p.fragment = generatePrefixAccessor('fragment', '#');
p.search = function(v, build) {
var t = this.query(v, build);
return typeof t === 'string' && t.length ? ('?' + t) : t;
};
p.hash = function(v, build) {
var t = this.fragment(v, build);
return typeof t === 'string' && t.length ? ('#' + t) : t;
};
p.pathname = function(v, build) {
if (v === undefined || v === true) {
var res = this._parts.path || (this._parts.hostname ? '/' : '');
return v ? (this._parts.urn ? URI.decodeUrnPath : URI.decodePath)(res) : res;
} else {
if (this._parts.urn) {
this._parts.path = v ? URI.recodeUrnPath(v) : '';
} else {
this._parts.path = v ? URI.recodePath(v) : '/';
}
this.build(!build);
return this;
}
};
p.path = p.pathname;
p.href = function(href, build) {
var key;
if (href === undefined) {
return this.toString();
}
this._string = '';
this._parts = URI._parts();
var _URI = href instanceof URI;
var _object = typeof href === 'object' && (href.hostname || href.path || href.pathname);
if (href.nodeName) {
var attribute = URI.getDomAttribute(href);
href = href[attribute] || '';
_object = false;
}
// window.location is reported to be an object, but it's not the sort
// of object we're looking for:
// * location.protocol ends with a colon
// * location.query != object.search
// * location.hash != object.fragment
// simply serializing the unknown object should do the trick
// (for location, not for everything...)
if (!_URI && _object && href.pathname !== undefined) {
href = href.toString();
}
if (typeof href === 'string' || href instanceof String) {
this._parts = URI.parse(String(href), this._parts);
} else if (_URI || _object) {
var src = _URI ? href._parts : href;
for (key in src) {
if (key === 'query') { continue; }
if (hasOwn.call(this._parts, key)) {
this._parts[key] = src[key];
}
}
if (src.query) {
this.query(src.query, false);
}
} else {
throw new TypeError('invalid input');
}
this.build(!build);
return this;
};
// identification accessors
p.is = function(what) {
var ip = false;
var ip4 = false;
var ip6 = false;
var name = false;
var sld = false;
var idn = false;
var punycode = false;
var relative = !this._parts.urn;
if (this._parts.hostname) {
relative = false;
ip4 = URI.ip4_expression.test(this._parts.hostname);
ip6 = URI.ip6_expression.test(this._parts.hostname);
ip = ip4 || ip6;
name = !ip;
sld = name && SLD && SLD.has(this._parts.hostname);
idn = name && URI.idn_expression.test(this._parts.hostname);
punycode = name && URI.punycode_expression.test(this._parts.hostname);
}
switch (what.toLowerCase()) {
case 'relative':
return relative;
case 'absolute':
return !relative;
// hostname identification
case 'domain':
case 'name':
return name;
case 'sld':
return sld;
case 'ip':
return ip;
case 'ip4':
case 'ipv4':
case 'inet4':
return ip4;
case 'ip6':
case 'ipv6':
case 'inet6':
return ip6;
case 'idn':
return idn;
case 'url':
return !this._parts.urn;
case 'urn':
return !!this._parts.urn;
case 'punycode':
return punycode;
}
return null;
};
// component specific input validation
var _protocol = p.protocol;
var _port = p.port;
var _hostname = p.hostname;
p.protocol = function(v, build) {
if (v) {
// accept trailing ://
v = v.replace(/:(\/\/)?$/, '');
if (!v.match(URI.protocol_expression)) {
throw new TypeError('Protocol "' + v + '" contains characters other than [A-Z0-9.+-] or doesn\'t start with [A-Z]');
}
}
return _protocol.call(this, v, build);
};
p.scheme = p.protocol;
p.port = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v !== undefined) {
if (v === 0) {
v = null;
}
if (v) {
v += '';
if (v.charAt(0) === ':') {
v = v.substring(1);
}
URI.ensureValidPort(v);
}
}
return _port.call(this, v, build);
};
p.hostname = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v !== undefined) {
var x = { preventInvalidHostname: this._parts.preventInvalidHostname };
var res = URI.parseHost(v, x);
if (res !== '/') {
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-]');
}
v = x.hostname;
if (this._parts.preventInvalidHostname) {
URI.ensureValidHostname(v, this._parts.protocol);
}
}
return _hostname.call(this, v, build);
};
// compound accessors
p.origin = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v === undefined) {
var protocol = this.protocol();
var authority = this.authority();
if (!authority) {
return '';
}
return (protocol ? protocol + '://' : '') + this.authority();
} else {
var origin = URI(v);
this
.protocol(origin.protocol())
.authority(origin.authority())
.build(!build);
return this;
}
};
p.host = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v === undefined) {
return this._parts.hostname ? URI.buildHost(this._parts) : '';
} else {
var res = URI.parseHost(v, this._parts);
if (res !== '/') {
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-]');
}
this.build(!build);
return this;
}
};
p.authority = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v === undefined) {
return this._parts.hostname ? URI.buildAuthority(this._parts) : '';
} else {
var res = URI.parseAuthority(v, this._parts);
if (res !== '/') {
throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-]');
}
this.build(!build);
return this;
}
};
p.userinfo = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v === undefined) {
var t = URI.buildUserinfo(this._parts);
return t ? t.substring(0, t.length -1) : t;
} else {
if (v[v.length-1] !== '@') {
v += '@';
}
URI.parseUserinfo(v, this._parts);
this.build(!build);
return this;
}
};
p.resource = function(v, build) {
var parts;
if (v === undefined) {
return this.path() + this.search() + this.hash();
}
parts = URI.parse(v);
this._parts.path = parts.path;
this._parts.query = parts.query;
this._parts.fragment = parts.fragment;
this.build(!build);
return this;
};
// fraction accessors
p.subdomain = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
// convenience, return "www" from "www.example.org"
if (v === undefined) {
if (!this._parts.hostname || this.is('IP')) {
return '';
}
// grab domain and add another segment
var end = this._parts.hostname.length - this.domain().length - 1;
return this._parts.hostname.substring(0, end) || '';
} else {
var e = this._parts.hostname.length - this.domain().length;
var sub = this._parts.hostname.substring(0, e);
var replace = new RegExp('^' + escapeRegEx(sub));
if (v && v.charAt(v.length - 1) !== '.') {
v += '.';
}
if (v.indexOf(':') !== -1) {
throw new TypeError('Domains cannot contain colons');
}
if (v) {
URI.ensureValidHostname(v, this._parts.protocol);
}
this._parts.hostname = this._parts.hostname.replace(replace, v);
this.build(!build);
return this;
}
};
p.domain = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (typeof v === 'boolean') {
build = v;
v = undefined;
}
// convenience, return "example.org" from "www.example.org"
if (v === undefined) {
if (!this._parts.hostname || this.is('IP')) {
return '';
}
// if hostname consists of 1 or 2 segments, it must be the domain
var t = this._parts.hostname.match(/\./g);
if (t && t.length < 2) {
return this._parts.hostname;
}
// grab tld and add another segment
var end = this._parts.hostname.length - this.tld(build).length - 1;
end = this._parts.hostname.lastIndexOf('.', end -1) + 1;
return this._parts.hostname.substring(end) || '';
} else {
if (!v) {
throw new TypeError('cannot set domain empty');
}
if (v.indexOf(':') !== -1) {
throw new TypeError('Domains cannot contain colons');
}
URI.ensureValidHostname(v, this._parts.protocol);
if (!this._parts.hostname || this.is('IP')) {
this._parts.hostname = v;
} else {
var replace = new RegExp(escapeRegEx(this.domain()) + '$');
this._parts.hostname = this._parts.hostname.replace(replace, v);
}
this.build(!build);
return this;
}
};
p.tld = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (typeof v === 'boolean') {
build = v;
v = undefined;
}
// return "org" from "www.example.org"
if (v === undefined) {
if (!this._parts.hostname || this.is('IP')) {
return '';
}
var pos = this._parts.hostname.lastIndexOf('.');
var tld = this._parts.hostname.substring(pos + 1);
if (build !== true && SLD && SLD.list[tld.toLowerCase()]) {
return SLD.get(this._parts.hostname) || tld;
}
return tld;
} else {
var replace;
if (!v) {
throw new TypeError('cannot set TLD empty');
} else if (v.match(/[^a-zA-Z0-9-]/)) {
if (SLD && SLD.is(v)) {
replace = new RegExp(escapeRegEx(this.tld()) + '$');
this._parts.hostname = this._parts.hostname.replace(replace, v);
} else {
throw new TypeError('TLD "' + v + '" contains characters other than [A-Z0-9]');
}
} else if (!this._parts.hostname || this.is('IP')) {
throw new ReferenceError('cannot set TLD on non-domain host');
} else {
replace = new RegExp(escapeRegEx(this.tld()) + '$');
this._parts.hostname = this._parts.hostname.replace(replace, v);
}
this.build(!build);
return this;
}
};
p.directory = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v === undefined || v === true) {
if (!this._parts.path && !this._parts.hostname) {
return '';
}
if (this._parts.path === '/') {
return '/';
}
var end = this._parts.path.length - this.filename().length - 1;
var res = this._parts.path.substring(0, end) || (this._parts.hostname ? '/' : '');
return v ? URI.decodePath(res) : res;
} else {
var e = this._parts.path.length - this.filename().length;
var directory = this._parts.path.substring(0, e);
var replace = new RegExp('^' + escapeRegEx(directory));
// fully qualifier directories begin with a slash
if (!this.is('relative')) {
if (!v) {
v = '/';
}
if (v.charAt(0) !== '/') {
v = '/' + v;
}
}
// directories always end with a slash
if (v && v.charAt(v.length - 1) !== '/') {
v += '/';
}
v = URI.recodePath(v);
this._parts.path = this._parts.path.replace(replace, v);
this.build(!build);
return this;
}
};
p.filename = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (typeof v !== 'string') {
if (!this._parts.path || this._parts.path === '/') {
return '';
}
var pos = this._parts.path.lastIndexOf('/');
var res = this._parts.path.substring(pos+1);
return v ? URI.decodePathSegment(res) : res;
} else {
var mutatedDirectory = false;
if (v.charAt(0) === '/') {
v = v.substring(1);
}
if (v.match(/\.?\//)) {
mutatedDirectory = true;
}
var replace = new RegExp(escapeRegEx(this.filename()) + '$');
v = URI.recodePath(v);
this._parts.path = this._parts.path.replace(replace, v);
if (mutatedDirectory) {
this.normalizePath(build);
} else {
this.build(!build);
}
return this;
}
};
p.suffix = function(v, build) {
if (this._parts.urn) {
return v === undefined ? '' : this;
}
if (v === undefined || v === true) {
if (!this._parts.path || this._parts.path === '/') {
return '';
}
var filename = this.filename();
var pos = filename.lastIndexOf('.');
var s, res;
if (pos === -1) {
return '';
}
// suffix may only contain alnum characters (yup, I made this up.)
s = filename.substring(pos+1);
res = (/^[a-z0-9%]+$/i).test(s) ? s : '';
return v ? URI.decodePathSegment(res) : res;
} else {
if (v.charAt(0) === '.') {
v = v.substring(1);
}
var suffix = this.suffix();
var replace;
if (!suffix) {
if (!v) {
return this;
}
this._parts.path += '.' + URI.recodePath(v);
} else if (!v) {
replace = new RegExp(escapeRegEx('.' + suffix) + '$');
} else {
replace = new RegExp(escapeRegEx(suffix) + '$');
}
if (replace) {
v = URI.recodePath(v);
this._parts.path = this._parts.path.replace(replace, v);
}
this.build(!build);
return this;
}
};
p.segment = function(segment, v, build) {
var separator = this._parts.urn ? ':' : '/';
var path = this.path();
var absolute = path.substring(0, 1) === '/';
var segments = path.split(separator);
if (segment !== undefined && typeof segment !== 'number') {
build = v;
v = segment;
segment = undefined;
}
if (segment !== undefined && typeof segment !== 'number') {
throw new Error('Bad segment "' + segment + '", must be 0-based integer');
}
if (absolute) {
segments.shift();
}
if (segment < 0) {
// allow negative indexes to address from the end
segment = Math.max(segments.length + segment, 0);
}
if (v === undefined) {
/*jshint laxbreak: true */
return segment === undefined
? segments
: segments[segment];
/*jshint laxbreak: false */
} else if (segment === null || segments[segment] === undefined) {
if (isArray(v)) {
segments = [];
// collapse empty elements within array
for (var i=0, l=v.length; i < l; i++) {
if (!v[i].length && (!segments.length || !segments[segments.length -1].length)) {
continue;
}
if (segments.length && !segments[segments.length -1].length) {
segments.pop();
}
segments.push(trimSlashes(v[i]));
}
} else if (v || typeof v === 'string') {
v = trimSlashes(v);
if (segments[segments.length -1] === '') {
// empty trailing elements have to be overwritten
// to prevent results such as /foo//bar
segments[segments.length -1] = v;
} else {
segments.push(v);
}
}
} else {
if (v) {
segments[segment] = trimSlashes(v);
} else {
segments.splice(segment, 1);
}
}
if (absolute) {
segments.unshift('');
}
return this.path(segments.join(separator), build);
};
p.segmentCoded = function(segment, v, build) {
var segments, i, l;
if (typeof segment !== 'number') {
build = v;
v = segment;
segment = undefined;
}
if (v === undefined) {
segments = this.segment(segment, v, build);
if (!isArray(segments)) {
segments = segments !== undefined ? URI.decode(segments) : undefined;
} else {
for (i = 0, l = segments.length; i < l; i++) {
segments[i] = URI.decode(segments[i]);
}
}
return segments;
}
if (!isArray(v)) {
v = (typeof v === 'string' || v instanceof String) ? URI.encode(v) : v;
} else {
for (i = 0, l = v.length; i < l; i++) {
v[i] = URI.encode(v[i]);
}
}
return this.segment(segment, v, build);
};
// mutating query string
var q = p.query;
p.query = function(v, build) {
if (v === true) {
return URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
} else if (typeof v === 'function') {
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
var result = v.call(this, data);
this._parts.query = URI.buildQuery(result || data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
this.build(!build);
return this;
} else if (v !== undefined && typeof v !== 'string') {
this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
this.build(!build);
return this;
} else {
return q.call(this, v, build);
}
};
p.setQuery = function(name, value, build) {
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
if (typeof name === 'string' || name instanceof String) {
data[name] = value !== undefined ? value : null;
} else if (typeof name === 'object') {
for (var key in name) {
if (hasOwn.call(name, key)) {
data[key] = name[key];
}
}
} else {
throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');
}
this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
if (typeof name !== 'string') {
build = value;
}
this.build(!build);
return this;
};
p.addQuery = function(name, value, build) {
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
URI.addQuery(data, name, value === undefined ? null : value);
this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
if (typeof name !== 'string') {
build = value;
}
this.build(!build);
return this;
};
p.removeQuery = function(name, value, build) {
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
URI.removeQuery(data, name, value);
this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
if (typeof name !== 'string') {
build = value;
}
this.build(!build);
return this;
};
p.hasQuery = function(name, value, withinArray) {
var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
return URI.hasQuery(data, name, value, withinArray);
};
p.setSearch = p.setQuery;
p.addSearch = p.addQuery;
p.removeSearch = p.removeQuery;
p.hasSearch = p.hasQuery;
// sanitizing URLs
p.normalize = function() {
if (this._parts.urn) {
return this
.normalizeProtocol(false)
.normalizePath(false)
.normalizeQuery(false)
.normalizeFragment(false)
.build();
}
return this
.normalizeProtocol(false)
.normalizeHostname(false)
.normalizePort(false)
.normalizePath(false)
.normalizeQuery(false)
.normalizeFragment(false)
.build();
};
p.normalizeProtocol = function(build) {
if (typeof this._parts.protocol === 'string') {
this._parts.protocol = this._parts.protocol.toLowerCase();
this.build(!build);
}
return this;
};
p.normalizeHostname = function(build) {
if (this._parts.hostname) {
if (this.is('IDN') && punycode) {
this._parts.hostname = punycode.toASCII(this._parts.hostname);
} else if (this.is('IPv6') && IPv6) {
this._parts.hostname = IPv6.best(this._parts.hostname);
}
this._parts.hostname = this._parts.hostname.toLowerCase();
this.build(!build);
}
return this;
};
p.normalizePort = function(build) {
// remove port of it's the protocol's default
if (typeof this._parts.protocol === 'string' && this._parts.port === URI.defaultPorts[this._parts.protocol]) {
this._parts.port = null;
this.build(!build);
}
return this;
};
p.normalizePath = function(build) {
var _path = this._parts.path;
if (!_path) {
return this;
}
if (this._parts.urn) {
this._parts.path = URI.recodeUrnPath(this._parts.path);
this.build(!build);
return this;
}
if (this._parts.path === '/') {
return this;
}
_path = URI.recodePath(_path);
var _was_relative;
var _leadingParents = '';
var _parent, _pos;
// handle relative paths
if (_path.charAt(0) !== '/') {
_was_relative = true;
_path = '/' + _path;
}
// handle relative files (as opposed to directories)
if (_path.slice(-3) === '/..' || _path.slice(-2) === '/.') {
_path += '/';
}
// resolve simples
_path = _path
.replace(/(\/(\.\/)+)|(\/\.$)/g, '/')
.replace(/\/{2,}/g, '/');
// remember leading parents
if (_was_relative) {
_leadingParents = _path.substring(1).match(/^(\.\.\/)+/) || '';
if (_leadingParents) {
_leadingParents = _leadingParents[0];
}
}
// resolve parents
while (true) {
_parent = _path.search(/\/\.\.(\/|$)/);
if (_parent === -1) {
// no more ../ to resolve
break;
} else if (_parent === 0) {
// top level cannot be relative, skip it
_path = _path.substring(3);
continue;
}
_pos = _path.substring(0, _parent).lastIndexOf('/');
if (_pos === -1) {
_pos = _parent;
}
_path = _path.substring(0, _pos) + _path.substring(_parent + 3);
}
// revert to relative
if (_was_relative && this.is('relative')) {
_path = _leadingParents + _path.substring(1);
}
this._parts.path = _path;
this.build(!build);
return this;
};
p.normalizePathname = p.normalizePath;
p.normalizeQuery = function(build) {
if (typeof this._parts.query === 'string') {
if (!this._parts.query.length) {
this._parts.query = null;
} else {
this.query(URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace));
}
this.build(!build);
}
return this;
};
p.normalizeFragment = function(build) {
if (!this._parts.fragment) {
this._parts.fragment = null;
this.build(!build);
}
return this;
};
p.normalizeSearch = p.normalizeQuery;
p.normalizeHash = p.normalizeFragment;
p.iso8859 = function() {
// expect unicode input, iso8859 output
var e = URI.encode;
var d = URI.decode;
URI.encode = escape;
URI.decode = decodeURIComponent;
try {
this.normalize();
} finally {
URI.encode = e;
URI.decode = d;
}
return this;
};
p.unicode = function() {
// expect iso8859 input, unicode output
var e = URI.encode;
var d = URI.decode;
URI.encode = strictEncodeURIComponent;
URI.decode = unescape;
try {
this.normalize();
} finally {
URI.encode = e;
URI.decode = d;
}
return this;
};
p.readable = function() {
var uri = this.clone();
// removing username, password, because they shouldn't be displayed according to RFC 3986
uri.username('').password('').normalize();
var t = '';
if (uri._parts.protocol) {
t += uri._parts.protocol + '://';
}
if (uri._parts.hostname) {
if (uri.is('punycode') && punycode) {
t += punycode.toUnicode(uri._parts.hostname);
if (uri._parts.port) {
t += ':' + uri._parts.port;
}
} else {
t += uri.host();
}
}
if (uri._parts.hostname && uri._parts.path && uri._parts.path.charAt(0) !== '/') {
t += '/';
}
t += uri.path(true);
if (uri._parts.query) {
var q = '';
for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) {
var kv = (qp[i] || '').split('=');
q += '&' + URI.decodeQuery(kv[0], this._parts.escapeQuerySpace)
.replace(/&/g, '%26');
if (kv[1] !== undefined) {
q += '=' + URI.decodeQuery(kv[1], this._parts.escapeQuerySpace)
.replace(/&/g, '%26');
}
}
t += '?' + q.substring(1);
}
t += URI.decodeQuery(uri.hash(), true);
return t;
};
// resolving relative and absolute URLs
p.absoluteTo = function(base) {
var resolved = this.clone();
var properties = ['protocol', 'username', 'password', 'hostname', 'port'];
var basedir, i, p;
if (this._parts.urn) {
throw new Error('URNs do not have any generally defined hierarchical components');
}
if (!(base instanceof URI)) {
base = new URI(base);
}
if (resolved._parts.protocol) {
// Directly returns even if this._parts.hostname is empty.
return resolved;
} else {
resolved._parts.protocol = base._parts.protocol;
}
if (this._parts.hostname) {
return resolved;
}
for (i = 0; (p = properties[i]); i++) {
resolved._parts[p] = base._parts[p];
}
if (!resolved._parts.path) {
resolved._parts.path = base._parts.path;
if (!resolved._parts.query) {
resolved._parts.query = base._parts.query;
}
} else {
if (resolved._parts.path.substring(-2) === '..') {
resolved._parts.path += '/';
}
if (resolved.path().charAt(0) !== '/') {
basedir = base.directory();
basedir = basedir ? basedir : base.path().indexOf('/') === 0 ? '/' : '';
resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path;
resolved.normalizePath();
}
}
resolved.build();
return resolved;
};
p.relativeTo = function(base) {
var relative = this.clone().normalize();
var relativeParts, baseParts, common, relativePath, basePath;
if (relative._parts.urn) {
throw new Error('URNs do not have any generally defined hierarchical components');
}
base = new URI(base).normalize();
relativeParts = relative._parts;
baseParts = base._parts;
relativePath = relative.path();
basePath = base.path();
if (relativePath.charAt(0) !== '/') {
throw new Error('URI is already relative');
}
if (basePath.charAt(0) !== '/') {
throw new Error('Cannot calculate a URI relative to another relative URI');
}
if (relativeParts.protocol === baseParts.protocol) {
relativeParts.protocol = null;
}
if (relativeParts.username !== baseParts.username || relativeParts.password !== baseParts.password) {
return relative.build();
}
if (relativeParts.protocol !== null || relativeParts.username !== null || relativeParts.password !== null) {
return relative.build();
}
if (relativeParts.hostname === baseParts.hostname && relativeParts.port === baseParts.port) {
relativeParts.hostname = null;
relativeParts.port = null;
} else {
return relative.build();
}
if (relativePath === basePath) {
relativeParts.path = '';
return relative.build();
}
// determine common sub path
common = URI.commonPath(relativePath, basePath);
// If the paths have nothing in common, return a relative URL with the absolute path.
if (!common) {
return relative.build();
}
var parents = baseParts.path
.substring(common.length)
.replace(/[^\/]*$/, '')
.replace(/.*?\//g, '../');
relativeParts.path = (parents + relativeParts.path.substring(common.length)) || './';
return relative.build();
};
// comparing URIs
p.equals = function(uri) {
var one = this.clone();
var two = new URI(uri);
var one_map = {};
var two_map = {};
var checked = {};
var one_query, two_query, key;
one.normalize();
two.normalize();
// exact match
if (one.toString() === two.toString()) {
return true;
}
// extract query string
one_query = one.query();
two_query = two.query();
one.query('');
two.query('');
// definitely not equal if not even non-query parts match
if (one.toString() !== two.toString()) {
return false;
}
// query parameters have the same length, even if they're permuted
if (one_query.length !== two_query.length) {
return false;
}
one_map = URI.parseQuery(one_query, this._parts.escapeQuerySpace);
two_map = URI.parseQuery(two_query, this._parts.escapeQuerySpace);
for (key in one_map) {
if (hasOwn.call(one_map, key)) {
if (!isArray(one_map[key])) {
if (one_map[key] !== two_map[key]) {
return false;
}
} else if (!arraysEqual(one_map[key], two_map[key])) {
return false;
}
checked[key] = true;
}
}
for (key in two_map) {
if (hasOwn.call(two_map, key)) {
if (!checked[key]) {
// two contains a parameter not present in one
return false;
}
}
}
return true;
};
// state
p.preventInvalidHostname = function(v) {
this._parts.preventInvalidHostname = !!v;
return this;
};
p.duplicateQueryParameters = function(v) {
this._parts.duplicateQueryParameters = !!v;
return this;
};
p.escapeQuerySpace = function(v) {
this._parts.escapeQuerySpace = !!v;
return this;
};
return URI;
}));
});
/**
* Given a relative Uri and a base Uri, returns the absolute Uri of the relative Uri.
* @function
*
* @param {String} relative The relative Uri.
* @param {String} [base] The base Uri.
* @returns {String} The absolute Uri of the given relative Uri.
*
* @example
* //absolute Uri will be "https://test.com/awesome.png";
* const absoluteUri = Cesium.getAbsoluteUri('awesome.png', 'https://test.com');
*/
function getAbsoluteUri(relative, base) {
let documentObject;
if (typeof document !== "undefined") {
documentObject = document;
}
return getAbsoluteUri._implementation(relative, base, documentObject);
}
getAbsoluteUri._implementation = function (relative, base, documentObject) {
//>>includeStart('debug', pragmas.debug);
if (!defined(relative)) {
throw new DeveloperError("relative uri is required.");
}
//>>includeEnd('debug');
if (!defined(base)) {
if (typeof documentObject === "undefined") {
return relative;
}
base = defaultValue(documentObject.baseURI, documentObject.location.href);
}
const relativeUri = new URI(relative);
if (relativeUri.scheme() !== "") {
return relativeUri.toString();
}
return relativeUri.absoluteTo(base).toString();
};
/* This file is automatically rebuilt by the Cesium build process. */
var when = createCommonjsModule(function (module, exports) {
/** @license MIT License (c) copyright B Cavalier & J Hann */
/**
* A lightweight CommonJS Promises/A and when() implementation
* when is part of the cujo.js family of libraries (http://cujojs.com/)
*
* Licensed under the MIT License at:
* http://www.opensource.org/licenses/mit-license.php
*
* @version 1.7.1
*/
(function(define) {define(function () {
var reduceArray, slice, undef;
//
// Public API
//
when.defer = defer; // Create a deferred
when.resolve = resolve; // Create a resolved promise
when.reject = reject; // Create a rejected promise
when.join = join; // Join 2 or more promises
when.all = all; // Resolve a list of promises
when.map = map; // Array.map() for promises
when.reduce = reduce; // Array.reduce() for promises
when.any = any; // One-winner race
when.some = some; // Multi-winner race
when.chain = chain; // Make a promise trigger another resolver
when.isPromise = isPromise; // Determine if a thing is a promise
/**
* Register an observer for a promise or immediate value.
*
* @param {*} promiseOrValue
* @param {function?} [onFulfilled] callback to be called when promiseOrValue is
* successfully fulfilled. If promiseOrValue is an immediate value, callback
* will be invoked immediately.
* @param {function?} [onRejected] callback to be called when promiseOrValue is
* rejected.
* @param {function?} [onProgress] callback to be called when progress updates
* are issued for promiseOrValue.
* @returns {Promise} a new {@link Promise} that will complete with the return
* value of callback or errback or the completion value of promiseOrValue if
* callback and/or errback is not supplied.
*/
function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
// Get a trusted promise for the input promiseOrValue, and then
// register promise handlers
return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
}
/**
* Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if
* promiseOrValue is a foreign promise, or a new, already-fulfilled {@link Promise}
* whose value is promiseOrValue if promiseOrValue is an immediate value.
*
* @param {*} promiseOrValue
* @returns Guaranteed to return a trusted Promise. If promiseOrValue is a when.js {@link Promise}
* returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link Promise}
* whose resolution value is:
* * the resolution value of promiseOrValue if it's a foreign promise, or
* * promiseOrValue if it's a value
*/
function resolve(promiseOrValue) {
var promise, deferred;
if(promiseOrValue instanceof Promise) {
// It's a when.js promise, so we trust it
promise = promiseOrValue;
} else {
// It's not a when.js promise. See if it's a foreign promise or a value.
if(isPromise(promiseOrValue)) {
// It's a thenable, but we don't know where it came from, so don't trust
// its implementation entirely. Introduce a trusted middleman when.js promise
deferred = defer();
// IMPORTANT: This is the only place when.js should ever call .then() on an
// untrusted promise. Don't expose the return value to the untrusted promise
promiseOrValue.then(
function(value) { deferred.resolve(value); },
function(reason) { deferred.reject(reason); },
function(update) { deferred.progress(update); }
);
promise = deferred.promise;
} else {
// It's a value, not a promise. Create a resolved promise for it.
promise = fulfilled(promiseOrValue);
}
}
return promise;
}
/**
* Returns a rejected promise for the supplied promiseOrValue. The returned
* promise will be rejected with:
* - promiseOrValue, if it is a value, or
* - if promiseOrValue is a promise
* - promiseOrValue's value after it is fulfilled
* - promiseOrValue's reason after it is rejected
* @param {*} promiseOrValue the rejected value of the returned {@link Promise}
* @return {Promise} rejected {@link Promise}
*/
function reject(promiseOrValue) {
return when(promiseOrValue, rejected);
}
/**
* Trusted Promise constructor. A Promise created from this constructor is
* a trusted when.js promise. Any other duck-typed promise is considered
* untrusted.
* @constructor
* @name Promise
*/
function Promise(then) {
this.then = then;
}
Promise.prototype = {
/**
* Register a callback that will be called when a promise is
* fulfilled or rejected. Optionally also register a progress handler.
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress)
* @param {function?} [onFulfilledOrRejected]
* @param {function?} [onProgress]
* @return {Promise}
*/
always: function(onFulfilledOrRejected, onProgress) {
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
},
/**
* Register a rejection handler. Shortcut for .then(undefined, onRejected)
* @param {function?} onRejected
* @return {Promise}
*/
otherwise: function(onRejected) {
return this.then(undef, onRejected);
},
/**
* Shortcut for .then(function() { return value; })
* @param {*} value
* @return {Promise} a promise that:
* - is fulfilled if value is not a promise, or
* - if value is a promise, will fulfill with its value, or reject
* with its reason.
*/
yield: function(value) {
return this.then(function() {
return value;
});
},
/**
* Assumes that this promise will fulfill with an array, and arranges
* for the onFulfilled to be called with the array as its argument list
* i.e. onFulfilled.spread(undefined, array).
* @param {function} onFulfilled function to receive spread arguments
* @return {Promise}
*/
spread: function(onFulfilled) {
return this.then(function(array) {
// array may contain promises, so resolve its contents.
return all(array, function(array) {
return onFulfilled.apply(undef, array);
});
});
}
};
/**
* Create an already-resolved promise for the supplied value
* @private
*
* @param {*} value
* @return {Promise} fulfilled promise
*/
function fulfilled(value) {
var p = new Promise(function(onFulfilled) {
// TODO: Promises/A+ check typeof onFulfilled
try {
return resolve(onFulfilled ? onFulfilled(value) : value);
} catch(e) {
return rejected(e);
}
});
return p;
}
/**
* Create an already-rejected {@link Promise} with the supplied
* rejection reason.
* @private
*
* @param {*} reason
* @return {Promise} rejected promise
*/
function rejected(reason) {
var p = new Promise(function(_, onRejected) {
// TODO: Promises/A+ check typeof onRejected
try {
return onRejected ? resolve(onRejected(reason)) : rejected(reason);
} catch(e) {
return rejected(e);
}
});
return p;
}
/**
* Creates a new, Deferred with fully isolated resolver and promise parts,
* either or both of which may be given out safely to consumers.
* The Deferred itself has the full API: resolve, reject, progress, and
* then. The resolver has resolve, reject, and progress. The promise
* only has then.
*
* @return {Deferred}
*/
function defer() {
var deferred, promise, handlers, progressHandlers,
_then, _progress, _resolve;
/**
* The promise for the new deferred
* @type {Promise}
*/
promise = new Promise(then);
/**
* The full Deferred object, with {@link Promise} and {@link Resolver} parts
* @class Deferred
* @name Deferred
*/
deferred = {
then: then, // DEPRECATED: use deferred.promise.then
resolve: promiseResolve,
reject: promiseReject,
// TODO: Consider renaming progress() to notify()
progress: promiseProgress,
promise: promise,
resolver: {
resolve: promiseResolve,
reject: promiseReject,
progress: promiseProgress
}
};
handlers = [];
progressHandlers = [];
/**
* Pre-resolution then() that adds the supplied callback, errback, and progback
* functions to the registered listeners
* @private
*
* @param {function?} [onFulfilled] resolution handler
* @param {function?} [onRejected] rejection handler
* @param {function?} [onProgress] progress handler
*/
_then = function(onFulfilled, onRejected, onProgress) {
// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
var deferred, progressHandler;
deferred = defer();
progressHandler = typeof onProgress === 'function'
? function(update) {
try {
// Allow progress handler to transform progress event
deferred.progress(onProgress(update));
} catch(e) {
// Use caught value as progress
deferred.progress(e);
}
}
: function(update) { deferred.progress(update); };
handlers.push(function(promise) {
promise.then(onFulfilled, onRejected)
.then(deferred.resolve, deferred.reject, progressHandler);
});
progressHandlers.push(progressHandler);
return deferred.promise;
};
/**
* Issue a progress event, notifying all progress listeners
* @private
* @param {*} update progress event payload to pass to all listeners
*/
_progress = function(update) {
processQueue(progressHandlers, update);
return update;
};
/**
* Transition from pre-resolution state to post-resolution state, notifying
* all listeners of the resolution or rejection
* @private
* @param {*} value the value of this deferred
*/
_resolve = function(value) {
value = resolve(value);
// Replace _then with one that directly notifies with the result.
_then = value.then;
// Replace _resolve so that this Deferred can only be resolved once
_resolve = resolve;
// Make _progress a noop, to disallow progress for the resolved promise.
_progress = noop;
// Notify handlers
processQueue(handlers, value);
// Free progressHandlers array since we'll never issue progress events
progressHandlers = handlers = undef;
return value;
};
return deferred;
/**
* Wrapper to allow _then to be replaced safely
* @param {function?} [onFulfilled] resolution handler
* @param {function?} [onRejected] rejection handler
* @param {function?} [onProgress] progress handler
* @return {Promise} new promise
*/
function then(onFulfilled, onRejected, onProgress) {
// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
return _then(onFulfilled, onRejected, onProgress);
}
/**
* Wrapper to allow _resolve to be replaced
*/
function promiseResolve(val) {
return _resolve(val);
}
/**
* Wrapper to allow _reject to be replaced
*/
function promiseReject(err) {
return _resolve(rejected(err));
}
/**
* Wrapper to allow _progress to be replaced
*/
function promiseProgress(update) {
return _progress(update);
}
}
/**
* Determines if promiseOrValue is a promise or not. Uses the feature
* test from http://wiki.commonjs.org/wiki/Promises/A to determine if
* promiseOrValue is a promise.
*
* @param {*} promiseOrValue anything
* @returns {boolean} true if promiseOrValue is a {@link Promise}
*/
function isPromise(promiseOrValue) {
return promiseOrValue && typeof promiseOrValue.then === 'function';
}
/**
* Initiates a competitive race, returning a promise that will resolve when
* howMany of the supplied promisesOrValues have resolved, or will reject when
* it becomes impossible for howMany to resolve, for example, when
* (promisesOrValues.length - howMany) + 1 input promises reject.
*
* @param {Array} promisesOrValues array of anything, may contain a mix
* of promises and values
* @param howMany {number} number of promisesOrValues to resolve
* @param {function?} [onFulfilled] resolution handler
* @param {function?} [onRejected] rejection handler
* @param {function?} [onProgress] progress handler
* @returns {Promise} promise that will resolve to an array of howMany values that
* resolved first, or will reject with an array of (promisesOrValues.length - howMany) + 1
* rejection reasons.
*/
function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
checkCallbacks(2, arguments);
return when(promisesOrValues, function(promisesOrValues) {
var toResolve, toReject, values, reasons, deferred, fulfillOne, rejectOne, progress, len, i;
len = promisesOrValues.length >>> 0;
toResolve = Math.max(0, Math.min(howMany, len));
values = [];
toReject = (len - toResolve) + 1;
reasons = [];
deferred = defer();
// No items in the input, resolve immediately
if (!toResolve) {
deferred.resolve(values);
} else {
progress = deferred.progress;
rejectOne = function(reason) {
reasons.push(reason);
if(!--toReject) {
fulfillOne = rejectOne = noop;
deferred.reject(reasons);
}
};
fulfillOne = function(val) {
// This orders the values based on promise resolution order
// Another strategy would be to use the original position of
// the corresponding promise.
values.push(val);
if (!--toResolve) {
fulfillOne = rejectOne = noop;
deferred.resolve(values);
}
};
for(i = 0; i < len; ++i) {
if(i in promisesOrValues) {
when(promisesOrValues[i], fulfiller, rejecter, progress);
}
}
}
return deferred.then(onFulfilled, onRejected, onProgress);
function rejecter(reason) {
rejectOne(reason);
}
function fulfiller(val) {
fulfillOne(val);
}
});
}
/**
* Initiates a competitive race, returning a promise that will resolve when
* any one of the supplied promisesOrValues has resolved or will reject when
* *all* promisesOrValues have rejected.
*
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix
* of {@link Promise}s and values
* @param {function?} [onFulfilled] resolution handler
* @param {function?} [onRejected] rejection handler
* @param {function?} [onProgress] progress handler
* @returns {Promise} promise that will resolve to the value that resolved first, or
* will reject with an array of all rejected inputs.
*/
function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
function unwrapSingleResult(val) {
return onFulfilled ? onFulfilled(val[0]) : val[0];
}
return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
}
/**
* Return a promise that will resolve only once all the supplied promisesOrValues
* have resolved. The resolution value of the returned promise will be an array
* containing the resolution values of each of the promisesOrValues.
* @memberOf when
*
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix
* of {@link Promise}s and values
* @param {function?} [onFulfilled] resolution handler
* @param {function?} [onRejected] rejection handler
* @param {function?} [onProgress] progress handler
* @returns {Promise}
*/
function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
checkCallbacks(1, arguments);
return map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
}
/**
* Joins multiple promises into a single returned promise.
* @return {Promise} a promise that will fulfill when *all* the input promises
* have fulfilled, or will reject when *any one* of the input promises rejects.
*/
function join(/* ...promises */) {
return map(arguments, identity);
}
/**
* Traditional map function, similar to `Array.prototype.map()`, but allows
* input to contain {@link Promise}s and/or values, and mapFunc may return
* either a value or a {@link Promise}
*
* @param {Array|Promise} promise array of anything, may contain a mix
* of {@link Promise}s and values
* @param {function} mapFunc mapping function mapFunc(value) which may return
* either a {@link Promise} or value
* @returns {Promise} a {@link Promise} that will resolve to an array containing
* the mapped output values.
*/
function map(promise, mapFunc) {
return when(promise, function(array) {
var results, len, toResolve, resolve, i, d;
// Since we know the resulting length, we can preallocate the results
// array to avoid array expansions.
toResolve = len = array.length >>> 0;
results = [];
d = defer();
if(!toResolve) {
d.resolve(results);
} else {
resolve = function resolveOne(item, i) {
when(item, mapFunc).then(function(mapped) {
results[i] = mapped;
if(!--toResolve) {
d.resolve(results);
}
}, d.reject);
};
// Since mapFunc may be async, get all invocations of it into flight
for(i = 0; i < len; i++) {
if(i in array) {
resolve(array[i], i);
} else {
--toResolve;
}
}
}
return d.promise;
});
}
/**
* Traditional reduce function, similar to `Array.prototype.reduce()`, but
* input may contain promises and/or values, and reduceFunc
* may return either a value or a promise, *and* initialValue may
* be a promise for the starting value.
*
* @param {Array|Promise} promise array or promise for an array of anything,
* may contain a mix of promises and values.
* @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
* where total is the total number of items being reduced, and will be the same
* in each call to reduceFunc.
* @returns {Promise} that will resolve to the final reduced value
*/
function reduce(promise, reduceFunc /*, initialValue */) {
var args = slice.call(arguments, 1);
return when(promise, function(array) {
var total;
total = array.length;
// Wrap the supplied reduceFunc with one that handles promises and then
// delegates to the supplied.
args[0] = function (current, val, i) {
return when(current, function (c) {
return when(val, function (value) {
return reduceFunc(c, value, i, total);
});
});
};
return reduceArray.apply(array, args);
});
}
/**
* Ensure that resolution of promiseOrValue will trigger resolver with the
* value or reason of promiseOrValue, or instead with resolveValue if it is provided.
*
* @param promiseOrValue
* @param {Object} resolver
* @param {function} resolver.resolve
* @param {function} resolver.reject
* @param {*} [resolveValue]
* @returns {Promise}
*/
function chain(promiseOrValue, resolver, resolveValue) {
var useResolveValue = arguments.length > 2;
return when(promiseOrValue,
function(val) {
val = useResolveValue ? resolveValue : val;
resolver.resolve(val);
return val;
},
function(reason) {
resolver.reject(reason);
return rejected(reason);
},
resolver.progress
);
}
//
// Utility functions
//
/**
* Apply all functions in queue to value
* @param {Array} queue array of functions to execute
* @param {*} value argument passed to each function
*/
function processQueue(queue, value) {
var handler, i = 0;
while (handler = queue[i++]) {
handler(value);
}
}
/**
* Helper that checks arrayOfCallbacks to ensure that each element is either
* a function, or null or undefined.
* @private
* @param {number} start index at which to start checking items in arrayOfCallbacks
* @param {Array} arrayOfCallbacks array to check
* @throws {Error} if any element of arrayOfCallbacks is something other than
* a functions, null, or undefined.
*/
function checkCallbacks(start, arrayOfCallbacks) {
// TODO: Promises/A+ update type checking and docs
var arg, i = arrayOfCallbacks.length;
while(i > start) {
arg = arrayOfCallbacks[--i];
if (arg != null && typeof arg != 'function') {
throw new Error('arg '+i+' must be a function');
}
}
}
/**
* No-Op function used in method replacement
* @private
*/
function noop() {}
slice = [].slice;
// ES5 reduce implementation if native not available
// See: http://es5.github.com/#x15.4.4.21 as there are many
// specifics and edge cases.
reduceArray = [].reduce ||
function(reduceFunc /*, initialValue */) {
/*jshint maxcomplexity: 7*/
// ES5 dictates that reduce.length === 1
// This implementation deviates from ES5 spec in the following ways:
// 1. It does not check if reduceFunc is a Callable
var arr, args, reduced, len, i;
i = 0;
// This generates a jshint warning, despite being valid
// "Missing 'new' prefix when invoking a constructor."
// See https://github.com/jshint/jshint/issues/392
arr = Object(this);
len = arr.length >>> 0;
args = arguments;
// If no initialValue, use first item of array (we know length !== 0 here)
// and adjust i to start at second item
if(args.length <= 1) {
// Skip to the first real element in the array
for(;;) {
if(i in arr) {
reduced = arr[i++];
break;
}
// If we reached the end of the array without finding any real
// elements, it's a TypeError
if(++i >= len) {
throw new TypeError();
}
}
} else {
// If initialValue provided, use it
reduced = args[1];
}
// Do the actual reduce
for(;i < len; ++i) {
// Skip holes
if(i in arr) {
reduced = reduceFunc(reduced, arr[i], i, arr);
}
}
return reduced;
};
function identity(x) {
return x;
}
return when;
});
})(function (factory) { (module.exports = factory())
;
}
// Boilerplate for AMD, Node, and browser global
);
});
/**
* @private
*/
function appendForwardSlash(url) {
if (url.length === 0 || url[url.length - 1] !== "/") {
url = `${url}/`;
}
return url;
}
/**
* Clones an object, returning a new object containing the same properties.
*
* @function
*
* @param {Object} object The object to clone.
* @param {Boolean} [deep=false] If true, all properties will be deep cloned recursively.
* @returns {Object} The cloned object.
*/
function clone$1(object, deep) {
if (object === null || typeof object !== "object") {
return object;
}
deep = defaultValue(deep, false);
const result = new object.constructor();
for (const propertyName in object) {
if (object.hasOwnProperty(propertyName)) {
let value = object[propertyName];
if (deep) {
value = clone$1(value, deep);
}
result[propertyName] = value;
}
}
return result;
}
/**
* Merges two objects, copying their properties onto a new combined object. When two objects have the same
* property, the value of the property on the first object is used. If either object is undefined,
* it will be treated as an empty object.
*
* @example
* const object1 = {
* propOne : 1,
* propTwo : {
* value1 : 10
* }
* }
* const object2 = {
* propTwo : 2
* }
* const final = Cesium.combine(object1, object2);
*
* // final === {
* // propOne : 1,
* // propTwo : {
* // value1 : 10
* // }
* // }
*
* @param {Object} [object1] The first object to merge.
* @param {Object} [object2] The second object to merge.
* @param {Boolean} [deep=false] Perform a recursive merge.
* @returns {Object} The combined object containing all properties from both objects.
*
* @function
*/
function combine$2(object1, object2, deep) {
deep = defaultValue(deep, false);
const result = {};
const object1Defined = defined(object1);
const object2Defined = defined(object2);
let property;
let object1Value;
let object2Value;
if (object1Defined) {
for (property in object1) {
if (object1.hasOwnProperty(property)) {
object1Value = object1[property];
if (
object2Defined &&
deep &&
typeof object1Value === "object" &&
object2.hasOwnProperty(property)
) {
object2Value = object2[property];
if (typeof object2Value === "object") {
result[property] = combine$2(object1Value, object2Value, deep);
} else {
result[property] = object1Value;
}
} else {
result[property] = object1Value;
}
}
}
}
if (object2Defined) {
for (property in object2) {
if (
object2.hasOwnProperty(property) &&
!result.hasOwnProperty(property)
) {
object2Value = object2[property];
result[property] = object2Value;
}
}
}
return result;
}
/**
* Given a URI, returns the base path of the URI.
* @function
*
* @param {String} uri The Uri.
* @param {Boolean} [includeQuery = false] Whether or not to include the query string and fragment form the uri
* @returns {String} The base path of the Uri.
*
* @example
* // basePath will be "/Gallery/";
* const basePath = Cesium.getBaseUri('/Gallery/simple.czml?value=true&example=false');
*
* // basePath will be "/Gallery/?value=true&example=false";
* const basePath = Cesium.getBaseUri('/Gallery/simple.czml?value=true&example=false', true);
*/
function getBaseUri(uri, includeQuery) {
//>>includeStart('debug', pragmas.debug);
if (!defined(uri)) {
throw new DeveloperError("uri is required.");
}
//>>includeEnd('debug');
let basePath = "";
const i = uri.lastIndexOf("/");
if (i !== -1) {
basePath = uri.substring(0, i + 1);
}
if (!includeQuery) {
return basePath;
}
uri = new URI(uri);
if (uri.query().length !== 0) {
basePath += `?${uri.query()}`;
}
if (uri.fragment().length !== 0) {
basePath += `#${uri.fragment()}`;
}
return basePath;
}
/**
* Given a URI, returns the extension of the URI.
* @function getExtensionFromUri
*
* @param {String} uri The Uri.
* @returns {String} The extension of the Uri.
*
* @example
* //extension will be "czml";
* const extension = Cesium.getExtensionFromUri('/Gallery/simple.czml?value=true&example=false');
*/
function getExtensionFromUri(uri) {
//>>includeStart('debug', pragmas.debug);
if (!defined(uri)) {
throw new DeveloperError("uri is required.");
}
//>>includeEnd('debug');
const uriObject = new URI(uri);
uriObject.normalize();
let path = uriObject.path();
let index = path.lastIndexOf("/");
if (index !== -1) {
path = path.substr(index + 1);
}
index = path.lastIndexOf(".");
if (index === -1) {
path = "";
} else {
path = path.substr(index + 1);
}
return path;
}
const context2DsByWidthAndHeight = {};
/**
* Extract a pixel array from a loaded image. Draws the image
* into a canvas so it can read the pixels back.
*
* @function getImagePixels
*
* @param {HTMLImageElement|ImageBitmap} image The image to extract pixels from.
* @param {Number} width The width of the image. If not defined, then image.width is assigned.
* @param {Number} height The height of the image. If not defined, then image.height is assigned.
* @returns {ImageData} The pixels of the image.
*/
function getImagePixels(image, width, height) {
if (!defined(width)) {
width = image.width;
}
if (!defined(height)) {
height = image.height;
}
let context2DsByHeight = context2DsByWidthAndHeight[width];
if (!defined(context2DsByHeight)) {
context2DsByHeight = {};
context2DsByWidthAndHeight[width] = context2DsByHeight;
}
let context2d = context2DsByHeight[height];
if (!defined(context2d)) {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
context2d = canvas.getContext("2d");
context2d.globalCompositeOperation = "copy";
context2DsByHeight[height] = context2d;
}
context2d.drawImage(image, 0, 0, width, height);
return context2d.getImageData(0, 0, width, height).data;
}
const blobUriRegex = /^blob:/i;
/**
* Determines if the specified uri is a blob uri.
*
* @function isBlobUri
*
* @param {String} uri The uri to test.
* @returns {Boolean} true when the uri is a blob uri; otherwise, false.
*
* @private
*/
function isBlobUri(uri) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("uri", uri);
//>>includeEnd('debug');
return blobUriRegex.test(uri);
}
let a$2;
/**
* Given a URL, determine whether that URL is considered cross-origin to the current page.
*
* @private
*/
function isCrossOriginUrl(url) {
if (!defined(a$2)) {
a$2 = document.createElement("a");
}
// copy window location into the anchor to get consistent results
// when the port is default for the protocol (e.g. 80 for HTTP)
a$2.href = window.location.href;
// host includes both hostname and port if the port is not standard
const host = a$2.host;
const protocol = a$2.protocol;
a$2.href = url;
// IE only absolutizes href on get, not set
// eslint-disable-next-line no-self-assign
a$2.href = a$2.href;
return protocol !== a$2.protocol || host !== a$2.host;
}
const dataUriRegex$2 = /^data:/i;
/**
* Determines if the specified uri is a data uri.
*
* @function isDataUri
*
* @param {String} uri The uri to test.
* @returns {Boolean} true when the uri is a data uri; otherwise, false.
*
* @private
*/
function isDataUri(uri) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("uri", uri);
//>>includeEnd('debug');
return dataUriRegex$2.test(uri);
}
/**
* @private
*/
function loadAndExecuteScript(url) {
const deferred = when.defer();
const script = document.createElement("script");
script.async = true;
script.src = url;
const head = document.getElementsByTagName("head")[0];
script.onload = function () {
script.onload = undefined;
head.removeChild(script);
deferred.resolve();
};
script.onerror = function (e) {
deferred.reject(e);
};
head.appendChild(script);
return deferred.promise;
}
/**
* Converts an object representing a set of name/value pairs into a query string,
* with names and values encoded properly for use in a URL. Values that are arrays
* will produce multiple values with the same name.
* @function objectToQuery
*
* @param {Object} obj The object containing data to encode.
* @returns {String} An encoded query string.
*
*
* @example
* const str = Cesium.objectToQuery({
* key1 : 'some value',
* key2 : 'a/b',
* key3 : ['x', 'y']
* });
*
* @see queryToObject
* // str will be:
* // 'key1=some%20value&key2=a%2Fb&key3=x&key3=y'
*/
function objectToQuery(obj) {
//>>includeStart('debug', pragmas.debug);
if (!defined(obj)) {
throw new DeveloperError("obj is required.");
}
//>>includeEnd('debug');
let result = "";
for (const propName in obj) {
if (obj.hasOwnProperty(propName)) {
const value = obj[propName];
const part = `${encodeURIComponent(propName)}=`;
if (Array.isArray(value)) {
for (let i = 0, len = value.length; i < len; ++i) {
result += `${part + encodeURIComponent(value[i])}&`;
}
} else {
result += `${part + encodeURIComponent(value)}&`;
}
}
}
// trim last &
result = result.slice(0, -1);
// This function used to replace %20 with + which is more compact and readable.
// However, some servers didn't properly handle + as a space.
// https://github.com/CesiumGS/cesium/issues/2192
return result;
}
/**
* Parses a query string into an object, where the keys and values of the object are the
* name/value pairs from the query string, decoded. If a name appears multiple times,
* the value in the object will be an array of values.
* @function queryToObject
*
* @param {String} queryString The query string.
* @returns {Object} An object containing the parameters parsed from the query string.
*
*
* @example
* const obj = Cesium.queryToObject('key1=some%20value&key2=a%2Fb&key3=x&key3=y');
* // obj will be:
* // {
* // key1 : 'some value',
* // key2 : 'a/b',
* // key3 : ['x', 'y']
* // }
*
* @see objectToQuery
*/
function queryToObject(queryString) {
//>>includeStart('debug', pragmas.debug);
if (!defined(queryString)) {
throw new DeveloperError("queryString is required.");
}
//>>includeEnd('debug');
const result = {};
if (queryString === "") {
return result;
}
const parts = queryString.replace(/\+/g, "%20").split(/[&;]/);
for (let i = 0, len = parts.length; i < len; ++i) {
const subparts = parts[i].split("=");
const name = decodeURIComponent(subparts[0]);
let value = subparts[1];
if (defined(value)) {
value = decodeURIComponent(value);
} else {
value = "";
}
const resultValue = result[name];
if (typeof resultValue === "string") {
// expand the single value to an array
result[name] = [resultValue, value];
} else if (Array.isArray(resultValue)) {
resultValue.push(value);
} else {
result[name] = value;
}
}
return result;
}
/**
* State of the request.
*
* @enum {Number}
*/
const RequestState = {
/**
* Initial unissued state.
*
* @type Number
* @constant
*/
UNISSUED: 0,
/**
* Issued but not yet active. Will become active when open slots are available.
*
* @type Number
* @constant
*/
ISSUED: 1,
/**
* Actual http request has been sent.
*
* @type Number
* @constant
*/
ACTIVE: 2,
/**
* Request completed successfully.
*
* @type Number
* @constant
*/
RECEIVED: 3,
/**
* Request was cancelled, either explicitly or automatically because of low priority.
*
* @type Number
* @constant
*/
CANCELLED: 4,
/**
* Request failed.
*
* @type Number
* @constant
*/
FAILED: 5,
};
var RequestState$1 = Object.freeze(RequestState);
/**
* An enum identifying the type of request. Used for finer grained logging and priority sorting.
*
* @enum {Number}
*/
const RequestType = {
/**
* Terrain request.
*
* @type Number
* @constant
*/
TERRAIN: 0,
/**
* Imagery request.
*
* @type Number
* @constant
*/
IMAGERY: 1,
/**
* 3D Tiles request.
*
* @type Number
* @constant
*/
TILES3D: 2,
/**
* Other request.
*
* @type Number
* @constant
*/
OTHER: 3,
};
var RequestType$1 = Object.freeze(RequestType);
/**
* Stores information for making a request. In general this does not need to be constructed directly.
*
* @alias Request
* @constructor
* @param {Object} [options] An object with the following properties:
* @param {String} [options.url] The url to request.
* @param {Request.RequestCallback} [options.requestFunction] The function that makes the actual data request.
* @param {Request.CancelCallback} [options.cancelFunction] The function that is called when the request is cancelled.
* @param {Request.PriorityCallback} [options.priorityFunction] The function that is called to update the request's priority, which occurs once per frame.
* @param {Number} [options.priority=0.0] The initial priority of the request.
* @param {Boolean} [options.throttle=false] Whether to throttle and prioritize the request. If false, the request will be sent immediately. If true, the request will be throttled and sent based on priority.
* @param {Boolean} [options.throttleByServer=false] Whether to throttle the request by server.
* @param {RequestType} [options.type=RequestType.OTHER] The type of request.
*/
function Request(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
const throttleByServer = defaultValue(options.throttleByServer, false);
const throttle = defaultValue(options.throttle, false);
/**
* The URL to request.
*
* @type {String}
*/
this.url = options.url;
/**
* The function that makes the actual data request.
*
* @type {Request.RequestCallback}
*/
this.requestFunction = options.requestFunction;
/**
* The function that is called when the request is cancelled.
*
* @type {Request.CancelCallback}
*/
this.cancelFunction = options.cancelFunction;
/**
* The function that is called to update the request's priority, which occurs once per frame.
*
* @type {Request.PriorityCallback}
*/
this.priorityFunction = options.priorityFunction;
/**
* Priority is a unit-less value where lower values represent higher priority.
* For world-based objects, this is usually the distance from the camera.
* A request that does not have a priority function defaults to a priority of 0.
*
* If priorityFunction is defined, this value is updated every frame with the result of that call.
*
* @type {Number}
* @default 0.0
*/
this.priority = defaultValue(options.priority, 0.0);
/**
* Whether to throttle and prioritize the request. If false, the request will be sent immediately. If true, the
* request will be throttled and sent based on priority.
*
* @type {Boolean}
* @readonly
*
* @default false
*/
this.throttle = throttle;
/**
* Whether to throttle the request by server. Browsers typically support about 6-8 parallel connections
* for HTTP/1 servers, and an unlimited amount of connections for HTTP/2 servers. Setting this value
* to true
is preferable for requests going through HTTP/1 servers.
*
* @type {Boolean}
* @readonly
*
* @default false
*/
this.throttleByServer = throttleByServer;
/**
* Type of request.
*
* @type {RequestType}
* @readonly
*
* @default RequestType.OTHER
*/
this.type = defaultValue(options.type, RequestType$1.OTHER);
/**
* A key used to identify the server that a request is going to. It is derived from the url's authority and scheme.
*
* @type {String}
*
* @private
*/
this.serverKey = undefined;
/**
* The current state of the request.
*
* @type {RequestState}
* @readonly
*/
this.state = RequestState$1.UNISSUED;
/**
* The requests's deferred promise.
*
* @type {Object}
*
* @private
*/
this.deferred = undefined;
/**
* Whether the request was explicitly cancelled.
*
* @type {Boolean}
*
* @private
*/
this.cancelled = false;
}
/**
* Mark the request as cancelled.
*
* @private
*/
Request.prototype.cancel = function () {
this.cancelled = true;
};
/**
* Duplicates a Request instance.
*
* @param {Request} [result] The object onto which to store the result.
*
* @returns {Request} The modified result parameter or a new Resource instance if one was not provided.
*/
Request.prototype.clone = function (result) {
if (!defined(result)) {
return new Request(this);
}
result.url = this.url;
result.requestFunction = this.requestFunction;
result.cancelFunction = this.cancelFunction;
result.priorityFunction = this.priorityFunction;
result.priority = this.priority;
result.throttle = this.throttle;
result.throttleByServer = this.throttleByServer;
result.type = this.type;
result.serverKey = this.serverKey;
// These get defaulted because the cloned request hasn't been issued
result.state = this.RequestState.UNISSUED;
result.deferred = undefined;
result.cancelled = false;
return result;
};
/**
* Parses the result of XMLHttpRequest's getAllResponseHeaders() method into
* a dictionary.
*
* @function parseResponseHeaders
*
* @param {String} headerString The header string returned by getAllResponseHeaders(). The format is
* described here: http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
* @returns {Object} A dictionary of key/value pairs, where each key is the name of a header and the corresponding value
* is that header's value.
*
* @private
*/
function parseResponseHeaders(headerString) {
const headers = {};
if (!headerString) {
return headers;
}
const headerPairs = headerString.split("\u000d\u000a");
for (let i = 0; i < headerPairs.length; ++i) {
const headerPair = headerPairs[i];
// Can't use split() here because it does the wrong thing
// if the header value has the string ": " in it.
const index = headerPair.indexOf("\u003a\u0020");
if (index > 0) {
const key = headerPair.substring(0, index);
const val = headerPair.substring(index + 2);
headers[key] = val;
}
}
return headers;
}
/**
* An event that is raised when a request encounters an error.
*
* @constructor
* @alias RequestErrorEvent
*
* @param {Number} [statusCode] The HTTP error status code, such as 404.
* @param {Object} [response] The response included along with the error.
* @param {String|Object} [responseHeaders] The response headers, represented either as an object literal or as a
* string in the format returned by XMLHttpRequest's getAllResponseHeaders() function.
*/
function RequestErrorEvent(statusCode, response, responseHeaders) {
/**
* The HTTP error status code, such as 404. If the error does not have a particular
* HTTP code, this property will be undefined.
*
* @type {Number}
*/
this.statusCode = statusCode;
/**
* The response included along with the error. If the error does not include a response,
* this property will be undefined.
*
* @type {Object}
*/
this.response = response;
/**
* The headers included in the response, represented as an object literal of key/value pairs.
* If the error does not include any headers, this property will be undefined.
*
* @type {Object}
*/
this.responseHeaders = responseHeaders;
if (typeof this.responseHeaders === "string") {
this.responseHeaders = parseResponseHeaders(this.responseHeaders);
}
}
/**
* Creates a string representing this RequestErrorEvent.
* @memberof RequestErrorEvent
*
* @returns {String} A string representing the provided RequestErrorEvent.
*/
RequestErrorEvent.prototype.toString = function () {
let str = "Request has failed.";
if (defined(this.statusCode)) {
str += ` Status Code: ${this.statusCode}`;
}
return str;
};
/**
* A generic utility class for managing subscribers for a particular event.
* This class is usually instantiated inside of a container class and
* exposed as a property for others to subscribe to.
*
* @alias Event
* @constructor
* @example
* MyObject.prototype.myListener = function(arg1, arg2) {
* this.myArg1Copy = arg1;
* this.myArg2Copy = arg2;
* }
*
* const myObjectInstance = new MyObject();
* const evt = new Cesium.Event();
* evt.addEventListener(MyObject.prototype.myListener, myObjectInstance);
* evt.raiseEvent('1', '2');
* evt.removeEventListener(MyObject.prototype.myListener);
*/
function Event() {
this._listeners = [];
this._scopes = [];
this._toRemove = [];
this._insideRaiseEvent = false;
}
Object.defineProperties(Event.prototype, {
/**
* The number of listeners currently subscribed to the event.
* @memberof Event.prototype
* @type {Number}
* @readonly
*/
numberOfListeners: {
get: function () {
return this._listeners.length - this._toRemove.length;
},
},
});
/**
* Registers a callback function to be executed whenever the event is raised.
* An optional scope can be provided to serve as the this
pointer
* in which the function will execute.
*
* @param {Function} listener The function to be executed when the event is raised.
* @param {Object} [scope] An optional object scope to serve as the this
* pointer in which the listener function will execute.
* @returns {Event.RemoveCallback} A function that will remove this event listener when invoked.
*
* @see Event#raiseEvent
* @see Event#removeEventListener
*/
Event.prototype.addEventListener = function (listener, scope) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.func("listener", listener);
//>>includeEnd('debug');
this._listeners.push(listener);
this._scopes.push(scope);
const event = this;
return function () {
event.removeEventListener(listener, scope);
};
};
/**
* Unregisters a previously registered callback.
*
* @param {Function} listener The function to be unregistered.
* @param {Object} [scope] The scope that was originally passed to addEventListener.
* @returns {Boolean} true
if the listener was removed; false
if the listener and scope are not registered with the event.
*
* @see Event#addEventListener
* @see Event#raiseEvent
*/
Event.prototype.removeEventListener = function (listener, scope) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.func("listener", listener);
//>>includeEnd('debug');
const listeners = this._listeners;
const scopes = this._scopes;
let index = -1;
for (let i = 0; i < listeners.length; i++) {
if (listeners[i] === listener && scopes[i] === scope) {
index = i;
break;
}
}
if (index !== -1) {
if (this._insideRaiseEvent) {
//In order to allow removing an event subscription from within
//a callback, we don't actually remove the items here. Instead
//remember the index they are at and undefined their value.
this._toRemove.push(index);
listeners[index] = undefined;
scopes[index] = undefined;
} else {
listeners.splice(index, 1);
scopes.splice(index, 1);
}
return true;
}
return false;
};
function compareNumber(a, b) {
return b - a;
}
/**
* Raises the event by calling each registered listener with all supplied arguments.
*
* @param {...Object} arguments This method takes any number of parameters and passes them through to the listener functions.
*
* @see Event#addEventListener
* @see Event#removeEventListener
*/
Event.prototype.raiseEvent = function () {
this._insideRaiseEvent = true;
let i;
const listeners = this._listeners;
const scopes = this._scopes;
let length = listeners.length;
for (i = 0; i < length; i++) {
const listener = listeners[i];
if (defined(listener)) {
listeners[i].apply(scopes[i], arguments);
}
}
//Actually remove items removed in removeEventListener.
const toRemove = this._toRemove;
length = toRemove.length;
if (length > 0) {
toRemove.sort(compareNumber);
for (i = 0; i < length; i++) {
const index = toRemove[i];
listeners.splice(index, 1);
scopes.splice(index, 1);
}
toRemove.length = 0;
}
this._insideRaiseEvent = false;
};
/**
* Array implementation of a heap.
*
* @alias Heap
* @constructor
* @private
*
* @param {Object} options Object with the following properties:
* @param {Heap.ComparatorCallback} options.comparator The comparator to use for the heap. If comparator(a, b) is less than 0, sort a to a lower index than b, otherwise sort to a higher index.
*/
function Heap(options) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options", options);
Check.defined("options.comparator", options.comparator);
//>>includeEnd('debug');
this._comparator = options.comparator;
this._array = [];
this._length = 0;
this._maximumLength = undefined;
}
Object.defineProperties(Heap.prototype, {
/**
* Gets the length of the heap.
*
* @memberof Heap.prototype
*
* @type {Number}
* @readonly
*/
length: {
get: function () {
return this._length;
},
},
/**
* Gets the internal array.
*
* @memberof Heap.prototype
*
* @type {Array}
* @readonly
*/
internalArray: {
get: function () {
return this._array;
},
},
/**
* Gets and sets the maximum length of the heap.
*
* @memberof Heap.prototype
*
* @type {Number}
*/
maximumLength: {
get: function () {
return this._maximumLength;
},
set: function (value) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("maximumLength", value, 0);
//>>includeEnd('debug');
const originalLength = this._length;
if (value < originalLength) {
const array = this._array;
// Remove trailing references
for (let i = value; i < originalLength; ++i) {
array[i] = undefined;
}
this._length = value;
array.length = value;
}
this._maximumLength = value;
},
},
/**
* The comparator to use for the heap. If comparator(a, b) is less than 0, sort a to a lower index than b, otherwise sort to a higher index.
*
* @memberof Heap.prototype
*
* @type {Heap.ComparatorCallback}
*/
comparator: {
get: function () {
return this._comparator;
},
},
});
function swap$3(array, a, b) {
const temp = array[a];
array[a] = array[b];
array[b] = temp;
}
/**
* Resizes the internal array of the heap.
*
* @param {Number} [length] The length to resize internal array to. Defaults to the current length of the heap.
*/
Heap.prototype.reserve = function (length) {
length = defaultValue(length, this._length);
this._array.length = length;
};
/**
* Update the heap so that index and all descendants satisfy the heap property.
*
* @param {Number} [index=0] The starting index to heapify from.
*/
Heap.prototype.heapify = function (index) {
index = defaultValue(index, 0);
const length = this._length;
const comparator = this._comparator;
const array = this._array;
let candidate = -1;
let inserting = true;
while (inserting) {
const right = 2 * (index + 1);
const left = right - 1;
if (left < length && comparator(array[left], array[index]) < 0) {
candidate = left;
} else {
candidate = index;
}
if (right < length && comparator(array[right], array[candidate]) < 0) {
candidate = right;
}
if (candidate !== index) {
swap$3(array, candidate, index);
index = candidate;
} else {
inserting = false;
}
}
};
/**
* Resort the heap.
*/
Heap.prototype.resort = function () {
const length = this._length;
for (let i = Math.ceil(length / 2); i >= 0; --i) {
this.heapify(i);
}
};
/**
* Insert an element into the heap. If the length would grow greater than maximumLength
* of the heap, extra elements are removed.
*
* @param {*} element The element to insert
*
* @return {*} The element that was removed from the heap if the heap is at full capacity.
*/
Heap.prototype.insert = function (element) {
//>>includeStart('debug', pragmas.debug);
Check.defined("element", element);
//>>includeEnd('debug');
const array = this._array;
const comparator = this._comparator;
const maximumLength = this._maximumLength;
let index = this._length++;
if (index < array.length) {
array[index] = element;
} else {
array.push(element);
}
while (index !== 0) {
const parent = Math.floor((index - 1) / 2);
if (comparator(array[index], array[parent]) < 0) {
swap$3(array, index, parent);
index = parent;
} else {
break;
}
}
let removedElement;
if (defined(maximumLength) && this._length > maximumLength) {
removedElement = array[maximumLength];
this._length = maximumLength;
}
return removedElement;
};
/**
* Remove the element specified by index from the heap and return it.
*
* @param {Number} [index=0] The index to remove.
* @returns {*} The specified element of the heap.
*/
Heap.prototype.pop = function (index) {
index = defaultValue(index, 0);
if (this._length === 0) {
return undefined;
}
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.lessThan("index", index, this._length);
//>>includeEnd('debug');
const array = this._array;
const root = array[index];
swap$3(array, index, --this._length);
this.heapify(index);
array[this._length] = undefined; // Remove trailing reference
return root;
};
function sortRequests(a, b) {
return a.priority - b.priority;
}
const statistics = {
numberOfAttemptedRequests: 0,
numberOfActiveRequests: 0,
numberOfCancelledRequests: 0,
numberOfCancelledActiveRequests: 0,
numberOfFailedRequests: 0,
numberOfActiveRequestsEver: 0,
lastNumberOfActiveRequests: 0,
};
let priorityHeapLength = 20;
const requestHeap = new Heap({
comparator: sortRequests,
});
requestHeap.maximumLength = priorityHeapLength;
requestHeap.reserve(priorityHeapLength);
const activeRequests = [];
let numberOfActiveRequestsByServer = {};
const pageUri =
typeof document !== "undefined" ? new URI(document.location.href) : new URI();
const requestCompletedEvent = new Event();
/**
* The request scheduler is used to track and constrain the number of active requests in order to prioritize incoming requests. The ability
* to retain control over the number of requests in CesiumJS is important because due to events such as changes in the camera position,
* a lot of new requests may be generated and a lot of in-flight requests may become redundant. The request scheduler manually constrains the
* number of requests so that newer requests wait in a shorter queue and don't have to compete for bandwidth with requests that have expired.
*
* @namespace RequestScheduler
*
*/
function RequestScheduler() {}
/**
* The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit.
* @type {Number}
* @default 50
*/
RequestScheduler.maximumRequests = 50;
/**
* The maximum number of simultaneous active requests per server. Un-throttled requests or servers specifically
* listed in {@link requestsByServer} do not observe this limit.
* @type {Number}
* @default 6
*/
RequestScheduler.maximumRequestsPerServer = 6;
/**
* A per server key list of overrides to use for throttling instead of maximumRequestsPerServer
* @type {Object}
*
* @example
* RequestScheduler.requestsByServer = {
* 'api.cesium.com:443': 18,
* 'assets.cesium.com:443': 18
* };
*/
RequestScheduler.requestsByServer = {
"api.cesium.com:443": 18,
"assets.cesium.com:443": 18,
};
/**
* Specifies if the request scheduler should throttle incoming requests, or let the browser queue requests under its control.
* @type {Boolean}
* @default true
*/
RequestScheduler.throttleRequests = true;
/**
* When true, log statistics to the console every frame
* @type {Boolean}
* @default false
* @private
*/
RequestScheduler.debugShowStatistics = false;
/**
* An event that's raised when a request is completed. Event handlers are passed
* the error object if the request fails.
*
* @type {Event}
* @default Event()
* @private
*/
RequestScheduler.requestCompletedEvent = requestCompletedEvent;
Object.defineProperties(RequestScheduler, {
/**
* Returns the statistics used by the request scheduler.
*
* @memberof RequestScheduler
*
* @type Object
* @readonly
* @private
*/
statistics: {
get: function () {
return statistics;
},
},
/**
* The maximum size of the priority heap. This limits the number of requests that are sorted by priority. Only applies to requests that are not yet active.
*
* @memberof RequestScheduler
*
* @type {Number}
* @default 20
* @private
*/
priorityHeapLength: {
get: function () {
return priorityHeapLength;
},
set: function (value) {
// If the new length shrinks the heap, need to cancel some of the requests.
// Since this value is not intended to be tweaked regularly it is fine to just cancel the high priority requests.
if (value < priorityHeapLength) {
while (requestHeap.length > value) {
const request = requestHeap.pop();
cancelRequest(request);
}
}
priorityHeapLength = value;
requestHeap.maximumLength = value;
requestHeap.reserve(value);
},
},
});
function updatePriority(request) {
if (defined(request.priorityFunction)) {
request.priority = request.priorityFunction();
}
}
/**
* Check if there are open slots for a particular server key. If desiredRequests is greater than 1, this checks if the queue has room for scheduling multiple requests.
* @param {String} serverKey The server key returned by {@link RequestScheduler.getServerKey}.
* @param {Number} [desiredRequests=1] How many requests the caller plans to request
* @return {Boolean} True if there are enough open slots for desiredRequests
more requests.
* @private
*/
RequestScheduler.serverHasOpenSlots = function (serverKey, desiredRequests) {
desiredRequests = defaultValue(desiredRequests, 1);
const maxRequests = defaultValue(
RequestScheduler.requestsByServer[serverKey],
RequestScheduler.maximumRequestsPerServer
);
const hasOpenSlotsServer =
numberOfActiveRequestsByServer[serverKey] + desiredRequests <= maxRequests;
return hasOpenSlotsServer;
};
/**
* Check if the priority heap has open slots, regardless of which server they
* are from. This is used in {@link Multiple3DTileContent} for determining when
* all requests can be scheduled
* @param {Number} desiredRequests The number of requests the caller intends to make
* @return {Boolean} true
if the heap has enough available slots to meet the desiredRequests. false
otherwise.
*
* @private
*/
RequestScheduler.heapHasOpenSlots = function (desiredRequests) {
const hasOpenSlotsHeap =
requestHeap.length + desiredRequests <= priorityHeapLength;
return hasOpenSlotsHeap;
};
function issueRequest(request) {
if (request.state === RequestState$1.UNISSUED) {
request.state = RequestState$1.ISSUED;
request.deferred = when.defer();
}
return request.deferred.promise;
}
function getRequestReceivedFunction(request) {
return function (results) {
if (request.state === RequestState$1.CANCELLED) {
// If the data request comes back but the request is cancelled, ignore it.
return;
}
// explicitly set to undefined to ensure GC of request response data. See #8843
const deferred = request.deferred;
--statistics.numberOfActiveRequests;
--numberOfActiveRequestsByServer[request.serverKey];
requestCompletedEvent.raiseEvent();
request.state = RequestState$1.RECEIVED;
request.deferred = undefined;
deferred.resolve(results);
};
}
function getRequestFailedFunction(request) {
return function (error) {
if (request.state === RequestState$1.CANCELLED) {
// If the data request comes back but the request is cancelled, ignore it.
return;
}
++statistics.numberOfFailedRequests;
--statistics.numberOfActiveRequests;
--numberOfActiveRequestsByServer[request.serverKey];
requestCompletedEvent.raiseEvent(error);
request.state = RequestState$1.FAILED;
request.deferred.reject(error);
};
}
function startRequest(request) {
const promise = issueRequest(request);
request.state = RequestState$1.ACTIVE;
activeRequests.push(request);
++statistics.numberOfActiveRequests;
++statistics.numberOfActiveRequestsEver;
++numberOfActiveRequestsByServer[request.serverKey];
request
.requestFunction()
.then(getRequestReceivedFunction(request))
.otherwise(getRequestFailedFunction(request));
return promise;
}
function cancelRequest(request) {
const active = request.state === RequestState$1.ACTIVE;
request.state = RequestState$1.CANCELLED;
++statistics.numberOfCancelledRequests;
// check that deferred has not been cleared since cancelRequest can be called
// on a finished request, e.g. by clearForSpecs during tests
if (defined(request.deferred)) {
const deferred = request.deferred;
request.deferred = undefined;
deferred.reject();
}
if (active) {
--statistics.numberOfActiveRequests;
--numberOfActiveRequestsByServer[request.serverKey];
++statistics.numberOfCancelledActiveRequests;
}
if (defined(request.cancelFunction)) {
request.cancelFunction();
}
}
/**
* Sort requests by priority and start requests.
* @private
*/
RequestScheduler.update = function () {
let i;
let request;
// Loop over all active requests. Cancelled, failed, or received requests are removed from the array to make room for new requests.
let removeCount = 0;
const activeLength = activeRequests.length;
for (i = 0; i < activeLength; ++i) {
request = activeRequests[i];
if (request.cancelled) {
// Request was explicitly cancelled
cancelRequest(request);
}
if (request.state !== RequestState$1.ACTIVE) {
// Request is no longer active, remove from array
++removeCount;
continue;
}
if (removeCount > 0) {
// Shift back to fill in vacated slots from completed requests
activeRequests[i - removeCount] = request;
}
}
activeRequests.length -= removeCount;
// Update priority of issued requests and resort the heap
const issuedRequests = requestHeap.internalArray;
const issuedLength = requestHeap.length;
for (i = 0; i < issuedLength; ++i) {
updatePriority(issuedRequests[i]);
}
requestHeap.resort();
// Get the number of open slots and fill with the highest priority requests.
// Un-throttled requests are automatically added to activeRequests, so activeRequests.length may exceed maximumRequests
const openSlots = Math.max(
RequestScheduler.maximumRequests - activeRequests.length,
0
);
let filledSlots = 0;
while (filledSlots < openSlots && requestHeap.length > 0) {
// Loop until all open slots are filled or the heap becomes empty
request = requestHeap.pop();
if (request.cancelled) {
// Request was explicitly cancelled
cancelRequest(request);
continue;
}
if (
request.throttleByServer &&
!RequestScheduler.serverHasOpenSlots(request.serverKey)
) {
// Open slots are available, but the request is throttled by its server. Cancel and try again later.
cancelRequest(request);
continue;
}
startRequest(request);
++filledSlots;
}
updateStatistics();
};
/**
* Get the server key from a given url.
*
* @param {String} url The url.
* @returns {String} The server key.
* @private
*/
RequestScheduler.getServerKey = function (url) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("url", url);
//>>includeEnd('debug');
let uri = new URI(url);
if (uri.scheme() === "") {
uri = new URI(url).absoluteTo(pageUri);
uri.normalize();
}
let serverKey = uri.authority();
if (!/:/.test(serverKey)) {
// If the authority does not contain a port number, add port 443 for https or port 80 for http
serverKey = `${serverKey}:${uri.scheme() === "https" ? "443" : "80"}`;
}
const length = numberOfActiveRequestsByServer[serverKey];
if (!defined(length)) {
numberOfActiveRequestsByServer[serverKey] = 0;
}
return serverKey;
};
/**
* Issue a request. If request.throttle is false, the request is sent immediately. Otherwise the request will be
* queued and sorted by priority before being sent.
*
* @param {Request} request The request object.
*
* @returns {Promise|undefined} A Promise for the requested data, or undefined if this request does not have high enough priority to be issued.
*
* @private
*/
RequestScheduler.request = function (request) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("request", request);
Check.typeOf.string("request.url", request.url);
Check.typeOf.func("request.requestFunction", request.requestFunction);
//>>includeEnd('debug');
if (isDataUri(request.url) || isBlobUri(request.url)) {
requestCompletedEvent.raiseEvent();
request.state = RequestState$1.RECEIVED;
return request.requestFunction();
}
++statistics.numberOfAttemptedRequests;
if (!defined(request.serverKey)) {
request.serverKey = RequestScheduler.getServerKey(request.url);
}
if (
RequestScheduler.throttleRequests &&
request.throttleByServer &&
!RequestScheduler.serverHasOpenSlots(request.serverKey)
) {
// Server is saturated. Try again later.
return undefined;
}
if (!RequestScheduler.throttleRequests || !request.throttle) {
return startRequest(request);
}
if (activeRequests.length >= RequestScheduler.maximumRequests) {
// Active requests are saturated. Try again later.
return undefined;
}
// Insert into the priority heap and see if a request was bumped off. If this request is the lowest
// priority it will be returned.
updatePriority(request);
const removedRequest = requestHeap.insert(request);
if (defined(removedRequest)) {
if (removedRequest === request) {
// Request does not have high enough priority to be issued
return undefined;
}
// A previously issued request has been bumped off the priority heap, so cancel it
cancelRequest(removedRequest);
}
return issueRequest(request);
};
function updateStatistics() {
if (!RequestScheduler.debugShowStatistics) {
return;
}
if (
statistics.numberOfActiveRequests === 0 &&
statistics.lastNumberOfActiveRequests > 0
) {
if (statistics.numberOfAttemptedRequests > 0) {
console.log(
`Number of attempted requests: ${statistics.numberOfAttemptedRequests}`
);
statistics.numberOfAttemptedRequests = 0;
}
if (statistics.numberOfCancelledRequests > 0) {
console.log(
`Number of cancelled requests: ${statistics.numberOfCancelledRequests}`
);
statistics.numberOfCancelledRequests = 0;
}
if (statistics.numberOfCancelledActiveRequests > 0) {
console.log(
`Number of cancelled active requests: ${statistics.numberOfCancelledActiveRequests}`
);
statistics.numberOfCancelledActiveRequests = 0;
}
if (statistics.numberOfFailedRequests > 0) {
console.log(
`Number of failed requests: ${statistics.numberOfFailedRequests}`
);
statistics.numberOfFailedRequests = 0;
}
}
statistics.lastNumberOfActiveRequests = statistics.numberOfActiveRequests;
}
/**
* For testing only. Clears any requests that may not have completed from previous tests.
*
* @private
*/
RequestScheduler.clearForSpecs = function () {
while (requestHeap.length > 0) {
const request = requestHeap.pop();
cancelRequest(request);
}
const length = activeRequests.length;
for (let i = 0; i < length; ++i) {
cancelRequest(activeRequests[i]);
}
activeRequests.length = 0;
numberOfActiveRequestsByServer = {};
// Clear stats
statistics.numberOfAttemptedRequests = 0;
statistics.numberOfActiveRequests = 0;
statistics.numberOfCancelledRequests = 0;
statistics.numberOfCancelledActiveRequests = 0;
statistics.numberOfFailedRequests = 0;
statistics.numberOfActiveRequestsEver = 0;
statistics.lastNumberOfActiveRequests = 0;
};
/**
* For testing only.
*
* @private
*/
RequestScheduler.numberOfActiveRequestsByServer = function (serverKey) {
return numberOfActiveRequestsByServer[serverKey];
};
/**
* For testing only.
*
* @private
*/
RequestScheduler.requestHeap = requestHeap;
/**
* A singleton that contains all of the servers that are trusted. Credentials will be sent with
* any requests to these servers.
*
* @namespace TrustedServers
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
*/
const TrustedServers = {};
let _servers = {};
/**
* Adds a trusted server to the registry
*
* @param {String} host The host to be added.
* @param {Number} port The port used to access the host.
*
* @example
* // Add a trusted server
* TrustedServers.add('my.server.com', 80);
*/
TrustedServers.add = function (host, port) {
//>>includeStart('debug', pragmas.debug);
if (!defined(host)) {
throw new DeveloperError("host is required.");
}
if (!defined(port) || port <= 0) {
throw new DeveloperError("port is required to be greater than 0.");
}
//>>includeEnd('debug');
const authority = `${host.toLowerCase()}:${port}`;
if (!defined(_servers[authority])) {
_servers[authority] = true;
}
};
/**
* Removes a trusted server from the registry
*
* @param {String} host The host to be removed.
* @param {Number} port The port used to access the host.
*
* @example
* // Remove a trusted server
* TrustedServers.remove('my.server.com', 80);
*/
TrustedServers.remove = function (host, port) {
//>>includeStart('debug', pragmas.debug);
if (!defined(host)) {
throw new DeveloperError("host is required.");
}
if (!defined(port) || port <= 0) {
throw new DeveloperError("port is required to be greater than 0.");
}
//>>includeEnd('debug');
const authority = `${host.toLowerCase()}:${port}`;
if (defined(_servers[authority])) {
delete _servers[authority];
}
};
function getAuthority(url) {
const uri = new URI(url);
uri.normalize();
// Removes username:password@ so we just have host[:port]
let authority = uri.authority();
if (authority.length === 0) {
return undefined; // Relative URL
}
uri.authority(authority);
if (authority.indexOf("@") !== -1) {
const parts = authority.split("@");
authority = parts[1];
}
// If the port is missing add one based on the scheme
if (authority.indexOf(":") === -1) {
let scheme = uri.scheme();
if (scheme.length === 0) {
scheme = window.location.protocol;
scheme = scheme.substring(0, scheme.length - 1);
}
if (scheme === "http") {
authority += ":80";
} else if (scheme === "https") {
authority += ":443";
} else {
return undefined;
}
}
return authority;
}
/**
* Tests whether a server is trusted or not. The server must have been added with the port if it is included in the url.
*
* @param {String} url The url to be tested against the trusted list
*
* @returns {boolean} Returns true if url is trusted, false otherwise.
*
* @example
* // Add server
* TrustedServers.add('my.server.com', 81);
*
* // Check if server is trusted
* if (TrustedServers.contains('https://my.server.com:81/path/to/file.png')) {
* // my.server.com:81 is trusted
* }
* if (TrustedServers.contains('https://my.server.com/path/to/file.png')) {
* // my.server.com isn't trusted
* }
*/
TrustedServers.contains = function (url) {
//>>includeStart('debug', pragmas.debug);
if (!defined(url)) {
throw new DeveloperError("url is required.");
}
//>>includeEnd('debug');
const authority = getAuthority(url);
if (defined(authority) && defined(_servers[authority])) {
return true;
}
return false;
};
/**
* Clears the registry
*
* @example
* // Remove a trusted server
* TrustedServers.clear();
*/
TrustedServers.clear = function () {
_servers = {};
};
const xhrBlobSupported = (function () {
try {
const xhr = new XMLHttpRequest();
xhr.open("GET", "#", true);
xhr.responseType = "blob";
return xhr.responseType === "blob";
} catch (e) {
return false;
}
})();
/**
* Parses a query string and returns the object equivalent.
*
* @param {Uri} uri The Uri with a query object.
* @param {Resource} resource The Resource that will be assigned queryParameters.
* @param {Boolean} merge If true, we'll merge with the resource's existing queryParameters. Otherwise they will be replaced.
* @param {Boolean} preserveQueryParameters If true duplicate parameters will be concatenated into an array. If false, keys in uri will take precedence.
*
* @private
*/
function parseQuery(uri, resource, merge, preserveQueryParameters) {
const queryString = uri.query();
if (queryString.length === 0) {
return {};
}
let query;
// Special case we run into where the querystring is just a string, not key/value pairs
if (queryString.indexOf("=") === -1) {
const result = {};
result[queryString] = undefined;
query = result;
} else {
query = queryToObject(queryString);
}
if (merge) {
resource._queryParameters = combineQueryParameters(
query,
resource._queryParameters,
preserveQueryParameters
);
} else {
resource._queryParameters = query;
}
uri.search("");
}
/**
* Converts a query object into a string.
*
* @param {Uri} uri The Uri object that will have the query object set.
* @param {Resource} resource The resource that has queryParameters
*
* @private
*/
function stringifyQuery(uri, resource) {
const queryObject = resource._queryParameters;
const keys = Object.keys(queryObject);
// We have 1 key with an undefined value, so this is just a string, not key/value pairs
if (keys.length === 1 && !defined(queryObject[keys[0]])) {
uri.search(keys[0]);
} else {
uri.search(objectToQuery(queryObject));
}
}
/**
* Clones a value if it is defined, otherwise returns the default value
*
* @param {*} [val] The value to clone.
* @param {*} [defaultVal] The default value.
*
* @returns {*} A clone of val or the defaultVal.
*
* @private
*/
function defaultClone(val, defaultVal) {
if (!defined(val)) {
return defaultVal;
}
return defined(val.clone) ? val.clone() : clone$1(val);
}
/**
* Checks to make sure the Resource isn't already being requested.
*
* @param {Request} request The request to check.
*
* @private
*/
function checkAndResetRequest(request) {
if (
request.state === RequestState$1.ISSUED ||
request.state === RequestState$1.ACTIVE
) {
throw new RuntimeError("The Resource is already being fetched.");
}
request.state = RequestState$1.UNISSUED;
request.deferred = undefined;
}
/**
* This combines a map of query parameters.
*
* @param {Object} q1 The first map of query parameters. Values in this map will take precedence if preserveQueryParameters is false.
* @param {Object} q2 The second map of query parameters.
* @param {Boolean} preserveQueryParameters If true duplicate parameters will be concatenated into an array. If false, keys in q1 will take precedence.
*
* @returns {Object} The combined map of query parameters.
*
* @example
* const q1 = {
* a: 1,
* b: 2
* };
* const q2 = {
* a: 3,
* c: 4
* };
* const q3 = {
* b: [5, 6],
* d: 7
* }
*
* // Returns
* // {
* // a: [1, 3],
* // b: 2,
* // c: 4
* // };
* combineQueryParameters(q1, q2, true);
*
* // Returns
* // {
* // a: 1,
* // b: 2,
* // c: 4
* // };
* combineQueryParameters(q1, q2, false);
*
* // Returns
* // {
* // a: 1,
* // b: [2, 5, 6],
* // d: 7
* // };
* combineQueryParameters(q1, q3, true);
*
* // Returns
* // {
* // a: 1,
* // b: 2,
* // d: 7
* // };
* combineQueryParameters(q1, q3, false);
*
* @private
*/
function combineQueryParameters(q1, q2, preserveQueryParameters) {
if (!preserveQueryParameters) {
return combine$2(q1, q2);
}
const result = clone$1(q1, true);
for (const param in q2) {
if (q2.hasOwnProperty(param)) {
let value = result[param];
const q2Value = q2[param];
if (defined(value)) {
if (!Array.isArray(value)) {
value = result[param] = [value];
}
result[param] = value.concat(q2Value);
} else {
result[param] = Array.isArray(q2Value) ? q2Value.slice() : q2Value;
}
}
}
return result;
}
/**
* A resource that includes the location and any other parameters we need to retrieve it or create derived resources. It also provides the ability to retry requests.
*
* @alias Resource
* @constructor
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
*
* @example
* function refreshTokenRetryCallback(resource, error) {
* if (error.statusCode === 403) {
* // 403 status code means a new token should be generated
* return getNewAccessToken()
* .then(function(token) {
* resource.queryParameters.access_token = token;
* return true;
* })
* .otherwise(function() {
* return false;
* });
* }
*
* return false;
* }
*
* const resource = new Resource({
* url: 'http://server.com/path/to/resource.json',
* proxy: new DefaultProxy('/proxy/'),
* headers: {
* 'X-My-Header': 'valueOfHeader'
* },
* queryParameters: {
* 'access_token': '123-435-456-000'
* },
* retryCallback: refreshTokenRetryCallback,
* retryAttempts: 1
* });
*/
function Resource(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
if (typeof options === "string") {
options = {
url: options,
};
}
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("options.url", options.url);
//>>includeEnd('debug');
this._url = undefined;
this._templateValues = defaultClone(options.templateValues, {});
this._queryParameters = defaultClone(options.queryParameters, {});
/**
* Additional HTTP headers that will be sent with the request.
*
* @type {Object}
*/
this.headers = defaultClone(options.headers, {});
/**
* A Request object that will be used. Intended for internal use only.
*
* @type {Request}
*/
this.request = defaultValue(options.request, new Request());
/**
* A proxy to be used when loading the resource.
*
* @type {Proxy}
*/
this.proxy = options.proxy;
/**
* Function to call when a request for this resource fails. If it returns true or a Promise that resolves to true, the request will be retried.
*
* @type {Function}
*/
this.retryCallback = options.retryCallback;
/**
* The number of times the retryCallback should be called before giving up.
*
* @type {Number}
*/
this.retryAttempts = defaultValue(options.retryAttempts, 0);
this._retryCount = 0;
const uri = new URI(options.url);
parseQuery(uri, this, true, true);
// Remove the fragment as it's not sent with a request
uri.fragment("");
this._url = uri.toString();
}
/**
* A helper function to create a resource depending on whether we have a String or a Resource
*
* @param {Resource|String} resource A Resource or a String to use when creating a new Resource.
*
* @returns {Resource} If resource is a String, a Resource constructed with the url and options. Otherwise the resource parameter is returned.
*
* @private
*/
Resource.createIfNeeded = function (resource) {
if (resource instanceof Resource) {
// Keep existing request object. This function is used internally to duplicate a Resource, so that it can't
// be modified outside of a class that holds it (eg. an imagery or terrain provider). Since the Request objects
// are managed outside of the providers, by the tile loading code, we want to keep the request property the same so if it is changed
// in the underlying tiling code the requests for this resource will use it.
return resource.getDerivedResource({
request: resource.request,
});
}
if (typeof resource !== "string") {
return resource;
}
return new Resource({
url: resource,
});
};
let supportsImageBitmapOptionsPromise;
/**
* A helper function to check whether createImageBitmap supports passing ImageBitmapOptions.
*
* @returns {Promise} A promise that resolves to true if this browser supports creating an ImageBitmap with options.
*
* @private
*/
Resource.supportsImageBitmapOptions = function () {
// Until the HTML folks figure out what to do about this, we need to actually try loading an image to
// know if this browser supports passing options to the createImageBitmap function.
// https://github.com/whatwg/html/pull/4248
//
// We also need to check whether the colorSpaceConversion option is supported.
// We do this by loading a PNG with an embedded color profile, first with
// colorSpaceConversion: "none" and then with colorSpaceConversion: "default".
// If the pixel color is different then we know the option is working.
// As of Webkit 17612.3.6.1.6 the createImageBitmap promise resolves but the
// option is not actually supported.
if (defined(supportsImageBitmapOptionsPromise)) {
return supportsImageBitmapOptionsPromise;
}
if (typeof createImageBitmap !== "function") {
supportsImageBitmapOptionsPromise = when.resolve(false);
return supportsImageBitmapOptionsPromise;
}
const imageDataUri =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABGdBTUEAAE4g3rEiDgAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADElEQVQI12Ng6GAAAAEUAIngE3ZiAAAAAElFTkSuQmCC";
supportsImageBitmapOptionsPromise = Resource.fetchBlob({
url: imageDataUri,
})
.then(function (blob) {
const imageBitmapOptions = {
imageOrientation: "flipY", // default is "none"
premultiplyAlpha: "none", // default is "default"
colorSpaceConversion: "none", // default is "default"
};
return when.all([
createImageBitmap(blob, imageBitmapOptions),
createImageBitmap(blob),
]);
})
.then(function (imageBitmaps) {
// Check whether the colorSpaceConversion option had any effect on the green channel
const colorWithOptions = getImagePixels(imageBitmaps[0]);
const colorWithDefaults = getImagePixels(imageBitmaps[1]);
return colorWithOptions[1] !== colorWithDefaults[1];
})
.otherwise(function () {
return false;
});
return supportsImageBitmapOptionsPromise;
};
Object.defineProperties(Resource, {
/**
* Returns true if blobs are supported.
*
* @memberof Resource
* @type {Boolean}
*
* @readonly
*/
isBlobSupported: {
get: function () {
return xhrBlobSupported;
},
},
});
Object.defineProperties(Resource.prototype, {
/**
* Query parameters appended to the url.
*
* @memberof Resource.prototype
* @type {Object}
*
* @readonly
*/
queryParameters: {
get: function () {
return this._queryParameters;
},
},
/**
* The key/value pairs used to replace template parameters in the url.
*
* @memberof Resource.prototype
* @type {Object}
*
* @readonly
*/
templateValues: {
get: function () {
return this._templateValues;
},
},
/**
* The url to the resource with template values replaced, query string appended and encoded by proxy if one was set.
*
* @memberof Resource.prototype
* @type {String}
*/
url: {
get: function () {
return this.getUrlComponent(true, true);
},
set: function (value) {
const uri = new URI(value);
parseQuery(uri, this, false);
// Remove the fragment as it's not sent with a request
uri.fragment("");
this._url = uri.toString();
},
},
/**
* The file extension of the resource.
*
* @memberof Resource.prototype
* @type {String}
*
* @readonly
*/
extension: {
get: function () {
return getExtensionFromUri(this._url);
},
},
/**
* True if the Resource refers to a data URI.
*
* @memberof Resource.prototype
* @type {Boolean}
*/
isDataUri: {
get: function () {
return isDataUri(this._url);
},
},
/**
* True if the Resource refers to a blob URI.
*
* @memberof Resource.prototype
* @type {Boolean}
*/
isBlobUri: {
get: function () {
return isBlobUri(this._url);
},
},
/**
* True if the Resource refers to a cross origin URL.
*
* @memberof Resource.prototype
* @type {Boolean}
*/
isCrossOriginUrl: {
get: function () {
return isCrossOriginUrl(this._url);
},
},
/**
* True if the Resource has request headers. This is equivalent to checking if the headers property has any keys.
*
* @memberof Resource.prototype
* @type {Boolean}
*/
hasHeaders: {
get: function () {
return Object.keys(this.headers).length > 0;
},
},
});
/**
* Override Object#toString so that implicit string conversion gives the
* complete URL represented by this Resource.
*
* @returns {String} The URL represented by this Resource
*/
Resource.prototype.toString = function () {
return this.getUrlComponent(true, true);
};
/**
* Returns the url, optional with the query string and processed by a proxy.
*
* @param {Boolean} [query=false] If true, the query string is included.
* @param {Boolean} [proxy=false] If true, the url is processed by the proxy object, if defined.
*
* @returns {String} The url with all the requested components.
*/
Resource.prototype.getUrlComponent = function (query, proxy) {
if (this.isDataUri) {
return this._url;
}
const uri = new URI(this._url);
if (query) {
stringifyQuery(uri, this);
}
// objectToQuery escapes the placeholders. Undo that.
let url = uri.toString().replace(/%7B/g, "{").replace(/%7D/g, "}");
const templateValues = this._templateValues;
url = url.replace(/{(.*?)}/g, function (match, key) {
const replacement = templateValues[key];
if (defined(replacement)) {
// use the replacement value from templateValues if there is one...
return encodeURIComponent(replacement);
}
// otherwise leave it unchanged
return match;
});
if (proxy && defined(this.proxy)) {
url = this.proxy.getURL(url);
}
return url;
};
/**
* Combines the specified object and the existing query parameters. This allows you to add many parameters at once,
* as opposed to adding them one at a time to the queryParameters property. If a value is already set, it will be replaced with the new value.
*
* @param {Object} params The query parameters
* @param {Boolean} [useAsDefault=false] If true the params will be used as the default values, so they will only be set if they are undefined.
*/
Resource.prototype.setQueryParameters = function (params, useAsDefault) {
if (useAsDefault) {
this._queryParameters = combineQueryParameters(
this._queryParameters,
params,
false
);
} else {
this._queryParameters = combineQueryParameters(
params,
this._queryParameters,
false
);
}
};
/**
* Combines the specified object and the existing query parameters. This allows you to add many parameters at once,
* as opposed to adding them one at a time to the queryParameters property.
*
* @param {Object} params The query parameters
*/
Resource.prototype.appendQueryParameters = function (params) {
this._queryParameters = combineQueryParameters(
params,
this._queryParameters,
true
);
};
/**
* Combines the specified object and the existing template values. This allows you to add many values at once,
* as opposed to adding them one at a time to the templateValues property. If a value is already set, it will become an array and the new value will be appended.
*
* @param {Object} template The template values
* @param {Boolean} [useAsDefault=false] If true the values will be used as the default values, so they will only be set if they are undefined.
*/
Resource.prototype.setTemplateValues = function (template, useAsDefault) {
if (useAsDefault) {
this._templateValues = combine$2(this._templateValues, template);
} else {
this._templateValues = combine$2(template, this._templateValues);
}
};
/**
* Returns a resource relative to the current instance. All properties remain the same as the current instance unless overridden in options.
*
* @param {Object} options An object with the following properties
* @param {String} [options.url] The url that will be resolved relative to the url of the current instance.
* @param {Object} [options.queryParameters] An object containing query parameters that will be combined with those of the current instance.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}). These will be combined with those of the current instance.
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The function to call when loading the resource fails.
* @param {Number} [options.retryAttempts] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {Boolean} [options.preserveQueryParameters=false] If true, this will keep all query parameters from the current resource and derived resource. If false, derived parameters will replace those of the current resource.
*
* @returns {Resource} The resource derived from the current one.
*/
Resource.prototype.getDerivedResource = function (options) {
const resource = this.clone();
resource._retryCount = 0;
if (defined(options.url)) {
const uri = new URI(options.url);
const preserveQueryParameters = defaultValue(
options.preserveQueryParameters,
false
);
parseQuery(uri, resource, true, preserveQueryParameters);
// Remove the fragment as it's not sent with a request
uri.fragment("");
if (uri.scheme() !== "") {
resource._url = uri.toString();
} else {
resource._url = uri
.absoluteTo(new URI(getAbsoluteUri(this._url)))
.toString();
}
}
if (defined(options.queryParameters)) {
resource._queryParameters = combine$2(
options.queryParameters,
resource._queryParameters
);
}
if (defined(options.templateValues)) {
resource._templateValues = combine$2(
options.templateValues,
resource.templateValues
);
}
if (defined(options.headers)) {
resource.headers = combine$2(options.headers, resource.headers);
}
if (defined(options.proxy)) {
resource.proxy = options.proxy;
}
if (defined(options.request)) {
resource.request = options.request;
}
if (defined(options.retryCallback)) {
resource.retryCallback = options.retryCallback;
}
if (defined(options.retryAttempts)) {
resource.retryAttempts = options.retryAttempts;
}
return resource;
};
/**
* Called when a resource fails to load. This will call the retryCallback function if defined until retryAttempts is reached.
*
* @param {Error} [error] The error that was encountered.
*
* @returns {Promise} A promise to a boolean, that if true will cause the resource request to be retried.
*
* @private
*/
Resource.prototype.retryOnError = function (error) {
const retryCallback = this.retryCallback;
if (
typeof retryCallback !== "function" ||
this._retryCount >= this.retryAttempts
) {
return when(false);
}
const that = this;
return when(retryCallback(this, error)).then(function (result) {
++that._retryCount;
return result;
});
};
/**
* Duplicates a Resource instance.
*
* @param {Resource} [result] The object onto which to store the result.
*
* @returns {Resource} The modified result parameter or a new Resource instance if one was not provided.
*/
Resource.prototype.clone = function (result) {
if (!defined(result)) {
result = new Resource({
url: this._url,
});
}
result._url = this._url;
result._queryParameters = clone$1(this._queryParameters);
result._templateValues = clone$1(this._templateValues);
result.headers = clone$1(this.headers);
result.proxy = this.proxy;
result.retryCallback = this.retryCallback;
result.retryAttempts = this.retryAttempts;
result._retryCount = 0;
result.request = this.request.clone();
return result;
};
/**
* Returns the base path of the Resource.
*
* @param {Boolean} [includeQuery = false] Whether or not to include the query string and fragment form the uri
*
* @returns {String} The base URI of the resource
*/
Resource.prototype.getBaseUri = function (includeQuery) {
return getBaseUri(this.getUrlComponent(includeQuery), includeQuery);
};
/**
* Appends a forward slash to the URL.
*/
Resource.prototype.appendForwardSlash = function () {
this._url = appendForwardSlash(this._url);
};
/**
* Asynchronously loads the resource as raw binary data. Returns a promise that will resolve to
* an ArrayBuffer once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
* @example
* // load a single URL asynchronously
* resource.fetchArrayBuffer().then(function(arrayBuffer) {
* // use the data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchArrayBuffer = function () {
return this.fetch({
responseType: "arraybuffer",
});
};
/**
* Creates a Resource and calls fetchArrayBuffer() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchArrayBuffer = function (options) {
const resource = new Resource(options);
return resource.fetchArrayBuffer();
};
/**
* Asynchronously loads the given resource as a blob. Returns a promise that will resolve to
* a Blob once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
* @example
* // load a single URL asynchronously
* resource.fetchBlob().then(function(blob) {
* // use the data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchBlob = function () {
return this.fetch({
responseType: "blob",
});
};
/**
* Creates a Resource and calls fetchBlob() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchBlob = function (options) {
const resource = new Resource(options);
return resource.fetchBlob();
};
/**
* Asynchronously loads the given image resource. Returns a promise that will resolve to
* an {@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap|ImageBitmap} if preferImageBitmap
is true and the browser supports createImageBitmap
or otherwise an
* {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement|Image} once loaded, or reject if the image failed to load.
*
* @param {Object} [options] An object with the following properties.
* @param {Boolean} [options.preferBlob=false] If true, we will load the image via a blob.
* @param {Boolean} [options.preferImageBitmap=false] If true, image will be decoded during fetch and an ImageBitmap
is returned.
* @param {Boolean} [options.flipY=false] If true, image will be vertically flipped during decode. Only applies if the browser supports createImageBitmap
.
* @param {Boolean} [options.skipColorSpaceConversion=false] If true, any custom gamma or color profiles in the image will be ignored. Only applies if the browser supports createImageBitmap
.
* @returns {Promise.|Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* // load a single image asynchronously
* resource.fetchImage().then(function(image) {
* // use the loaded image
* }).otherwise(function(error) {
* // an error occurred
* });
*
* // load several images in parallel
* when.all([resource1.fetchImage(), resource2.fetchImage()]).then(function(images) {
* // images is an array containing all the loaded images
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchImage = function (options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
const preferImageBitmap = defaultValue(options.preferImageBitmap, false);
const preferBlob = defaultValue(options.preferBlob, false);
const flipY = defaultValue(options.flipY, false);
const skipColorSpaceConversion = defaultValue(
options.skipColorSpaceConversion,
false
);
checkAndResetRequest(this.request);
// We try to load the image normally if
// 1. Blobs aren't supported
// 2. It's a data URI
// 3. It's a blob URI
// 4. It doesn't have request headers and we preferBlob is false
if (
!xhrBlobSupported ||
this.isDataUri ||
this.isBlobUri ||
(!this.hasHeaders && !preferBlob)
) {
return fetchImage({
resource: this,
flipY: flipY,
skipColorSpaceConversion: skipColorSpaceConversion,
preferImageBitmap: preferImageBitmap,
});
}
const blobPromise = this.fetchBlob();
if (!defined(blobPromise)) {
return;
}
let supportsImageBitmap;
let useImageBitmap;
let generatedBlobResource;
let generatedBlob;
return Resource.supportsImageBitmapOptions()
.then(function (result) {
supportsImageBitmap = result;
useImageBitmap = supportsImageBitmap && preferImageBitmap;
return blobPromise;
})
.then(function (blob) {
if (!defined(blob)) {
return;
}
generatedBlob = blob;
if (useImageBitmap) {
return Resource.createImageBitmapFromBlob(blob, {
flipY: flipY,
premultiplyAlpha: false,
skipColorSpaceConversion: skipColorSpaceConversion,
});
}
const blobUrl = window.URL.createObjectURL(blob);
generatedBlobResource = new Resource({
url: blobUrl,
});
return fetchImage({
resource: generatedBlobResource,
flipY: flipY,
skipColorSpaceConversion: skipColorSpaceConversion,
preferImageBitmap: false,
});
})
.then(function (image) {
if (!defined(image)) {
return;
}
// The blob object may be needed for use by a TileDiscardPolicy,
// so attach it to the image.
image.blob = generatedBlob;
if (useImageBitmap) {
return image;
}
window.URL.revokeObjectURL(generatedBlobResource.url);
return image;
})
.otherwise(function (error) {
if (defined(generatedBlobResource)) {
window.URL.revokeObjectURL(generatedBlobResource.url);
}
// If the blob load succeeded but the image decode failed, attach the blob
// to the error object for use by a TileDiscardPolicy.
// In particular, BingMapsImageryProvider uses this to detect the
// zero-length response that is returned when a tile is not available.
error.blob = generatedBlob;
return when.reject(error);
});
};
/**
* Fetches an image and returns a promise to it.
*
* @param {Object} [options] An object with the following properties.
* @param {Resource} [options.resource] Resource object that points to an image to fetch.
* @param {Boolean} [options.preferImageBitmap] If true, image will be decoded during fetch and an ImageBitmap
is returned.
* @param {Boolean} [options.flipY] If true, image will be vertically flipped during decode. Only applies if the browser supports createImageBitmap
.
* @param {Boolean} [options.skipColorSpaceConversion=false] If true, any custom gamma or color profiles in the image will be ignored. Only applies if the browser supports createImageBitmap
.
* @private
*/
function fetchImage(options) {
const resource = options.resource;
const flipY = options.flipY;
const skipColorSpaceConversion = options.skipColorSpaceConversion;
const preferImageBitmap = options.preferImageBitmap;
const request = resource.request;
request.url = resource.url;
request.requestFunction = function () {
let crossOrigin = false;
// data URIs can't have crossorigin set.
if (!resource.isDataUri && !resource.isBlobUri) {
crossOrigin = resource.isCrossOriginUrl;
}
const deferred = when.defer();
Resource._Implementations.createImage(
request,
crossOrigin,
deferred,
flipY,
skipColorSpaceConversion,
preferImageBitmap
);
return deferred.promise;
};
const promise = RequestScheduler.request(request);
if (!defined(promise)) {
return;
}
return promise.otherwise(function (e) {
// Don't retry cancelled or otherwise aborted requests
if (request.state !== RequestState$1.FAILED) {
return when.reject(e);
}
return resource.retryOnError(e).then(function (retry) {
if (retry) {
// Reset request so it can try again
request.state = RequestState$1.UNISSUED;
request.deferred = undefined;
return fetchImage({
resource: resource,
flipY: flipY,
skipColorSpaceConversion: skipColorSpaceConversion,
preferImageBitmap: preferImageBitmap,
});
}
return when.reject(e);
});
});
}
/**
* Creates a Resource and calls fetchImage() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Boolean} [options.flipY=false] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap
.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {Boolean} [options.preferBlob=false] If true, we will load the image via a blob.
* @param {Boolean} [options.preferImageBitmap=false] If true, image will be decoded during fetch and an ImageBitmap
is returned.
* @param {Boolean} [options.skipColorSpaceConversion=false] If true, any custom gamma or color profiles in the image will be ignored. Only applies when requesting an image and the browser supports createImageBitmap
.
* @returns {Promise.|Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchImage = function (options) {
const resource = new Resource(options);
return resource.fetchImage({
flipY: options.flipY,
skipColorSpaceConversion: options.skipColorSpaceConversion,
preferBlob: options.preferBlob,
preferImageBitmap: options.preferImageBitmap,
});
};
/**
* Asynchronously loads the given resource as text. Returns a promise that will resolve to
* a String once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
* @example
* // load text from a URL, setting a custom header
* const resource = new Resource({
* url: 'http://someUrl.com/someJson.txt',
* headers: {
* 'X-Custom-Header' : 'some value'
* }
* });
* resource.fetchText().then(function(text) {
* // Do something with the text
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchText = function () {
return this.fetch({
responseType: "text",
});
};
/**
* Creates a Resource and calls fetchText() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchText = function (options) {
const resource = new Resource(options);
return resource.fetchText();
};
// note: */* below is */* but that ends the comment block early
/**
* Asynchronously loads the given resource as JSON. Returns a promise that will resolve to
* a JSON object once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled. This function
* adds 'Accept: application/json,*/*;q=0.01' to the request headers, if not
* already specified.
*
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.fetchJson().then(function(jsonData) {
* // Do something with the JSON object
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchJson = function () {
const promise = this.fetch({
responseType: "text",
headers: {
Accept: "application/json,*/*;q=0.01",
},
});
if (!defined(promise)) {
return undefined;
}
return promise.then(function (value) {
if (!defined(value)) {
return;
}
return JSON.parse(value);
});
};
/**
* Creates a Resource and calls fetchJson() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchJson = function (options) {
const resource = new Resource(options);
return resource.fetchJson();
};
/**
* Asynchronously loads the given resource as XML. Returns a promise that will resolve to
* an XML Document once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* // load XML from a URL, setting a custom header
* Cesium.loadXML('http://someUrl.com/someXML.xml', {
* 'X-Custom-Header' : 'some value'
* }).then(function(document) {
* // Do something with the document
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchXML = function () {
return this.fetch({
responseType: "document",
overrideMimeType: "text/xml",
});
};
/**
* Creates a Resource and calls fetchXML() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchXML = function (options) {
const resource = new Resource(options);
return resource.fetchXML();
};
/**
* Requests a resource using JSONP.
*
* @param {String} [callbackParameterName='callback'] The callback parameter name that the server expects.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* // load a data asynchronously
* resource.fetchJsonp().then(function(data) {
* // use the loaded data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetchJsonp = function (callbackParameterName) {
callbackParameterName = defaultValue(callbackParameterName, "callback");
checkAndResetRequest(this.request);
//generate a unique function name
let functionName;
do {
functionName = `loadJsonp${CesiumMath.nextRandomNumber()
.toString()
.substring(2, 8)}`;
} while (defined(window[functionName]));
return fetchJsonp(this, callbackParameterName, functionName);
};
function fetchJsonp(resource, callbackParameterName, functionName) {
const callbackQuery = {};
callbackQuery[callbackParameterName] = functionName;
resource.setQueryParameters(callbackQuery);
const request = resource.request;
request.url = resource.url;
request.requestFunction = function () {
const deferred = when.defer();
//assign a function with that name in the global scope
window[functionName] = function (data) {
deferred.resolve(data);
try {
delete window[functionName];
} catch (e) {
window[functionName] = undefined;
}
};
Resource._Implementations.loadAndExecuteScript(
resource.url,
functionName,
deferred
);
return deferred.promise;
};
const promise = RequestScheduler.request(request);
if (!defined(promise)) {
return;
}
return promise.otherwise(function (e) {
if (request.state !== RequestState$1.FAILED) {
return when.reject(e);
}
return resource.retryOnError(e).then(function (retry) {
if (retry) {
// Reset request so it can try again
request.state = RequestState$1.UNISSUED;
request.deferred = undefined;
return fetchJsonp(resource, callbackParameterName, functionName);
}
return when.reject(e);
});
});
}
/**
* Creates a Resource from a URL and calls fetchJsonp() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.callbackParameterName='callback'] The callback parameter name that the server expects.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetchJsonp = function (options) {
const resource = new Resource(options);
return resource.fetchJsonp(options.callbackParameterName);
};
/**
* @private
*/
Resource.prototype._makeRequest = function (options) {
const resource = this;
checkAndResetRequest(resource.request);
const request = resource.request;
request.url = resource.url;
request.requestFunction = function () {
const responseType = options.responseType;
const headers = combine$2(options.headers, resource.headers);
const overrideMimeType = options.overrideMimeType;
const method = options.method;
const data = options.data;
const deferred = when.defer();
const xhr = Resource._Implementations.loadWithXhr(
resource.url,
responseType,
method,
data,
headers,
deferred,
overrideMimeType
);
if (defined(xhr) && defined(xhr.abort)) {
request.cancelFunction = function () {
xhr.abort();
};
}
return deferred.promise;
};
const promise = RequestScheduler.request(request);
if (!defined(promise)) {
return;
}
return promise
.then(function (data) {
// explicitly set to undefined to ensure GC of request response data. See #8843
request.cancelFunction = undefined;
return data;
})
.otherwise(function (e) {
request.cancelFunction = undefined;
if (request.state !== RequestState$1.FAILED) {
return when.reject(e);
}
return resource.retryOnError(e).then(function (retry) {
if (retry) {
// Reset request so it can try again
request.state = RequestState$1.UNISSUED;
request.deferred = undefined;
return resource.fetch(options);
}
return when.reject(e);
});
});
};
const dataUriRegex$1 = /^data:(.*?)(;base64)?,(.*)$/;
function decodeDataUriText(isBase64, data) {
const result = decodeURIComponent(data);
if (isBase64) {
return atob(result);
}
return result;
}
function decodeDataUriArrayBuffer(isBase64, data) {
const byteString = decodeDataUriText(isBase64, data);
const buffer = new ArrayBuffer(byteString.length);
const view = new Uint8Array(buffer);
for (let i = 0; i < byteString.length; i++) {
view[i] = byteString.charCodeAt(i);
}
return buffer;
}
function decodeDataUri(dataUriRegexResult, responseType) {
responseType = defaultValue(responseType, "");
const mimeType = dataUriRegexResult[1];
const isBase64 = !!dataUriRegexResult[2];
const data = dataUriRegexResult[3];
let buffer;
let parser;
switch (responseType) {
case "":
case "text":
return decodeDataUriText(isBase64, data);
case "arraybuffer":
return decodeDataUriArrayBuffer(isBase64, data);
case "blob":
buffer = decodeDataUriArrayBuffer(isBase64, data);
return new Blob([buffer], {
type: mimeType,
});
case "document":
parser = new DOMParser();
return parser.parseFromString(
decodeDataUriText(isBase64, data),
mimeType
);
case "json":
return JSON.parse(decodeDataUriText(isBase64, data));
default:
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError(`Unhandled responseType: ${responseType}`);
//>>includeEnd('debug');
}
}
/**
* Asynchronously loads the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled. It's recommended that you use
* the more specific functions eg. fetchJson, fetchBlob, etc.
*
* @param {Object} [options] Object with the following properties:
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.fetch()
* .then(function(body) {
* // use the data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.fetch = function (options) {
options = defaultClone(options, {});
options.method = "GET";
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls fetch() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.fetch = function (options) {
const resource = new Resource(options);
return resource.fetch({
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
});
};
/**
* Asynchronously deletes the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {Object} [options] Object with the following properties:
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.delete()
* .then(function(body) {
* // use the data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.delete = function (options) {
options = defaultClone(options, {});
options.method = "DELETE";
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls delete() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.data] Data that is posted with the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.delete = function (options) {
const resource = new Resource(options);
return resource.delete({
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
data: options.data,
});
};
/**
* Asynchronously gets headers the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {Object} [options] Object with the following properties:
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.head()
* .then(function(headers) {
* // use the data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.head = function (options) {
options = defaultClone(options, {});
options.method = "HEAD";
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls head() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.head = function (options) {
const resource = new Resource(options);
return resource.head({
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
});
};
/**
* Asynchronously gets options the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {Object} [options] Object with the following properties:
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.options()
* .then(function(headers) {
* // use the data
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.options = function (options) {
options = defaultClone(options, {});
options.method = "OPTIONS";
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls options() on it.
*
* @param {String|Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.options = function (options) {
const resource = new Resource(options);
return resource.options({
// Make copy of just the needed fields because headers can be passed to both the constructor and to fetch
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
});
};
/**
* Asynchronously posts data to the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {Object} data Data that is posted with the resource.
* @param {Object} [options] Object with the following properties:
* @param {Object} [options.data] Data that is posted with the resource.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.post(data)
* .then(function(result) {
* // use the result
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.post = function (data, options) {
Check.defined("data", data);
options = defaultClone(options, {});
options.method = "POST";
options.data = data;
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls post() on it.
*
* @param {Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} options.data Data that is posted with the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.post = function (options) {
const resource = new Resource(options);
return resource.post(options.data, {
// Make copy of just the needed fields because headers can be passed to both the constructor and to post
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
});
};
/**
* Asynchronously puts data to the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {Object} data Data that is posted with the resource.
* @param {Object} [options] Object with the following properties:
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.put(data)
* .then(function(result) {
* // use the result
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.put = function (data, options) {
Check.defined("data", data);
options = defaultClone(options, {});
options.method = "PUT";
options.data = data;
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls put() on it.
*
* @param {Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} options.data Data that is posted with the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.put = function (options) {
const resource = new Resource(options);
return resource.put(options.data, {
// Make copy of just the needed fields because headers can be passed to both the constructor and to post
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
});
};
/**
* Asynchronously patches data to the given resource. Returns a promise that will resolve to
* the result once loaded, or reject if the resource failed to load. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {Object} data Data that is posted with the resource.
* @param {Object} [options] Object with the following properties:
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {Object} [options.headers] Additional HTTP headers to send with the request, if any.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*
*
* @example
* resource.patch(data)
* .then(function(result) {
* // use the result
* }).otherwise(function(error) {
* // an error occurred
* });
*
* @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A}
*/
Resource.prototype.patch = function (data, options) {
Check.defined("data", data);
options = defaultClone(options, {});
options.method = "PATCH";
options.data = data;
return this._makeRequest(options);
};
/**
* Creates a Resource from a URL and calls patch() on it.
*
* @param {Object} options A url or an object with the following properties
* @param {String} options.url The url of the resource.
* @param {Object} options.data Data that is posted with the resource.
* @param {Object} [options.queryParameters] An object containing query parameters that will be sent when retrieving the resource.
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
* @param {Proxy} [options.proxy] A proxy to be used when loading the resource.
* @param {Resource.RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
* @param {String} [options.responseType] The type of response. This controls the type of item returned.
* @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server.
* @returns {Promise.<*>|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle
is true and the request does not have high enough priority.
*/
Resource.patch = function (options) {
const resource = new Resource(options);
return resource.patch(options.data, {
// Make copy of just the needed fields because headers can be passed to both the constructor and to post
responseType: options.responseType,
overrideMimeType: options.overrideMimeType,
});
};
/**
* Contains implementations of functions that can be replaced for testing
*
* @private
*/
Resource._Implementations = {};
function loadImageElement(url, crossOrigin, deferred) {
const image = new Image();
image.onload = function () {
deferred.resolve(image);
};
image.onerror = function (e) {
deferred.reject(e);
};
if (crossOrigin) {
if (TrustedServers.contains(url)) {
image.crossOrigin = "use-credentials";
} else {
image.crossOrigin = "";
}
}
image.src = url;
}
Resource._Implementations.createImage = function (
request,
crossOrigin,
deferred,
flipY,
skipColorSpaceConversion,
preferImageBitmap
) {
const url = request.url;
// Passing an Image to createImageBitmap will force it to run on the main thread
// since DOM elements don't exist on workers. We convert it to a blob so it's non-blocking.
// See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1044102#c38
// https://bugs.chromium.org/p/chromium/issues/detail?id=580202#c10
Resource.supportsImageBitmapOptions()
.then(function (supportsImageBitmap) {
// We can only use ImageBitmap if we can flip on decode.
// See: https://github.com/CesiumGS/cesium/pull/7579#issuecomment-466146898
if (!(supportsImageBitmap && preferImageBitmap)) {
loadImageElement(url, crossOrigin, deferred);
return;
}
const responseType = "blob";
const method = "GET";
const xhrDeferred = when.defer();
const xhr = Resource._Implementations.loadWithXhr(
url,
responseType,
method,
undefined,
undefined,
xhrDeferred,
undefined,
undefined,
undefined
);
if (defined(xhr) && defined(xhr.abort)) {
request.cancelFunction = function () {
xhr.abort();
};
}
return xhrDeferred.promise
.then(function (blob) {
if (!defined(blob)) {
deferred.reject(
new RuntimeError(
`Successfully retrieved ${url} but it contained no content.`
)
);
return;
}
return Resource.createImageBitmapFromBlob(blob, {
flipY: flipY,
premultiplyAlpha: false,
skipColorSpaceConversion: skipColorSpaceConversion,
});
})
.then(deferred.resolve);
})
.otherwise(deferred.reject);
};
/**
* Wrapper for createImageBitmap
*
* @private
*/
Resource.createImageBitmapFromBlob = function (blob, options) {
Check.defined("options", options);
Check.typeOf.bool("options.flipY", options.flipY);
Check.typeOf.bool("options.premultiplyAlpha", options.premultiplyAlpha);
Check.typeOf.bool(
"options.skipColorSpaceConversion",
options.skipColorSpaceConversion
);
return createImageBitmap(blob, {
imageOrientation: options.flipY ? "flipY" : "none",
premultiplyAlpha: options.premultiplyAlpha ? "premultiply" : "none",
colorSpaceConversion: options.skipColorSpaceConversion ? "none" : "default",
});
};
function decodeResponse(loadWithHttpResponse, responseType) {
switch (responseType) {
case "text":
return loadWithHttpResponse.toString("utf8");
case "json":
return JSON.parse(loadWithHttpResponse.toString("utf8"));
default:
return new Uint8Array(loadWithHttpResponse).buffer;
}
}
function loadWithHttpRequest(
url,
responseType,
method,
data,
headers,
deferred,
overrideMimeType
) {
// Note: only the 'json' and 'text' responseTypes transforms the loaded buffer
/* eslint-disable no-undef */
const URL = require("url").parse(url);
const http = URL.protocol === "https:" ? require("https") : require("http");
const zlib = require("zlib");
/* eslint-enable no-undef */
const options = {
protocol: URL.protocol,
hostname: URL.hostname,
port: URL.port,
path: URL.path,
query: URL.query,
method: method,
headers: headers,
};
http
.request(options)
.on("response", function (res) {
if (res.statusCode < 200 || res.statusCode >= 300) {
deferred.reject(
new RequestErrorEvent(res.statusCode, res, res.headers)
);
return;
}
const chunkArray = [];
res.on("data", function (chunk) {
chunkArray.push(chunk);
});
res.on("end", function () {
// eslint-disable-next-line no-undef
const result = Buffer.concat(chunkArray);
if (res.headers["content-encoding"] === "gzip") {
zlib.gunzip(result, function (error, resultUnzipped) {
if (error) {
deferred.reject(
new RuntimeError("Error decompressing response.")
);
} else {
deferred.resolve(decodeResponse(resultUnzipped, responseType));
}
});
} else {
deferred.resolve(decodeResponse(result, responseType));
}
});
})
.on("error", function (e) {
deferred.reject(new RequestErrorEvent());
})
.end();
}
const noXMLHttpRequest = typeof XMLHttpRequest === "undefined";
Resource._Implementations.loadWithXhr = function (
url,
responseType,
method,
data,
headers,
deferred,
overrideMimeType
) {
const dataUriRegexResult = dataUriRegex$1.exec(url);
if (dataUriRegexResult !== null) {
deferred.resolve(decodeDataUri(dataUriRegexResult, responseType));
return;
}
if (noXMLHttpRequest) {
loadWithHttpRequest(
url,
responseType,
method,
data,
headers,
deferred);
return;
}
const xhr = new XMLHttpRequest();
if (TrustedServers.contains(url)) {
xhr.withCredentials = true;
}
xhr.open(method, url, true);
if (defined(overrideMimeType) && defined(xhr.overrideMimeType)) {
xhr.overrideMimeType(overrideMimeType);
}
if (defined(headers)) {
for (const key in headers) {
if (headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, headers[key]);
}
}
}
if (defined(responseType)) {
xhr.responseType = responseType;
}
// While non-standard, file protocol always returns a status of 0 on success
let localFile = false;
if (typeof url === "string") {
localFile =
url.indexOf("file://") === 0 ||
(typeof window !== "undefined" && window.location.origin === "file://");
}
xhr.onload = function () {
if (
(xhr.status < 200 || xhr.status >= 300) &&
!(localFile && xhr.status === 0)
) {
deferred.reject(
new RequestErrorEvent(
xhr.status,
xhr.response,
xhr.getAllResponseHeaders()
)
);
return;
}
const response = xhr.response;
const browserResponseType = xhr.responseType;
if (method === "HEAD" || method === "OPTIONS") {
const responseHeaderString = xhr.getAllResponseHeaders();
const splitHeaders = responseHeaderString.trim().split(/[\r\n]+/);
const responseHeaders = {};
splitHeaders.forEach(function (line) {
const parts = line.split(": ");
const header = parts.shift();
responseHeaders[header] = parts.join(": ");
});
deferred.resolve(responseHeaders);
return;
}
//All modern browsers will go into either the first or second if block or last else block.
//Other code paths support older browsers that either do not support the supplied responseType
//or do not support the xhr.response property.
if (xhr.status === 204) {
// accept no content
deferred.resolve();
} else if (
defined(response) &&
(!defined(responseType) || browserResponseType === responseType)
) {
deferred.resolve(response);
} else if (responseType === "json" && typeof response === "string") {
try {
deferred.resolve(JSON.parse(response));
} catch (e) {
deferred.reject(e);
}
} else if (
(browserResponseType === "" || browserResponseType === "document") &&
defined(xhr.responseXML) &&
xhr.responseXML.hasChildNodes()
) {
deferred.resolve(xhr.responseXML);
} else if (
(browserResponseType === "" || browserResponseType === "text") &&
defined(xhr.responseText)
) {
deferred.resolve(xhr.responseText);
} else {
deferred.reject(
new RuntimeError("Invalid XMLHttpRequest response type.")
);
}
};
xhr.onerror = function (e) {
deferred.reject(new RequestErrorEvent());
};
xhr.send(data);
return xhr;
};
Resource._Implementations.loadAndExecuteScript = function (
url,
functionName,
deferred
) {
return loadAndExecuteScript(url).otherwise(deferred.reject);
};
/**
* The default implementations
*
* @private
*/
Resource._DefaultImplementations = {};
Resource._DefaultImplementations.createImage =
Resource._Implementations.createImage;
Resource._DefaultImplementations.loadWithXhr =
Resource._Implementations.loadWithXhr;
Resource._DefaultImplementations.loadAndExecuteScript =
Resource._Implementations.loadAndExecuteScript;
/**
* A resource instance initialized to the current browser location
*
* @type {Resource}
* @constant
*/
Resource.DEFAULT = Object.freeze(
new Resource({
url:
typeof document === "undefined"
? ""
: document.location.href.split("?")[0],
})
);
/*global CESIUM_BASE_URL,define,require*/
const cesiumScriptRegex = /((?:.*\/)|^)Cesium\.js(?:\?|\#|$)/;
function getBaseUrlFromCesiumScript() {
const scripts = document.getElementsByTagName("script");
for (let i = 0, len = scripts.length; i < len; ++i) {
const src = scripts[i].getAttribute("src");
const result = cesiumScriptRegex.exec(src);
if (result !== null) {
return result[1];
}
}
return undefined;
}
let a$1;
function tryMakeAbsolute(url) {
if (typeof document === "undefined") {
//Node.js and Web Workers. In both cases, the URL will already be absolute.
return url;
}
if (!defined(a$1)) {
a$1 = document.createElement("a");
}
a$1.href = url;
// IE only absolutizes href on get, not set
// eslint-disable-next-line no-self-assign
a$1.href = a$1.href;
return a$1.href;
}
let baseResource;
function getCesiumBaseUrl() {
if (defined(baseResource)) {
return baseResource;
}
let baseUrlString;
if (typeof CESIUM_BASE_URL !== "undefined") {
baseUrlString = CESIUM_BASE_URL;
} else if (
typeof define === "object" &&
defined(define.amd) &&
!define.amd.toUrlUndefined &&
defined(require.toUrl)
) {
baseUrlString = getAbsoluteUri(
"..",
buildModuleUrl("Core/buildModuleUrl.js")
);
} else {
baseUrlString = getBaseUrlFromCesiumScript();
}
//>>includeStart('debug', pragmas.debug);
if (!defined(baseUrlString)) {
throw new DeveloperError(
"Unable to determine Cesium base URL automatically, try defining a global variable called CESIUM_BASE_URL."
);
}
//>>includeEnd('debug');
baseResource = new Resource({
url: tryMakeAbsolute(baseUrlString),
});
baseResource.appendForwardSlash();
return baseResource;
}
function buildModuleUrlFromRequireToUrl(moduleID) {
//moduleID will be non-relative, so require it relative to this module, in Core.
return tryMakeAbsolute(require.toUrl(`../${moduleID}`));
}
function buildModuleUrlFromBaseUrl(moduleID) {
const resource = getCesiumBaseUrl().getDerivedResource({
url: moduleID,
});
return resource.url;
}
let implementation$2;
/**
* Given a relative URL under the Cesium base URL, returns an absolute URL.
* @function
*
* @param {String} relativeUrl The relative path.
* @returns {String} The absolutely URL representation of the provided path.
*
* @example
* const viewer = new Cesium.Viewer("cesiumContainer", {
* imageryProvider: new Cesium.TileMapServiceImageryProvider({
* url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
* }),
* baseLayerPicker: false,
* });
*/
function buildModuleUrl(relativeUrl) {
if (!defined(implementation$2)) {
//select implementation
if (
typeof define === "object" &&
defined(define.amd) &&
!define.amd.toUrlUndefined &&
defined(require.toUrl)
) {
implementation$2 = buildModuleUrlFromRequireToUrl;
} else {
implementation$2 = buildModuleUrlFromBaseUrl;
}
}
const url = implementation$2(relativeUrl);
return url;
}
// exposed for testing
buildModuleUrl._cesiumScriptRegex = cesiumScriptRegex;
buildModuleUrl._buildModuleUrlFromBaseUrl = buildModuleUrlFromBaseUrl;
buildModuleUrl._clearBaseResource = function () {
baseResource = undefined;
};
/**
* Sets the base URL for resolving modules.
* @param {String} value The new base URL.
*/
buildModuleUrl.setBaseUrl = function (value) {
baseResource = Resource.DEFAULT.getDerivedResource({
url: value,
});
};
/**
* Gets the base URL for resolving modules.
*/
buildModuleUrl.getCesiumBaseUrl = getCesiumBaseUrl;
/**
* A 2D Cartesian point.
* @alias Cartesian2
* @constructor
*
* @param {Number} [x=0.0] The X component.
* @param {Number} [y=0.0] The Y component.
*
* @see Cartesian3
* @see Cartesian4
* @see Packable
*/
function Cartesian2(x, y) {
/**
* The X component.
* @type {Number}
* @default 0.0
*/
this.x = defaultValue(x, 0.0);
/**
* The Y component.
* @type {Number}
* @default 0.0
*/
this.y = defaultValue(y, 0.0);
}
/**
* Creates a Cartesian2 instance from x and y coordinates.
*
* @param {Number} x The x coordinate.
* @param {Number} y The y coordinate.
* @param {Cartesian2} [result] The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
*/
Cartesian2.fromElements = function (x, y, result) {
if (!defined(result)) {
return new Cartesian2(x, y);
}
result.x = x;
result.y = y;
return result;
};
/**
* Duplicates a Cartesian2 instance.
*
* @param {Cartesian2} cartesian The Cartesian to duplicate.
* @param {Cartesian2} [result] The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. (Returns undefined if cartesian is undefined)
*/
Cartesian2.clone = function (cartesian, result) {
if (!defined(cartesian)) {
return undefined;
}
if (!defined(result)) {
return new Cartesian2(cartesian.x, cartesian.y);
}
result.x = cartesian.x;
result.y = cartesian.y;
return result;
};
/**
* Creates a Cartesian2 instance from an existing Cartesian3. This simply takes the
* x and y properties of the Cartesian3 and drops z.
* @function
*
* @param {Cartesian3} cartesian The Cartesian3 instance to create a Cartesian2 instance from.
* @param {Cartesian2} [result] The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
*/
Cartesian2.fromCartesian3 = Cartesian2.clone;
/**
* Creates a Cartesian2 instance from an existing Cartesian4. This simply takes the
* x and y properties of the Cartesian4 and drops z and w.
* @function
*
* @param {Cartesian4} cartesian The Cartesian4 instance to create a Cartesian2 instance from.
* @param {Cartesian2} [result] The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
*/
Cartesian2.fromCartesian4 = Cartesian2.clone;
/**
* The number of elements used to pack the object into an array.
* @type {Number}
*/
Cartesian2.packedLength = 2;
/**
* Stores the provided instance into the provided array.
*
* @param {Cartesian2} value The value to pack.
* @param {Number[]} array The array to pack into.
* @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
*
* @returns {Number[]} The array that was packed into
*/
Cartesian2.pack = function (value, array, startingIndex) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("value", value);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
array[startingIndex++] = value.x;
array[startingIndex] = value.y;
return array;
};
/**
* Retrieves an instance from a packed array.
*
* @param {Number[]} array The packed array.
* @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
* @param {Cartesian2} [result] The object into which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
*/
Cartesian2.unpack = function (array, startingIndex, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
startingIndex = defaultValue(startingIndex, 0);
if (!defined(result)) {
result = new Cartesian2();
}
result.x = array[startingIndex++];
result.y = array[startingIndex];
return result;
};
/**
* Flattens an array of Cartesian2s into an array of components.
*
* @param {Cartesian2[]} array The array of cartesians to pack.
* @param {Number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 2 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 2) elements.
* @returns {Number[]} The packed array.
*/
Cartesian2.packArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
//>>includeEnd('debug');
const length = array.length;
const resultLength = length * 2;
if (!defined(result)) {
result = new Array(resultLength);
} else if (!Array.isArray(result) && result.length !== resultLength) {
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError(
"If result is a typed array, it must have exactly array.length * 2 elements"
);
//>>includeEnd('debug');
} else if (result.length !== resultLength) {
result.length = resultLength;
}
for (let i = 0; i < length; ++i) {
Cartesian2.pack(array[i], result, i * 2);
}
return result;
};
/**
* Unpacks an array of cartesian components into an array of Cartesian2s.
*
* @param {Number[]} array The array of components to unpack.
* @param {Cartesian2[]} [result] The array onto which to store the result.
* @returns {Cartesian2[]} The unpacked array.
*/
Cartesian2.unpackArray = function (array, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined("array", array);
Check.typeOf.number.greaterThanOrEquals("array.length", array.length, 2);
if (array.length % 2 !== 0) {
throw new DeveloperError("array length must be a multiple of 2.");
}
//>>includeEnd('debug');
const length = array.length;
if (!defined(result)) {
result = new Array(length / 2);
} else {
result.length = length / 2;
}
for (let i = 0; i < length; i += 2) {
const index = i / 2;
result[index] = Cartesian2.unpack(array, i, result[index]);
}
return result;
};
/**
* Creates a Cartesian2 from two consecutive elements in an array.
* @function
*
* @param {Number[]} array The array whose two consecutive elements correspond to the x and y components, respectively.
* @param {Number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x component.
* @param {Cartesian2} [result] The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
*
* @example
* // Create a Cartesian2 with (1.0, 2.0)
* const v = [1.0, 2.0];
* const p = Cesium.Cartesian2.fromArray(v);
*
* // Create a Cartesian2 with (1.0, 2.0) using an offset into an array
* const v2 = [0.0, 0.0, 1.0, 2.0];
* const p2 = Cesium.Cartesian2.fromArray(v2, 2);
*/
Cartesian2.fromArray = Cartesian2.unpack;
/**
* Computes the value of the maximum component for the supplied Cartesian.
*
* @param {Cartesian2} cartesian The cartesian to use.
* @returns {Number} The value of the maximum component.
*/
Cartesian2.maximumComponent = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return Math.max(cartesian.x, cartesian.y);
};
/**
* Computes the value of the minimum component for the supplied Cartesian.
*
* @param {Cartesian2} cartesian The cartesian to use.
* @returns {Number} The value of the minimum component.
*/
Cartesian2.minimumComponent = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return Math.min(cartesian.x, cartesian.y);
};
/**
* Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
*
* @param {Cartesian2} first A cartesian to compare.
* @param {Cartesian2} second A cartesian to compare.
* @param {Cartesian2} result The object into which to store the result.
* @returns {Cartesian2} A cartesian with the minimum components.
*/
Cartesian2.minimumByComponent = function (first, second, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("first", first);
Check.typeOf.object("second", second);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.min(first.x, second.x);
result.y = Math.min(first.y, second.y);
return result;
};
/**
* Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
*
* @param {Cartesian2} first A cartesian to compare.
* @param {Cartesian2} second A cartesian to compare.
* @param {Cartesian2} result The object into which to store the result.
* @returns {Cartesian2} A cartesian with the maximum components.
*/
Cartesian2.maximumByComponent = function (first, second, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("first", first);
Check.typeOf.object("second", second);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.max(first.x, second.x);
result.y = Math.max(first.y, second.y);
return result;
};
/**
* Computes the provided Cartesian's squared magnitude.
*
* @param {Cartesian2} cartesian The Cartesian instance whose squared magnitude is to be computed.
* @returns {Number} The squared magnitude.
*/
Cartesian2.magnitudeSquared = function (cartesian) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
//>>includeEnd('debug');
return cartesian.x * cartesian.x + cartesian.y * cartesian.y;
};
/**
* Computes the Cartesian's magnitude (length).
*
* @param {Cartesian2} cartesian The Cartesian instance whose magnitude is to be computed.
* @returns {Number} The magnitude.
*/
Cartesian2.magnitude = function (cartesian) {
return Math.sqrt(Cartesian2.magnitudeSquared(cartesian));
};
const distanceScratch$1 = new Cartesian2();
/**
* Computes the distance between two points.
*
* @param {Cartesian2} left The first point to compute the distance from.
* @param {Cartesian2} right The second point to compute the distance to.
* @returns {Number} The distance between two points.
*
* @example
* // Returns 1.0
* const d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(2.0, 0.0));
*/
Cartesian2.distance = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian2.subtract(left, right, distanceScratch$1);
return Cartesian2.magnitude(distanceScratch$1);
};
/**
* Computes the squared distance between two points. Comparing squared distances
* using this function is more efficient than comparing distances using {@link Cartesian2#distance}.
*
* @param {Cartesian2} left The first point to compute the distance from.
* @param {Cartesian2} right The second point to compute the distance to.
* @returns {Number} The distance between two points.
*
* @example
* // Returns 4.0, not 2.0
* const d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(3.0, 0.0));
*/
Cartesian2.distanceSquared = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian2.subtract(left, right, distanceScratch$1);
return Cartesian2.magnitudeSquared(distanceScratch$1);
};
/**
* Computes the normalized form of the supplied Cartesian.
*
* @param {Cartesian2} cartesian The Cartesian to be normalized.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.normalize = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const magnitude = Cartesian2.magnitude(cartesian);
result.x = cartesian.x / magnitude;
result.y = cartesian.y / magnitude;
//>>includeStart('debug', pragmas.debug);
if (isNaN(result.x) || isNaN(result.y)) {
throw new DeveloperError("normalized result is not a number");
}
//>>includeEnd('debug');
return result;
};
/**
* Computes the dot (scalar) product of two Cartesians.
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @returns {Number} The dot product.
*/
Cartesian2.dot = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
return left.x * right.x + left.y * right.y;
};
/**
* Computes the magnitude of the cross product that would result from implicitly setting the Z coordinate of the input vectors to 0
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @returns {Number} The cross product.
*/
Cartesian2.cross = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
return left.x * right.y - left.y * right.x;
};
/**
* Computes the componentwise product of two Cartesians.
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.multiplyComponents = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x * right.x;
result.y = left.y * right.y;
return result;
};
/**
* Computes the componentwise quotient of two Cartesians.
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.divideComponents = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x / right.x;
result.y = left.y / right.y;
return result;
};
/**
* Computes the componentwise sum of two Cartesians.
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.add = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x + right.x;
result.y = left.y + right.y;
return result;
};
/**
* Computes the componentwise difference of two Cartesians.
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.subtract = function (left, right, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = left.x - right.x;
result.y = left.y - right.y;
return result;
};
/**
* Multiplies the provided Cartesian componentwise by the provided scalar.
*
* @param {Cartesian2} cartesian The Cartesian to be scaled.
* @param {Number} scalar The scalar to multiply with.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.multiplyByScalar = function (cartesian, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = cartesian.x * scalar;
result.y = cartesian.y * scalar;
return result;
};
/**
* Divides the provided Cartesian componentwise by the provided scalar.
*
* @param {Cartesian2} cartesian The Cartesian to be divided.
* @param {Number} scalar The scalar to divide by.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.divideByScalar = function (cartesian, scalar, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.number("scalar", scalar);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = cartesian.x / scalar;
result.y = cartesian.y / scalar;
return result;
};
/**
* Negates the provided Cartesian.
*
* @param {Cartesian2} cartesian The Cartesian to be negated.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.negate = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = -cartesian.x;
result.y = -cartesian.y;
return result;
};
/**
* Computes the absolute value of the provided Cartesian.
*
* @param {Cartesian2} cartesian The Cartesian whose absolute value is to be computed.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.abs = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
result.x = Math.abs(cartesian.x);
result.y = Math.abs(cartesian.y);
return result;
};
const lerpScratch$1 = new Cartesian2();
/**
* Computes the linear interpolation or extrapolation at t using the provided cartesians.
*
* @param {Cartesian2} start The value corresponding to t at 0.0.
* @param {Cartesian2} end The value corresponding to t at 1.0.
* @param {Number} t The point along t at which to interpolate.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter.
*/
Cartesian2.lerp = function (start, end, t, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("start", start);
Check.typeOf.object("end", end);
Check.typeOf.number("t", t);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
Cartesian2.multiplyByScalar(end, t, lerpScratch$1);
result = Cartesian2.multiplyByScalar(start, 1.0 - t, result);
return Cartesian2.add(lerpScratch$1, result, result);
};
const angleBetweenScratch = new Cartesian2();
const angleBetweenScratch2 = new Cartesian2();
/**
* Returns the angle, in radians, between the provided Cartesians.
*
* @param {Cartesian2} left The first Cartesian.
* @param {Cartesian2} right The second Cartesian.
* @returns {Number} The angle between the Cartesians.
*/
Cartesian2.angleBetween = function (left, right) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("left", left);
Check.typeOf.object("right", right);
//>>includeEnd('debug');
Cartesian2.normalize(left, angleBetweenScratch);
Cartesian2.normalize(right, angleBetweenScratch2);
return CesiumMath.acosClamped(
Cartesian2.dot(angleBetweenScratch, angleBetweenScratch2)
);
};
const mostOrthogonalAxisScratch = new Cartesian2();
/**
* Returns the axis that is most orthogonal to the provided Cartesian.
*
* @param {Cartesian2} cartesian The Cartesian on which to find the most orthogonal axis.
* @param {Cartesian2} result The object onto which to store the result.
* @returns {Cartesian2} The most orthogonal axis.
*/
Cartesian2.mostOrthogonalAxis = function (cartesian, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("cartesian", cartesian);
Check.typeOf.object("result", result);
//>>includeEnd('debug');
const f = Cartesian2.normalize(cartesian, mostOrthogonalAxisScratch);
Cartesian2.abs(f, f);
if (f.x <= f.y) {
result = Cartesian2.clone(Cartesian2.UNIT_X, result);
} else {
result = Cartesian2.clone(Cartesian2.UNIT_Y, result);
}
return result;
};
/**
* Compares the provided Cartesians componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartesian2} [left] The first Cartesian.
* @param {Cartesian2} [right] The second Cartesian.
* @returns {Boolean} true
if left and right are equal, false
otherwise.
*/
Cartesian2.equals = function (left, right) {
return (
left === right ||
(defined(left) &&
defined(right) &&
left.x === right.x &&
left.y === right.y)
);
};
/**
* @private
*/
Cartesian2.equalsArray = function (cartesian, array, offset) {
return cartesian.x === array[offset] && cartesian.y === array[offset + 1];
};
/**
* Compares the provided Cartesians componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Cartesian2} [left] The first Cartesian.
* @param {Cartesian2} [right] The second Cartesian.
* @param {Number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if left and right are within the provided epsilon, false
otherwise.
*/
Cartesian2.equalsEpsilon = function (
left,
right,
relativeEpsilon,
absoluteEpsilon
) {
return (
left === right ||
(defined(left) &&
defined(right) &&
CesiumMath.equalsEpsilon(
left.x,
right.x,
relativeEpsilon,
absoluteEpsilon
) &&
CesiumMath.equalsEpsilon(
left.y,
right.y,
relativeEpsilon,
absoluteEpsilon
))
);
};
/**
* An immutable Cartesian2 instance initialized to (0.0, 0.0).
*
* @type {Cartesian2}
* @constant
*/
Cartesian2.ZERO = Object.freeze(new Cartesian2(0.0, 0.0));
/**
* An immutable Cartesian2 instance initialized to (1.0, 1.0).
*
* @type {Cartesian2}
* @constant
*/
Cartesian2.ONE = Object.freeze(new Cartesian2(1.0, 1.0));
/**
* An immutable Cartesian2 instance initialized to (1.0, 0.0).
*
* @type {Cartesian2}
* @constant
*/
Cartesian2.UNIT_X = Object.freeze(new Cartesian2(1.0, 0.0));
/**
* An immutable Cartesian2 instance initialized to (0.0, 1.0).
*
* @type {Cartesian2}
* @constant
*/
Cartesian2.UNIT_Y = Object.freeze(new Cartesian2(0.0, 1.0));
/**
* Duplicates this Cartesian2 instance.
*
* @param {Cartesian2} [result] The object onto which to store the result.
* @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided.
*/
Cartesian2.prototype.clone = function (result) {
return Cartesian2.clone(this, result);
};
/**
* Compares this Cartesian against the provided Cartesian componentwise and returns
* true
if they are equal, false
otherwise.
*
* @param {Cartesian2} [right] The right hand side Cartesian.
* @returns {Boolean} true
if they are equal, false
otherwise.
*/
Cartesian2.prototype.equals = function (right) {
return Cartesian2.equals(this, right);
};
/**
* Compares this Cartesian against the provided Cartesian componentwise and returns
* true
if they pass an absolute or relative tolerance test,
* false
otherwise.
*
* @param {Cartesian2} [right] The right hand side Cartesian.
* @param {Number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
* @param {Number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
* @returns {Boolean} true
if they are within the provided epsilon, false
otherwise.
*/
Cartesian2.prototype.equalsEpsilon = function (
right,
relativeEpsilon,
absoluteEpsilon
) {
return Cartesian2.equalsEpsilon(
this,
right,
relativeEpsilon,
absoluteEpsilon
);
};
/**
* Creates a string representing this Cartesian in the format '(x, y)'.
*
* @returns {String} A string representing the provided Cartesian in the format '(x, y)'.
*/
Cartesian2.prototype.toString = function () {
return `(${this.x}, ${this.y})`;
};
/**
* A tiling scheme for geometry referenced to a simple {@link GeographicProjection} where
* longitude and latitude are directly mapped to X and Y. This projection is commonly
* known as geographic, equirectangular, equidistant cylindrical, or plate carrée.
*
* @alias GeographicTilingScheme
* @constructor
*
* @param {Object} [options] Object with the following properties:
* @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to
* the WGS84 ellipsoid.
* @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the tiling scheme.
* @param {Number} [options.numberOfLevelZeroTilesX=2] The number of tiles in the X direction at level zero of
* the tile tree.
* @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of
* the tile tree.
*/
function GeographicTilingScheme(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
this._rectangle = defaultValue(options.rectangle, Rectangle.MAX_VALUE);
this._projection = new GeographicProjection(this._ellipsoid);
this._numberOfLevelZeroTilesX = defaultValue(
options.numberOfLevelZeroTilesX,
2
);
this._numberOfLevelZeroTilesY = defaultValue(
options.numberOfLevelZeroTilesY,
1
);
}
Object.defineProperties(GeographicTilingScheme.prototype, {
/**
* Gets the ellipsoid that is tiled by this tiling scheme.
* @memberof GeographicTilingScheme.prototype
* @type {Ellipsoid}
*/
ellipsoid: {
get: function () {
return this._ellipsoid;
},
},
/**
* Gets the rectangle, in radians, covered by this tiling scheme.
* @memberof GeographicTilingScheme.prototype
* @type {Rectangle}
*/
rectangle: {
get: function () {
return this._rectangle;
},
},
/**
* Gets the map projection used by this tiling scheme.
* @memberof GeographicTilingScheme.prototype
* @type {MapProjection}
*/
projection: {
get: function () {
return this._projection;
},
},
});
/**
* Gets the total number of tiles in the X direction at a specified level-of-detail.
*
* @param {Number} level The level-of-detail.
* @returns {Number} The number of tiles in the X direction at the given level.
*/
GeographicTilingScheme.prototype.getNumberOfXTilesAtLevel = function (level) {
return this._numberOfLevelZeroTilesX << level;
};
/**
* Gets the total number of tiles in the Y direction at a specified level-of-detail.
*
* @param {Number} level The level-of-detail.
* @returns {Number} The number of tiles in the Y direction at the given level.
*/
GeographicTilingScheme.prototype.getNumberOfYTilesAtLevel = function (level) {
return this._numberOfLevelZeroTilesY << level;
};
/**
* Transforms a rectangle specified in geodetic radians to the native coordinate system
* of this tiling scheme.
*
* @param {Rectangle} rectangle The rectangle to transform.
* @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance
* should be created.
* @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result'
* is undefined.
*/
GeographicTilingScheme.prototype.rectangleToNativeRectangle = function (
rectangle,
result
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("rectangle", rectangle);
//>>includeEnd('debug');
const west = CesiumMath.toDegrees(rectangle.west);
const south = CesiumMath.toDegrees(rectangle.south);
const east = CesiumMath.toDegrees(rectangle.east);
const north = CesiumMath.toDegrees(rectangle.north);
if (!defined(result)) {
return new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates
* of the tiling scheme.
*
* @param {Number} x The integer x coordinate of the tile.
* @param {Number} y The integer y coordinate of the tile.
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
* should be created.
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
* if 'result' is undefined.
*/
GeographicTilingScheme.prototype.tileXYToNativeRectangle = function (
x,
y,
level,
result
) {
const rectangleRadians = this.tileXYToRectangle(x, y, level, result);
rectangleRadians.west = CesiumMath.toDegrees(rectangleRadians.west);
rectangleRadians.south = CesiumMath.toDegrees(rectangleRadians.south);
rectangleRadians.east = CesiumMath.toDegrees(rectangleRadians.east);
rectangleRadians.north = CesiumMath.toDegrees(rectangleRadians.north);
return rectangleRadians;
};
/**
* Converts tile x, y coordinates and level to a cartographic rectangle in radians.
*
* @param {Number} x The integer x coordinate of the tile.
* @param {Number} y The integer y coordinate of the tile.
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
* @param {Object} [result] The instance to which to copy the result, or undefined if a new instance
* should be created.
* @returns {Rectangle} The specified 'result', or a new object containing the rectangle
* if 'result' is undefined.
*/
GeographicTilingScheme.prototype.tileXYToRectangle = function (
x,
y,
level,
result
) {
const rectangle = this._rectangle;
const xTiles = this.getNumberOfXTilesAtLevel(level);
const yTiles = this.getNumberOfYTilesAtLevel(level);
const xTileWidth = rectangle.width / xTiles;
const west = x * xTileWidth + rectangle.west;
const east = (x + 1) * xTileWidth + rectangle.west;
const yTileHeight = rectangle.height / yTiles;
const north = rectangle.north - y * yTileHeight;
const south = rectangle.north - (y + 1) * yTileHeight;
if (!defined(result)) {
result = new Rectangle(west, south, east, north);
}
result.west = west;
result.south = south;
result.east = east;
result.north = north;
return result;
};
/**
* Calculates the tile x, y coordinates of the tile containing
* a given cartographic position.
*
* @param {Cartographic} position The position.
* @param {Number} level The tile level-of-detail. Zero is the least detailed.
* @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance
* should be created.
* @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates
* if 'result' is undefined.
*/
GeographicTilingScheme.prototype.positionToTileXY = function (
position,
level,
result
) {
const rectangle = this._rectangle;
if (!Rectangle.contains(rectangle, position)) {
// outside the bounds of the tiling scheme
return undefined;
}
const xTiles = this.getNumberOfXTilesAtLevel(level);
const yTiles = this.getNumberOfYTilesAtLevel(level);
const xTileWidth = rectangle.width / xTiles;
const yTileHeight = rectangle.height / yTiles;
let longitude = position.longitude;
if (rectangle.east < rectangle.west) {
longitude += CesiumMath.TWO_PI;
}
let xTileCoordinate = ((longitude - rectangle.west) / xTileWidth) | 0;
if (xTileCoordinate >= xTiles) {
xTileCoordinate = xTiles - 1;
}
let yTileCoordinate =
((rectangle.north - position.latitude) / yTileHeight) | 0;
if (yTileCoordinate >= yTiles) {
yTileCoordinate = yTiles - 1;
}
if (!defined(result)) {
return new Cartesian2(xTileCoordinate, yTileCoordinate);
}
result.x = xTileCoordinate;
result.y = yTileCoordinate;
return result;
};
const scratchDiagonalCartesianNE = new Cartesian3();
const scratchDiagonalCartesianSW = new Cartesian3();
const scratchDiagonalCartographic = new Cartographic();
const scratchCenterCartesian = new Cartesian3();
const scratchSurfaceCartesian = new Cartesian3();
const scratchBoundingSphere$4 = new BoundingSphere();
const tilingScheme = new GeographicTilingScheme();
const scratchCorners = [
new Cartographic(),
new Cartographic(),
new Cartographic(),
new Cartographic(),
];
const scratchTileXY = new Cartesian2();
/**
* A collection of functions for approximating terrain height
* @private
*/
const ApproximateTerrainHeights = {};
/**
* Initializes the minimum and maximum terrain heights
* @return {Promise}
*/
ApproximateTerrainHeights.initialize = function () {
let initPromise = ApproximateTerrainHeights._initPromise;
if (defined(initPromise)) {
return initPromise;
}
initPromise = Resource.fetchJson(
buildModuleUrl("Assets/approximateTerrainHeights.json")
).then(function (json) {
ApproximateTerrainHeights._terrainHeights = json;
});
ApproximateTerrainHeights._initPromise = initPromise;
return initPromise;
};
/**
* Computes the minimum and maximum terrain heights for a given rectangle
* @param {Rectangle} rectangle The bounding rectangle
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid
* @return {{minimumTerrainHeight: Number, maximumTerrainHeight: Number}}
*/
ApproximateTerrainHeights.getMinimumMaximumHeights = function (
rectangle,
ellipsoid
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("rectangle", rectangle);
if (!defined(ApproximateTerrainHeights._terrainHeights)) {
throw new DeveloperError(
"You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function"
);
}
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
const xyLevel = getTileXYLevel(rectangle);
// Get the terrain min/max for that tile
let minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight;
let maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight;
if (defined(xyLevel)) {
const key = `${xyLevel.level}-${xyLevel.x}-${xyLevel.y}`;
const heights = ApproximateTerrainHeights._terrainHeights[key];
if (defined(heights)) {
minTerrainHeight = heights[0];
maxTerrainHeight = heights[1];
}
// Compute min by taking the center of the NE->SW diagonal and finding distance to the surface
ellipsoid.cartographicToCartesian(
Rectangle.northeast(rectangle, scratchDiagonalCartographic),
scratchDiagonalCartesianNE
);
ellipsoid.cartographicToCartesian(
Rectangle.southwest(rectangle, scratchDiagonalCartographic),
scratchDiagonalCartesianSW
);
Cartesian3.midpoint(
scratchDiagonalCartesianSW,
scratchDiagonalCartesianNE,
scratchCenterCartesian
);
const surfacePosition = ellipsoid.scaleToGeodeticSurface(
scratchCenterCartesian,
scratchSurfaceCartesian
);
if (defined(surfacePosition)) {
const distance = Cartesian3.distance(
scratchCenterCartesian,
surfacePosition
);
minTerrainHeight = Math.min(minTerrainHeight, -distance);
} else {
minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight;
}
}
minTerrainHeight = Math.max(
ApproximateTerrainHeights._defaultMinTerrainHeight,
minTerrainHeight
);
return {
minimumTerrainHeight: minTerrainHeight,
maximumTerrainHeight: maxTerrainHeight,
};
};
/**
* Computes the bounding sphere based on the tile heights in the rectangle
* @param {Rectangle} rectangle The bounding rectangle
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid
* @return {BoundingSphere} The result bounding sphere
*/
ApproximateTerrainHeights.getBoundingSphere = function (rectangle, ellipsoid) {
//>>includeStart('debug', pragmas.debug);
Check.defined("rectangle", rectangle);
if (!defined(ApproximateTerrainHeights._terrainHeights)) {
throw new DeveloperError(
"You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function"
);
}
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
const xyLevel = getTileXYLevel(rectangle);
// Get the terrain max for that tile
let maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight;
if (defined(xyLevel)) {
const key = `${xyLevel.level}-${xyLevel.x}-${xyLevel.y}`;
const heights = ApproximateTerrainHeights._terrainHeights[key];
if (defined(heights)) {
maxTerrainHeight = heights[1];
}
}
const result = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, 0.0);
BoundingSphere.fromRectangle3D(
rectangle,
ellipsoid,
maxTerrainHeight,
scratchBoundingSphere$4
);
return BoundingSphere.union(result, scratchBoundingSphere$4, result);
};
function getTileXYLevel(rectangle) {
Cartographic.fromRadians(
rectangle.east,
rectangle.north,
0.0,
scratchCorners[0]
);
Cartographic.fromRadians(
rectangle.west,
rectangle.north,
0.0,
scratchCorners[1]
);
Cartographic.fromRadians(
rectangle.east,
rectangle.south,
0.0,
scratchCorners[2]
);
Cartographic.fromRadians(
rectangle.west,
rectangle.south,
0.0,
scratchCorners[3]
);
// Determine which tile the bounding rectangle is in
let lastLevelX = 0,
lastLevelY = 0;
let currentX = 0,
currentY = 0;
const maxLevel = ApproximateTerrainHeights._terrainHeightsMaxLevel;
let i;
for (i = 0; i <= maxLevel; ++i) {
let failed = false;
for (let j = 0; j < 4; ++j) {
const corner = scratchCorners[j];
tilingScheme.positionToTileXY(corner, i, scratchTileXY);
if (j === 0) {
currentX = scratchTileXY.x;
currentY = scratchTileXY.y;
} else if (currentX !== scratchTileXY.x || currentY !== scratchTileXY.y) {
failed = true;
break;
}
}
if (failed) {
break;
}
lastLevelX = currentX;
lastLevelY = currentY;
}
if (i === 0) {
return undefined;
}
return {
x: lastLevelX,
y: lastLevelY,
level: i > maxLevel ? maxLevel : i - 1,
};
}
ApproximateTerrainHeights._terrainHeightsMaxLevel = 6;
ApproximateTerrainHeights._defaultMaxTerrainHeight = 9000.0;
ApproximateTerrainHeights._defaultMinTerrainHeight = -100000.0;
ApproximateTerrainHeights._terrainHeights = undefined;
ApproximateTerrainHeights._initPromise = undefined;
Object.defineProperties(ApproximateTerrainHeights, {
/**
* Determines if the terrain heights are initialized and ready to use. To initialize the terrain heights,
* call {@link ApproximateTerrainHeights#initialize} and wait for the returned promise to resolve.
* @type {Boolean}
* @readonly
* @memberof ApproximateTerrainHeights
*/
initialized: {
get: function () {
return defined(ApproximateTerrainHeights._terrainHeights);
},
},
});
/* This file is automatically rebuilt by the Cesium build process. */
/*! @license DOMPurify 2.3.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.6/LICENSE */
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var hasOwnProperty = Object.hasOwnProperty,
setPrototypeOf = Object.setPrototypeOf,
isFrozen = Object.isFrozen,
getPrototypeOf = Object.getPrototypeOf,
getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
var freeze = Object.freeze,
seal = Object.seal,
create = Object.create; // eslint-disable-line import/no-mutable-exports
var _ref = typeof Reflect !== 'undefined' && Reflect,
apply = _ref.apply,
construct = _ref.construct;
if (!apply) {
apply = function apply(fun, thisValue, args) {
return fun.apply(thisValue, args);
};
}
if (!freeze) {
freeze = function freeze(x) {
return x;
};
}
if (!seal) {
seal = function seal(x) {
return x;
};
}
if (!construct) {
construct = function construct(Func, args) {
return new (Function.prototype.bind.apply(Func, [null].concat(_toConsumableArray(args))))();
};
}
var arrayForEach = unapply(Array.prototype.forEach);
var arrayPop = unapply(Array.prototype.pop);
var arrayPush = unapply(Array.prototype.push);
var stringToLowerCase = unapply(String.prototype.toLowerCase);
var stringMatch = unapply(String.prototype.match);
var stringReplace = unapply(String.prototype.replace);
var stringIndexOf = unapply(String.prototype.indexOf);
var stringTrim = unapply(String.prototype.trim);
var regExpTest = unapply(RegExp.prototype.test);
var typeErrorCreate = unconstruct(TypeError);
function unapply(func) {
return function (thisArg) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
return apply(func, thisArg, args);
};
}
function unconstruct(func) {
return function () {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return construct(func, args);
};
}
/* Add properties to a lookup table */
function addToSet(set, array) {
if (setPrototypeOf) {
// Make 'in' and truthy checks like Boolean(set.constructor)
// independent of any properties defined on Object.prototype.
// Prevent prototype setters from intercepting set as a this value.
setPrototypeOf(set, null);
}
var l = array.length;
while (l--) {
var element = array[l];
if (typeof element === 'string') {
var lcElement = stringToLowerCase(element);
if (lcElement !== element) {
// Config presets (e.g. tags.js, attrs.js) are immutable.
if (!isFrozen(array)) {
array[l] = lcElement;
}
element = lcElement;
}
}
set[element] = true;
}
return set;
}
/* Shallow clone an object */
function clone(object) {
var newObject = create(null);
var property = void 0;
for (property in object) {
if (apply(hasOwnProperty, object, [property])) {
newObject[property] = object[property];
}
}
return newObject;
}
/* IE10 doesn't support __lookupGetter__ so lets'
* simulate it. It also automatically checks
* if the prop is function or getter and behaves
* accordingly. */
function lookupGetter(object, prop) {
while (object !== null) {
var desc = getOwnPropertyDescriptor(object, prop);
if (desc) {
if (desc.get) {
return unapply(desc.get);
}
if (typeof desc.value === 'function') {
return unapply(desc.value);
}
}
object = getPrototypeOf(object);
}
function fallbackValue(element) {
console.warn('fallback value for', element);
return null;
}
return fallbackValue;
}
var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
// SVG
var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
// List of SVG elements that are disallowed by default.
// We still need to know them so that we can do namespace
// checks properly in case one wants to add them to
// allow-list.
var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
var mathMl = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']);
// Similarly to SVG, we want to know all MathML elements,
// even those that we disallow by default.
var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
var text = freeze(['#text']);
var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
var mathMl$1 = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
// eslint-disable-next-line unicorn/better-regex
var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
);
var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
);
var DOCTYPE_NAME = seal(/^html$/i);
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _toConsumableArray$1(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var getGlobal = function getGlobal() {
return typeof window === 'undefined' ? null : window;
};
/**
* Creates a no-op policy for internal use only.
* Don't export this function outside this module!
* @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
* @param {Document} document The document object (to determine policy name suffix)
* @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
* are not supported).
*/
var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
return null;
}
// Allow the callers to control the unique policy name
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
// Policy creation with duplicate names throws in Trusted Types.
var suffix = null;
var ATTR_NAME = 'data-tt-policy-suffix';
if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
suffix = document.currentScript.getAttribute(ATTR_NAME);
}
var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
try {
return trustedTypes.createPolicy(policyName, {
createHTML: function createHTML(html$$1) {
return html$$1;
}
});
} catch (_) {
// Policy creation failed (most likely another DOMPurify script has
// already run). Skip creating the policy, as this will only cause errors
// if TT are enforced.
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
return null;
}
};
function createDOMPurify() {
var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
var DOMPurify = function DOMPurify(root) {
return createDOMPurify(root);
};
/**
* Version label, exposed for easier checks
* if DOMPurify is up to date or not
*/
DOMPurify.version = '2.3.6';
/**
* Array of elements that DOMPurify removed during sanitation.
* Empty if nothing was removed.
*/
DOMPurify.removed = [];
if (!window || !window.document || window.document.nodeType !== 9) {
// Not running in a browser, provide a factory function
// so that you can pass your own Window
DOMPurify.isSupported = false;
return DOMPurify;
}
var originalDocument = window.document;
var document = window.document;
var DocumentFragment = window.DocumentFragment,
HTMLTemplateElement = window.HTMLTemplateElement,
Node = window.Node,
Element = window.Element,
NodeFilter = window.NodeFilter,
_window$NamedNodeMap = window.NamedNodeMap,
NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
HTMLFormElement = window.HTMLFormElement,
DOMParser = window.DOMParser,
trustedTypes = window.trustedTypes;
var ElementPrototype = Element.prototype;
var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
// As per issue #47, the web-components registry is inherited by a
// new document created via createHTMLDocument. As per the spec
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
// a new empty registry is used when creating a template contents owner
// document, so we use that as our parent document to ensure nothing
// is inherited.
if (typeof HTMLTemplateElement === 'function') {
var template = document.createElement('template');
if (template.content && template.content.ownerDocument) {
document = template.content.ownerDocument;
}
}
var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
var _document = document,
implementation = _document.implementation,
createNodeIterator = _document.createNodeIterator,
createDocumentFragment = _document.createDocumentFragment,
getElementsByTagName = _document.getElementsByTagName;
var importNode = originalDocument.importNode;
var documentMode = {};
try {
documentMode = clone(document).documentMode ? document.documentMode : {};
} catch (_) {}
var hooks = {};
/**
* Expose whether this browser supports running the full DOMPurify.
*/
DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
ERB_EXPR$$1 = ERB_EXPR,
DATA_ATTR$$1 = DATA_ATTR,
ARIA_ATTR$$1 = ARIA_ATTR,
IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA,
ATTR_WHITESPACE$$1 = ATTR_WHITESPACE;
var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI;
/**
* We consider the elements and attributes below to be safe. Ideally
* don't add any new ones but feel free to remove unwanted ones.
*/
/* allowed element names */
var ALLOWED_TAGS = null;
var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(html), _toConsumableArray$1(svg), _toConsumableArray$1(svgFilters), _toConsumableArray$1(mathMl), _toConsumableArray$1(text)));
/* Allowed attribute names */
var ALLOWED_ATTR = null;
var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml)));
/*
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
*/
var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
tagNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
attributeNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
allowCustomizedBuiltInElements: {
writable: true,
configurable: false,
enumerable: true,
value: false
}
}));
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
var FORBID_TAGS = null;
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
var FORBID_ATTR = null;
/* Decide if ARIA attributes are okay */
var ALLOW_ARIA_ATTR = true;
/* Decide if custom data attributes are okay */
var ALLOW_DATA_ATTR = true;
/* Decide if unknown protocols are okay */
var ALLOW_UNKNOWN_PROTOCOLS = false;
/* Output should be safe for common template engines.
* This means, DOMPurify removes data attributes, mustaches and ERB
*/
var SAFE_FOR_TEMPLATES = false;
/* Decide if document with ... should be returned */
var WHOLE_DOCUMENT = false;
/* Track whether config is already set on this instance of DOMPurify. */
var SET_CONFIG = false;
/* Decide if all elements (e.g. style, script) must be children of
* document.body. By default, browsers might move them to document.head */
var FORCE_BODY = false;
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
* string (or a TrustedHTML object if Trusted Types are supported).
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
*/
var RETURN_DOM = false;
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
* string (or a TrustedHTML object if Trusted Types are supported) */
var RETURN_DOM_FRAGMENT = false;
/* Try to return a Trusted Type object instead of a string, return a string in
* case Trusted Types are not supported */
var RETURN_TRUSTED_TYPE = false;
/* Output should be free from DOM clobbering attacks? */
var SANITIZE_DOM = true;
/* Keep element content when removing element? */
var KEEP_CONTENT = true;
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
* of importing it into a new Document and returning a sanitized copy */
var IN_PLACE = false;
/* Allow usage of profiles like html, svg and mathMl */
var USE_PROFILES = {};
/* Tags to ignore content of when KEEP_CONTENT is true */
var FORBID_CONTENTS = null;
var DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
/* Tags that are safe for data: URIs */
var DATA_URI_TAGS = null;
var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
/* Attributes safe for values like "javascript:" */
var URI_SAFE_ATTRIBUTES = null;
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
/* Document namespace */
var NAMESPACE = HTML_NAMESPACE;
var IS_EMPTY_INPUT = false;
/* Parsing of strict XHTML documents */
var PARSER_MEDIA_TYPE = void 0;
var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
var transformCaseFunc = void 0;
/* Keep a reference to config to pass to hooks */
var CONFIG = null;
/* Ideally, do not touch anything below this line */
/* ______________________________________________ */
var formElement = document.createElement('form');
var isRegexOrFunction = function isRegexOrFunction(testValue) {
return testValue instanceof RegExp || testValue instanceof Function;
};
/**
* _parseConfig
*
* @param {Object} cfg optional config literal
*/
// eslint-disable-next-line complexity
var _parseConfig = function _parseConfig(cfg) {
if (CONFIG && CONFIG === cfg) {
return;
}
/* Shield configuration object from tampering */
if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
cfg = {};
}
/* Shield configuration object from prototype pollution */
cfg = clone(cfg);
/* Set configuration parameters */
ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
IN_PLACE = cfg.IN_PLACE || false; // Default false
IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
}
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
}
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
}
PARSER_MEDIA_TYPE =
// eslint-disable-next-line unicorn/prefer-includes
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
return x;
} : stringToLowerCase;
if (SAFE_FOR_TEMPLATES) {
ALLOW_DATA_ATTR = false;
}
if (RETURN_DOM_FRAGMENT) {
RETURN_DOM = true;
}
/* Parse profile info */
if (USE_PROFILES) {
ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(text)));
ALLOWED_ATTR = [];
if (USE_PROFILES.html === true) {
addToSet(ALLOWED_TAGS, html);
addToSet(ALLOWED_ATTR, html$1);
}
if (USE_PROFILES.svg === true) {
addToSet(ALLOWED_TAGS, svg);
addToSet(ALLOWED_ATTR, svg$1);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.svgFilters === true) {
addToSet(ALLOWED_TAGS, svgFilters);
addToSet(ALLOWED_ATTR, svg$1);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.mathMl === true) {
addToSet(ALLOWED_TAGS, mathMl);
addToSet(ALLOWED_ATTR, mathMl$1);
addToSet(ALLOWED_ATTR, xml);
}
}
/* Merge configuration parameters */
if (cfg.ADD_TAGS) {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
}
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
}
if (cfg.ADD_ATTR) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
}
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
}
if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
}
if (cfg.FORBID_CONTENTS) {
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
FORBID_CONTENTS = clone(FORBID_CONTENTS);
}
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
}
/* Add #text in case KEEP_CONTENT is set to true */
if (KEEP_CONTENT) {
ALLOWED_TAGS['#text'] = true;
}
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
if (WHOLE_DOCUMENT) {
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
}
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
if (ALLOWED_TAGS.table) {
addToSet(ALLOWED_TAGS, ['tbody']);
delete FORBID_TAGS.tbody;
}
// Prevent further manipulation of configuration.
// Not available in IE8, Safari 5, etc.
if (freeze) {
freeze(cfg);
}
CONFIG = cfg;
};
var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
/* Keep track of all possible SVG and MathML tags
* so that we can perform the namespace checks
* correctly. */
var ALL_SVG_TAGS = addToSet({}, svg);
addToSet(ALL_SVG_TAGS, svgFilters);
addToSet(ALL_SVG_TAGS, svgDisallowed);
var ALL_MATHML_TAGS = addToSet({}, mathMl);
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
/**
*
*
* @param {Element} element a DOM element whose namespace is being checked
* @returns {boolean} Return false if the element has a
* namespace that a spec-compliant parser would never
* return. Return true otherwise.
*/
var _checkValidNamespace = function _checkValidNamespace(element) {
var parent = getParentNode(element);
// In JSDOM, if we're inside shadow DOM, then parentNode
// can be null. We just simulate parent in this case.
if (!parent || !parent.tagName) {
parent = {
namespaceURI: HTML_NAMESPACE,
tagName: 'template'
};
}
var tagName = stringToLowerCase(element.tagName);
var parentTagName = stringToLowerCase(parent.tagName);
if (element.namespaceURI === SVG_NAMESPACE) {
// The only way to switch from HTML namespace to SVG
// is via