diff --git a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Styling.html b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Styling.html index 3fe63914b5f8..733b9d6edc37 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Styling.html +++ b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Styling.html @@ -130,7 +130,7 @@ }); addStyle('Min and Max', { - color : "rgb(min(${POSITION}[0], 0.75) * 255, max(${POSITION}[2], 0.25) * 255, 255)", + color : "rgb(min(${POSITION}.x, 0.75) * 255, max(${POSITION}.z, 0.25) * 255, 255)", pointSize : "5" }); @@ -141,12 +141,11 @@ addStyle('Secondary Color', { color : { - expression : "[${secondaryColor}[0], ${secondaryColor}[1], ${secondaryColor}[2], 1.0]", conditions : [ - ["${id} < 250", "${expression}"], - ["${id} < 500", "${expression} * ${expression}"], - ["${id} < 750", "${expression} / 5.0"], - ["${id} < 1000", "rgb(0, 0, Number(${expression}[0] < 0.5) * 255)"] + ["${id} < 250", "vec4(${secondaryColor}, 1.0)"], + ["${id} < 500", "vec4(${secondaryColor} * ${secondaryColor}, 1.0)"], + ["${id} < 750", "vec4(${secondaryColor} / 5.0, 1.0)"], + ["${id} < 1000", "rgb(0, 0, Number(${secondaryColor}.x < 0.5) * 255)"] ] } }); @@ -159,8 +158,9 @@ show : "${POSITION}[0] > 0.5 || ${POSITION}[1] > 0.5 || ${POSITION}[2] > 0.5" }); +// POSITION contains 0 as its last component, so add 1.0 to make the point cloud opaque addStyle('Color based on position', { - color : "rgb(${POSITION}[0] * 255, ${POSITION}[1] * 255, ${POSITION}[2] * 255)" + color : "vec4(${POSITION}, 1.0)" }); addStyle('Style point size', { diff --git a/Apps/Sandcastle/gallery/Custom Geocoder.html b/Apps/Sandcastle/gallery/Custom Geocoder.html new file mode 100644 index 000000000000..b1f388c92db4 --- /dev/null +++ b/Apps/Sandcastle/gallery/Custom Geocoder.html @@ -0,0 +1,90 @@ + + +
+ + + + + +Boolean
, Number
, or String
, the corresponding JavaScript
* primitive type will be returned. If the result is a RegExp
, a Javascript RegExp
* object will be returned. If the result is a Color
, a {@link Color} object will be returned.
+ * If the result is a Cartesian2
, Cartesian3
, or Cartesian4
,
+ * a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} object will be returned.
*
* @param {FrameState} frameState The frame state.
* @param {Cesium3DTileFeature} feature The feature who's properties may be used as variables in the expression.
- * @returns {Boolean|Number|String|Color|RegExp} The result of evaluating the expression.
+ * @returns {Boolean|Number|String|Color|Cartesian2|Cartesian3|Cartesian4|RegExp} The result of evaluating the expression.
*/
Expression.prototype.evaluate = function(frameState, feature) {
ScratchStorage.reset();
var result = this._runtimeAst.evaluate(frameState, feature);
- if (result instanceof Color) {
- return Color.clone(result);
+ if ((result instanceof Color) || (result instanceof Cartesian2) || (result instanceof Cartesian3) || (result instanceof Cartesian4)) {
+ return result.clone();
}
return result;
};
@@ -286,6 +330,7 @@ define([
function parseCall(expression, ast) {
var args = ast.arguments;
+ var argsLength = args.length;
var call;
var val, left, right;
@@ -300,7 +345,7 @@ define([
throw new DeveloperError('Error: ' + call + ' is not a function.');
}
//>>includeEnd('debug');
- if (args.length === 0) {
+ if (argsLength === 0) {
if (call === 'test') {
return new Node(ExpressionNodeType.LITERAL_BOOLEAN, false);
} else {
@@ -323,7 +368,7 @@ define([
// Non-member function calls
call = ast.callee.name;
if (call === 'color') {
- if (args.length === 0) {
+ if (argsLength === 0) {
return new Node(ExpressionNodeType.LITERAL_COLOR, call);
}
val = createRuntimeAst(expression, args[0]);
@@ -334,7 +379,7 @@ define([
return new Node(ExpressionNodeType.LITERAL_COLOR, call, [val]);
} else if (call === 'rgb' || call === 'hsl') {
//>>includeStart('debug', pragmas.debug);
- if (args.length < 3) {
+ if (argsLength < 3) {
throw new DeveloperError('Error: ' + call + ' requires three arguments.');
}
//>>includeEnd('debug');
@@ -346,7 +391,7 @@ define([
return new Node(ExpressionNodeType.LITERAL_COLOR, call, val);
} else if (call === 'rgba' || call === 'hsla') {
//>>includeStart('debug', pragmas.debug);
- if (args.length < 4) {
+ if (argsLength < 4) {
throw new DeveloperError('Error: ' + call + ' requires four arguments.');
}
//>>includeEnd('debug');
@@ -357,8 +402,15 @@ define([
createRuntimeAst(expression, args[3])
];
return new Node(ExpressionNodeType.LITERAL_COLOR, call, val);
+ } else if (call === 'vec2' || call === 'vec3' || call === 'vec4') {
+ // Check for invalid constructors at evaluation time
+ val = new Array(argsLength);
+ for (var i = 0; i < argsLength; ++i) {
+ val[i] = createRuntimeAst(expression, args[i]);
+ }
+ return new Node(ExpressionNodeType.LITERAL_VECTOR, call, val);
} else if (call === 'isNaN' || call === 'isFinite') {
- if (args.length === 0) {
+ if (argsLength === 0) {
if (call === 'isNaN') {
return new Node(ExpressionNodeType.LITERAL_BOOLEAN, true);
} else {
@@ -369,7 +421,7 @@ define([
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (call === 'isExactClass' || call === 'isClass') {
//>>includeStart('debug', pragmas.debug);
- if (args.length < 1 || args.length > 1) {
+ if (argsLength < 1 || argsLength > 1) {
throw new DeveloperError('Error: ' + call + ' requires exactly one argument.');
}
//>>includeEnd('debug');
@@ -377,14 +429,14 @@ define([
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (call === 'getExactClassName') {
//>>includeStart('debug', pragmas.debug);
- if (args.length > 0) {
+ if (argsLength > 0) {
throw new DeveloperError('Error: ' + call + ' does not take any argument.');
}
//>>includeEnd('debug');
return new Node(ExpressionNodeType.UNARY, call);
} else if (defined(unaryFunctions[call])) {
//>>includeStart('debug', pragmas.debug);
- if (args.length !== 1) {
+ if (argsLength !== 1) {
throw new DeveloperError('Error: ' + call + ' requires exactly one argument.');
}
//>>includeEnd('debug');
@@ -392,7 +444,7 @@ define([
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (defined(binaryFunctions[call])) {
//>>includeStart('debug', pragmas.debug);
- if (args.length !== 2) {
+ if (argsLength !== 2) {
throw new DeveloperError('Error: ' + call + ' requires exactly two arguments.');
}
//>>includeEnd('debug');
@@ -401,7 +453,7 @@ define([
return new Node(ExpressionNodeType.BINARY, call, left, right);
} else if (defined(ternaryFunctions[call])) {
//>>includeStart('debug', pragmas.debug);
- if (args.length !== 3) {
+ if (argsLength !== 3) {
throw new DeveloperError('Error: ' + call + ' requires exactly three arguments.');
}
//>>includeEnd('debug');
@@ -410,19 +462,19 @@ define([
var test = createRuntimeAst(expression, args[2]);
return new Node(ExpressionNodeType.TERNARY, call, left, right, test);
} else if (call === 'Boolean') {
- if (args.length === 0) {
+ if (argsLength === 0) {
return new Node(ExpressionNodeType.LITERAL_BOOLEAN, false);
}
val = createRuntimeAst(expression, args[0]);
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (call === 'Number') {
- if (args.length === 0) {
+ if (argsLength === 0) {
return new Node(ExpressionNodeType.LITERAL_NUMBER, 0);
}
val = createRuntimeAst(expression, args[0]);
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (call === 'String') {
- if (args.length === 0) {
+ if (argsLength === 0) {
return new Node(ExpressionNodeType.LITERAL_STRING, '');
}
val = createRuntimeAst(expression, args[0]);
@@ -499,12 +551,14 @@ define([
}
function parseMemberExpression(expression, ast) {
+ var val;
var obj = createRuntimeAst(expression, ast.object);
if (ast.computed) {
- var val = createRuntimeAst(expression, ast.property);
+ val = createRuntimeAst(expression, ast.property);
return new Node(ExpressionNodeType.MEMBER, 'brackets', obj, val);
} else {
- return new Node(ExpressionNodeType.MEMBER, 'dot', obj, ast.property.name);
+ val = new Node(ExpressionNodeType.LITERAL_STRING, ast.property.name);
+ return new Node(ExpressionNodeType.MEMBER, 'dot', obj, val);
}
}
@@ -677,6 +731,8 @@ define([
node.evaluate = node._evaluateVariableString;
} else if (node._type === ExpressionNodeType.LITERAL_COLOR) {
node.evaluate = node._evaluateLiteralColor;
+ } else if (node._type === ExpressionNodeType.LITERAL_VECTOR) {
+ node.evaluate = node._evaluateLiteralVector;
} else if (node._type === ExpressionNodeType.LITERAL_STRING) {
node.evaluate = node._evaluateLiteralString;
} else if (node._type === ExpressionNodeType.REGEX) {
@@ -726,42 +782,101 @@ define([
if (!defined(args)) {
return Color.fromBytes(255, 255, 255, 255, result);
} else if (args.length > 1) {
- Color.fromCssColorString(args[0].evaluate(frameState, feature, result), result);
- result.alpha = args[1].evaluate(frameState, feature, result);
+ Color.fromCssColorString(args[0].evaluate(frameState, feature), result);
+ result.alpha = args[1].evaluate(frameState, feature);
} else {
- Color.fromCssColorString(args[0].evaluate(frameState, feature, result), result);
+ Color.fromCssColorString(args[0].evaluate(frameState, feature), result);
}
} else if (this._value === 'rgb') {
Color.fromBytes(
- args[0].evaluate(frameState, feature, result),
- args[1].evaluate(frameState, feature, result),
- args[2].evaluate(frameState, feature, result),
+ args[0].evaluate(frameState, feature),
+ args[1].evaluate(frameState, feature),
+ args[2].evaluate(frameState, feature),
255, result);
} else if (this._value === 'rgba') {
// convert between css alpha (0 to 1) and cesium alpha (0 to 255)
- var a = args[3].evaluate(frameState, feature, result) * 255;
+ var a = args[3].evaluate(frameState, feature) * 255;
Color.fromBytes(
- args[0].evaluate(frameState, feature, result),
- args[1].evaluate(frameState, feature, result),
- args[2].evaluate(frameState, feature, result),
+ args[0].evaluate(frameState, feature),
+ args[1].evaluate(frameState, feature),
+ args[2].evaluate(frameState, feature),
a, result);
} else if (this._value === 'hsl') {
Color.fromHsl(
- args[0].evaluate(frameState, feature, result),
- args[1].evaluate(frameState, feature, result),
- args[2].evaluate(frameState, feature, result),
+ args[0].evaluate(frameState, feature),
+ args[1].evaluate(frameState, feature),
+ args[2].evaluate(frameState, feature),
1.0, result);
} else if (this._value === 'hsla') {
Color.fromHsl(
- args[0].evaluate(frameState, feature, result),
- args[1].evaluate(frameState, feature, result),
- args[2].evaluate(frameState, feature, result),
- args[3].evaluate(frameState, feature, result),
+ args[0].evaluate(frameState, feature),
+ args[1].evaluate(frameState, feature),
+ args[2].evaluate(frameState, feature),
+ args[3].evaluate(frameState, feature),
result);
}
return result;
};
+ Node.prototype._evaluateLiteralVector = function(frameState, feature) {
+ // Gather the components that make up the vector, which includes components from interior vectors.
+ // For example vec3(1, 2, 3) or vec3(vec2(1, 2), 3) are both valid.
+ //
+ // If the number of components does not equal the vector's size, then a DeveloperError is thrown - with two exceptions:
+ // 1. A vector may be constructed from a larger vector and drop the extra components.
+ // 2. A vector may be constructed from a single component - vec3(1) will become vec3(1, 1, 1).
+ //
+ // Examples of invalid constructors include:
+ // vec4(1, 2) // not enough components
+ // vec3(vec2(1, 2)) // not enough components
+ // vec3(1, 2, 3, 4) // too many components
+ // vec2(vec4(1), 1) // too many components
+
+ var components = ScratchStorage.getArray();
+ var args = this._left;
+ var argsLength = args.length;
+ for (var i = 0; i < argsLength; ++i) {
+ var value = args[i].evaluate(frameState, feature);
+ if (typeof(value) === 'number') {
+ components.push(value);
+ } else if (value instanceof Cartesian2) {
+ components.push(value.x, value.y);
+ } else if (value instanceof Cartesian3) {
+ components.push(value.x, value.y, value.z);
+ } else if (value instanceof Cartesian4) {
+ components.push(value.x, value.y, value.z, value.w);
+ }
+ }
+
+ var componentsLength = components.length;
+ var call = this._value;
+ var vectorLength = parseInt(call.charAt(3));
+
+ //>>includeStart('debug', pragmas.debug);
+ if (componentsLength === 0) {
+ throw new DeveloperError('Error: Invalid ' + call + ' constructor. No valid arguments.');
+ } else if ((componentsLength < vectorLength) && (componentsLength > 1)) {
+ throw new DeveloperError('Error: Invalid ' + call + ' constructor. Not enough arguments.');
+ } else if ((componentsLength > vectorLength) && (argsLength > 1)) {
+ throw new DeveloperError('Error: Invalid ' + call + ' constructor. Too many arguments.');
+ }
+ //>>includeEnd('debug');
+
+ if (componentsLength === 1) {
+ // Add the same component 3 more times
+ var component = components[0];
+ components.push(component, component, component);
+ }
+
+ if (call === 'vec2') {
+ return Cartesian2.fromArray(components, 0, ScratchStorage.getCartesian2());
+ } else if (call === 'vec3') {
+ return Cartesian3.fromArray(components, 0, ScratchStorage.getCartesian3());
+ } else if (call === 'vec4') {
+ return Cartesian4.fromArray(components, 0, ScratchStorage.getCartesian4());
+ }
+ };
+
Node.prototype._evaluateLiteralString = function(frameState, feature) {
return this._value;
};
@@ -793,25 +908,66 @@ define([
// PERFORMANCE_IDEA: Determine if parent property needs to be computed before runtime
Node.prototype._evaluateMemberDot = function(frameState, feature) {
- if(checkFeature(this._left)) {
- return feature.getProperty(this._right);
+ if (checkFeature(this._left)) {
+ return feature.getProperty(this._right.evaluate(frameState, feature));
}
var property = this._left.evaluate(frameState, feature);
if (!defined(property)) {
return undefined;
}
- return property[this._right];
+
+ var member = this._right.evaluate(frameState, feature);
+ if (property instanceof Color) {
+ // Color components may be accessed with .x, .y, .z, .w and implicitly with .red, .green, .blue, .alpha
+ if (member === 'x') {
+ return property.red;
+ } else if (member === 'y') {
+ return property.green;
+ } else if (member === 'z') {
+ return property.blue;
+ } else if (member === 'w') {
+ return property.alpha;
+ }
+ }
+
+ return property[member];
};
Node.prototype._evaluateMemberBrackets = function(frameState, feature) {
- if(checkFeature(this._left)) {
+ if (checkFeature(this._left)) {
return feature.getProperty(this._right.evaluate(frameState, feature));
}
var property = this._left.evaluate(frameState, feature);
if (!defined(property)) {
return undefined;
}
- return property[this._right.evaluate(frameState, feature)];
+
+ var member = this._right.evaluate(frameState, feature);
+ if (property instanceof Color) {
+ // Color components may be accessed with [0][1][2][3], ['x']['y']['z']['w'], and implicitly with ['red']['green']['blue']['alpha']
+ if (member === 0 || member === 'x') {
+ return property.red;
+ } else if (member === 1 || member === 'y') {
+ return property.green;
+ } else if (member === 2 || member === 'z') {
+ return property.blue;
+ } else if (member === 3 || member === 'w') {
+ return property.alpha;
+ }
+ } else if ((property instanceof Cartesian2) || (property instanceof Cartesian3) || (property instanceof Cartesian4)) {
+ // Vector components may be accessed with [0][1][2][3] and implicitly with ['x']['y']['z']['w']
+ // For Cartesian2 and Cartesian3 out-of-range components will just return undefined
+ if (member === 0) {
+ return property.x;
+ } else if (member === 1) {
+ return property.y;
+ } else if (member === 2) {
+ return property.z;
+ } else if (member === 3) {
+ return property.w;
+ }
+ }
+ return property[member];
};
Node.prototype._evaluateArray = function(frameState, feature) {
@@ -830,11 +986,23 @@ define([
};
Node.prototype._evaluateNegative = function(frameState, feature) {
- return -(this._left.evaluate(frameState, feature));
+ var left = this._left.evaluate(frameState, feature);
+ if (left instanceof Cartesian2) {
+ return Cartesian2.negate(left, ScratchStorage.getCartesian2());
+ } else if (left instanceof Cartesian3) {
+ return Cartesian3.negate(left, ScratchStorage.getCartesian3());
+ } else if (left instanceof Cartesian4) {
+ return Cartesian4.negate(left, ScratchStorage.getCartesian4());
+ }
+ return -left;
};
Node.prototype._evaluatePositive = function(frameState, feature) {
- return +(this._left.evaluate(frameState, feature));
+ var left = this._left.evaluate(frameState, feature);
+ if ((left instanceof Color) || (left instanceof Cartesian2) || (left instanceof Cartesian3) || (left instanceof Cartesian4)) {
+ return left;
+ }
+ return +left;
};
Node.prototype._evaluateLessThan = function(frameState, feature) {
@@ -910,6 +1078,12 @@ define([
var right = this._right.evaluate(frameState, feature);
if ((right instanceof Color) && (left instanceof Color)) {
return Color.add(left, right, ScratchStorage.getColor());
+ } else if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) {
+ return Cartesian2.add(left, right, ScratchStorage.getCartesian2());
+ } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) {
+ return Cartesian3.add(left, right, ScratchStorage.getCartesian3());
+ } else if ((right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return Cartesian4.add(left, right, ScratchStorage.getCartesian4());
}
return left + right;
};
@@ -919,6 +1093,12 @@ define([
var right = this._right.evaluate(frameState, feature);
if ((right instanceof Color) && (left instanceof Color)) {
return Color.subtract(left, right, ScratchStorage.getColor());
+ } else if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) {
+ return Cartesian2.subtract(left, right, ScratchStorage.getCartesian2());
+ } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) {
+ return Cartesian3.subtract(left, right, ScratchStorage.getCartesian3());
+ } else if ((right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return Cartesian4.subtract(left, right, ScratchStorage.getCartesian4());
}
return left - right;
};
@@ -932,6 +1112,24 @@ define([
return Color.multiplyByScalar(right, left, ScratchStorage.getColor());
} else if ((left instanceof Color) && (typeof(right) === 'number')) {
return Color.multiplyByScalar(left, right, ScratchStorage.getColor());
+ } else if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) {
+ return Cartesian2.multiplyComponents(left, right, ScratchStorage.getCartesian2());
+ } else if ((right instanceof Cartesian2) && (typeof(left) === 'number')) {
+ return Cartesian2.multiplyByScalar(right, left, ScratchStorage.getCartesian2());
+ } else if ((left instanceof Cartesian2) && (typeof(right) === 'number')) {
+ return Cartesian2.multiplyByScalar(left, right, ScratchStorage.getCartesian2());
+ } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) {
+ return Cartesian3.multiplyComponents(left, right, ScratchStorage.getCartesian3());
+ } else if ((right instanceof Cartesian3) && (typeof(left) === 'number')) {
+ return Cartesian3.multiplyByScalar(right, left, ScratchStorage.getCartesian3());
+ } else if ((left instanceof Cartesian3) && (typeof(right) === 'number')) {
+ return Cartesian3.multiplyByScalar(left, right, ScratchStorage.getCartesian3());
+ } else if ((right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return Cartesian4.multiplyComponents(left, right, ScratchStorage.getCartesian4());
+ } else if ((right instanceof Cartesian4) && (typeof(left) === 'number')) {
+ return Cartesian4.multiplyByScalar(right, left, ScratchStorage.getCartesian4());
+ } else if ((left instanceof Cartesian4) && (typeof(right) === 'number')) {
+ return Cartesian4.multiplyByScalar(left, right, ScratchStorage.getCartesian4());
}
return left * right;
};
@@ -943,6 +1141,18 @@ define([
return Color.divide(left, right, ScratchStorage.getColor());
} else if ((left instanceof Color) && (typeof(right) === 'number')) {
return Color.divideByScalar(left, right, ScratchStorage.getColor());
+ } else if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) {
+ return Cartesian2.divideComponents(left, right, ScratchStorage.getCartesian2());
+ } else if ((left instanceof Cartesian2) && (typeof(right) === 'number')) {
+ return Cartesian2.divideByScalar(left, right, ScratchStorage.getCartesian2());
+ } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) {
+ return Cartesian3.divideComponents(left, right, ScratchStorage.getCartesian3());
+ } else if ((left instanceof Cartesian3) && (typeof(right) === 'number')) {
+ return Cartesian3.divideByScalar(left, right, ScratchStorage.getCartesian3());
+ } else if ((right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return Cartesian4.divideComponents(left, right, ScratchStorage.getCartesian4());
+ } else if ((left instanceof Cartesian4) && (typeof(right) === 'number')) {
+ return Cartesian4.divideByScalar(left, right, ScratchStorage.getCartesian4());
}
return left / right;
};
@@ -952,6 +1162,12 @@ define([
var right = this._right.evaluate(frameState, feature);
if ((right instanceof Color) && (left instanceof Color)) {
return Color.mod(left, right, ScratchStorage.getColor());
+ } else if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) {
+ return Cartesian2.fromElements(left.x % right.x, left.y % right.y, ScratchStorage.getCartesian2());
+ } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) {
+ return Cartesian3.fromElements(left.x % right.x, left.y % right.y, left.z % right.z, ScratchStorage.getCartesian3());
+ } else if ((right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return Cartesian4.fromElements(left.x % right.x, left.y % right.y, left.z % right.z, left.w % right.w, ScratchStorage.getCartesian4());
}
return left % right;
};
@@ -959,8 +1175,11 @@ define([
Node.prototype._evaluateEqualsStrict = function(frameState, feature) {
var left = this._left.evaluate(frameState, feature);
var right = this._right.evaluate(frameState, feature);
- if ((right instanceof Color) && (left instanceof Color)) {
- return Color.equals(left, right);
+ if ((right instanceof Color) && (left instanceof Color) ||
+ (right instanceof Cartesian2) && (left instanceof Cartesian2) ||
+ (right instanceof Cartesian3) && (left instanceof Cartesian3) ||
+ (right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return left.equals(right);
}
return left === right;
};
@@ -968,8 +1187,11 @@ define([
Node.prototype._evaluateEquals = function(frameState, feature) {
var left = this._left.evaluate(frameState, feature);
var right = this._right.evaluate(frameState, feature);
- if ((right instanceof Color) && (left instanceof Color)) {
- return Color.equals(left, right);
+ if ((right instanceof Color) && (left instanceof Color) ||
+ (right instanceof Cartesian2) && (left instanceof Cartesian2) ||
+ (right instanceof Cartesian3) && (left instanceof Cartesian3) ||
+ (right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return left.equals(right);
}
// Specifically want to do an abstract equality comparison (==) instead of a strict equality comparison (===)
@@ -980,8 +1202,11 @@ define([
Node.prototype._evaluateNotEqualsStrict = function(frameState, feature) {
var left = this._left.evaluate(frameState, feature);
var right = this._right.evaluate(frameState, feature);
- if ((right instanceof Color) && (left instanceof Color)) {
- return !Color.equals(left, right);
+ if ((right instanceof Color) && (left instanceof Color) ||
+ (right instanceof Cartesian2) && (left instanceof Cartesian2) ||
+ (right instanceof Cartesian3) && (left instanceof Cartesian3) ||
+ (right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return !left.equals(right);
}
return left !== right;
};
@@ -989,8 +1214,11 @@ define([
Node.prototype._evaluateNotEquals = function(frameState, feature) {
var left = this._left.evaluate(frameState, feature);
var right = this._right.evaluate(frameState, feature);
- if ((right instanceof Color) && (left instanceof Color)) {
- return !Color.equals(left, right);
+ if ((right instanceof Color) && (left instanceof Color) ||
+ (right instanceof Cartesian2) && (left instanceof Cartesian2) ||
+ (right instanceof Cartesian3) && (left instanceof Cartesian3) ||
+ (right instanceof Cartesian4) && (left instanceof Cartesian4)) {
+ return !left.equals(right);
}
// Specifically want to do an abstract inequality comparison (!=) instead of a strict inequality comparison (!==)
// so that cases like "5 != '5'" return false. Tell jsHint to ignore this line.
@@ -1093,7 +1321,7 @@ define([
Node.prototype._evaluateToString = function(frameState, feature) {
var left = this._left.evaluate(frameState, feature);
- if ((left instanceof RegExp) || (left instanceof Color)) {
+ if ((left instanceof RegExp) || (left instanceof Color) || (left instanceof Cartesian2) || (left instanceof Cartesian3) || (left instanceof Cartesian4)) {
return String(left);
}
//>>includeStart('debug', pragmas.debug);
@@ -1162,11 +1390,11 @@ define([
return 'vec4(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
}
- function getExpressionArray(array, attributePrefix, shaderState) {
+ function getExpressionArray(array, attributePrefix, shaderState, parent) {
var length = array.length;
var expressions = new Array(length);
for (var i = 0; i < length; ++i) {
- var shader = array[i].getShaderExpression(attributePrefix, shaderState);
+ var shader = array[i].getShaderExpression(attributePrefix, shaderState, parent);
if (!defined(shader)) {
// If any of the expressions are not valid, the array is not valid
return undefined;
@@ -1176,7 +1404,7 @@ define([
return expressions;
}
- Node.prototype.getShaderExpression = function(attributePrefix, shaderState) {
+ Node.prototype.getShaderExpression = function(attributePrefix, shaderState, parent) {
var color;
var left;
var right;
@@ -1185,21 +1413,12 @@ define([
var type = this._type;
var value = this._value;
- // Right may be a string if it's a member variable: e.g. "${property.name}"
- if (typeof(this._right) === 'string') {
- //>>includeStart('debug', pragmas.debug);
- throw new DeveloperError('Error generating style shader: string members are not supported.');
- //>>includeEnd('debug');
- // Return undefined when not in debug. Tell jsHint to ignore this line.
- return; // jshint ignore:line
- }
-
if (defined(this._left)) {
if (isArray(this._left)) {
- // Left can be an array if the type is LITERAL_COLOR
- left = getExpressionArray(this._left, attributePrefix, shaderState);
+ // Left can be an array if the type is LITERAL_COLOR or LITERAL_VECTOR
+ left = getExpressionArray(this._left, attributePrefix, shaderState, this);
} else {
- left = this._left.getShaderExpression(attributePrefix, shaderState);
+ left = this._left.getShaderExpression(attributePrefix, shaderState, this);
}
if (!defined(left)) {
// If the left side is not valid shader code, then the expression is not valid
@@ -1208,7 +1427,7 @@ define([
}
if (defined(this._right)) {
- right = this._right.getShaderExpression(attributePrefix, shaderState);
+ right = this._right.getShaderExpression(attributePrefix, shaderState, this);
if (!defined(right)) {
// If the right side is not valid shader code, then the expression is not valid
return undefined;
@@ -1216,7 +1435,7 @@ define([
}
if (defined(this._test)) {
- test = this._test.getShaderExpression(attributePrefix, shaderState);
+ test = this._test.getShaderExpression(attributePrefix, shaderState, this);
if (!defined(test)) {
// If the test is not valid shader code, then the expression is not valid
return undefined;
@@ -1225,7 +1444,7 @@ define([
if (isArray(this._value)) {
// For ARRAY type
- value = getExpressionArray(this._value, attributePrefix, shaderState);
+ value = getExpressionArray(this._value, attributePrefix, shaderState, this);
if (!defined(value)) {
// If the values are not valid shader code, then the expression is not valid
return undefined;
@@ -1247,14 +1466,15 @@ define([
return 'cos(' + left + ')';
} else if (value === 'sqrt') {
return 'sqrt(' + left + ')';
+ } else if ((value === 'isNaN') || (value === 'isFinite') || (value === 'String') || (value === 'isExactClass') || (value === 'isClass') || (value === 'getExactClassName')) {
+ //>>includeStart('debug', pragmas.debug);
+ throw new DeveloperError('Error generating style shader: "' + value + '" is not supported.');
+ //>>includeEnd('debug');
+ // Return undefined when not in debug. Tell jsHint to ignore this line.
+ return undefined; // jshint ignore:line
} else if (defined(unaryFunctions[value])) {
return value + '(' + left + ')';
}
- //>>includeStart('debug', pragmas.debug);
- else if ((value === 'isNaN') || (value === 'isFinite') || (value === 'String') || (value === 'isExactClass') || (value === 'isClass') || (value === 'getExactClassName')) {
- throw new DeveloperError('Error generating style shader: "' + value + '" is not supported.');
- }
- //>>includeEnd('debug');
return value + left;
case ExpressionNodeType.BINARY:
// Supported types: ||, &&, ===, ==, !==, !=, <, >, <=, >=, +, -, *, /, %
@@ -1278,7 +1498,18 @@ define([
case ExpressionNodeType.CONDITIONAL:
return '(' + test + ' ? ' + left + ' : ' + right + ')';
case ExpressionNodeType.MEMBER:
- // This is intended for accessing the components of vec2, vec3, and vec4 properties. String members aren't supported.
+ // This is intended for accessing the components of vector properties. String members aren't supported.
+ // Check for 0.0 rather than 0 because all numbers are previously converted to decimals.
+ // In this shader there is not much distinction between colors and vectors so allow .red to access the 0th component for both.
+ if (right === 'red' || right === 'x' || right === '0.0') {
+ return left + '[0]';
+ } else if (right === 'green' || right === 'y' || right === '1.0') {
+ return left + '[1]';
+ } else if (right === 'blue' || right === 'z' || right === '2.0') {
+ return left + '[2]';
+ } else if (right === 'alpha' || right === 'w' || right === '3.0') {
+ return left + '[3]';
+ }
return left + '[int(' + right + ')]';
case ExpressionNodeType.FUNCTION_CALL:
//>>includeStart('debug', pragmas.debug);
@@ -1315,7 +1546,15 @@ define([
case ExpressionNodeType.LITERAL_NUMBER:
return numberToString(value);
case ExpressionNodeType.LITERAL_STRING:
- // The only supported strings are css color strings
+ // Check if parent is of type MEMBER. Otherwise it is not possible to know whether 'red', 'green', and 'blue'
+ // refer to CSS strings or component accessors.
+ if (defined(parent) && (parent._type === ExpressionNodeType.MEMBER)) {
+ if (value === 'red' || value === 'green' || value === 'blue' || value === 'alpha' ||
+ value === 'x' || value === 'y' || value === 'z' || value === 'w') {
+ return value;
+ }
+ }
+ // Check for css color strings
color = Color.fromCssColorString(value, scratchColor);
if (defined(color)) {
return colorToVec3(color);
@@ -1377,6 +1616,17 @@ define([
}
}
break;
+ case ExpressionNodeType.LITERAL_VECTOR:
+ var length = left.length;
+ var vectorExpression = value + '(';
+ for (var i = 0; i < length; ++i) {
+ vectorExpression += left[i];
+ if (i < (length - 1)) {
+ vectorExpression += ', ';
+ }
+ }
+ vectorExpression += ')';
+ return vectorExpression;
case ExpressionNodeType.LITERAL_REGEX:
//>>includeStart('debug', pragmas.debug);
throw new DeveloperError('Error generating style shader: Regular expressions are not supported.');
diff --git a/Source/Scene/ExpressionNodeType.js b/Source/Scene/ExpressionNodeType.js
index bf8ccd9e9094..f7d9a85fa1ca 100644
--- a/Source/Scene/ExpressionNodeType.js
+++ b/Source/Scene/ExpressionNodeType.js
@@ -24,9 +24,10 @@ define([
LITERAL_NUMBER : 12,
LITERAL_STRING : 13,
LITERAL_COLOR : 14,
- LITERAL_REGEX : 15,
- LITERAL_UNDEFINED : 16,
- LITERAL_GLOBAL : 17
+ LITERAL_VECTOR : 15,
+ LITERAL_REGEX : 16,
+ LITERAL_UNDEFINED : 17,
+ LITERAL_GLOBAL : 18
};
return freezeObject(ExpressionNodeType);
diff --git a/Source/Scene/FrustumCommands.js b/Source/Scene/FrustumCommands.js
index 2d33d09d338a..fe5828910791 100644
--- a/Source/Scene/FrustumCommands.js
+++ b/Source/Scene/FrustumCommands.js
@@ -1,7 +1,7 @@
/*global define*/
define([
'../Core/defaultValue',
- './Pass'
+ '../Renderer/Pass'
], function(
defaultValue,
Pass) {
diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js
index ee15de74b801..bb92954ec673 100644
--- a/Source/Scene/Globe.js
+++ b/Source/Scene/Globe.js
@@ -14,6 +14,7 @@ define([
'../Core/Event',
'../Core/IntersectionTests',
'../Core/loadImage',
+ '../Core/Math',
'../Core/Ray',
'../Core/Rectangle',
'../Renderer/ShaderSource',
@@ -43,6 +44,7 @@ define([
Event,
IntersectionTests,
loadImage,
+ CesiumMath,
Ray,
Rectangle,
ShaderSource,
@@ -424,10 +426,27 @@ define([
}
var ellipsoid = this._surface._tileProvider.tilingScheme.ellipsoid;
- var cartesian = ellipsoid.cartographicToCartesian(cartographic, scratchGetHeightCartesian);
+
+ //cartesian has to be on the ellipsoid surface for `ellipsoid.geodeticSurfaceNormal`
+ var cartesian = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0, ellipsoid, scratchGetHeightCartesian);
var ray = scratchGetHeightRay;
- Cartesian3.normalize(cartesian, ray.direction);
+ var surfaceNormal = ellipsoid.geodeticSurfaceNormal(cartesian, ray.direction);
+
+ // Try to find the intersection point between the surface normal and z-axis.
+ // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
+ var rayOrigin = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesian, 11500.0, ray.origin);
+
+ // Theoretically, not with Earth datums, the intersection point can be outside the ellipsoid
+ if (!defined(rayOrigin)) {
+ // intersection point is outside the ellipsoid, try other value
+ // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
+ var magnitude = Math.min(defaultValue(tile.data.minimumHeight, 0.0),-11500.0);
+
+ // multiply by the *positive* value of the magnitude
+ var vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, Math.abs(magnitude) + 1, scratchGetHeightIntersection);
+ Cartesian3.subtract(cartesian, vectorToMinimumPoint, ray.origin);
+ }
var intersection = tile.data.pick(ray, undefined, undefined, false, scratchGetHeightIntersection);
if (!defined(intersection)) {
diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js
index eea28a81bcdb..7383e795dd83 100644
--- a/Source/Scene/GlobeSurfaceTileProvider.js
+++ b/Source/Scene/GlobeSurfaceTileProvider.js
@@ -30,11 +30,11 @@ define([
'../Renderer/BufferUsage',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/VertexArray',
'../Scene/BlendingState',
'../Scene/DepthFunction',
- '../Scene/Pass',
'../Scene/PerInstanceColorAppearance',
'../Scene/Primitive',
'./GlobeSurfaceTile',
@@ -73,11 +73,11 @@ define([
BufferUsage,
ContextLimits,
DrawCommand,
+ Pass,
RenderState,
VertexArray,
BlendingState,
DepthFunction,
- Pass,
PerInstanceColorAppearance,
Primitive,
GlobeSurfaceTile,
diff --git a/Source/Scene/GroundPrimitive.js b/Source/Scene/GroundPrimitive.js
index cfcea5ec94e3..9939662eea12 100644
--- a/Source/Scene/GroundPrimitive.js
+++ b/Source/Scene/GroundPrimitive.js
@@ -20,6 +20,7 @@ define([
'../Core/OrientedBoundingBox',
'../Core/Rectangle',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
@@ -28,7 +29,6 @@ define([
'../ThirdParty/when',
'./BlendingState',
'./DepthFunction',
- './Pass',
'./PerInstanceColorAppearance',
'./Primitive',
'./SceneMode',
@@ -55,6 +55,7 @@ define([
OrientedBoundingBox,
Rectangle,
DrawCommand,
+ Pass,
RenderState,
ShaderProgram,
ShaderSource,
@@ -63,7 +64,6 @@ define([
when,
BlendingState,
DepthFunction,
- Pass,
PerInstanceColorAppearance,
Primitive,
SceneMode,
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index cd329db67f94..8c10bdded593 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -42,6 +42,7 @@ define([
'../Renderer/Buffer',
'../Renderer/BufferUsage',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/Sampler',
'../Renderer/ShaderProgram',
@@ -65,7 +66,6 @@ define([
'./modelMaterialsCommon',
'./ModelMesh',
'./ModelNode',
- './Pass',
'./SceneMode',
'./ShadowMode'
], function(
@@ -111,6 +111,7 @@ define([
Buffer,
BufferUsage,
DrawCommand,
+ Pass,
RenderState,
Sampler,
ShaderProgram,
@@ -134,7 +135,6 @@ define([
modelMaterialsCommon,
ModelMesh,
ModelNode,
- Pass,
SceneMode,
ShadowMode) {
'use strict';
diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js
index 6b4e3f954d7c..e00cea225aec 100644
--- a/Source/Scene/PointCloud3DTileContent.js
+++ b/Source/Scene/PointCloud3DTileContent.js
@@ -23,6 +23,7 @@ define([
'../Renderer/Buffer',
'../Renderer/BufferUsage',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
@@ -33,8 +34,7 @@ define([
'./Cesium3DTileColorBlendMode',
'./Cesium3DTileContentState',
'./Cesium3DTileFeature',
- './Cesium3DTileFeatureTable',
- './Pass'
+ './Cesium3DTileFeatureTable'
], function(
Cartesian3,
Color,
@@ -59,6 +59,7 @@ define([
Buffer,
BufferUsage,
DrawCommand,
+ Pass,
RenderState,
ShaderProgram,
ShaderSource,
@@ -69,8 +70,7 @@ define([
Cesium3DTileColorBlendMode,
Cesium3DTileContentState,
Cesium3DTileFeature,
- Cesium3DTileFeatureTable,
- Pass) {
+ Cesium3DTileFeatureTable) {
'use strict';
/**
@@ -908,12 +908,7 @@ define([
attributeLocations.a_batchId = batchIdLocation;
}
- var vs = 'attribute vec3 a_position; \n' +
- 'varying vec4 v_color; \n' +
- 'uniform float u_pointSize; \n' +
- 'uniform vec4 u_constantColor; \n' +
- 'uniform vec4 u_highlightColor; \n' +
- 'uniform float u_tilesetTime; \n';
+ var attributeDeclarations = '';
var length = styleableProperties.length;
for (i = 0; i < length; ++i) {
@@ -934,10 +929,19 @@ define([
attributeType = 'vec' + componentCount;
}
- vs += 'attribute ' + attributeType + ' ' + attributeName + '; \n';
+ attributeDeclarations += 'attribute ' + attributeType + ' ' + attributeName + '; \n';
attributeLocations[attributeName] = attribute.location;
}
+ var vs = 'attribute vec3 a_position; \n' +
+ 'varying vec4 v_color; \n' +
+ 'uniform float u_pointSize; \n' +
+ 'uniform vec4 u_constantColor; \n' +
+ 'uniform vec4 u_highlightColor; \n' +
+ 'uniform float u_tilesetTime; \n';
+
+ vs += attributeDeclarations;
+
if (usesColors) {
if (isTranslucent) {
vs += 'attribute vec4 a_color; \n';
diff --git a/Source/Scene/PointPrimitiveCollection.js b/Source/Scene/PointPrimitiveCollection.js
index 78820c715716..52f0b5f42a80 100644
--- a/Source/Scene/PointPrimitiveCollection.js
+++ b/Source/Scene/PointPrimitiveCollection.js
@@ -16,6 +16,7 @@ define([
'../Renderer/BufferUsage',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
@@ -23,7 +24,6 @@ define([
'../Shaders/PointPrimitiveCollectionFS',
'../Shaders/PointPrimitiveCollectionVS',
'./BlendingState',
- './Pass',
'./PointPrimitive',
'./SceneMode'
], function(
@@ -43,6 +43,7 @@ define([
BufferUsage,
ContextLimits,
DrawCommand,
+ Pass,
RenderState,
ShaderProgram,
ShaderSource,
@@ -50,7 +51,6 @@ define([
PointPrimitiveCollectionFS,
PointPrimitiveCollectionVS,
BlendingState,
- Pass,
PointPrimitive,
SceneMode) {
'use strict';
diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js
index 3e24d43528c3..4d491863be01 100644
--- a/Source/Scene/PolylineCollection.js
+++ b/Source/Scene/PolylineCollection.js
@@ -23,6 +23,7 @@ define([
'../Renderer/BufferUsage',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
@@ -33,7 +34,6 @@ define([
'./BatchTable',
'./BlendingState',
'./Material',
- './Pass',
'./Polyline',
'./SceneMode'
], function(
@@ -60,6 +60,7 @@ define([
BufferUsage,
ContextLimits,
DrawCommand,
+ Pass,
RenderState,
ShaderProgram,
ShaderSource,
@@ -70,7 +71,6 @@ define([
BatchTable,
BlendingState,
Material,
- Pass,
Polyline,
SceneMode) {
'use strict';
diff --git a/Source/Scene/Primitive.js b/Source/Scene/Primitive.js
index dd05d4749feb..23b812e41b38 100644
--- a/Source/Scene/Primitive.js
+++ b/Source/Scene/Primitive.js
@@ -27,6 +27,7 @@ define([
'../Renderer/BufferUsage',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
@@ -34,7 +35,6 @@ define([
'../ThirdParty/when',
'./BatchTable',
'./CullFace',
- './Pass',
'./PrimitivePipeline',
'./PrimitiveState',
'./SceneMode',
@@ -67,6 +67,7 @@ define([
BufferUsage,
ContextLimits,
DrawCommand,
+ Pass,
RenderState,
ShaderProgram,
ShaderSource,
@@ -74,7 +75,6 @@ define([
when,
BatchTable,
CullFace,
- Pass,
PrimitivePipeline,
PrimitiveState,
SceneMode,
diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js
index 782230e37ea2..9149b60359e4 100644
--- a/Source/Scene/QuadtreePrimitive.js
+++ b/Source/Scene/QuadtreePrimitive.js
@@ -240,7 +240,7 @@ define([
QuadtreePrimitive.prototype.updateHeight = function(cartographic, callback) {
var primitive = this;
var object = {
- position : undefined,
+ positionOnEllipsoidSurface : undefined,
positionCartographic : cartographic,
level : -1,
callback : callback
@@ -455,7 +455,7 @@ define([
customDataRemoved.length = 0;
}
- // Our goal with load ordering is to first load all of the tiles we need to
+ // Our goal with load ordering is to first load all of the tiles we need to
// render the current scene at full detail. Loading any other tiles is just
// a form of prefetching, and we need not do it at all (other concerns aside). This
// simple and obvious statement gets more complicated when we realize that, because
@@ -761,13 +761,30 @@ define([
var data = customData[i];
if (tile.level > data.level) {
- if (!defined(data.position)) {
- data.position = ellipsoid.cartographicToCartesian(data.positionCartographic);
+ if (!defined(data.positionOnEllipsoidSurface)) {
+ // cartesian has to be on the ellipsoid surface for `ellipsoid.geodeticSurfaceNormal`
+ data.positionOnEllipsoidSurface = Cartesian3.fromRadians(data.positionCartographic.longitude, data.positionCartographic.latitude, 0.0, ellipsoid);
}
if (mode === SceneMode.SCENE3D) {
- Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin);
- Cartesian3.normalize(data.position, scratchRay.direction);
+ var surfaceNormal = ellipsoid.geodeticSurfaceNormal(data.positionOnEllipsoidSurface, scratchRay.direction);
+
+ // compute origin point
+
+ // Try to find the intersection point between the surface normal and z-axis.
+ // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
+ var rayOrigin = ellipsoid.getSurfaceNormalIntersectionWithZAxis(data.positionOnEllipsoidSurface, 11500.0, scratchRay.origin);
+
+ // Theoretically, not with Earth datums, the intersection point can be outside the ellipsoid
+ if (!defined(rayOrigin)) {
+ // intersection point is outside the ellipsoid, try other value
+ // minimum height (-11500.0) for the terrain set, need to get this information from the terrain provider
+ var magnitude = Math.min(defaultValue(tile.data.minimumHeight, 0.0),-11500.0);
+
+ // multiply by the *positive* value of the magnitude
+ var vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, Math.abs(magnitude) + 1, scratchPosition);
+ Cartesian3.subtract(data.positionOnEllipsoidSurface, vectorToMinimumPoint, scratchRay.origin);
+ }
} else {
Cartographic.clone(data.positionCartographic, scratchCartographic);
diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index cb4baa2efd11..88f9d7a77612 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -36,6 +36,7 @@ define([
'../Renderer/Context',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Pass',
'../Renderer/PassState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
@@ -53,7 +54,6 @@ define([
'./MapMode2D',
'./OIT',
'./OrthographicFrustum',
- './Pass',
'./PerformanceDisplay',
'./PerInstanceColorAppearance',
'./PerspectiveFrustum',
@@ -105,6 +105,7 @@ define([
Context,
ContextLimits,
DrawCommand,
+ Pass,
PassState,
ShaderProgram,
ShaderSource,
@@ -122,7 +123,6 @@ define([
MapMode2D,
OIT,
OrthographicFrustum,
- Pass,
PerformanceDisplay,
PerInstanceColorAppearance,
PerspectiveFrustum,
@@ -1628,7 +1628,7 @@ define([
var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
var scratchOrthographicFrustum = new OrthographicFrustum();
- function executeCommands(scene, passState) {
+ function executeCommands(scene, passState, picking) {
var camera = scene._camera;
var context = scene.context;
var us = context.uniformState;
@@ -1652,37 +1652,40 @@ define([
us.updateFrustum(frustum);
us.updatePass(Pass.ENVIRONMENT);
+ var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D;
var environmentState = scene._environmentState;
- var skyBoxCommand = environmentState.skyBoxCommand;
- if (defined(skyBoxCommand)) {
- executeCommand(skyBoxCommand, scene, context, passState);
- }
- if (environmentState.isSkyAtmosphereVisible) {
- executeCommand(environmentState.skyAtmosphereCommand, scene, context, passState);
- }
+ // Do not render environment primitives during a pick pass since they do not generate picking commands.
+ if (!picking) {
+ var skyBoxCommand = environmentState.skyBoxCommand;
+ if (defined(skyBoxCommand)) {
+ executeCommand(skyBoxCommand, scene, context, passState);
+ }
- var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D;
+ if (environmentState.isSkyAtmosphereVisible) {
+ executeCommand(environmentState.skyAtmosphereCommand, scene, context, passState);
+ }
- if (environmentState.isSunVisible) {
- environmentState.sunDrawCommand.execute(context, passState);
- if (scene.sunBloom && !useWebVR) {
- var framebuffer;
- if (environmentState.useGlobeDepthFramebuffer) {
- framebuffer = scene._globeDepth.framebuffer;
- } else if (environmentState.useFXAA) {
- framebuffer = scene._fxaa.getColorFramebuffer();
- } else {
- framebuffer = environmentState.originalFramebuffer;
+ if (environmentState.isSunVisible) {
+ environmentState.sunDrawCommand.execute(context, passState);
+ if (scene.sunBloom && !useWebVR) {
+ var framebuffer;
+ if (environmentState.useGlobeDepthFramebuffer) {
+ framebuffer = scene._globeDepth.framebuffer;
+ } else if (environmentState.useFXAA) {
+ framebuffer = scene._fxaa.getColorFramebuffer();
+ } else {
+ framebuffer = environmentState.originalFramebuffer;
+ }
+ scene._sunPostProcess.execute(context, framebuffer);
+ passState.framebuffer = framebuffer;
}
- scene._sunPostProcess.execute(context, framebuffer);
- passState.framebuffer = framebuffer;
}
- }
- // Moon can be seen through the atmosphere, since the sun is rendered after the atmosphere.
- if (environmentState.isMoonVisible) {
- environmentState.moonCommand.execute(context, passState);
+ // Moon can be seen through the atmosphere, since the sun is rendered after the atmosphere.
+ if (environmentState.isMoonVisible) {
+ environmentState.moonCommand.execute(context, passState);
+ }
}
// Determine how translucent surfaces will be handled.
@@ -1958,14 +1961,14 @@ define([
Cartesian3.add(savedCamera.position, eyeTranslation, camera.position);
camera.frustum.xOffset = offset;
- executeCommands(scene, passState);
+ executeCommands(scene, passState, picking);
viewport.x = passState.viewport.width;
Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position);
camera.frustum.xOffset = -offset;
- executeCommands(scene, passState);
+ executeCommands(scene, passState, picking);
Camera.clone(savedCamera, camera);
} else {
@@ -2116,7 +2119,7 @@ define([
executeShadowMapCastCommands(scene);
}
- executeCommands(scene, passState);
+ executeCommands(scene, passState, picking);
}
function updateEnvironment(scene) {
@@ -2345,7 +2348,7 @@ define([
if (defined(this._deviceOrientationCameraController)) {
this._deviceOrientationCameraController.update();
}
-
+
this._camera.update(this._mode);
this._camera._updateCameraChanged();
};
diff --git a/Source/Scene/SceneTransitioner.js b/Source/Scene/SceneTransitioner.js
index 59ccefbd81bb..76c0989a6786 100644
--- a/Source/Scene/SceneTransitioner.js
+++ b/Source/Scene/SceneTransitioner.js
@@ -126,11 +126,12 @@ define([
if (duration > 0.0) {
position.x = 0.0;
- position.y = 0.0;
- position.z = 5.0 * ellipsoid.maximumRadius;
+ position.y = -1.0;
+ position.z = 1.0;
+ position = Cartesian3.multiplyByScalar(Cartesian3.normalize(position, position), 5.0 * ellipsoid.maximumRadius, position);
- Cartesian3.negate(Cartesian3.UNIT_Z, direction);
- Cartesian3.clone(Cartesian3.UNIT_Y, up);
+ Cartesian3.negate(Cartesian3.normalize(position, direction), direction);
+ Cartesian3.cross(Cartesian3.UNIT_X, direction, up);
} else {
var camera = scene.camera;
if (this._previousMode === SceneMode.SCENE2D) {
@@ -694,48 +695,42 @@ define([
var scene = transitioner._scene;
var camera = scene.camera;
- var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
- var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
- var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
-
var endPos = Cartesian3.clone(cameraCV.position, scratch3DToCVEndPos);
var endDir = Cartesian3.clone(cameraCV.direction, scratch3DToCVEndDir);
var endUp = Cartesian3.clone(cameraCV.up, scratch3DToCVEndUp);
- var startRight = camera.frustum.right;
- var endRight = endPos.z * 0.5;
-
- function update(value) {
- columbusViewMorph(startPos, endPos, value.time, camera.position);
- columbusViewMorph(startDir, endDir, value.time, camera.direction);
- columbusViewMorph(startUp, endUp, value.time, camera.up);
- Cartesian3.cross(camera.direction, camera.up, camera.right);
- Cartesian3.normalize(camera.right, camera.right);
-
- var frustum = camera.frustum;
- frustum.right = CesiumMath.lerp(startRight, endRight, value.time);
- frustum.left = -frustum.right;
- frustum.top = frustum.right * (scene.drawingBufferHeight / scene.drawingBufferWidth);
- frustum.bottom = -frustum.top;
-
- camera.position.z = 2.0 * scene.mapProjection.ellipsoid.maximumRadius;
- }
- var tween = scene.tweens.add({
- duration : duration,
- easingFunction : EasingFunction.QUARTIC_OUT,
- startObject : {
- time : 0.0
- },
- stopObject : {
- time : 1.0
- },
- update : update,
- complete : function() {
- scene._mode = SceneMode.MORPHING;
- morphOrthographicToPerspective(transitioner, duration, cameraCV, complete);
+ scene._mode = SceneMode.MORPHING;
+ morphOrthographicToPerspective(transitioner, 0.0, cameraCV, function() {
+ camera.frustum = cameraCV.frustum.clone();
+
+ var startPos = Cartesian3.clone(camera.position, scratch3DToCVStartPos);
+ var startDir = Cartesian3.clone(camera.direction, scratch3DToCVStartDir);
+ var startUp = Cartesian3.clone(camera.up, scratch3DToCVStartUp);
+ startPos.z = endPos.z;
+
+ function update(value) {
+ columbusViewMorph(startPos, endPos, value.time, camera.position);
+ columbusViewMorph(startDir, endDir, value.time, camera.direction);
+ columbusViewMorph(startUp, endUp, value.time, camera.up);
+ Cartesian3.cross(camera.direction, camera.up, camera.right);
+ Cartesian3.normalize(camera.right, camera.right);
}
+ var tween = scene.tweens.add({
+ duration : duration,
+ easingFunction : EasingFunction.QUARTIC_OUT,
+ startObject : {
+ time : 0.0
+ },
+ stopObject : {
+ time : 1.0
+ },
+ update : update,
+ complete : function() {
+ complete(transitioner);
+ }
+ });
+ transitioner._currentTweens.push(tween);
});
- transitioner._currentTweens.push(tween);
}
var scratch3DToCVStartPos = new Cartesian3();
diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js
index 8a52c42dd7df..7f0652571b0a 100644
--- a/Source/Scene/ScreenSpaceCameraController.js
+++ b/Source/Scene/ScreenSpaceCameraController.js
@@ -153,9 +153,9 @@ define([
*/
this.bounceAnimationTime = 3.0;
/**
- * The minimum magnitude, in meters, of the camera position when zooming. Defaults to 20.0.
+ * The minimum magnitude, in meters, of the camera position when zooming. Defaults to 1.0.
* @type {Number}
- * @default 20.0
+ * @default 1.0
*/
this.minimumZoomDistance = 1.0;
/**
diff --git a/Source/Scene/ShadowMap.js b/Source/Scene/ShadowMap.js
index 594bc3346381..cce66085ebdb 100644
--- a/Source/Scene/ShadowMap.js
+++ b/Source/Scene/ShadowMap.js
@@ -30,6 +30,7 @@ define([
'../Renderer/CubeMap',
'../Renderer/DrawCommand',
'../Renderer/Framebuffer',
+ '../Renderer/Pass',
'../Renderer/PassState',
'../Renderer/PixelDatatype',
'../Renderer/Renderbuffer',
@@ -46,7 +47,6 @@ define([
'./CullingVolume',
'./DebugCameraPrimitive',
'./OrthographicFrustum',
- './Pass',
'./PerInstanceColorAppearance',
'./PerspectiveFrustum',
'./Primitive',
@@ -82,6 +82,7 @@ define([
CubeMap,
DrawCommand,
Framebuffer,
+ Pass,
PassState,
PixelDatatype,
Renderbuffer,
@@ -98,7 +99,6 @@ define([
CullingVolume,
DebugCameraPrimitive,
OrthographicFrustum,
- Pass,
PerInstanceColorAppearance,
PerspectiveFrustum,
Primitive,
diff --git a/Source/Scene/ViewportQuad.js b/Source/Scene/ViewportQuad.js
index 5d26694eb94b..b8dbeb2269f9 100644
--- a/Source/Scene/ViewportQuad.js
+++ b/Source/Scene/ViewportQuad.js
@@ -5,24 +5,24 @@ define([
'../Core/defined',
'../Core/destroyObject',
'../Core/DeveloperError',
+ '../Renderer/Pass',
'../Renderer/RenderState',
'../Renderer/ShaderSource',
'../Shaders/ViewportQuadFS',
'./BlendingState',
- './Material',
- './Pass'
+ './Material'
], function(
BoundingRectangle,
Color,
defined,
destroyObject,
DeveloperError,
+ Pass,
RenderState,
ShaderSource,
ViewportQuadFS,
BlendingState,
- Material,
- Pass) {
+ Material) {
'use strict';
/**
diff --git a/Source/Scene/modelMaterialsCommon.js b/Source/Scene/modelMaterialsCommon.js
index 9d1ca8abe7d6..69f3a6182337 100644
--- a/Source/Scene/modelMaterialsCommon.js
+++ b/Source/Scene/modelMaterialsCommon.js
@@ -353,7 +353,7 @@ define([
if (options.addBatchIdToGeneratedShaders) {
techniqueAttributes.a_batchId = 'batchId';
techniqueParameters.batchId = {
- semantic: 'BATCHID',
+ semantic: '_BATCHID',
type: WebGLConstants.FLOAT
};
vertexShader += 'attribute float a_batchId;\n';
diff --git a/Source/ThirdParty/gltfDefaults.js b/Source/ThirdParty/gltfDefaults.js
index 14cb12615d82..d9174d665b2f 100644
--- a/Source/ThirdParty/gltfDefaults.js
+++ b/Source/ThirdParty/gltfDefaults.js
@@ -401,7 +401,7 @@ define([
for (var name in skins) {
if (skins.hasOwnProperty(name)) {
var skin = skins[name];
- if (defined(skin.bindShapeMatrix)) {
+ if (!defined(skin.bindShapeMatrix)) {
skin.bindShapeMatrix = [
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
diff --git a/Source/Widgets/Geocoder/Geocoder.css b/Source/Widgets/Geocoder/Geocoder.css
index b8da4c244277..244e41de2c8d 100644
--- a/Source/Widgets/Geocoder/Geocoder.css
+++ b/Source/Widgets/Geocoder/Geocoder.css
@@ -37,6 +37,33 @@
width: 250px;
}
+.cesium-viewer-geocoderContainer .search-results {
+ position: absolute;
+ background-color: #000;
+ color: #eee;
+ overflow-y: auto;
+ opacity: 0.8;
+ width: 100%;
+}
+
+.cesium-viewer-geocoderContainer .search-results ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+.cesium-viewer-geocoderContainer .search-results ul li {
+ font-size: 14px;
+ padding: 3px 10px;
+}
+.cesium-viewer-geocoderContainer .search-results ul li:hover {
+ cursor: pointer;
+}
+
+.cesium-viewer-geocoderContainer .search-results ul li.active {
+ background: #48b;
+}
+
.cesium-geocoder-searchButton {
background-color: #303336;
display: inline-block;
diff --git a/Source/Widgets/Geocoder/Geocoder.js b/Source/Widgets/Geocoder/Geocoder.js
index 6ed87298029e..2b42e86a2ccb 100644
--- a/Source/Widgets/Geocoder/Geocoder.js
+++ b/Source/Widgets/Geocoder/Geocoder.js
@@ -32,6 +32,8 @@ define([
* @param {Object} options Object with the following properties:
* @param {Element|String} options.container The DOM element or ID that will contain the widget.
* @param {Scene} options.scene The Scene instance to use.
+ * @param {GeocoderService[]} [options.geocoderServices] The geocoder services to be used
+ * @param {Boolean} [options.autoComplete = true] True if the geocoder should query as the user types to autocomplete
* @param {String} [options.url='https://dev.virtualearth.net'] The base URL of the Bing Maps API.
* @param {String} [options.key] The Bing Maps key for your application, which can be
* created at {@link https://www.bingmapsportal.com}.
@@ -66,10 +68,11 @@ define([
textBox.className = 'cesium-geocoder-input';
textBox.setAttribute('placeholder', 'Enter an address or landmark...');
textBox.setAttribute('data-bind', '\
-value: searchText,\
-valueUpdate: "afterkeydown",\
+textInput: searchText,\
disable: isSearchInProgress,\
-css: { "cesium-geocoder-input-wide" : keepExpanded || searchText.length > 0 }');
+event: { keyup: handleKeyUp, keydown: handleKeyDown, mouseover: deselectSuggestion },\
+css: { "cesium-geocoder-input-wide" : keepExpanded || searchText.length > 0 },\
+hasFocus: _focusTextbox');
this._onTextBoxFocus = function() {
// as of 2016-10-19, setTimeout is required to ensure that the
@@ -92,21 +95,41 @@ cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath,
container.appendChild(form);
+ var searchSuggestionsContainer = document.createElement('div');
+ searchSuggestionsContainer.className = 'search-results';
+ searchSuggestionsContainer.setAttribute('data-bind', 'visible: _suggestionsVisible');
+
+ var suggestionsList = document.createElement('ul');
+ suggestionsList.setAttribute('data-bind', 'foreach: _suggestions');
+ var suggestions = document.createElement('li');
+ suggestionsList.appendChild(suggestions);
+ suggestions.setAttribute('data-bind', 'text: $data.displayName, \
+click: $parent.activateSuggestion, \
+event: { mouseover: $parent.handleMouseover}, \
+css: { active: $data === $parent._selectedSuggestion }');
+
+ searchSuggestionsContainer.appendChild(suggestionsList);
+ container.appendChild(searchSuggestionsContainer);
+
knockout.applyBindings(viewModel, form);
+ knockout.applyBindings(viewModel, searchSuggestionsContainer);
this._container = container;
+ this._searchSuggestionsContainer = searchSuggestionsContainer;
this._viewModel = viewModel;
this._form = form;
this._onInputBegin = function(e) {
if (!container.contains(e.target)) {
- textBox.blur();
+ viewModel._focusTextbox = false;
+ viewModel.hideSuggestions();
}
};
this._onInputEnd = function(e) {
if (container.contains(e.target)) {
- textBox.focus();
+ viewModel._focusTextbox = true;
+ viewModel.showSuggestions();
}
};
@@ -140,6 +163,18 @@ cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath,
}
},
+ /**
+ * Gets the parent container.
+ * @memberof Geocoder.prototype
+ *
+ * @type {Element}
+ */
+ searchSuggestionsContainer : {
+ get : function() {
+ return this._searchSuggestionsContainer;
+ }
+ },
+
/**
* Gets the view model.
* @memberof Geocoder.prototype
@@ -174,9 +209,11 @@ cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath,
document.removeEventListener('touchstart', this._onInputBegin, true);
document.removeEventListener('touchend', this._onInputEnd, true);
}
-
+ this._viewModel.destroy();
knockout.cleanNode(this._form);
+ knockout.cleanNode(this._searchSuggestionsContainer);
this._container.removeChild(this._form);
+ this._container.removeChild(this._searchSuggestionsContainer);
this._textBox.removeEventListener('focus', this._onTextBoxFocus, false);
return destroyObject(this);
diff --git a/Source/Widgets/Geocoder/GeocoderViewModel.js b/Source/Widgets/Geocoder/GeocoderViewModel.js
index 4f30f7912303..6f51f93db92b 100644
--- a/Source/Widgets/Geocoder/GeocoderViewModel.js
+++ b/Source/Widgets/Geocoder/GeocoderViewModel.js
@@ -1,34 +1,40 @@
/*global define*/
define([
'../../Core/BingMapsApi',
+ '../../Core/BingMapsGeocoderService',
'../../Core/Cartesian3',
'../../Core/defaultValue',
'../../Core/defined',
'../../Core/defineProperties',
+ '../../Core/deprecationWarning',
'../../Core/DeveloperError',
'../../Core/Event',
- '../../Core/loadJsonp',
+ '../../Core/CartographicGeocoderService',
'../../Core/Matrix4',
'../../Core/Rectangle',
'../../Core/RequestScheduler',
'../../ThirdParty/knockout',
'../../ThirdParty/when',
- '../createCommand'
+ '../createCommand',
+ '../getElement'
], function(
BingMapsApi,
+ BingMapsGeocoderService,
Cartesian3,
defaultValue,
defined,
defineProperties,
+ deprecationWarning,
DeveloperError,
Event,
- loadJsonp,
+ CartographicGeocoderService,
Matrix4,
Rectangle,
RequestScheduler,
knockout,
when,
- createCommand) {
+ createCommand,
+ getElement) {
'use strict';
/**
@@ -38,6 +44,9 @@ define([
*
* @param {Object} options Object with the following properties:
* @param {Scene} options.scene The Scene instance to use.
+ * @param {GeocoderService[]} [options.geocoderServices] Geocoder services to use for geocoding queries.
+ * If more than one are supplied, suggestions will be gathered for the geocoders that support it,
+ * and if no suggestion is selected the result from the first geocoder service wil be used.
* @param {String} [options.url='https://dev.virtualearth.net'] The base URL of the Bing Maps API.
* @param {String} [options.key] The Bing Maps key for your application, which can be
* created at {@link https://www.bingmapsportal.com}.
@@ -55,33 +64,123 @@ define([
}
//>>includeEnd('debug');
+ if (defined(options.geocoderServices)) {
+ this._geocoderServices = options.geocoderServices;
+ } else {
+ this._geocoderServices = [
+ new CartographicGeocoderService(),
+ new BingMapsGeocoderService()
+ ];
+ }
+
+ var errorCredit;
this._url = defaultValue(options.url, 'https://dev.virtualearth.net/');
if (this._url.length > 0 && this._url[this._url.length - 1] !== '/') {
this._url += '/';
}
this._key = BingMapsApi.getKey(options.key);
- var errorCredit = BingMapsApi.getErrorCredit(options.key);
+ this._defaultGeocoderOptions = {
+ url: this._url,
+ key: this._key
+ };
+
+ if (defined(options.key)) {
+ errorCredit = BingMapsApi.getErrorCredit(options.key);
+ }
if (defined(errorCredit)) {
options.scene._frameState.creditDisplay.addDefaultCredit(errorCredit);
}
+ this._viewContainer = options.container;
this._scene = options.scene;
this._flightDuration = options.flightDuration;
this._searchText = '';
this._isSearchInProgress = false;
- this._geocodeInProgress = undefined;
+ this._geocodePromise = undefined;
this._complete = new Event();
+ this._suggestions = [];
+ this._selectedSuggestion = undefined;
+ this._showSuggestions = true;
+ this._updateCamera = updateCamera;
+ this._adjustSuggestionsScroll = adjustSuggestionsScroll;
+ this._updateSearchSuggestions = updateSearchSuggestions;
+ this._handleArrowDown = handleArrowDown;
+ this._handleArrowUp = handleArrowUp;
var that = this;
+
+ this._suggestionsVisible = knockout.pureComputed(function () {
+ var suggestions = knockout.getObservable(that, '_suggestions');
+ var suggestionsNotEmpty = suggestions().length > 0;
+ var showSuggestions = knockout.getObservable(that, '_showSuggestions')();
+ return suggestionsNotEmpty && showSuggestions;
+ });
+
this._searchCommand = createCommand(function() {
+ that.hideSuggestions();
+ if (defined(that._selectedSuggestion)) {
+ that.activateSuggestion(that._selectedSuggestion);
+ return false;
+ }
if (that.isSearchInProgress) {
cancelGeocode(that);
} else {
- geocode(that);
+ geocode(that, that._geocoderServices);
}
});
+ this.deselectSuggestion = function () {
+ that._selectedSuggestion = undefined;
+ };
+
+ this.handleKeyDown = function(data, event) {
+ var downKey = event.key === 'ArrowDown' || event.key === 'Down' || event.keyCode === 40;
+ var upKey = event.key === 'ArrowUp' || event.key === 'Up' || event.keyCode === 38;
+ if (downKey || upKey) {
+ event.preventDefault();
+ }
+
+ return true;
+ };
+
+ this.handleKeyUp = function (data, event) {
+ var downKey = event.key === 'ArrowDown' || event.key === 'Down' || event.keyCode === 40;
+ var upKey = event.key === 'ArrowUp' || event.key === 'Up' || event.keyCode === 38;
+ var enterKey = event.key === 'Enter' || event.keyCode === 13;
+ if (upKey) {
+ handleArrowUp(that);
+ } else if (downKey) {
+ handleArrowDown(that);
+ } else if (enterKey) {
+ that._searchCommand();
+ }
+ return true;
+ };
+
+ this.activateSuggestion = function (data) {
+ that.hideSuggestions();
+ that._searchText = data.displayName;
+ var destination = data.destination;
+ clearSuggestions(that);
+ updateCamera(that, destination);
+ };
+
+ this.hideSuggestions = function () {
+ that._showSuggestions = false;
+ that._selectedSuggestion = undefined;
+ };
+
+ this.showSuggestions = function () {
+ that._showSuggestions = true;
+ };
+
+ this.handleMouseover = function (data, event) {
+ if (data !== that._selectedSuggestion) {
+ that._selectedSuggestion = data;
+ }
+ };
+
/**
* Gets or sets a value indicating if this instance should always show its text input field.
*
@@ -90,8 +189,22 @@ define([
*/
this.keepExpanded = false;
- knockout.track(this, ['_searchText', '_isSearchInProgress', 'keepExpanded']);
+ /**
+ * True if the geocoder should query as the user types to autocomplete
+ * @type {Booelan}
+ * @default true
+ */
+ this.autoComplete = defaultValue(options.autocomplete, true);
+
+ this._focusTextbox = false;
+ knockout.track(this, ['_searchText', '_isSearchInProgress', 'keepExpanded', '_suggestions', '_selectedSuggestion', '_showSuggestions', '_focusTextbox']);
+
+ var searchTextObservable = knockout.getObservable(this, '_searchText');
+ searchTextObservable.extend({ rateLimit: { timeout: 500 } });
+ this._suggestionSubscription = searchTextObservable.subscribe(function() {
+ updateSearchSuggestions(that);
+ });
/**
* Gets a value indicating whether a search is currently in progress. This property is observable.
*
@@ -116,6 +229,7 @@ define([
if (this.isSearchInProgress) {
return 'Searching...';
}
+
return this._searchText;
},
set : function(value) {
@@ -124,7 +238,6 @@ define([
throw new DeveloperError('value must be a valid string.');
}
//>>includeEnd('debug');
-
this._searchText = value;
}
});
@@ -157,24 +270,28 @@ define([
defineProperties(GeocoderViewModel.prototype, {
/**
* Gets the Bing maps url.
+ * @deprecated
* @memberof GeocoderViewModel.prototype
*
* @type {String}
*/
url : {
get : function() {
+ deprecationWarning('url is deprecated', 'The url property was deprecated in Cesium 1.30 and will be removed in version 1.31.');
return this._url;
}
},
/**
* Gets the Bing maps key.
+ * @deprecated
* @memberof GeocoderViewModel.prototype
*
* @type {String}
*/
key : {
get : function() {
+ deprecationWarning('key is deprecated', 'The key property was deprecated in Cesium 1.30 and will be removed in version 1.31.');
return this._key;
}
},
@@ -213,9 +330,68 @@ define([
get : function() {
return this._searchCommand;
}
+ },
+
+ /**
+ * Gets the currently selected geocoder search suggestion
+ * @memberof GeocoderViewModel.prototype
+ *
+ * @type {Object}
+ */
+ selectedSuggestion : {
+ get : function() {
+ return this._selectedSuggestion;
+ }
+ },
+
+ /**
+ * Gets the list of geocoder search suggestions
+ * @memberof GeocoderViewModel.prototype
+ *
+ * @type {Object[]}
+ */
+ suggestions : {
+ get : function() {
+ return this._suggestions;
+ }
}
});
+ /**
+ * Destroys the widget. Should be called if permanently
+ * removing the widget from layout.
+ */
+ GeocoderViewModel.prototype.destroy = function() {
+ this._suggestionSubscription.dispose();
+ };
+
+ function handleArrowUp(viewModel) {
+ if (viewModel._suggestions.length === 0) {
+ return;
+ }
+ var next;
+ var currentIndex = viewModel._suggestions.indexOf(viewModel._selectedSuggestion);
+ if (currentIndex === -1 || currentIndex === 0) {
+ viewModel._selectedSuggestion = undefined;
+ return;
+ }
+ next = currentIndex - 1;
+ viewModel._selectedSuggestion = viewModel._suggestions[next];
+ adjustSuggestionsScroll(viewModel, next);
+ }
+
+ function handleArrowDown(viewModel) {
+ if (viewModel._suggestions.length === 0) {
+ return;
+ }
+ var numberOfSuggestions = viewModel._suggestions.length;
+ var currentIndex = viewModel._suggestions.indexOf(viewModel._selectedSuggestion);
+ var next = (currentIndex + 1) % numberOfSuggestions;
+ viewModel._selectedSuggestion = viewModel._suggestions[next];
+
+ adjustSuggestionsScroll(viewModel, next);
+ }
+
function updateCamera(viewModel, destination) {
viewModel._scene.camera.flyTo({
destination : destination,
@@ -227,81 +403,124 @@ define([
});
}
- function geocode(viewModel) {
- var query = viewModel.searchText;
+ function chainPromise(promise, geocoderService, query) {
+ return promise
+ .then(function(result) {
+ if (defined(result) && result.state === 'fulfilled' && result.value.length > 0){
+ return result;
+ }
+ var nextPromise = geocoderService.geocode(query)
+ .then(function (result) {
+ return {state: 'fulfilled', value: result};
+ })
+ .otherwise(function (err) {
+ return {state: 'rejected', reason: err};
+ });
+
+ return nextPromise;
+ });
+ }
- if (/^\s*$/.test(query)) {
- //whitespace string
+ function geocode(viewModel, geocoderServices) {
+ var query = viewModel._searchText;
+
+ if (hasOnlyWhitespace(query)) {
+ viewModel.showSuggestions();
return;
}
- // If the user entered (longitude, latitude, [height]) in degrees/meters,
- // fly without calling the geocoder.
- var splitQuery = query.match(/[^\s,\n]+/g);
- if ((splitQuery.length === 2) || (splitQuery.length === 3)) {
- var longitude = +splitQuery[0];
- var latitude = +splitQuery[1];
- var height = (splitQuery.length === 3) ? +splitQuery[2] : 300.0;
-
- if (!isNaN(longitude) && !isNaN(latitude) && !isNaN(height)) {
- updateCamera(viewModel, Cartesian3.fromDegrees(longitude, latitude, height));
- return;
- }
- }
viewModel._isSearchInProgress = true;
- var promise = RequestScheduler.request(viewModel._url + 'REST/v1/Locations', loadJsonp, {
- parameters : {
- query : query,
- key : viewModel._key
+ var promise = when.resolve();
+ for (var i = 0; i < geocoderServices.length; i++) {
+ promise = chainPromise(promise, geocoderServices[i], query);
+ }
- },
- callbackParameterName : 'jsonp'
- });
+ viewModel._geocodePromise = promise;
+ promise
+ .then(function (result) {
+ if (promise.cancel) {
+ return;
+ }
+ viewModel._isSearchInProgress = false;
- var geocodeInProgress = viewModel._geocodeInProgress = when(promise, function(result) {
- if (geocodeInProgress.cancel) {
- return;
- }
- viewModel._isSearchInProgress = false;
+ var geocoderResults = result.value;
+ if (result.state === 'fulfilled' && defined(geocoderResults) && geocoderResults.length > 0) {
+ viewModel._searchText = geocoderResults[0].displayName;
+ updateCamera(viewModel, geocoderResults[0].destination);
+ return;
+ }
+ viewModel._searchText = query + ' (not found)';
+ });
+ }
- if (result.resourceSets.length === 0) {
- viewModel.searchText = viewModel._searchText + ' (not found)';
- return;
- }
+ function adjustSuggestionsScroll(viewModel, focusedItemIndex) {
+ var container = getElement(viewModel._viewContainer);
+ var searchResults = container.getElementsByClassName('search-results')[0];
+ var listItems = container.getElementsByTagName('li');
+ var element = listItems[focusedItemIndex];
- var resourceSet = result.resourceSets[0];
- if (resourceSet.resources.length === 0) {
- viewModel.searchText = viewModel._searchText + ' (not found)';
- return;
- }
+ if (focusedItemIndex === 0) {
+ searchResults.scrollTop = 0;
+ return;
+ }
- var resource = resourceSet.resources[0];
+ var offsetTop = element.offsetTop;
+ if (offsetTop + element.clientHeight > searchResults.clientHeight) {
+ searchResults.scrollTop = offsetTop + element.clientHeight;
+ } else if (offsetTop < searchResults.scrollTop) {
+ searchResults.scrollTop = offsetTop;
+ }
+ }
- viewModel._searchText = resource.name;
- var bbox = resource.bbox;
- var south = bbox[0];
- var west = bbox[1];
- var north = bbox[2];
- var east = bbox[3];
+ function cancelGeocode(viewModel) {
+ viewModel._isSearchInProgress = false;
+ if (defined(viewModel._geocodePromise)) {
+ viewModel._geocodePromise.cancel = true;
+ viewModel._geocodePromise = undefined;
+ }
+ }
- updateCamera(viewModel, Rectangle.fromDegrees(west, south, east, north));
- }, function() {
- if (geocodeInProgress.cancel) {
- return;
- }
+ function hasOnlyWhitespace(string) {
+ return /^\s*$/.test(string);
+ }
- viewModel._isSearchInProgress = false;
- viewModel.searchText = viewModel._searchText + ' (error)';
- });
+ function clearSuggestions(viewModel) {
+ knockout.getObservable(viewModel, '_suggestions').removeAll();
}
- function cancelGeocode(viewModel) {
- viewModel._isSearchInProgress = false;
- if (defined(viewModel._geocodeInProgress)) {
- viewModel._geocodeInProgress.cancel = true;
- viewModel._geocodeInProgress = undefined;
+ function updateSearchSuggestions(viewModel) {
+ if (!viewModel.autoComplete) {
+ return;
+ }
+
+ var query = viewModel._searchText;
+
+ clearSuggestions(viewModel);
+ if (hasOnlyWhitespace(query)) {
+ return;
}
+
+ var promise = when.resolve([]);
+ viewModel._geocoderServices.forEach(function (service) {
+ promise = promise.then(function(results) {
+ if (results.length >= 5) {
+ return results;
+ }
+ return service.geocode(query)
+ .then(function(newResults) {
+ results = results.concat(newResults);
+ return results;
+ });
+ });
+ });
+ promise
+ .then(function (results) {
+ var suggestions = viewModel._suggestions;
+ for (var i = 0; i < results.length; i++) {
+ suggestions.push(results[i]);
+ }
+ });
}
return GeocoderViewModel;
diff --git a/Source/Widgets/Viewer/Viewer.js b/Source/Widgets/Viewer/Viewer.js
index 0688f4ad8ad5..63a858b38c9b 100644
--- a/Source/Widgets/Viewer/Viewer.js
+++ b/Source/Widgets/Viewer/Viewer.js
@@ -469,6 +469,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to
toolbar.appendChild(geocoderContainer);
geocoder = new Geocoder({
container : geocoderContainer,
+ geocoderServices: defined(options.geocoder) ? (isArray(options.geocoder) ? options.geocoder : [options.geocoder]) : undefined,
scene : cesiumWidget.scene
});
// Subscribe to search so that we can clear the trackedEntity when it is clicked.
@@ -1266,6 +1267,11 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to
baseLayerPickerDropDown.style.maxHeight = panelMaxHeight + 'px';
}
+ if (defined(this._geocoder)) {
+ var geocoderSuggestions = this._geocoder.searchSuggestionsContainer;
+ geocoderSuggestions.style.maxHeight = panelMaxHeight + 'px';
+ }
+
if (defined(this._infoBox)) {
this._infoBox.viewModel.maxHeight = panelMaxHeight;
}
diff --git a/Specs/Core/BingMapsGeocoderServiceSpec.js b/Specs/Core/BingMapsGeocoderServiceSpec.js
new file mode 100644
index 000000000000..5c68a7804d1c
--- /dev/null
+++ b/Specs/Core/BingMapsGeocoderServiceSpec.js
@@ -0,0 +1,57 @@
+/*global defineSuite*/
+defineSuite([
+ 'Core/BingMapsGeocoderService',
+ 'Core/Cartesian3',
+ 'Core/loadJsonp',
+ 'Core/Rectangle'
+], function(
+ BingMapsGeocoderService,
+ Cartesian3,
+ loadJsonp,
+ Rectangle) {
+ 'use strict';
+
+ var service = new BingMapsGeocoderService();
+
+ it('returns geocoder results', function (done) {
+ var query = 'some query';
+ jasmine.createSpy('testSpy', loadJsonp).and.returnValue({
+ resourceSets: [{
+ resources : [{
+ name : 'a',
+ bbox : [32.0, 3.0, 3.0, 4.0]
+ }]
+ }]
+ });
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(1);
+ expect(results[0].displayName).toEqual('a');
+ expect(results[0].destination).toBeInstanceOf(Rectangle);
+ done();
+ });
+ });
+
+ it('returns no geocoder results if Bing has no results', function (done) {
+ var query = 'some query';
+ jasmine.createSpy('testSpy', loadJsonp).and.returnValue({
+ resourceSets: []
+ });
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(0);
+ done();
+ });
+ });
+
+ it('returns no geocoder results if Bing has results but no resources', function (done) {
+ var query = 'some query';
+ jasmine.createSpy('testSpy', loadJsonp).and.returnValue({
+ resourceSets: [{
+ resources: []
+ }]
+ });
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(0);
+ done();
+ });
+ });
+});
diff --git a/Specs/Core/CartographicGeocoderServiceSpec.js b/Specs/Core/CartographicGeocoderServiceSpec.js
new file mode 100644
index 000000000000..5ecf68dbca37
--- /dev/null
+++ b/Specs/Core/CartographicGeocoderServiceSpec.js
@@ -0,0 +1,47 @@
+/*global defineSuite*/
+defineSuite([
+ 'Core/CartographicGeocoderService',
+ 'Core/Cartesian3'
+], function(
+ CartographicGeocoderService,
+ Cartesian3) {
+ 'use strict';
+
+ var service = new CartographicGeocoderService();
+
+ it('returns cartesian with matching coordinates for long/lat/height input', function (done) {
+ var query = ' 1.0, 2.0, 3.0 ';
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(1);
+ expect(results[0]).toEqual(Cartesian3.fromDegrees(1.0, 2.0, 3.0));
+ done();
+ });
+ });
+
+ it('returns cartesian with matching coordinates for long/lat input', function (done) {
+ var query = ' 1.0, 2.0 ';
+ var defaultHeight = 300.0;
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(1);
+ expect(results[0]).toEqual(Cartesian3.fromDegrees(1.0, 2.0, defaultHeight));
+ done();
+ });
+ });
+
+ it('returns empty array for input with only one number', function (done) {
+ var query = ' 2.0 ';
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(0);
+ done();
+ });
+ });
+
+ it('returns empty array for with string', function (done) {
+ var query = ' aoeu ';
+ service.geocode(query, function(err, results) {
+ expect(results.length).toEqual(0);
+ done();
+ });
+ });
+
+});
diff --git a/Specs/Core/CheckSpec.js b/Specs/Core/CheckSpec.js
new file mode 100644
index 000000000000..54bcc1cd304b
--- /dev/null
+++ b/Specs/Core/CheckSpec.js
@@ -0,0 +1,177 @@
+/*global defineSuite*/
+defineSuite([
+ 'Core/Check'
+ ], function(
+ Check) {
+ 'use strict';
+
+ describe('type checks', function () {
+ it('Check.typeOf.boolean does not throw when passed a boolean', function () {
+ expect(function () {
+ Check.typeOf.boolean(true);
+ }).not.toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.boolean throws when passed a non-boolean', function () {
+ expect(function () {
+ Check.typeOf.boolean({}, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.boolean([], 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.boolean(1, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.boolean('snth', 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.boolean(function () {return true;}, 'mockName');
+ }).toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.func does not throw when passed a function', function () {
+ expect(function () {
+ Check.typeOf.func(function () {return true;}, 'mockName');
+ }).not.toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.func throws when passed a non-function', function () {
+ expect(function () {
+ Check.typeOf.func({}, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.func([], 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.func(1, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.func('snth', 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.func(true, 'mockName');
+ }).toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.object does not throw when passed object', function() {
+ expect(function () {
+ Check.typeOf.object({}, 'mockName');
+ }).not.toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.object throws when passed non-object', function() {
+ expect(function () {
+ Check.typeOf.object('snth', 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.object(true, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.object(1, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.object(function () {return true;}, 'mockName');
+ }).toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.number does not throw when passed number', function() {
+ expect(function () {
+ Check.typeOf.number(2, 'mockName');
+ }).not.toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.number throws when passed non-number', function() {
+ expect(function () {
+ Check.typeOf.number('snth', 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.number(true, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.number({}, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.number([2], 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.number(function () {return true;}, 'mockName');
+ }).toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.string does not throw when passed a string', function () {
+ expect(function () {
+ Check.typeOf.string('s', 'mockName');
+ }).not.toThrowDeveloperError();
+ });
+
+ it('Check.typeOf.string throws on non-string', function () {
+ expect(function () {
+ Check.typeOf.string({}, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.string(true, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.string(1, 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.string([2], 'mockName');
+ }).toThrowDeveloperError();
+ expect(function () {
+ Check.typeOf.string(function () {return true;}, 'mockName');
+ }).toThrowDeveloperError();
+ });
+ });
+
+ describe('Check.numeric', function () {
+ it('minimum throws on value less than minimum', function () {
+ expect(function () {
+ Check.numeric.minimum(4, 5);
+ }).toThrowDeveloperError();
+ });
+ it('minimum does not throw on value at least as big as minimum', function () {
+ expect(function () {
+ Check.numeric.minimum(4, 4);
+ Check.numeric.minimum(4, 3);
+ }).not.toThrowDeveloperError();
+ });
+
+ it('maximum throws on value greater than maximum', function () {
+ expect(function () {
+ Check.numeric.maximum(6, 5);
+ }).toThrowDeveloperError();
+ });
+ it('maximum does not throw on value at most as big as maximum', function () {
+ expect(function () {
+ Check.numeric.maximum(5, 5);
+ Check.numeric.maximum(4, 5);
+ }).not.toThrowDeveloperError();
+ });
+ });
+
+ it('Check.defined does not throw unless passed value that is undefined or null', function () {
+ expect(function () {
+ Check.defined({}, 'mockName');
+ }).not.toThrowDeveloperError();
+ expect(function () {
+ Check.defined([], 'mockName');
+ }).not.toThrowDeveloperError();
+ expect(function () {
+ Check.defined(2, 'mockName');
+ }).not.toThrowDeveloperError();
+ expect(function () {
+ Check.defined(function() {return true;}, 'mockName');
+ }).not.toThrowDeveloperError();
+ expect(function () {
+ Check.defined('snt', 'mockName');
+ }).not.toThrowDeveloperError();
+ });
+
+ it('Check.defined throws when passed undefined', function () {
+ expect(function () {
+ Check.defined(undefined, 'mockName');
+ }).toThrowDeveloperError();
+ });
+
+});
diff --git a/Specs/Core/EllipsoidSpec.js b/Specs/Core/EllipsoidSpec.js
index d4dfa16d1092..944c388ebb21 100644
--- a/Specs/Core/EllipsoidSpec.js
+++ b/Specs/Core/EllipsoidSpec.js
@@ -434,5 +434,114 @@ defineSuite([
expect(cloned).toEqual(myEllipsoid);
});
+ it('getSurfaceNormalIntersectionWithZAxis throws with no position', function() {
+ expect(function() {
+ Ellipsoid.WGS84.getSurfaceNormalIntersectionWithZAxis(undefined);
+ }).toThrowDeveloperError();
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis throws if the ellipsoid is not an ellipsoid of revolution', function() {
+ expect(function() {
+ var ellipsoid = new Ellipsoid(1,2,3);
+ var cartesian = new Cartesian3();
+ ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesian);
+ }).toThrowDeveloperError();
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis throws if the ellipsoid has radii.z === 0', function() {
+ expect(function() {
+ var ellipsoid = new Ellipsoid(1,2,0);
+ var cartesian = new Cartesian3();
+ ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesian);
+ }).toThrowDeveloperError();
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis works without a result parameter', function() {
+ var ellipsoid = Ellipsoid.WGS84;
+ var cartographic = Cartographic.fromDegrees(35.23,33.23);
+ var cartesianOnTheSurface = ellipsoid.cartographicToCartesian(cartographic);
+ var returnedResult = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface);
+ expect(returnedResult instanceof Cartesian3).toBe(true);
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis works with a result parameter', function() {
+ var ellipsoid = Ellipsoid.WGS84;
+ var cartographic = Cartographic.fromDegrees(35.23,33.23);
+ var cartesianOnTheSurface = ellipsoid.cartographicToCartesian(cartographic);
+ var returnedResult = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, undefined , cartesianOnTheSurface);
+ expect(returnedResult).toBe(cartesianOnTheSurface);
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis returns undefined if the result is outside the ellipsoid with buffer parameter', function() {
+ var ellipsoid = Ellipsoid.WGS84;
+ var cartographic = Cartographic.fromDegrees(35.23,33.23);
+ var cartesianOnTheSurface = ellipsoid.cartographicToCartesian(cartographic);
+ var returnedResult = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, ellipsoid.radii.z);
+ expect(returnedResult).toBe(undefined);
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis returns undefined if the result is outside the ellipsoid without buffer parameter', function() {
+ var majorAxis = 10;
+ var minorAxis = 1;
+ var ellipsoid = new Ellipsoid(majorAxis,majorAxis,minorAxis);
+ var cartographic = Cartographic.fromDegrees(45.0,90.0);
+ var cartesianOnTheSurface = ellipsoid.cartographicToCartesian(cartographic);
+ var returnedResult = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, undefined);
+ expect(returnedResult).toBe(undefined);
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis returns a result that is equal to a value that computed in a different way', function() {
+ var ellipsoid = Ellipsoid.WGS84;
+ var cartographic = Cartographic.fromDegrees(35.23,33.23);
+ var cartesianOnTheSurface = ellipsoid.cartographicToCartesian(cartographic);
+ var surfaceNormal = ellipsoid.geodeticSurfaceNormal(cartesianOnTheSurface);
+ var magnitude = cartesianOnTheSurface.x / surfaceNormal.x;
+
+ var expected = new Cartesian3();
+ expected.z = cartesianOnTheSurface.z - surfaceNormal.z * magnitude;
+ var result = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, undefined);
+ expect(result).toEqualEpsilon(expected, CesiumMath.EPSILON8);
+
+ // at the equator
+ cartesianOnTheSurface = new Cartesian3(ellipsoid.radii.x, 0 , 0);
+ result = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, undefined);
+ expect(result).toEqualEpsilon(Cartesian3.ZERO, CesiumMath.EPSILON8);
+
+ });
+
+ it('getSurfaceNormalIntersectionWithZAxis returns a result that when it\'s used as an origin for a vector with the surface normal direction it produces an accurate cartographic', function() {
+ var ellipsoid = Ellipsoid.WGS84;
+ var cartographic = Cartographic.fromDegrees(35.23,33.23);
+ var cartesianOnTheSurface = ellipsoid.cartographicToCartesian(cartographic);
+ var surfaceNormal = ellipsoid.geodeticSurfaceNormal(cartesianOnTheSurface);
+
+ var result = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, undefined);
+
+ var surfaceNormalWithLength = Cartesian3.multiplyByScalar(surfaceNormal, ellipsoid.maximumRadius, new Cartesian3());
+ var position = Cartesian3.add(result,surfaceNormalWithLength,new Cartesian3());
+ var resultCartographic = ellipsoid.cartesianToCartographic(position);
+ resultCartographic.height = 0.0;
+ expect(resultCartographic).toEqualEpsilon(cartographic, CesiumMath.EPSILON8);
+
+ // at the north pole
+ cartographic = Cartographic.fromDegrees(0,90);
+ cartesianOnTheSurface = new Cartesian3(0, 0 ,ellipsoid.radii.z);
+ surfaceNormal = ellipsoid.geodeticSurfaceNormal(cartesianOnTheSurface);
+ surfaceNormalWithLength = Cartesian3.multiplyByScalar(surfaceNormal, ellipsoid.maximumRadius, new Cartesian3());
+ result = ellipsoid.getSurfaceNormalIntersectionWithZAxis(cartesianOnTheSurface, undefined);
+ position = Cartesian3.add(result,surfaceNormalWithLength,new Cartesian3());
+ resultCartographic = ellipsoid.cartesianToCartographic(position);
+ resultCartographic.height = 0.0;
+ expect(resultCartographic).toEqualEpsilon(cartographic, CesiumMath.EPSILON8);
+
+ });
+
+ it('ellipsoid is initialized with _sqauredXOverSquaredZ property', function() {
+ var ellipsoid = new Ellipsoid(4 , 4 , 3);
+
+ var sqauredXOverSquaredZ = ellipsoid.radiiSquared.x / ellipsoid.radiiSquared.z;
+ expect(ellipsoid._sqauredXOverSquaredZ).toEqual(sqauredXOverSquaredZ);
+ });
+
createPackableSpecs(Ellipsoid, Ellipsoid.WGS84, [Ellipsoid.WGS84.radii.x, Ellipsoid.WGS84.radii.y, Ellipsoid.WGS84.radii.z]);
});
diff --git a/Specs/DataSources/DataSourceClockSpec.js b/Specs/DataSources/DataSourceClockSpec.js
index e957725cb1f1..3a40542bb5d9 100644
--- a/Specs/DataSources/DataSourceClockSpec.js
+++ b/Specs/DataSources/DataSourceClockSpec.js
@@ -89,4 +89,34 @@ defineSuite([
target.merge(undefined);
}).toThrowDeveloperError();
});
+
+ it('gets value as a clock instance',function () {
+ var source = new DataSourceClock();
+ source.startTime = JulianDate.now();
+ source.stopTime = JulianDate.now();
+ source.currentTime = JulianDate.now();
+ source.clockRange = ClockRange.CLAMPED;
+ source.clockStep = ClockStep.TICK_DEPENDENT;
+ source.multiplier = 2;
+
+ var clock = source.getValue();
+ expect(clock.startTime).toEqual(source.startTime);
+ expect(clock.stopTime).toEqual(source.stopTime);
+ expect(clock.currentTime).toEqual(source.currentTime);
+ expect(clock.clockRange).toEqual(source.clockRange);
+ expect(clock.clockStep).toEqual(source.clockStep);
+ expect(clock.multiplier).toEqual(source.multiplier);
+
+ source.multiplier = undefined;
+ source.clockStep = undefined;
+ source.clockRange = undefined;
+
+ clock = source.getValue();
+ expect(clock.startTime).toEqual(source.startTime);
+ expect(clock.stopTime).toEqual(source.stopTime);
+ expect(clock.currentTime).toEqual(source.currentTime);
+ expect(clock.clockRange).toEqual(ClockRange.UNBOUNDED);
+ expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER);
+ expect(clock.multiplier).toEqual(1.0);
+ });
});
diff --git a/Specs/Renderer/AutomaticUniformSpec.js b/Specs/Renderer/AutomaticUniformSpec.js
index b00f04ae2779..8e4c5010ee30 100644
--- a/Specs/Renderer/AutomaticUniformSpec.js
+++ b/Specs/Renderer/AutomaticUniformSpec.js
@@ -4,9 +4,9 @@ defineSuite([
'Core/Cartesian3',
'Core/defaultValue',
'Core/Matrix4',
+ 'Renderer/Pass',
'Renderer/Texture',
'Scene/OrthographicFrustum',
- 'Scene/Pass',
'Scene/SceneMode',
'Specs/createCamera',
'Specs/createContext',
@@ -16,9 +16,9 @@ defineSuite([
Cartesian3,
defaultValue,
Matrix4,
+ Pass,
Texture,
OrthographicFrustum,
- Pass,
SceneMode,
createCamera,
createContext,
diff --git a/Specs/Renderer/DrawCommandSpec.js b/Specs/Renderer/DrawCommandSpec.js
index b15ff6c9b772..a066f2cf8e06 100644
--- a/Specs/Renderer/DrawCommandSpec.js
+++ b/Specs/Renderer/DrawCommandSpec.js
@@ -1,11 +1,11 @@
/*global defineSuite*/
defineSuite([
- 'Renderer/DrawCommand',
'Core/PrimitiveType',
- 'Scene/Pass'
+ 'Renderer/DrawCommand',
+ 'Renderer/Pass'
], function(
- DrawCommand,
PrimitiveType,
+ DrawCommand,
Pass) {
'use strict';
diff --git a/Specs/Scene/Batched3DModel3DTileContentSpec.js b/Specs/Scene/Batched3DModel3DTileContentSpec.js
index 182e05286be5..255fd33acbb9 100644
--- a/Specs/Scene/Batched3DModel3DTileContentSpec.js
+++ b/Specs/Scene/Batched3DModel3DTileContentSpec.js
@@ -103,11 +103,12 @@ defineSuite([
});
it('logs deprecation warning for use of BATCHID without prefixed underscore', function() {
- var deprecationWarningSpy = jasmine.createSpy(deprecationWarning);
- return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
- expect(deprecationWarningSpy).toHaveBeenCalled();
- Cesium3DTilesTester.expectRenderTileset(scene, tileset);
- });
+ spyOn(Batched3DModel3DTileContent, '_deprecationWarning');
+ return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl)
+ .then(function(tileset) {
+ expect(Batched3DModel3DTileContent._deprecationWarning).toHaveBeenCalled();
+ Cesium3DTilesTester.expectRenderTileset(scene, tileset);
+ });
});
it('throws with empty gltf', function() {
diff --git a/Specs/Scene/ExpressionSpec.js b/Specs/Scene/ExpressionSpec.js
index c8b8ced4c52d..078761b40a2e 100644
--- a/Specs/Scene/ExpressionSpec.js
+++ b/Specs/Scene/ExpressionSpec.js
@@ -1,11 +1,17 @@
/*global defineSuite*/
defineSuite([
'Scene/Expression',
+ 'Core/Cartesian2',
+ 'Core/Cartesian3',
+ 'Core/Cartesian4',
'Core/Color',
'Core/Math',
'Scene/ExpressionNodeType'
], function(
Expression,
+ Cartesian2,
+ Cartesian3,
+ Cartesian4,
Color,
CesiumMath,
ExpressionNodeType) {
@@ -485,7 +491,7 @@ defineSuite([
}).toThrowDeveloperError();
});
- it('evaluates color properties', function() {
+ it('evaluates color properties (reg, green, blue, alpha)', function() {
var expression = new Expression('color(\'#ffffff\').red');
expect(expression.evaluate(frameState, undefined)).toEqual(1);
@@ -499,6 +505,254 @@ defineSuite([
expect(expression.evaluate(frameState, undefined)).toEqual(0.5);
});
+ it('evaluates color properties (x, y, z, w)', function() {
+ var expression = new Expression('color(\'#ffffff\').x');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgb(255, 255, 0).y');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('color("cyan").z');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgba(255, 255, 0, 0.5).w');
+ expect(expression.evaluate(frameState, undefined)).toEqual(0.5);
+ });
+
+ it('evaluates color properties ([0], [1], [2]. [3])', function() {
+ var expression = new Expression('color(\'#ffffff\')[0]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgb(255, 255, 0)[1]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('color("cyan")[2]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgba(255, 255, 0, 0.5)[3]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(0.5);
+ });
+
+ it('evaluates color properties (["red"], ["green"], ["blue"], ["alpha"])', function() {
+ var expression = new Expression('color(\'#ffffff\')["red"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgb(255, 255, 0)["green"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('color("cyan")["blue"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgba(255, 255, 0, 0.5)["alpha"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(0.5);
+ });
+
+ it('evaluates color properties (["x"], ["y"], ["z"], ["w"])', function() {
+ var expression = new Expression('color(\'#ffffff\')["x"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgb(255, 255, 0)["y"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('color("cyan")["z"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1);
+
+ expression = new Expression('rgba(255, 255, 0, 0.5)["w"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(0.5);
+ });
+
+ it('evaluates vec2', function() {
+ var expression = new Expression('vec2(2.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(2.0, 2.0));
+
+ expression = new Expression('vec2(3.0, 4.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0));
+
+ expression = new Expression('vec2(vec2(3.0, 4.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0));
+
+ expression = new Expression('vec2(vec3(3.0, 4.0, 5.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0));
+
+ expression = new Expression('vec2(vec4(3.0, 4.0, 5.0, 6.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0));
+ });
+
+ it('throws if vec2 has invalid number of arguments', function() {
+ var expression = new Expression('vec2()');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec2(3.0, 4.0, 5.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec2(vec2(3.0, 4.0), 5.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+ });
+
+ it('evaluates vec3', function() {
+ var expression = new Expression('vec3(2.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(2.0, 2.0, 2.0));
+
+ expression = new Expression('vec3(3.0, 4.0, 5.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0));
+
+ expression = new Expression('vec3(vec2(3.0, 4.0), 5.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0));
+
+ expression = new Expression('vec3(3.0, vec2(4.0, 5.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0));
+
+ expression = new Expression('vec3(vec3(3.0, 4.0, 5.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0));
+
+ expression = new Expression('vec3(vec4(3.0, 4.0, 5.0, 6.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0));
+ });
+
+ it ('throws if vec3 has invalid number of arguments', function() {
+ var expression = new Expression('vec3()');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec3(3.0, 4.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec3(3.0, 4.0, 5.0, 6.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec3(vec2(3.0, 4.0), vec2(5.0, 6.0))');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec3(vec4(3.0, 4.0, 5.0, 6.0), 1.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+ });
+
+ it('evaluates vec4', function() {
+ var expression = new Expression('vec4(2.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2.0, 2.0, 2.0, 2.0));
+
+ expression = new Expression('vec4(3.0, 4.0, 5.0, 6.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+
+ expression = new Expression('vec4(vec2(3.0, 4.0), 5.0, 6.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+
+ expression = new Expression('vec4(3.0, vec2(4.0, 5.0), 6.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+
+ expression = new Expression('vec4(3.0, 4.0, vec2(5.0, 6.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+
+ expression = new Expression('vec4(vec3(3.0, 4.0, 5.0), 6.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+
+ expression = new Expression('vec4(3.0, vec3(4.0, 5.0, 6.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+
+ expression = new Expression('vec4(vec4(3.0, 4.0, 5.0, 6.0))');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0));
+ });
+
+ it ('throws if vec4 has invalid number of arguments', function() {
+ var expression = new Expression('vec4()');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec4(3.0, 4.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec4(3.0, 4.0, 5.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec4(3.0, 4.0, 5.0, 6.0, 7.0)');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+
+ expression = new Expression('vec4(vec3(3.0, 4.0, 5.0))');
+ expect(function() {
+ expression.evaluate(frameState, undefined);
+ }).toThrowDeveloperError();
+ });
+
+ it('evaluates vector with expressions as arguments', function() {
+ var feature = new MockFeature();
+ feature.addProperty('height', 2);
+ feature.addProperty('width', 4);
+ feature.addProperty('depth', 3);
+ feature.addProperty('scale', 1);
+
+ var expression = new Expression('vec4(${height}, ${width}, ${depth}, ${scale})');
+ expect(expression.evaluate(frameState, feature)).toEqual(new Cartesian4(2.0, 4.0, 3.0, 1.0));
+ });
+
+ it('evaluates expression with multiple nested vectors', function() {
+ var expression = new Expression('vec4(vec2(1, 2)[vec3(6, 1, 5).y], 2, vec4(1.0).w, 5)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2.0, 2.0, 1.0, 5.0));
+ });
+
+ it('evaluates vector properties (x, y, z, w)', function() {
+ var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).x');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).y');
+ expect(expression.evaluate(frameState, undefined)).toEqual(2.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).z');
+ expect(expression.evaluate(frameState, undefined)).toEqual(3.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).w');
+ expect(expression.evaluate(frameState, undefined)).toEqual(4.0);
+ });
+
+ it('evaluates vector properties ([0], [1], [2], [3])', function() {
+ var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[0]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[1]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(2.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[2]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(3.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[3]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(4.0);
+ });
+
+ it('evaluates vector properties (["x"], ["y"], ["z"]. ["w"])', function() {
+ var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["x"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(1.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["y"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(2.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["z"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(3.0);
+
+ expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["w"]');
+ expect(expression.evaluate(frameState, undefined)).toEqual(4.0);
+ });
+
it('evaluates unary not', function() {
var expression = new Expression('!true');
expect(expression.evaluate(frameState, undefined)).toEqual(false);
@@ -748,7 +1002,10 @@ defineSuite([
});
it('evaluates color operations', function() {
- var expression = new Expression('rgba(255, 0, 0, 0.5) + rgba(0, 0, 255, 0.5)');
+ var expression = new Expression('+rgba(255, 0, 0, 1.0)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(Color.RED);
+
+ expression = new Expression('rgba(255, 0, 0, 0.5) + rgba(0, 0, 255, 0.5)');
expect(expression.evaluate(frameState, undefined)).toEqual(Color.MAGENTA);
expression = new Expression('rgba(0, 255, 255, 1.0) - rgba(0, 255, 0, 0)');
@@ -783,6 +1040,140 @@ defineSuite([
expression = new Expression('color(\'green\') != color(\'green\')');
expect(expression.evaluate(frameState, undefined)).toEqual(false);
+
+ expression = new Expression('color(\'green\') !== color(\'green\')');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
+ });
+
+ it('evaluates vector operations', function() {
+ var expression = new Expression('+vec2(1, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1, 2));
+
+ expression = new Expression('+vec3(1, 2, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1, 2, 3));
+
+ expression = new Expression('+vec4(1, 2, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1, 2, 3, 4));
+
+ expression = new Expression('-vec2(1, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(-1, -2));
+
+ expression = new Expression('-vec3(1, 2, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(-1, -2, -3));
+
+ expression = new Expression('-vec4(1, 2, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-1, -2, -3, -4));
+
+ expression = new Expression('vec2(1, 2) + vec2(3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(4, 6));
+
+ expression = new Expression('vec3(1, 2, 3) + vec3(3, 4, 5)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(4, 6, 8));
+
+ expression = new Expression('vec4(1, 2, 3, 4) + vec4(3, 4, 5, 6)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(4, 6, 8, 10));
+
+ expression = new Expression('vec2(1, 2) - vec2(3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(-2, -2));
+
+ expression = new Expression('vec3(1, 2, 3) - vec3(3, 4, 5)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(-2, -2, -2));
+
+ expression = new Expression('vec4(1, 2, 3, 4) - vec4(3, 4, 5, 6)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-2, -2, -2, -2));
+
+ expression = new Expression('vec2(1, 2) * vec2(3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3, 8));
+
+ expression = new Expression('vec2(1, 2) * 3.0');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3, 6));
+
+ expression = new Expression('3.0 * vec2(1, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3, 6));
+
+ expression = new Expression('vec3(1, 2, 3) * vec3(3, 4, 5)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3, 8, 15));
+
+ expression = new Expression('vec3(1, 2, 3) * 3.0');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3, 6, 9));
+
+ expression = new Expression('3.0 * vec3(1, 2, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3, 6, 9));
+
+ expression = new Expression('vec4(1, 2, 3, 4) * vec4(3, 4, 5, 6)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3, 8, 15, 24));
+
+ expression = new Expression('vec4(1, 2, 3, 4) * 3.0');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3, 6, 9, 12));
+
+ expression = new Expression('3.0 * vec4(1, 2, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3, 6, 9, 12));
+
+ expression = new Expression('vec2(1, 2) / vec2(2, 5)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.5, 0.4));
+
+ expression = new Expression('vec2(1, 2) / 2.0');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.5, 1.0));
+
+ expression = new Expression('vec3(1, 2, 3) / vec3(2, 5, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.5, 0.4, 1.0));
+
+ expression = new Expression('vec3(1, 2, 3) / 2.0');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.5, 1.0, 1.5));
+
+ expression = new Expression('vec4(1, 2, 3, 4) / vec4(2, 5, 3, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.5, 0.4, 1.0, 2.0));
+
+ expression = new Expression('vec4(1, 2, 3, 4) / 2.0');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.5, 1.0, 1.5, 2.0));
+
+ expression = new Expression('vec2(2, 3) % vec2(3, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(2, 0));
+
+ expression = new Expression('vec3(2, 3, 4) % vec3(3, 3, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(2, 0, 1));
+
+ expression = new Expression('vec4(2, 3, 4, 5) % vec4(3, 3, 3, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2, 0, 1, 1));
+
+ expression = new Expression('vec2(1, 3) == vec2(1, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('vec3(1, 3, 4) == vec3(1, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('vec4(1, 3, 4, 6) == vec4(1, 3, 4, 6)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('vec2(1, 2) === vec2(1, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('vec3(1, 2, 3) === vec3(1, 2, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('vec4(1, 2, 3, 4) === vec4(1, 2, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('!!vec4(1.0) == true');
+ expect(expression.evaluate(frameState, undefined)).toEqual(true);
+
+ expression = new Expression('vec2(1, 2) != vec2(1, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
+
+ expression = new Expression('vec3(1, 2, 3) != vec3(1, 2, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
+
+ expression = new Expression('vec4(1, 2, 3, 4) != vec4(1, 2, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
+
+ expression = new Expression('vec2(1, 2) !== vec2(1, 2)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
+
+ expression = new Expression('vec3(1, 2, 3) !== vec3(1, 2, 3)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
+
+ expression = new Expression('vec4(1, 2, 3, 4) !== vec4(1, 2, 3, 4)');
+ expect(expression.evaluate(frameState, undefined)).toEqual(false);
});
it('evaluates color toString function', function() {
@@ -799,6 +1190,23 @@ defineSuite([
expect(expression.evaluate(frameState, feature)).toEqual('(0, 0, 1, 1)');
});
+ it('evaluates vector toString function', function() {
+ var feature = new MockFeature();
+ feature.addProperty('property', new Cartesian4(1, 2, 3, 4));
+
+ var expression = new Expression('vec2(1, 2).toString()');
+ expect(expression.evaluate(frameState, undefined)).toEqual('(1, 2)');
+
+ expression = new Expression('vec3(1, 2, 3).toString()');
+ expect(expression.evaluate(frameState, undefined)).toEqual('(1, 2, 3)');
+
+ expression = new Expression('vec4(1, 2, 3, 4).toString()');
+ expect(expression.evaluate(frameState, undefined)).toEqual('(1, 2, 3, 4)');
+
+ expression = new Expression('${property}.toString()');
+ expect(expression.evaluate(frameState, feature)).toEqual('(1, 2, 3, 4)');
+ });
+
it('evaluates isNaN function', function() {
var expression = new Expression('isNaN()');
expect(expression.evaluate(frameState, undefined)).toEqual(true);
@@ -1524,7 +1932,7 @@ defineSuite([
expect(expression.evaluate(frameState, feature)).toEqual(false);
});
- it('throws if test is not call with a RegExp', function() {
+ it('throws if test is not called with a RegExp', function() {
expect(function() {
return new Expression('color("blue").test()');
}).toThrowDeveloperError();
@@ -1780,12 +2188,12 @@ defineSuite([
it('gets shader expression for array indexing', function() {
var expression = new Expression('${property[0]}');
var shaderExpression = expression.getShaderExpression('', {});
- var expected = 'property[int(0.0)]';
+ var expected = 'property[0]';
expect(shaderExpression).toEqual(expected);
- expression = new Expression('rgb(0,0,0)[1]');
+ expression = new Expression('${property[4 / 2]}');
shaderExpression = expression.getShaderExpression('', {});
- expected = 'vec4(0.0, 0.0, 0.0, 1.0)[int(1.0)]';
+ expected = 'property[int((4.0 / 2.0))]';
expect(shaderExpression).toEqual(expected);
});
@@ -1944,6 +2352,55 @@ defineSuite([
expect(shaderState.translucent).toBe(true);
});
+ it('gets shader expression for color components', function() {
+ // .red, .green, .blue, .alpha
+ var expression = new Expression('color().red + color().green + color().blue + color().alpha');
+ var shaderExpression = expression.getShaderExpression('', {});
+ var expected = '(((vec4(1.0)[0] + vec4(1.0)[1]) + vec4(1.0)[2]) + vec4(1.0)[3])';
+ expect(shaderExpression).toEqual(expected);
+
+ // .x, .y, .z, .w
+ expression = new Expression('color().x + color().y + color().z + color().w');
+ shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual(expected);
+
+ // [0], [1], [2], [3]
+ expression = new Expression('color()[0] + color()[1] + color()[2] + color()[3]');
+ shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual(expected);
+ });
+
+ it('gets shader expression for vector', function() {
+ var expression = new Expression('vec4(1, 2, 3, 4)');
+ var shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual('vec4(1.0, 2.0, 3.0, 4.0)');
+
+ expression = new Expression('vec4(1) + vec4(2)');
+ shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual('(vec4(1.0) + vec4(2.0))');
+
+ expression = new Expression('vec4(1, ${property}, vec2(1, 2).x, 0)');
+ shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual('vec4(1.0, property, vec2(1.0, 2.0)[0], 0.0)');
+
+ expression = new Expression('vec4(vec3(2), 1.0)');
+ shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual('vec4(vec3(2.0), 1.0)');
+ });
+
+ it('gets shader expression for vector components', function() {
+ // .x, .y, .z, .w
+ var expression = new Expression('vec4(1).x + vec4(1).y + vec4(1).z + vec4(1).w');
+ var shaderExpression = expression.getShaderExpression('', {});
+ var expected = '(((vec4(1.0)[0] + vec4(1.0)[1]) + vec4(1.0)[2]) + vec4(1.0)[3])';
+ expect(shaderExpression).toEqual(expected);
+
+ // [0], [1], [2], [3]
+ expression = new Expression('vec4(1)[0] + vec4(1)[1] + vec4(1)[2] + vec4(1)[3]');
+ shaderExpression = expression.getShaderExpression('', {});
+ expect(shaderExpression).toEqual(expected);
+ });
+
it('gets shader expression for TILES3D_TILESET_TIME', function() {
var expression = new Expression('TILES3D_TILESET_TIME');
var shaderExpression = expression.getShaderExpression('', {});
diff --git a/Specs/Scene/FrustumCommandsSpec.js b/Specs/Scene/FrustumCommandsSpec.js
index 57bc636a5a0b..e3f5a7eb9afe 100644
--- a/Specs/Scene/FrustumCommandsSpec.js
+++ b/Specs/Scene/FrustumCommandsSpec.js
@@ -1,10 +1,10 @@
/*global defineSuite*/
defineSuite([
- 'Scene/FrustumCommands',
- 'Scene/Pass'
+ 'Renderer/Pass',
+ 'Scene/FrustumCommands'
], function(
- FrustumCommands,
- Pass) {
+ Pass,
+ FrustumCommands) {
'use strict';
it('constructs without arguments', function() {
diff --git a/Specs/Scene/GroundPrimitiveSpec.js b/Specs/Scene/GroundPrimitiveSpec.js
index a64916d714dc..4b46d3a7a17a 100644
--- a/Specs/Scene/GroundPrimitiveSpec.js
+++ b/Specs/Scene/GroundPrimitiveSpec.js
@@ -1,6 +1,5 @@
/*global defineSuite*/
defineSuite([
- 'Scene/GroundPrimitive',
'Core/Color',
'Core/ColorGeometryInstanceAttribute',
'Core/destroyObject',
@@ -13,13 +12,13 @@ defineSuite([
'Core/Rectangle',
'Core/RectangleGeometry',
'Core/ShowGeometryInstanceAttribute',
- 'Scene/Pass',
+ 'Renderer/Pass',
+ 'Scene/GroundPrimitive',
'Scene/PerInstanceColorAppearance',
'Scene/Primitive',
'Specs/createScene',
'Specs/pollToPromise'
], function(
- GroundPrimitive,
Color,
ColorGeometryInstanceAttribute,
destroyObject,
@@ -33,6 +32,7 @@ defineSuite([
RectangleGeometry,
ShowGeometryInstanceAttribute,
Pass,
+ GroundPrimitive,
PerInstanceColorAppearance,
Primitive,
createScene,
diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js
index a3c9496858ac..4593dc89358a 100644
--- a/Specs/Scene/ModelSpec.js
+++ b/Specs/Scene/ModelSpec.js
@@ -24,11 +24,11 @@ defineSuite([
'Core/PrimitiveType',
'Core/Transforms',
'Core/WebGLConstants',
+ 'Renderer/Pass',
'Renderer/RenderState',
'Renderer/ShaderSource',
'Scene/ColorBlendMode',
'Scene/HeightReference',
- 'Scene/Pass',
'Scene/ModelAnimationLoop',
'Specs/createScene',
'Specs/pollToPromise',
@@ -58,11 +58,11 @@ defineSuite([
PrimitiveType,
Transforms,
WebGLConstants,
+ Pass,
RenderState,
ShaderSource,
ColorBlendMode,
HeightReference,
- Pass,
ModelAnimationLoop,
createScene,
pollToPromise,
diff --git a/Specs/Scene/MultifrustumSpec.js b/Specs/Scene/MultifrustumSpec.js
index 7b0ff8a8f5c9..dfa07c5481fc 100644
--- a/Specs/Scene/MultifrustumSpec.js
+++ b/Specs/Scene/MultifrustumSpec.js
@@ -14,6 +14,7 @@ defineSuite([
'Core/Matrix4',
'Renderer/BufferUsage',
'Renderer/DrawCommand',
+ 'Renderer/Pass',
'Renderer/RenderState',
'Renderer/Sampler',
'Renderer/ShaderProgram',
@@ -22,7 +23,6 @@ defineSuite([
'Renderer/VertexArray',
'Scene/BillboardCollection',
'Scene/BlendingState',
- 'Scene/Pass',
'Scene/TextureAtlas',
'Specs/createScene',
'ThirdParty/when'
@@ -41,6 +41,7 @@ defineSuite([
Matrix4,
BufferUsage,
DrawCommand,
+ Pass,
RenderState,
Sampler,
ShaderProgram,
@@ -49,7 +50,6 @@ defineSuite([
VertexArray,
BillboardCollection,
BlendingState,
- Pass,
TextureAtlas,
createScene,
when) {
diff --git a/Specs/Scene/SceneSpec.js b/Specs/Scene/SceneSpec.js
index a4729f3cb711..b18de90eb279 100644
--- a/Specs/Scene/SceneSpec.js
+++ b/Specs/Scene/SceneSpec.js
@@ -16,6 +16,7 @@ defineSuite([
'Core/WebMercatorProjection',
'Renderer/DrawCommand',
'Renderer/Framebuffer',
+ 'Renderer/Pass',
'Renderer/PixelDatatype',
'Renderer/ShaderProgram',
'Renderer/Texture',
@@ -23,7 +24,6 @@ defineSuite([
'Scene/EllipsoidSurfaceAppearance',
'Scene/FrameState',
'Scene/Globe',
- 'Scene/Pass',
'Scene/Primitive',
'Scene/PrimitiveCollection',
'Scene/Scene',
@@ -51,6 +51,7 @@ defineSuite([
WebMercatorProjection,
DrawCommand,
Framebuffer,
+ Pass,
PixelDatatype,
ShaderProgram,
Texture,
@@ -58,7 +59,6 @@ defineSuite([
EllipsoidSurfaceAppearance,
FrameState,
Globe,
- Pass,
Primitive,
PrimitiveCollection,
Scene,
diff --git a/Specs/Widgets/Geocoder/GeocoderSpec.js b/Specs/Widgets/Geocoder/GeocoderSpec.js
index 484dfb350750..0b2bde8b24ad 100644
--- a/Specs/Widgets/Geocoder/GeocoderSpec.js
+++ b/Specs/Widgets/Geocoder/GeocoderSpec.js
@@ -1,13 +1,36 @@
/*global defineSuite*/
defineSuite([
'Widgets/Geocoder/Geocoder',
- 'Specs/createScene'
+ 'Core/Cartesian3',
+ 'Specs/createScene',
+ 'ThirdParty/when'
], function(
Geocoder,
- createScene) {
+ Cartesian3,
+ createScene,
+ when) {
'use strict';
var scene;
+
+ var mockDestination = new Cartesian3(1.0, 2.0, 3.0);
+ var geocoderResults = [{
+ displayName: 'a',
+ destination: mockDestination
+ }, {
+ displayName: 'b',
+ destination: mockDestination
+ }, {
+ displayName: 'c',
+ destination: mockDestination
+ }];
+
+ var customGeocoderOptions = {
+ autoComplete : true,
+ geocode : function (input) {
+ return when.resolve(geocoderResults);
+ }
+ };
beforeEach(function() {
scene = createScene();
});
@@ -80,4 +103,33 @@ defineSuite([
});
}).toThrowDeveloperError();
});
+
+ it('automatic suggestions can be navigated by arrow up/down keys', function() {
+ var container = document.createElement('div');
+ container.id = 'testContainer';
+ document.body.appendChild(container);
+ var geocoder = new Geocoder({
+ container : 'testContainer',
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
+ });
+ var viewModel = geocoder._viewModel;
+ viewModel._searchText = 'some_text';
+ viewModel._updateSearchSuggestions(viewModel);
+
+ expect(viewModel._selectedSuggestion).toEqual(undefined);
+ viewModel._handleArrowDown(viewModel);
+ expect(viewModel._selectedSuggestion.displayName).toEqual('a');
+ viewModel._handleArrowDown(viewModel);
+ viewModel._handleArrowDown(viewModel);
+ expect(viewModel._selectedSuggestion.displayName).toEqual('c');
+ viewModel._handleArrowDown(viewModel);
+ expect(viewModel._selectedSuggestion.displayName).toEqual('a');
+ viewModel._handleArrowDown(viewModel);
+ viewModel._handleArrowUp(viewModel);
+ expect(viewModel._selectedSuggestion.displayName).toEqual('a');
+ viewModel._handleArrowUp(viewModel);
+ expect(viewModel._selectedSuggestion).toBeUndefined();
+ });
+
}, 'WebGL');
diff --git a/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js b/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js
index 3df6917aad7d..442e7dd9ded2 100644
--- a/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js
+++ b/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js
@@ -4,16 +4,55 @@ defineSuite([
'Core/Cartesian3',
'Scene/Camera',
'Specs/createScene',
- 'Specs/pollToPromise'
+ 'Specs/pollToPromise',
+ 'ThirdParty/when'
], function(
GeocoderViewModel,
Cartesian3,
Camera,
createScene,
- pollToPromise) {
+ pollToPromise,
+ when) {
'use strict';
var scene;
+ var mockDestination = new Cartesian3(1.0, 2.0, 3.0);
+
+ var geocoderResults1 = [{
+ displayName: 'a',
+ destination: mockDestination
+ }, {
+ displayName: 'b',
+ destination: mockDestination
+ }];
+ var customGeocoderOptions = {
+ autoComplete: true,
+ geocode: function (input) {
+ return when.resolve(geocoderResults1);
+ }
+ };
+
+ var geocoderResults2 = [{
+ displayName: '1',
+ destination: mockDestination
+ }, {
+ displayName: '2',
+ destination: mockDestination
+ }];
+ var customGeocoderOptions2 = {
+ autoComplete: true,
+ geocode: function (input) {
+ return when.resolve(geocoderResults2);
+ }
+ };
+
+ var noResultsGeocoder = {
+ autoComplete: true,
+ geocode: function (input) {
+ return when.resolve([]);
+ }
+ };
+
beforeAll(function() {
scene = createScene();
});
@@ -55,7 +94,8 @@ defineSuite([
it('throws is searchText is not a string', function() {
var viewModel = new GeocoderViewModel({
- scene : scene
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
});
expect(function() {
viewModel.searchText = undefined;
@@ -64,7 +104,8 @@ defineSuite([
it('moves camera when search command invoked', function() {
var viewModel = new GeocoderViewModel({
- scene : scene
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
});
var cameraPosition = Cartesian3.clone(scene.camera.position);
@@ -78,27 +119,6 @@ defineSuite([
});
});
- it('Zooms to longitude, latitude, height', function() {
- var viewModel = new GeocoderViewModel({
- scene : scene
- });
-
- spyOn(Camera.prototype, 'flyTo');
-
- viewModel.searchText = ' 1.0, 2.0, 3.0 ';
- viewModel.search();
- expect(Camera.prototype.flyTo).toHaveBeenCalled();
- expect(Camera.prototype.flyTo.calls.mostRecent().args[0].destination).toEqual(Cartesian3.fromDegrees(1.0, 2.0, 3.0));
-
- viewModel.searchText = '1.0 2.0 3.0';
- viewModel.search();
- expect(Camera.prototype.flyTo.calls.mostRecent().args[0].destination).toEqual(Cartesian3.fromDegrees(1.0, 2.0, 3.0));
-
- viewModel.searchText = '-1.0, -2.0';
- viewModel.search();
- expect(Camera.prototype.flyTo.calls.mostRecent().args[0].destination).toEqual(Cartesian3.fromDegrees(-1.0, -2.0, 300.0));
- });
-
it('constructor throws without scene', function() {
expect(function() {
return new GeocoderViewModel();
@@ -108,7 +128,8 @@ defineSuite([
it('raises the complete event camera finished', function() {
var viewModel = new GeocoderViewModel({
scene : scene,
- flightDuration : 0
+ flightDuration : 0,
+ geocoderServices : [customGeocoderOptions]
});
var spyListener = jasmine.createSpy('listener');
@@ -120,7 +141,7 @@ defineSuite([
expect(spyListener.calls.count()).toBe(1);
viewModel.flightDuration = 1.5;
- viewModel.serachText = '2.0, 2.0';
+ viewModel.searchText = '2.0, 2.0';
viewModel.search();
return pollToPromise(function() {
@@ -128,4 +149,73 @@ defineSuite([
return spyListener.calls.count() === 2;
});
});
+
+ it('can be created with a custom geocoder', function() {
+ expect(function() {
+ return new GeocoderViewModel({
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
+ });
+ }).not.toThrowDeveloperError();
+ });
+
+ it('automatic suggestions can be retrieved', function() {
+ var geocoder = new GeocoderViewModel({
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
+ });
+ geocoder._searchText = 'some_text';
+ geocoder._updateSearchSuggestions(geocoder);
+ expect(geocoder._suggestions.length).toEqual(2);
+ });
+
+ it('update search suggestions results in empty list if the query is empty', function() {
+ var geocoder = new GeocoderViewModel({
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
+ });
+ geocoder._searchText = '';
+ spyOn(geocoder, '_adjustSuggestionsScroll');
+ geocoder._updateSearchSuggestions(geocoder);
+ expect(geocoder._suggestions.length).toEqual(0);
+ });
+
+ it('can activate selected search suggestion', function () {
+ var geocoder = new GeocoderViewModel({
+ scene : scene,
+ geocoderServices : [customGeocoderOptions]
+ });
+ spyOn(geocoder, '_updateCamera');
+ spyOn(geocoder, '_adjustSuggestionsScroll');
+
+ var suggestion = {displayName: 'a', destination: {west: 0.0, east: 0.1, north: 0.1, south: -0.1}};
+ geocoder._selectedSuggestion = suggestion;
+ geocoder.activateSuggestion(suggestion);
+ expect(geocoder._searchText).toEqual('a');
+ });
+
+ it('if more than one geocoder service is provided, use first result from first geocode in array order', function () {
+ var geocoder = new GeocoderViewModel({
+ scene : scene,
+ geocoderServices : [noResultsGeocoder, customGeocoderOptions2]
+ });
+ geocoder._searchText = 'sthsnth'; // an empty query will prevent geocoding
+ spyOn(geocoder, '_updateCamera');
+ spyOn(geocoder, '_adjustSuggestionsScroll');
+ geocoder.search();
+ expect(geocoder._searchText).toEqual(geocoderResults2[0].displayName);
+ });
+
+ it('can update autoComplete suggestions list using multiple geocoders', function () {
+ var geocoder = new GeocoderViewModel({
+ scene : scene,
+ geocoderServices : [customGeocoderOptions, customGeocoderOptions2]
+ });
+ geocoder._searchText = 'sthsnth'; // an empty query will prevent geocoding
+ spyOn(geocoder, '_updateCamera');
+ spyOn(geocoder, '_adjustSuggestionsScroll');
+ geocoder._updateSearchSuggestions(geocoder);
+ expect(geocoder._suggestions.length).toEqual(geocoderResults1.length + geocoderResults2.length);
+ });
+
}, 'WebGL');
diff --git a/Specs/pick.js b/Specs/pick.js
index 409a28f8549f..711798051a7d 100644
--- a/Specs/pick.js
+++ b/Specs/pick.js
@@ -4,19 +4,19 @@ define([
'Core/Color',
'Core/defined',
'Renderer/ClearCommand',
+ 'Renderer/Pass',
'Scene/CreditDisplay',
'Scene/FrameState',
- 'Scene/JobScheduler',
- 'Scene/Pass'
+ 'Scene/JobScheduler'
], function(
BoundingRectangle,
Color,
defined,
ClearCommand,
+ Pass,
CreditDisplay,
FrameState,
- JobScheduler,
- Pass) {
+ JobScheduler) {
'use strict';
function executeCommands(context, passState, commands) {
diff --git a/Specs/render.js b/Specs/render.js
index ed2caf3d0346..d239ed626176 100644
--- a/Specs/render.js
+++ b/Specs/render.js
@@ -2,7 +2,7 @@
define([
'Core/defined',
'Core/Intersect',
- 'Scene/Pass',
+ 'Renderer/Pass',
'Scene/SceneMode'
], function(
defined,
diff --git a/package.json b/package.json
index 1bce15dbaa92..c5df42eebcee 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "cesium",
- "version": "1.28.0",
+ "version": "1.29.0",
"description": "Cesium is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.",
"homepage": "http://cesiumjs.org",
"license": "Apache-2.0",