diff --git a/Apps/Sandcastle/gallery/Geometry Height Reference.html b/Apps/Sandcastle/gallery/Geometry Height Reference.html
new file mode 100644
index 000000000000..affc60edc5a0
--- /dev/null
+++ b/Apps/Sandcastle/gallery/Geometry Height Reference.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+ Cesium Demo
+
+
+
+
+
+
+
+Loading...
+
+
+
+
diff --git a/Apps/Sandcastle/gallery/Geometry Height Reference.jpg b/Apps/Sandcastle/gallery/Geometry Height Reference.jpg
new file mode 100644
index 000000000000..054d09cbc2e4
Binary files /dev/null and b/Apps/Sandcastle/gallery/Geometry Height Reference.jpg differ
diff --git a/CHANGES.md b/CHANGES.md
index 04cd837bf343..546089ba1afc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -14,9 +14,12 @@ Change Log
* Requires depth texture support (`WEBGL_depth_texture` or `WEBKIT_WEBGL_depth_texture`), otherwise `clampToGround` will be ignored. Use `Entity.supportsPolylinesOnTerrain` to check for support.
* Added `GroundPolylinePrimitive` and `GroundPolylineGeometry`.
* `PostProcessStage` has a `selected` property which is an array of primitives used for selectively applying a post-process stage. [#6476](https://github.com/AnalyticalGraphicsInc/cesium/pull/6476)
- * The `PostProcessStageLibrary.createBlackAndWhiteStage` and `PostProcessStageLibrary.createSilhouetteStage` have per-feature support.
+ * The `PostProcessStageLibrary.createBlackAndWhiteStage` and `PostProcessStageLibrary.createSilhouetteStage` have per-feature support.
* Added CZML support for `zIndex` for `corridor`, `ellipse`, `polygon`, `polyline` and `rectangle`. [#6708](https://github.com/AnalyticalGraphicsInc/cesium/pull/6708)
* Added CZML `clampToGround` option for `polyline`. [#6706](https://github.com/AnalyticalGraphicsInc/cesium/pull/6706)
+* Added `heightReference` and `extrudedHeightReference` properties to `CorridorGraphics`, `EllipseGraphics`, `PolygonGraphics` and `RectangleGraphics`. [#6717](https://github.com/AnalyticalGraphicsInc/cesium/pull/6717)
+ * This can be used in conjunction with the `height` and/or `extrudedHeight` properties to clamp the geometry to terrain or set the height relative to terrain.
+ * Note, this will not make the geometry conform to terrain. Extruded geoemtry that is clamped to the ground will have a flat top will sinks into the terrain at the base.
##### Fixes :wrench:
* Fixed a bug that caused Cesium to be unable to load local resources in Electron. [#6726](https://github.com/AnalyticalGraphicsInc/cesium/pull/6726)
diff --git a/Source/DataSources/CorridorGeometryUpdater.js b/Source/DataSources/CorridorGeometryUpdater.js
index ab1eef75de9b..69a6a65ac7f3 100644
--- a/Source/DataSources/CorridorGeometryUpdater.js
+++ b/Source/DataSources/CorridorGeometryUpdater.js
@@ -1,4 +1,6 @@
define([
+ '../Core/ApproximateTerrainHeights',
+ '../Core/Cartesian3',
'../Core/Check',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
@@ -8,9 +10,13 @@ define([
'../Core/DeveloperError',
'../Core/DistanceDisplayConditionGeometryInstanceAttribute',
'../Core/GeometryInstance',
+ '../Core/GeometryOffsetAttribute',
'../Core/Iso8601',
+ '../Core/OffsetGeometryInstanceAttribute',
+ '../Core/Rectangle',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/GroundPrimitive',
+ '../Scene/HeightReference',
'../Scene/MaterialAppearance',
'../Scene/PerInstanceColorAppearance',
'./ColorMaterialProperty',
@@ -19,6 +25,8 @@ define([
'./GroundGeometryUpdater',
'./Property'
], function(
+ ApproximateTerrainHeights,
+ Cartesian3,
Check,
Color,
ColorGeometryInstanceAttribute,
@@ -28,9 +36,13 @@ define([
DeveloperError,
DistanceDisplayConditionGeometryInstanceAttribute,
GeometryInstance,
+ GeometryOffsetAttribute,
Iso8601,
+ OffsetGeometryInstanceAttribute,
+ Rectangle,
ShowGeometryInstanceAttribute,
GroundPrimitive,
+ HeightReference,
MaterialAppearance,
PerInstanceColorAppearance,
ColorMaterialProperty,
@@ -41,6 +53,9 @@ define([
'use strict';
var scratchColor = new Color();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
+ var scratchRectangle = new Rectangle();
function CorridorGeometryOptions(entity) {
this.id = entity;
@@ -51,6 +66,7 @@ define([
this.height = undefined;
this.extrudedHeight = undefined;
this.granularity = undefined;
+ this.offsetAttribute = undefined;
}
/**
@@ -99,11 +115,13 @@ define([
var entity = this._entity;
var isAvailable = entity.isAvailable(time);
- var attributes;
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time)),
+ offset : undefined,
+ color : undefined
+ };
- var color;
- var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
- var distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time));
if (this._materialProperty instanceof ColorMaterialProperty) {
var currentColor;
if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
@@ -112,17 +130,11 @@ define([
if (!defined(currentColor)) {
currentColor = Color.WHITE;
}
- color = ColorGeometryInstanceAttribute.fromColor(currentColor);
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayCondition,
- color : color
- };
- } else {
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayCondition
- };
+ attributes.color = ColorGeometryInstanceAttribute.fromColor(currentColor);
+ }
+
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
}
return new GeometryInstance({
@@ -153,19 +165,34 @@ define([
var isAvailable = entity.isAvailable(time);
var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor);
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
+ color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time)),
+ offset : undefined
+ };
+
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
+ }
+
return new GeometryInstance({
id : entity,
geometry : new CorridorOutlineGeometry(this._options),
- attributes : {
- show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
- color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
- distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time))
- }
+ attributes : attributes
});
};
+ CorridorGeometryUpdater.prototype._computeCenter = function(time, result) {
+ var positions = Property.getValueOrUndefined(this._entity.corridor.positions, time);
+ if (!defined(positions) || positions.length === 0) {
+ return;
+ }
+ return Cartesian3.clone(positions[Math.floor(positions.length / 2.0)], result);
+ };
+
CorridorGeometryUpdater.prototype._isHidden = function(entity, corridor) {
- return !defined(corridor.positions) || GeometryUpdater.prototype._isHidden.call(this, entity, corridor);
+ return !defined(corridor.positions) || !defined(corridor.width) || GeometryUpdater.prototype._isHidden.call(this, entity, corridor);
};
CorridorGeometryUpdater.prototype._isOnTerrain = function(entity, corridor) {
@@ -193,20 +220,25 @@ define([
CorridorGeometryUpdater.prototype._setStaticOptions = function(entity, corridor) {
var height = corridor.height;
+ var heightReference = corridor.heightReference;
var extrudedHeight = corridor.extrudedHeight;
- var granularity = corridor.granularity;
- var width = corridor.width;
- var cornerType = corridor.cornerType;
- var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty;
+ var extrudedHeightReference = corridor.extrudedHeightReference;
var options = this._options;
- options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
+ options.vertexFormat = (this._materialProperty instanceof ColorMaterialProperty) ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
options.positions = corridor.positions.getValue(Iso8601.MINIMUM_VALUE, options.positions);
- options.height = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.extrudedHeight = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.width = defined(width) ? width.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.cornerType = defined(cornerType) ? cornerType.getValue(Iso8601.MINIMUM_VALUE) : undefined;
+ options.width = corridor.width.getValue(Iso8601.MINIMUM_VALUE);
+ options.granularity = Property.getValueOrUndefined(corridor.granularity, Iso8601.MINIMUM_VALUE);
+ options.cornerType = Property.getValueOrUndefined(corridor.cornerType, Iso8601.MINIMUM_VALUE);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ options.height = GroundGeometryUpdater.getGeometryHeight(height, heightReference, Iso8601.MINIMUM_VALUE);
+
+ var extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(CorridorGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
CorridorGeometryUpdater.DynamicGeometryUpdater = DynamicCorridorGeometryUpdater;
@@ -230,12 +262,24 @@ define([
DynamicCorridorGeometryUpdater.prototype._setOptions = function(entity, corridor, time) {
var options = this._options;
+ var height = corridor.height;
+ var heightReference = corridor.heightReference;
+ var extrudedHeight = corridor.extrudedHeight;
+ var extrudedHeightReference = corridor.extrudedHeightReference;
+
options.positions = Property.getValueOrUndefined(corridor.positions, time);
options.width = Property.getValueOrUndefined(corridor.width, time);
- options.height = Property.getValueOrUndefined(corridor.height, time);
- options.extrudedHeight = Property.getValueOrUndefined(corridor.extrudedHeight, time);
options.granularity = Property.getValueOrUndefined(corridor.granularity, time);
options.cornerType = Property.getValueOrUndefined(corridor.cornerType, time);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ options.height = GroundGeometryUpdater.getGeometryHeight(height, heightReference, time);
+
+ var extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, time);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(CorridorGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
return CorridorGeometryUpdater;
diff --git a/Source/DataSources/CorridorGraphics.js b/Source/DataSources/CorridorGraphics.js
index a1a7e3e9c8b5..268f4e7da314 100644
--- a/Source/DataSources/CorridorGraphics.js
+++ b/Source/DataSources/CorridorGraphics.js
@@ -29,7 +29,9 @@ define([
* @param {Property} [options.width] A numeric Property specifying the distance between the edges of the corridor.
* @param {Property} [options.cornerType=CornerType.ROUNDED] A {@link CornerType} Property specifying the style of the corners.
* @param {Property} [options.height=0] A numeric Property specifying the altitude of the corridor relative to the ellipsoid surface.
+ * @param {Property} [options.heightReference] A Property specifying what the height is relative to.
* @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the corridor's extruded face relative to the ellipsoid surface.
+ * @param {Property} [options.extrudedHeightReference] A Property specifying what the extrudedHeight is relative to.
* @param {Property} [options.show=true] A boolean Property specifying the visibility of the corridor.
* @param {Property} [options.fill=true] A boolean Property specifying whether the corridor is filled with the provided material.
* @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the corridor.
@@ -53,8 +55,12 @@ define([
this._positionsSubscription = undefined;
this._height = undefined;
this._heightSubscription = undefined;
+ this._heightReference = undefined;
+ this._heightReferenceSubscription = undefined;
this._extrudedHeight = undefined;
this._extrudedHeightSubscription = undefined;
+ this._extrudedHeightReference = undefined;
+ this._extrudedHeightReferenceSubscription = undefined;
this._granularity = undefined;
this._granularitySubscription = undefined;
this._width = undefined;
@@ -126,6 +132,14 @@ define([
*/
height : createPropertyDescriptor('height'),
+ /**
+ * Gets or sets the Property specifying the {@link HeightReference}.
+ * @memberof CorridorGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ heightReference : createPropertyDescriptor('heightReference'),
+
/**
* Gets or sets the numeric Property specifying the altitude of the corridor extrusion.
* Setting this property creates a corridor shaped volume starting at height and ending
@@ -135,6 +149,14 @@ define([
*/
extrudedHeight : createPropertyDescriptor('extrudedHeight'),
+ /**
+ * Gets or sets the Property specifying the extruded {@link HeightReference}.
+ * @memberof CorridorGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ extrudedHeightReference : createPropertyDescriptor('extrudedHeightReference'),
+
/**
* Gets or sets the numeric Property specifying the sampling distance between each latitude and longitude point.
* @memberof CorridorGraphics.prototype
@@ -237,7 +259,9 @@ define([
result.material = this.material;
result.positions = this.positions;
result.height = this.height;
+ result.heightReference = this.heightReference;
result.extrudedHeight = this.extrudedHeight;
+ result.extrudedHeightReference = this.extrudedHeightReference;
result.granularity = this.granularity;
result.width = this.width;
result.fill = this.fill;
@@ -269,7 +293,9 @@ define([
this.material = defaultValue(this.material, source.material);
this.positions = defaultValue(this.positions, source.positions);
this.height = defaultValue(this.height, source.height);
+ this.heightReference = defaultValue(this.heightReference, source.heightReference);
this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
+ this.extrudedHeightReference = defaultValue(this.extrudedHeightReference, source.extrudedHeightReference);
this.granularity = defaultValue(this.granularity, source.granularity);
this.width = defaultValue(this.width, source.width);
this.fill = defaultValue(this.fill, source.fill);
diff --git a/Source/DataSources/EllipseGeometryUpdater.js b/Source/DataSources/EllipseGeometryUpdater.js
index b577e28981ba..30fe5088f920 100644
--- a/Source/DataSources/EllipseGeometryUpdater.js
+++ b/Source/DataSources/EllipseGeometryUpdater.js
@@ -1,4 +1,6 @@
define([
+ '../Core/ApproximateTerrainHeights',
+ '../Core/Cartesian3',
'../Core/Check',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
@@ -8,9 +10,13 @@ define([
'../Core/EllipseGeometry',
'../Core/EllipseOutlineGeometry',
'../Core/GeometryInstance',
+ '../Core/GeometryOffsetAttribute',
'../Core/Iso8601',
+ '../Core/OffsetGeometryInstanceAttribute',
+ '../Core/Rectangle',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/GroundPrimitive',
+ '../Scene/HeightReference',
'../Scene/MaterialAppearance',
'../Scene/PerInstanceColorAppearance',
'./ColorMaterialProperty',
@@ -19,6 +25,8 @@ define([
'./GroundGeometryUpdater',
'./Property'
], function(
+ ApproximateTerrainHeights,
+ Cartesian3,
Check,
Color,
ColorGeometryInstanceAttribute,
@@ -28,9 +36,13 @@ define([
EllipseGeometry,
EllipseOutlineGeometry,
GeometryInstance,
+ GeometryOffsetAttribute,
Iso8601,
+ OffsetGeometryInstanceAttribute,
+ Rectangle,
ShowGeometryInstanceAttribute,
GroundPrimitive,
+ HeightReference,
MaterialAppearance,
PerInstanceColorAppearance,
ColorMaterialProperty,
@@ -41,6 +53,9 @@ define([
'use strict';
var scratchColor = new Color();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
+ var scratchRectangle = new Rectangle();
function EllipseGeometryOptions(entity) {
this.id = entity;
@@ -54,6 +69,7 @@ define([
this.granularity = undefined;
this.stRotation = undefined;
this.numberOfVerticalLines = undefined;
+ this.offsetAttribute = undefined;
}
/**
@@ -102,12 +118,13 @@ define([
var entity = this._entity;
var isAvailable = entity.isAvailable(time);
- var attributes;
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time)),
+ offset : undefined,
+ color : undefined
+ };
- var color;
- var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
- var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
- var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
if (this._materialProperty instanceof ColorMaterialProperty) {
var currentColor;
if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
@@ -116,17 +133,11 @@ define([
if (!defined(currentColor)) {
currentColor = Color.WHITE;
}
- color = ColorGeometryInstanceAttribute.fromColor(currentColor);
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayConditionAttribute,
- color : color
- };
- } else {
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayConditionAttribute
- };
+ attributes.color = ColorGeometryInstanceAttribute.fromColor(currentColor);
+ }
+
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
}
return new GeometryInstance({
@@ -158,17 +169,28 @@ define([
var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor);
var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
+ color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition),
+ offset : undefined
+ };
+
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
+ }
+
return new GeometryInstance({
id : entity,
geometry : new EllipseOutlineGeometry(this._options),
- attributes : {
- show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
- color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
- distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
- }
+ attributes : attributes
});
};
+ EllipseGeometryUpdater.prototype._computeCenter = function(time, result) {
+ return Property.getValueOrUndefined(this._entity.position, time, result);
+ };
+
EllipseGeometryUpdater.prototype._isHidden = function(entity, ellipse) {
var position = entity.position;
@@ -201,25 +223,29 @@ define([
};
EllipseGeometryUpdater.prototype._setStaticOptions = function(entity, ellipse) {
- var rotation = ellipse.rotation;
var height = ellipse.height;
+ var heightReference = ellipse.heightReference;
var extrudedHeight = ellipse.extrudedHeight;
- var granularity = ellipse.granularity;
- var stRotation = ellipse.stRotation;
- var numberOfVerticalLines = ellipse.numberOfVerticalLines;
- var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty;
+ var extrudedHeightReference = ellipse.extrudedHeightReference;
var options = this._options;
- options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
+ options.vertexFormat = (this._materialProperty instanceof ColorMaterialProperty) ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
options.center = entity.position.getValue(Iso8601.MINIMUM_VALUE, options.center);
options.semiMajorAxis = ellipse.semiMajorAxis.getValue(Iso8601.MINIMUM_VALUE, options.semiMajorAxis);
options.semiMinorAxis = ellipse.semiMinorAxis.getValue(Iso8601.MINIMUM_VALUE, options.semiMinorAxis);
- options.rotation = defined(rotation) ? rotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.height = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.extrudedHeight = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.stRotation = defined(stRotation) ? stRotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.numberOfVerticalLines = defined(numberOfVerticalLines) ? numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE) : undefined;
+ options.rotation = Property.getValueOrUndefined(ellipse.rotation, Iso8601.MINIMUM_VALUE);
+ options.granularity = Property.getValueOrUndefined(ellipse.granularity, Iso8601.MINIMUM_VALUE);
+ options.stRotation = Property.getValueOrUndefined(ellipse.stRotation, Iso8601.MINIMUM_VALUE);
+ options.numberOfVerticalLines = Property.getValueOrUndefined(ellipse.numberOfVerticalLines, Iso8601.MINIMUM_VALUE);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ options.height = GroundGeometryUpdater.getGeometryHeight(height, heightReference, Iso8601.MINIMUM_VALUE);
+
+ var extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(EllipseGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
EllipseGeometryUpdater.DynamicGeometryUpdater = DynamicEllipseGeometryUpdater;
@@ -243,15 +269,27 @@ define([
DynamicEllipseGeometryUpdater.prototype._setOptions = function(entity, ellipse, time) {
var options = this._options;
+ var height = ellipse.height;
+ var heightReference = ellipse.heightReference;
+ var extrudedHeight = ellipse.extrudedHeight;
+ var extrudedHeightReference = ellipse.extrudedHeightReference;
+
options.center = Property.getValueOrUndefined(entity.position, time, options.center);
options.semiMajorAxis = Property.getValueOrUndefined(ellipse.semiMajorAxis, time);
options.semiMinorAxis = Property.getValueOrUndefined(ellipse.semiMinorAxis, time);
options.rotation = Property.getValueOrUndefined(ellipse.rotation, time);
- options.height = Property.getValueOrUndefined(ellipse.height, time);
- options.extrudedHeight = Property.getValueOrUndefined(ellipse.extrudedHeight, time);
options.granularity = Property.getValueOrUndefined(ellipse.granularity, time);
options.stRotation = Property.getValueOrUndefined(ellipse.stRotation, time);
options.numberOfVerticalLines = Property.getValueOrUndefined(ellipse.numberOfVerticalLines, time);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ options.height = GroundGeometryUpdater.getGeometryHeight(height, heightReference, time);
+
+ var extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, time);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(EllipseGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
return EllipseGeometryUpdater;
diff --git a/Source/DataSources/EllipseGraphics.js b/Source/DataSources/EllipseGraphics.js
index bdb5e5f99fd0..c120ffc691c1 100644
--- a/Source/DataSources/EllipseGraphics.js
+++ b/Source/DataSources/EllipseGraphics.js
@@ -29,7 +29,9 @@ define([
* @param {Property} [options.semiMajorAxis] The numeric Property specifying the semi-major axis.
* @param {Property} [options.semiMinorAxis] The numeric Property specifying the semi-minor axis.
* @param {Property} [options.height=0] A numeric Property specifying the altitude of the ellipse relative to the ellipsoid surface.
+ * @param {Property} [options.heightReference] A Property specifying what the height is relative to.
* @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the ellipse's extruded face relative to the ellipsoid surface.
+ * @param {Property} [options.extrudedHeightReference] A Property specifying what the extrudedHeight is relative to.
* @param {Property} [options.show=true] A boolean Property specifying the visibility of the ellipse.
* @param {Property} [options.fill=true] A boolean Property specifying whether the ellipse is filled with the provided material.
* @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the ellipse.
@@ -59,8 +61,12 @@ define([
this._materialSubscription = undefined;
this._height = undefined;
this._heightSubscription = undefined;
+ this._heightReference = undefined;
+ this._heightReferenceSubscription = undefined;
this._extrudedHeight = undefined;
this._extrudedHeightSubscription = undefined;
+ this._extrudedHeightReference = undefined;
+ this._extrudedHeightReferenceSubscription = undefined;
this._granularity = undefined;
this._granularitySubscription = undefined;
this._stRotation = undefined;
@@ -148,6 +154,14 @@ define([
*/
height : createPropertyDescriptor('height'),
+ /**
+ * Gets or sets the Property specifying the {@link HeightReference}.
+ * @memberof EllipseGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ heightReference : createPropertyDescriptor('heightReference'),
+
/**
* Gets or sets the numeric Property specifying the altitude of the ellipse extrusion.
* Setting this property creates volume starting at height and ending at this altitude.
@@ -156,6 +170,14 @@ define([
*/
extrudedHeight : createPropertyDescriptor('extrudedHeight'),
+ /**
+ * Gets or sets the Property specifying the extruded {@link HeightReference}.
+ * @memberof EllipseGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ extrudedHeightReference : createPropertyDescriptor('extrudedHeightReference'),
+
/**
* Gets or sets the numeric Property specifying the angular distance between points on the ellipse.
* @memberof EllipseGraphics.prototype
@@ -261,7 +283,9 @@ define([
result.show = this.show;
result.material = this.material;
result.height = this.height;
+ result.heightReference = this.heightReference;
result.extrudedHeight = this.extrudedHeight;
+ result.extrudedHeightReference = this.extrudedHeightReference;
result.granularity = this.granularity;
result.stRotation = this.stRotation;
result.fill = this.fill;
@@ -295,7 +319,9 @@ define([
this.show = defaultValue(this.show, source.show);
this.material = defaultValue(this.material, source.material);
this.height = defaultValue(this.height, source.height);
+ this.heightReference = defaultValue(this.heightReference, source.heightReference);
this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
+ this.extrudedHeightReference = defaultValue(this.extrudedHeightReference, source.extrudedHeightReference);
this.granularity = defaultValue(this.granularity, source.granularity);
this.stRotation = defaultValue(this.stRotation, source.stRotation);
this.fill = defaultValue(this.fill, source.fill);
diff --git a/Source/DataSources/GeometryVisualizer.js b/Source/DataSources/GeometryVisualizer.js
index 9ea93859248f..2f70c1eb260a 100644
--- a/Source/DataSources/GeometryVisualizer.js
+++ b/Source/DataSources/GeometryVisualizer.js
@@ -142,23 +142,31 @@ define([
this._changedObjects = new AssociativeArray();
var numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
- this._outlineBatches = new Array(numberOfShadowModes);
- this._closedColorBatches = new Array(numberOfShadowModes);
- this._closedMaterialBatches = new Array(numberOfShadowModes);
- this._openColorBatches = new Array(numberOfShadowModes);
- this._openMaterialBatches = new Array(numberOfShadowModes);
+ this._outlineBatches = new Array(numberOfShadowModes*2);
+ this._closedColorBatches = new Array(numberOfShadowModes*2);
+ this._closedMaterialBatches = new Array(numberOfShadowModes*2);
+ this._openColorBatches = new Array(numberOfShadowModes*2);
+ this._openMaterialBatches = new Array(numberOfShadowModes*2);
var supportsMaterialsforEntitiesOnTerrain = Entity.supportsMaterialsforEntitiesOnTerrain(scene);
this._supportsMaterialsforEntitiesOnTerrain = supportsMaterialsforEntitiesOnTerrain;
var i;
for (i = 0; i < numberOfShadowModes; ++i) {
- this._outlineBatches[i] = new StaticOutlineGeometryBatch(primitives, scene, i);
+ this._outlineBatches[i] = new StaticOutlineGeometryBatch(primitives, scene, i, false);
+ this._outlineBatches[numberOfShadowModes + i] = new StaticOutlineGeometryBatch(primitives, scene, i, true);
- this._closedColorBatches[i] = new StaticGeometryColorBatch(primitives, PerInstanceColorAppearance, undefined, true, i);
- this._closedMaterialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, MaterialAppearance, undefined, true, i);
- this._openColorBatches[i] = new StaticGeometryColorBatch(primitives, PerInstanceColorAppearance, undefined, false, i);
- this._openMaterialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, MaterialAppearance, undefined, false, i);
+ this._closedColorBatches[i] = new StaticGeometryColorBatch(primitives, PerInstanceColorAppearance, undefined, true, i, true);
+ this._closedColorBatches[numberOfShadowModes + i] = new StaticGeometryColorBatch(primitives, PerInstanceColorAppearance, undefined, true, i, false);
+
+ this._closedMaterialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, MaterialAppearance, undefined, true, i, true);
+ this._closedMaterialBatches[numberOfShadowModes + i] = new StaticGeometryPerMaterialBatch(primitives, MaterialAppearance, undefined, true, i, false);
+
+ this._openColorBatches[i] = new StaticGeometryColorBatch(primitives, PerInstanceColorAppearance, undefined, false, i, true);
+ this._openColorBatches[numberOfShadowModes + i] = new StaticGeometryColorBatch(primitives, PerInstanceColorAppearance, undefined, false, i, false);
+
+ this._openMaterialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, MaterialAppearance, undefined, false, i, true);
+ this._openMaterialBatches[numberOfShadowModes + i] = new StaticGeometryPerMaterialBatch(primitives, MaterialAppearance, undefined, false, i, false);
}
var numberOfClassificationTypes = ClassificationType.NUMBER_OF_CLASSIFICATION_TYPES;
@@ -390,8 +398,13 @@ define([
shadows = updater.shadowsProperty.getValue(time);
}
+ var numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
if (updater.outlineEnabled) {
- this._outlineBatches[shadows].add(time, updater);
+ if (defined(updater.terrainOffsetProperty)) {
+ this._outlineBatches[numberOfShadowModes + shadows].add(time, updater);
+ } else {
+ this._outlineBatches[shadows].add(time, updater);
+ }
}
if (updater.fillEnabled) {
@@ -408,12 +421,24 @@ define([
}
} else if (updater.isClosed) {
if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
- this._closedColorBatches[shadows].add(time, updater);
+ if (defined(updater.terrainOffsetProperty)) {
+ this._closedColorBatches[numberOfShadowModes + shadows].add(time, updater);
+ } else {
+ this._closedColorBatches[shadows].add(time, updater);
+ }
+ } else if (defined(updater.terrainOffsetProperty)) {
+ this._closedMaterialBatches[numberOfShadowModes + shadows].add(time, updater);
} else {
this._closedMaterialBatches[shadows].add(time, updater);
}
} else if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
- this._openColorBatches[shadows].add(time, updater);
+ if (defined(updater.terrainOffsetProperty)) {
+ this._openColorBatches[numberOfShadowModes + shadows].add(time, updater);
+ } else {
+ this._openColorBatches[shadows].add(time, updater);
+ }
+ } else if (defined(updater.terrainOffsetProperty)) {
+ this._openMaterialBatches[numberOfShadowModes + shadows].add(time, updater);
} else {
this._openMaterialBatches[shadows].add(time, updater);
}
diff --git a/Source/DataSources/GroundGeometryUpdater.js b/Source/DataSources/GroundGeometryUpdater.js
index 43f2a98afc14..76c2c7b1810e 100644
--- a/Source/DataSources/GroundGeometryUpdater.js
+++ b/Source/DataSources/GroundGeometryUpdater.js
@@ -1,19 +1,37 @@
define([
+ '../Core/ApproximateTerrainHeights',
+ '../Core/Cartesian3',
+ '../Core/Check',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
+ '../Core/DeveloperError',
+ '../Core/GeometryOffsetAttribute',
'../Core/Iso8601',
'../Core/oneTimeWarning',
+ '../Scene/HeightReference',
+ './CallbackProperty',
'./ConstantProperty',
- './GeometryUpdater'
+ './GeometryUpdater',
+ './Property',
+ './TerrainOffsetProperty'
], function(
+ ApproximateTerrainHeights,
+ Cartesian3,
+ Check,
defaultValue,
defined,
defineProperties,
+ DeveloperError,
+ GeometryOffsetAttribute,
Iso8601,
oneTimeWarning,
+ HeightReference,
+ CallbackProperty,
ConstantProperty,
- GeometryUpdater) {
+ GeometryUpdater,
+ Property,
+ TerrainOffsetProperty) {
'use strict';
var defaultZIndex = new ConstantProperty(0);
@@ -33,6 +51,7 @@ define([
GeometryUpdater.call(this, options);
this._zIndex = 0;
+ this._terrainOffsetProperty = undefined;
}
if (defined(Object.create)) {
@@ -51,9 +70,17 @@ define([
get: function() {
return this._zIndex;
}
+ },
+
+ terrainOffsetProperty: {
+ get: function() {
+ return this._terrainOffsetProperty;
+ }
}
});
+ GroundGeometryUpdater.prototype._computeCenter = DeveloperError.throwInstantiationError;
+
GroundGeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue) {
GeometryUpdater.prototype._onEntityPropertyChanged.call(this, entity, propertyName, newValue, oldValue);
if (this._observedPropertyNames.indexOf(propertyName) === -1) {
@@ -69,6 +96,71 @@ define([
}
this._zIndex = defaultValue(geometry.zIndex, defaultZIndex);
+
+ if (defined(this._terrainOffsetProperty)) {
+ this._terrainOffsetProperty.destroy();
+ this._terrainOffsetProperty = undefined;
+ }
+
+ var heightReferenceProperty = geometry.heightReference;
+ var extrudedHeightReferenceProperty = geometry.extrudedHeightReference;
+
+ if (defined(heightReferenceProperty) || defined(extrudedHeightReferenceProperty)) {
+ var centerPosition = new CallbackProperty(this._computeCenter.bind(this), !this._dynamic);
+ this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, heightReferenceProperty, extrudedHeightReferenceProperty, centerPosition);
+ }
+ };
+
+ /**
+ * @private
+ */
+ GroundGeometryUpdater.getGeometryHeight = function(heightProperty, heightReferenceProperty, time) {
+ var heightReference = Property.getValueOrDefault(heightReferenceProperty, time, HeightReference.NONE);
+ if (heightReference !== HeightReference.CLAMP_TO_GROUND) {
+ return Property.getValueOrUndefined(heightProperty, time);
+ }
+ return 0.0;
+ };
+
+ /**
+ * @private
+ */
+ GroundGeometryUpdater.getGeometryExtrudedHeight = function(extrudedHeightProperty, extrudedHeightReferenceProperty, time) {
+ var heightReference = Property.getValueOrDefault(extrudedHeightReferenceProperty, time, HeightReference.NONE);
+ if (heightReference !== HeightReference.CLAMP_TO_GROUND) {
+ return Property.getValueOrUndefined(extrudedHeightProperty, time);
+ }
+
+ return GroundGeometryUpdater.CLAMP_TO_GROUND;
+ };
+
+ /**
+ * @private
+ */
+ GroundGeometryUpdater.CLAMP_TO_GROUND = 'clamp';
+
+ /**
+ * @private
+ */
+ GroundGeometryUpdater.computeGeometryOffsetAttribute = function(heightReferenceProperty, extrudedHeightReferenceProperty, time) {
+ var heightReference = Property.getValueOrDefault(heightReferenceProperty, time, HeightReference.NONE);
+ var extrudedHeightReference = Property.getValueOrDefault(extrudedHeightReferenceProperty, time, HeightReference.NONE);
+
+ var n = 0;
+ if (heightReference !== HeightReference.NONE) {
+ n++;
+ }
+ if (extrudedHeightReference === HeightReference.RELATIVE_TO_GROUND) {
+ n++;
+ }
+ if (n === 2) {
+ return GeometryOffsetAttribute.ALL;
+ }
+ if (n === 1) {
+ return GeometryOffsetAttribute.TOP;
+ }
+
+ return undefined;
};
return GroundGeometryUpdater;
diff --git a/Source/DataSources/PolygonGeometryUpdater.js b/Source/DataSources/PolygonGeometryUpdater.js
index c56094f34b35..a26e346dcccd 100644
--- a/Source/DataSources/PolygonGeometryUpdater.js
+++ b/Source/DataSources/PolygonGeometryUpdater.js
@@ -1,4 +1,6 @@
define([
+ '../Core/ApproximateTerrainHeights',
+ '../Core/Cartesian3',
'../Core/Check',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
@@ -6,13 +8,17 @@ define([
'../Core/DeveloperError',
'../Core/DistanceDisplayConditionGeometryInstanceAttribute',
'../Core/GeometryInstance',
+ '../Core/GeometryOffsetAttribute',
'../Core/isArray',
'../Core/Iso8601',
+ '../Core/OffsetGeometryInstanceAttribute',
'../Core/PolygonGeometry',
'../Core/PolygonHierarchy',
'../Core/PolygonOutlineGeometry',
+ '../Core/Rectangle',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/GroundPrimitive',
+ '../Scene/HeightReference',
'../Scene/MaterialAppearance',
'../Scene/PerInstanceColorAppearance',
'./ColorMaterialProperty',
@@ -21,6 +27,8 @@ define([
'./GroundGeometryUpdater',
'./Property'
], function(
+ ApproximateTerrainHeights,
+ Cartesian3,
Check,
Color,
ColorGeometryInstanceAttribute,
@@ -28,13 +36,17 @@ define([
DeveloperError,
DistanceDisplayConditionGeometryInstanceAttribute,
GeometryInstance,
+ GeometryOffsetAttribute,
isArray,
Iso8601,
+ OffsetGeometryInstanceAttribute,
PolygonGeometry,
PolygonHierarchy,
PolygonOutlineGeometry,
+ Rectangle,
ShowGeometryInstanceAttribute,
GroundPrimitive,
+ HeightReference,
MaterialAppearance,
PerInstanceColorAppearance,
ColorMaterialProperty,
@@ -45,6 +57,9 @@ define([
'use strict';
var scratchColor = new Color();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
+ var scratchRectangle = new Rectangle();
function PolygonGeometryOptions(entity) {
this.id = entity;
@@ -57,6 +72,7 @@ define([
this.extrudedHeight = undefined;
this.granularity = undefined;
this.stRotation = undefined;
+ this.offsetAttribute = undefined;
}
/**
@@ -105,12 +121,13 @@ define([
var entity = this._entity;
var isAvailable = entity.isAvailable(time);
- var attributes;
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time)),
+ offset : undefined,
+ color : undefined
+ };
- var color;
- var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
- var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
- var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
if (this._materialProperty instanceof ColorMaterialProperty) {
var currentColor;
if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
@@ -119,17 +136,10 @@ define([
if (!defined(currentColor)) {
currentColor = Color.WHITE;
}
- color = ColorGeometryInstanceAttribute.fromColor(currentColor);
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayConditionAttribute,
- color : color
- };
- } else {
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayConditionAttribute
- };
+ attributes.color = ColorGeometryInstanceAttribute.fromColor(currentColor);
+ }
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
}
return new GeometryInstance({
@@ -161,17 +171,45 @@ define([
var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor);
var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
+ color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition),
+ offset : undefined
+ };
+
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
+ }
+
return new GeometryInstance({
id : entity,
geometry : new PolygonOutlineGeometry(this._options),
- attributes : {
- show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
- color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
- distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
- }
+ attributes : attributes
});
};
+ PolygonGeometryUpdater.prototype._computeCenter = function(time, result) {
+ var positions = Property.getValueOrUndefined(this._entity.polygon.hierarchy, time);
+ if (defined(positions) && !isArray(positions)) {
+ positions = positions.positions;
+ }
+ if (positions.length === 0) {
+ return;
+ }
+
+ var centroid = Cartesian3.clone(Cartesian3.ZERO, result);
+ var length = positions.length;
+ for (var i = 0; i < length; i++) {
+ centroid = Cartesian3.add(positions[i], centroid, centroid);
+ }
+ centroid = Cartesian3.multiplyByScalar(centroid, 1 / length, centroid);
+ if (defined(this._scene.globe)) {
+ centroid = this._scene.globe.ellipsoid.scaleToGeodeticSurface(centroid, centroid);
+ }
+ return centroid;
+ };
+
PolygonGeometryUpdater.prototype._isHidden = function(entity, polygon) {
return !defined(polygon.hierarchy) || GeometryUpdater.prototype._isHidden.call(this, entity, polygon);
};
@@ -208,10 +246,13 @@ define([
hierarchyValue = new PolygonHierarchy(hierarchyValue);
}
- var heightValue = Property.getValueOrUndefined(polygon.height, Iso8601.MINIMUM_VALUE);
- var closeTopValue = Property.getValueOrDefault(polygon.closeTop, Iso8601.MINIMUM_VALUE, true);
- var closeBottomValue = Property.getValueOrDefault(polygon.closeBottom, Iso8601.MINIMUM_VALUE, true);
- var extrudedHeightValue = Property.getValueOrUndefined(polygon.extrudedHeight, Iso8601.MINIMUM_VALUE);
+ var height = polygon.height;
+ var heightReference = polygon.heightReference;
+ var extrudedHeight = polygon.extrudedHeight;
+ var extrudedHeightReference = polygon.extrudedHeightReference;
+
+ var heightValue = GroundGeometryUpdater.getGeometryHeight(height, heightReference, Iso8601.MINIMUM_VALUE);
+ var extrudedHeightValue = Property.getValueOrUndefined(extrudedHeight, Iso8601.MINIMUM_VALUE);
var perPositionHeightValue = Property.getValueOrUndefined(polygon.perPositionHeight, Iso8601.MINIMUM_VALUE);
if (defined(extrudedHeightValue) && !defined(heightValue) && !defined(perPositionHeightValue)) {
@@ -219,13 +260,20 @@ define([
}
options.polygonHierarchy = hierarchyValue;
- options.height = heightValue;
- options.extrudedHeight = extrudedHeightValue;
options.granularity = Property.getValueOrUndefined(polygon.granularity, Iso8601.MINIMUM_VALUE);
options.stRotation = Property.getValueOrUndefined(polygon.stRotation, Iso8601.MINIMUM_VALUE);
options.perPositionHeight = perPositionHeightValue;
- options.closeTop = closeTopValue;
- options.closeBottom = closeBottomValue;
+ options.closeTop = Property.getValueOrDefault(polygon.closeTop, Iso8601.MINIMUM_VALUE, true);
+ options.closeBottom = Property.getValueOrDefault(polygon.closeBottom, Iso8601.MINIMUM_VALUE, true);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ options.height = heightValue;
+
+ extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(PolygonGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
PolygonGeometryUpdater.prototype._getIsClosed = function(options) {
@@ -255,6 +303,11 @@ define([
DyanmicPolygonGeometryUpdater.prototype._setOptions = function(entity, polygon, time) {
var options = this._options;
+ var height = polygon.height;
+ var heightReference = polygon.heightReference;
+ var extrudedHeight = polygon.extrudedHeight;
+ var extrudedHeightReference = polygon.extrudedHeightReference;
+
var hierarchy = Property.getValueOrUndefined(polygon.hierarchy, time);
if (isArray(hierarchy)) {
options.polygonHierarchy = new PolygonHierarchy(hierarchy);
@@ -262,13 +315,28 @@ define([
options.polygonHierarchy = hierarchy;
}
- options.height = Property.getValueOrUndefined(polygon.height, time);
- options.extrudedHeight = Property.getValueOrUndefined(polygon.extrudedHeight, time);
+ var heightValue = GroundGeometryUpdater.getGeometryHeight(height, heightReference, time);
+ var extrudedHeightValue = Property.getValueOrUndefined(extrudedHeight, time);
+ var perPositionHeightValue = Property.getValueOrUndefined(polygon.perPositionHeight, time);
+
+ if (defined(extrudedHeightValue) && !defined(heightValue) && !defined(perPositionHeightValue)) {
+ heightValue = 0;
+ }
+
options.granularity = Property.getValueOrUndefined(polygon.granularity, time);
options.stRotation = Property.getValueOrUndefined(polygon.stRotation, time);
options.perPositionHeight = Property.getValueOrUndefined(polygon.perPositionHeight, time);
options.closeTop = Property.getValueOrDefault(polygon.closeTop, time, true);
options.closeBottom = Property.getValueOrDefault(polygon.closeBottom, time, true);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ options.height = heightValue;
+
+ extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, time);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(PolygonGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
return PolygonGeometryUpdater;
diff --git a/Source/DataSources/PolygonGraphics.js b/Source/DataSources/PolygonGraphics.js
index 99c5243d86fe..5eb968df4d59 100644
--- a/Source/DataSources/PolygonGraphics.js
+++ b/Source/DataSources/PolygonGraphics.js
@@ -27,7 +27,9 @@ define([
* @param {Object} [options] Object with the following properties:
* @param {Property} [options.hierarchy] A Property specifying the {@link PolygonHierarchy}.
* @param {Property} [options.height=0] A numeric Property specifying the altitude of the polygon relative to the ellipsoid surface.
+ * @param {Property} [options.heightReference] A Property specifying what the height is relative to.
* @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the polygon's extruded face relative to the ellipsoid surface.
+ * @param {Property} [options.extrudedHeightReference] A Property specifying what the extrudedHeight is relative to.
* @param {Property} [options.show=true] A boolean Property specifying the visibility of the polygon.
* @param {Property} [options.fill=true] A boolean Property specifying whether the polygon is filled with the provided material.
* @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the polygon.
@@ -55,8 +57,12 @@ define([
this._hierarchySubscription = undefined;
this._height = undefined;
this._heightSubscription = undefined;
+ this._heightReference = undefined;
+ this._heightReferenceSubscription = undefined;
this._extrudedHeight = undefined;
this._extrudedHeightSubscription = undefined;
+ this._extrudedHeightReference = undefined;
+ this._extrudedHeightReferenceSubscription = undefined;
this._granularity = undefined;
this._granularitySubscription = undefined;
this._stRotation = undefined;
@@ -133,6 +139,14 @@ define([
*/
height : createPropertyDescriptor('height'),
+ /**
+ * Gets or sets the Property specifying the {@link HeightReference}.
+ * @memberof PolygonGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ heightReference : createPropertyDescriptor('heightReference'),
+
/**
* Gets or sets the numeric Property specifying the altitude of the polygon extrusion.
* If {@link PolygonGraphics#perPositionHeight} is false, the volume starts at {@link PolygonGraphics#height} and ends at this altitude.
@@ -142,6 +156,14 @@ define([
*/
extrudedHeight : createPropertyDescriptor('extrudedHeight'),
+ /**
+ * Gets or sets the Property specifying the extruded {@link HeightReference}.
+ * @memberof PolygonGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ extrudedHeightReference : createPropertyDescriptor('extrudedHeightReference'),
+
/**
* Gets or sets the numeric Property specifying the angular distance between points on the polygon.
* @memberof PolygonGraphics.prototype
@@ -260,7 +282,9 @@ define([
result.material = this.material;
result.hierarchy = this.hierarchy;
result.height = this.height;
+ result.heightReference = this.heightReference;
result.extrudedHeight = this.extrudedHeight;
+ result.extrudedHeightReference = this.extrudedHeightReference;
result.granularity = this.granularity;
result.stRotation = this.stRotation;
result.fill = this.fill;
@@ -295,7 +319,9 @@ define([
this.material = defaultValue(this.material, source.material);
this.hierarchy = defaultValue(this.hierarchy, source.hierarchy);
this.height = defaultValue(this.height, source.height);
+ this.heightReference = defaultValue(this.heightReference, source.heightReference);
this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
+ this.extrudedHeightReference = defaultValue(this.extrudedHeightReference, source.extrudedHeightReference);
this.granularity = defaultValue(this.granularity, source.granularity);
this.stRotation = defaultValue(this.stRotation, source.stRotation);
this.fill = defaultValue(this.fill, source.fill);
diff --git a/Source/DataSources/RectangleGeometryUpdater.js b/Source/DataSources/RectangleGeometryUpdater.js
index 21e6c35a89a0..9206ba1eb4df 100644
--- a/Source/DataSources/RectangleGeometryUpdater.js
+++ b/Source/DataSources/RectangleGeometryUpdater.js
@@ -1,16 +1,24 @@
define([
+ '../Core/ApproximateTerrainHeights',
+ '../Core/Cartesian3',
+ '../Core/Cartographic',
'../Core/Check',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
'../Core/defined',
'../Core/DeveloperError',
'../Core/DistanceDisplayConditionGeometryInstanceAttribute',
+ '../Core/Ellipsoid',
'../Core/GeometryInstance',
+ '../Core/GeometryOffsetAttribute',
'../Core/Iso8601',
+ '../Core/OffsetGeometryInstanceAttribute',
+ '../Core/Rectangle',
'../Core/RectangleGeometry',
'../Core/RectangleOutlineGeometry',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/GroundPrimitive',
+ '../Scene/HeightReference',
'../Scene/MaterialAppearance',
'../Scene/PerInstanceColorAppearance',
'./ColorMaterialProperty',
@@ -19,18 +27,26 @@ define([
'./GroundGeometryUpdater',
'./Property'
], function(
+ ApproximateTerrainHeights,
+ Cartesian3,
+ Cartographic,
Check,
Color,
ColorGeometryInstanceAttribute,
defined,
DeveloperError,
DistanceDisplayConditionGeometryInstanceAttribute,
+ Ellipsoid,
GeometryInstance,
+ GeometryOffsetAttribute,
Iso8601,
+ OffsetGeometryInstanceAttribute,
+ Rectangle,
RectangleGeometry,
RectangleOutlineGeometry,
ShowGeometryInstanceAttribute,
GroundPrimitive,
+ HeightReference,
MaterialAppearance,
PerInstanceColorAppearance,
ColorMaterialProperty,
@@ -41,6 +57,11 @@ define([
'use strict';
var scratchColor = new Color();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
+ var scratchRectangle = new Rectangle();
+ var scratchCenterRect = new Rectangle();
+ var scratchCarto = new Cartographic();
function RectangleGeometryOptions(entity) {
this.id = entity;
@@ -51,6 +72,7 @@ define([
this.granularity = undefined;
this.stRotation = undefined;
this.rotation = undefined;
+ this.offsetAttribute = undefined;
}
/**
@@ -99,12 +121,13 @@ define([
var entity = this._entity;
var isAvailable = entity.isAvailable(time);
- var attributes;
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(this._distanceDisplayConditionProperty.getValue(time)),
+ offset : undefined,
+ color : undefined
+ };
- var color;
- var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time));
- var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
- var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition);
if (this._materialProperty instanceof ColorMaterialProperty) {
var currentColor;
if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) {
@@ -113,17 +136,10 @@ define([
if (!defined(currentColor)) {
currentColor = Color.WHITE;
}
- color = ColorGeometryInstanceAttribute.fromColor(currentColor);
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayConditionAttribute,
- color : color
- };
- } else {
- attributes = {
- show : show,
- distanceDisplayCondition : distanceDisplayConditionAttribute
- };
+ attributes.color = ColorGeometryInstanceAttribute.fromColor(currentColor);
+ }
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
}
return new GeometryInstance({
@@ -155,17 +171,33 @@ define([
var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor);
var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time);
+ var attributes = {
+ show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
+ color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
+ distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition),
+ offset : undefined
+ };
+
+ if (defined(this._options.offsetAttribute)) {
+ attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch));
+ }
+
return new GeometryInstance({
id : entity,
geometry : new RectangleOutlineGeometry(this._options),
- attributes : {
- show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)),
- color : ColorGeometryInstanceAttribute.fromColor(outlineColor),
- distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition)
- }
+ attributes : attributes
});
};
+ RectangleGeometryUpdater.prototype._computeCenter = function(time, result) {
+ var rect = Property.getValueOrUndefined(this._entity.rectangle.coordinates, time, scratchCenterRect);
+ if (!defined(rect)) {
+ return;
+ }
+ var center = Rectangle.center(rect, scratchCarto);
+ return Cartographic.toCartesian(center, Ellipsoid.WGS84, result);
+ };
+
RectangleGeometryUpdater.prototype._isHidden = function(entity, rectangle) {
return !defined(rectangle.coordinates) || GeometryUpdater.prototype._isHidden.call(this, entity, rectangle);
};
@@ -190,19 +222,25 @@ define([
var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty;
var height = rectangle.height;
+ var heightReference = rectangle.heightReference;
var extrudedHeight = rectangle.extrudedHeight;
- var granularity = rectangle.granularity;
- var stRotation = rectangle.stRotation;
- var rotation = rectangle.rotation;
+ var extrudedHeightReference = rectangle.extrudedHeightReference;
var options = this._options;
options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat;
options.rectangle = rectangle.coordinates.getValue(Iso8601.MINIMUM_VALUE, options.rectangle);
- options.height = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.extrudedHeight = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.stRotation = defined(stRotation) ? stRotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
- options.rotation = defined(rotation) ? rotation.getValue(Iso8601.MINIMUM_VALUE) : undefined;
+ options.granularity = Property.getValueOrUndefined(rectangle.granularity, Iso8601.MINIMUM_VALUE);
+ options.stRotation = Property.getValueOrUndefined(rectangle.stRotation, Iso8601.MINIMUM_VALUE);
+ options.rotation = Property.getValueOrUndefined(rectangle.rotation, Iso8601.MINIMUM_VALUE);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ options.height = GroundGeometryUpdater.getGeometryHeight(height, heightReference, Iso8601.MINIMUM_VALUE);
+
+ var extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, Iso8601.MINIMUM_VALUE);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(RectangleGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
RectangleGeometryUpdater.prototype._getIsClosed = function(options) {
@@ -231,12 +269,24 @@ define([
DynamicRectangleGeometryUpdater.prototype._setOptions = function(entity, rectangle, time) {
var options = this._options;
+ var height = rectangle.height;
+ var heightReference = rectangle.heightReference;
+ var extrudedHeight = rectangle.extrudedHeight;
+ var extrudedHeightReference = rectangle.extrudedHeightReference;
+
options.rectangle = Property.getValueOrUndefined(rectangle.coordinates, time, options.rectangle);
- options.height = Property.getValueOrUndefined(rectangle.height, time);
- options.extrudedHeight = Property.getValueOrUndefined(rectangle.extrudedHeight, time);
options.granularity = Property.getValueOrUndefined(rectangle.granularity, time);
options.stRotation = Property.getValueOrUndefined(rectangle.stRotation, time);
options.rotation = Property.getValueOrUndefined(rectangle.rotation, time);
+ options.offsetAttribute = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ options.height = GroundGeometryUpdater.getGeometryHeight(height, heightReference, time);
+
+ var extrudedHeightValue = GroundGeometryUpdater.getGeometryExtrudedHeight(extrudedHeight, extrudedHeightReference, time);
+ if (extrudedHeightValue === GroundGeometryUpdater.CLAMP_TO_GROUND) {
+ extrudedHeightValue = ApproximateTerrainHeights.getApproximateTerrainHeights(RectangleGeometry.computeRectangle(options, scratchRectangle)).minimumTerrainHeight;
+ }
+
+ options.extrudedHeight = extrudedHeightValue;
};
return RectangleGeometryUpdater;
diff --git a/Source/DataSources/RectangleGraphics.js b/Source/DataSources/RectangleGraphics.js
index 290de41f8569..9840679d75d0 100644
--- a/Source/DataSources/RectangleGraphics.js
+++ b/Source/DataSources/RectangleGraphics.js
@@ -27,7 +27,9 @@ define([
* @param {Object} [options] Object with the following properties:
* @param {Property} [options.coordinates] The Property specifying the {@link Rectangle}.
* @param {Property} [options.height=0] A numeric Property specifying the altitude of the rectangle relative to the ellipsoid surface.
+ * @param {Property} [options.heightReference] A Property specifying what the height is relative to.
* @param {Property} [options.extrudedHeight] A numeric Property specifying the altitude of the rectangle's extruded face relative to the ellipsoid surface.
+ * @param {Property} [options.extrudedHeightReference] A Property specifying what the extrudedHeight is relative to.
* @param {Property} [options.show=true] A boolean Property specifying the visibility of the rectangle.
* @param {Property} [options.fill=true] A boolean Property specifying whether the rectangle is filled with the provided material.
* @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to fill the rectangle.
@@ -53,8 +55,12 @@ define([
this._coordinatesSubscription = undefined;
this._height = undefined;
this._heightSubscription = undefined;
+ this._heightReference = undefined;
+ this._heightReferenceSubscription = undefined;
this._extrudedHeight = undefined;
this._extrudedHeightSubscription = undefined;
+ this._extrudedHeightReference = undefined;
+ this._extrudedHeightReferenceSubscription = undefined;
this._granularity = undefined;
this._granularitySubscription = undefined;
this._stRotation = undefined;
@@ -128,6 +134,14 @@ define([
*/
height : createPropertyDescriptor('height'),
+ /**
+ * Gets or sets the Property specifying the {@link HeightReference}.
+ * @memberof RectangleGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ heightReference : createPropertyDescriptor('heightReference'),
+
/**
* Gets or sets the numeric Property specifying the altitude of the rectangle extrusion.
* Setting this property creates volume starting at height and ending at this altitude.
@@ -136,6 +150,14 @@ define([
*/
extrudedHeight : createPropertyDescriptor('extrudedHeight'),
+ /**
+ * Gets or sets the Property specifying the extruded {@link HeightReference}.
+ * @memberof RectangleGraphics.prototype
+ * @type {Property}
+ * @default HeightReference.NONE
+ */
+ extrudedHeightReference : createPropertyDescriptor('extrudedHeightReference'),
+
/**
* Gets or sets the numeric Property specifying the angular distance between points on the rectangle.
* @memberof RectangleGraphics.prototype
@@ -239,7 +261,9 @@ define([
result.coordinates = this.coordinates;
result.material = this.material;
result.height = this.height;
+ result.heightReference = this.heightReference;
result.extrudedHeight = this.extrudedHeight;
+ result.extrudedHeightReference = this.extrudedHeightReference;
result.granularity = this.granularity;
result.stRotation = this.stRotation;
result.rotation = this.rotation;
@@ -272,7 +296,9 @@ define([
this.coordinates = defaultValue(this.coordinates, source.coordinates);
this.material = defaultValue(this.material, source.material);
this.height = defaultValue(this.height, source.height);
+ this.heightReference = defaultValue(this.heightReference, source.heightReference);
this.extrudedHeight = defaultValue(this.extrudedHeight, source.extrudedHeight);
+ this.extrudedHeightReference = defaultValue(this.extrudedHeightReference, source.extrudedHeightReference);
this.granularity = defaultValue(this.granularity, source.granularity);
this.stRotation = defaultValue(this.stRotation, source.stRotation);
this.rotation = defaultValue(this.rotation, source.rotation);
diff --git a/Source/DataSources/StaticGeometryColorBatch.js b/Source/DataSources/StaticGeometryColorBatch.js
index 32168a30c123..7f87f7a1f699 100644
--- a/Source/DataSources/StaticGeometryColorBatch.js
+++ b/Source/DataSources/StaticGeometryColorBatch.js
@@ -1,10 +1,12 @@
define([
'../Core/AssociativeArray',
+ '../Core/Cartesian3',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
'../Core/defined',
'../Core/DistanceDisplayCondition',
'../Core/DistanceDisplayConditionGeometryInstanceAttribute',
+ '../Core/OffsetGeometryInstanceAttribute',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/Primitive',
'./BoundingSphereState',
@@ -13,11 +15,13 @@ define([
'./Property'
], function(
AssociativeArray,
+ Cartesian3,
Color,
ColorGeometryInstanceAttribute,
defined,
DistanceDisplayCondition,
DistanceDisplayConditionGeometryInstanceAttribute,
+ OffsetGeometryInstanceAttribute,
ShowGeometryInstanceAttribute,
Primitive,
BoundingSphereState,
@@ -29,6 +33,8 @@ define([
var colorScratch = new Color();
var distanceDisplayConditionScratch = new DistanceDisplayCondition();
var defaultDistanceDisplayCondition = new DistanceDisplayCondition();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
function Batch(primitives, translucent, appearanceType, depthFailAppearanceType, depthFailMaterialProperty, closed, shadows) {
this.translucent = translucent;
@@ -80,7 +86,7 @@ define([
this.createPrimitive = true;
this.geometry.set(id, instance);
this.updaters.set(id, updater);
- if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
+ if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty) || !Property.isConstant(updater.terrainOffsetProperty)) {
this.updatersWithAttributes.set(id, updater);
} else {
var that = this;
@@ -245,6 +251,15 @@ define([
attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
}
}
+
+ var offsetProperty = updater.terrainOffsetProperty;
+ if (!Property.isConstant(offsetProperty)) {
+ var offset = Property.getValueOrDefault(offsetProperty, time, defaultOffset, offsetScratch);
+ if (!Cartesian3.equals(offset, attributes._lastOffset)) {
+ attributes._lastOffset = Cartesian3.clone(offset, attributes._lastOffset);
+ attributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset);
+ }
+ }
}
this.updateShows(primitive);
diff --git a/Source/DataSources/StaticGeometryPerMaterialBatch.js b/Source/DataSources/StaticGeometryPerMaterialBatch.js
index 4734c5be14fd..0fd9eed26e2c 100644
--- a/Source/DataSources/StaticGeometryPerMaterialBatch.js
+++ b/Source/DataSources/StaticGeometryPerMaterialBatch.js
@@ -1,10 +1,12 @@
define([
'../Core/AssociativeArray',
+ '../Core/Cartesian3',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
'../Core/defined',
'../Core/DistanceDisplayCondition',
'../Core/DistanceDisplayConditionGeometryInstanceAttribute',
+ '../Core/OffsetGeometryInstanceAttribute',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/Primitive',
'./BoundingSphereState',
@@ -13,11 +15,13 @@ define([
'./Property'
], function(
AssociativeArray,
+ Cartesian3,
Color,
ColorGeometryInstanceAttribute,
defined,
DistanceDisplayCondition,
DistanceDisplayConditionGeometryInstanceAttribute,
+ OffsetGeometryInstanceAttribute,
ShowGeometryInstanceAttribute,
Primitive,
BoundingSphereState,
@@ -28,6 +32,8 @@ define([
var distanceDisplayConditionScratch = new DistanceDisplayCondition();
var defaultDistanceDisplayCondition = new DistanceDisplayCondition();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
function Batch(primitives, appearanceType, materialProperty, depthFailAppearanceType, depthFailMaterialProperty, closed, shadows) {
this.primitives = primitives;
@@ -74,7 +80,7 @@ define([
var id = updater.id;
this.updaters.set(id, updater);
this.geometry.set(id, updater.createFillGeometryInstance(time));
- if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
+ if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty) || !Property.isConstant(updater.terrainOffsetProperty)) {
this.updatersWithAttributes.set(id, updater);
} else {
var that = this;
@@ -234,6 +240,15 @@ define([
attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
}
}
+
+ var offsetProperty = updater.terrainOffsetProperty;
+ if (!Property.isConstant(offsetProperty)) {
+ var offset = Property.getValueOrDefault(offsetProperty, time, defaultOffset, offsetScratch);
+ if (!Cartesian3.equals(offset, attributes._lastOffset)) {
+ attributes._lastOffset = Cartesian3.clone(offset, attributes._lastOffset);
+ attributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset);
+ }
+ }
}
this.updateShows(primitive);
diff --git a/Source/DataSources/StaticOutlineGeometryBatch.js b/Source/DataSources/StaticOutlineGeometryBatch.js
index 848154fa3c51..def326371c71 100644
--- a/Source/DataSources/StaticOutlineGeometryBatch.js
+++ b/Source/DataSources/StaticOutlineGeometryBatch.js
@@ -1,10 +1,12 @@
define([
'../Core/AssociativeArray',
+ '../Core/Cartesian3',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
'../Core/defined',
'../Core/DistanceDisplayCondition',
'../Core/DistanceDisplayConditionGeometryInstanceAttribute',
+ '../Core/OffsetGeometryInstanceAttribute',
'../Core/ShowGeometryInstanceAttribute',
'../Scene/PerInstanceColorAppearance',
'../Scene/Primitive',
@@ -12,11 +14,13 @@ define([
'./Property'
], function(
AssociativeArray,
+ Cartesian3,
Color,
ColorGeometryInstanceAttribute,
defined,
DistanceDisplayCondition,
DistanceDisplayConditionGeometryInstanceAttribute,
+ OffsetGeometryInstanceAttribute,
ShowGeometryInstanceAttribute,
PerInstanceColorAppearance,
Primitive,
@@ -27,6 +31,8 @@ define([
var colorScratch = new Color();
var distanceDisplayConditionScratch = new DistanceDisplayCondition();
var defaultDistanceDisplayCondition = new DistanceDisplayCondition();
+ var defaultOffset = Cartesian3.ZERO;
+ var offsetScratch = new Cartesian3();
function Batch(primitives, translucent, width, shadows) {
this.translucent = translucent;
@@ -50,7 +56,7 @@ define([
this.createPrimitive = true;
this.geometry.set(id, instance);
this.updaters.set(id, updater);
- if (!updater.hasConstantOutline || !updater.outlineColorProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
+ if (!updater.hasConstantOutline || !updater.outlineColorProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty) || !Property.isConstant(updater.terrainOffsetProperty)) {
this.updatersWithAttributes.set(id, updater);
} else {
var that = this;
@@ -189,6 +195,15 @@ define([
attributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, attributes.distanceDisplayCondition);
}
}
+
+ var offsetProperty = updater.terrainOffsetProperty;
+ if (!Property.isConstant(offsetProperty)) {
+ var offset = Property.getValueOrDefault(offsetProperty, time, defaultOffset, offsetScratch);
+ if (!Cartesian3.equals(offset, attributes._lastOffset)) {
+ attributes._lastOffset = Cartesian3.clone(offset, attributes._lastOffset);
+ attributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset);
+ }
+ }
}
this.updateShows(primitive);
diff --git a/Source/DataSources/TerrainOffsetProperty.js b/Source/DataSources/TerrainOffsetProperty.js
new file mode 100644
index 000000000000..7f9f740cf7d7
--- /dev/null
+++ b/Source/DataSources/TerrainOffsetProperty.js
@@ -0,0 +1,208 @@
+define([
+ '../Core/Cartesian3',
+ '../Core/Cartographic',
+ '../Core/Check',
+ '../Core/defined',
+ '../Core/defineProperties',
+ '../Core/destroyObject',
+ '../Core/Event',
+ '../Core/Iso8601',
+ '../Core/Math',
+ '../Scene/HeightReference',
+ '../Scene/SceneMode',
+ './Property'
+], function(
+ Cartesian3,
+ Cartographic,
+ Check,
+ defined,
+ defineProperties,
+ destroyObject,
+ Event,
+ Iso8601,
+ CesiumMath,
+ HeightReference,
+ SceneMode,
+ Property) {
+ 'use strict';
+
+ var scratchPosition = new Cartesian3();
+ var scratchCarto = new Cartographic();
+
+ /**
+ * @private
+ */
+ function TerrainOffsetProperty(scene, heightReferenceProperty, extrudedHeightReferenceProperty, positionProperty) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.defined('scene', scene);
+ Check.defined('positionProperty', positionProperty);
+ //>>includeEnd('debug');
+
+ this._scene = scene;
+ this._heightReference = heightReferenceProperty;
+ this._extrudedHeightReference = extrudedHeightReferenceProperty;
+ this._positionProperty = positionProperty;
+
+ this._position = new Cartesian3();
+ this._cartographicPosition = new Cartographic();
+ this._normal = new Cartesian3();
+
+ this._definitionChanged = new Event();
+ this._terrainHeight = 0;
+ this._removeCallbackFunc = undefined;
+ this._removeEventListener = undefined;
+ this._removeModeListener = undefined;
+
+ var that = this;
+ if (defined(scene.globe)) {
+ this._removeEventListener = scene.terrainProviderChanged.addEventListener(function() {
+ that._updateClamping();
+ });
+ this._removeModeListener = scene.morphComplete.addEventListener(function() {
+ that._updateClamping();
+ });
+ }
+
+ if (positionProperty.isConstant) {
+ var position = positionProperty.getValue(Iso8601.MINIMUM_VALUE, scratchPosition);
+ if (!defined(position) || Cartesian3.equals(position, Cartesian3.ZERO) || !defined(scene.globe)) {
+ return;
+ }
+ this._position = Cartesian3.clone(position, this._position);
+
+ this._updateClamping();
+
+ this._normal = scene.globe.ellipsoid.geodeticSurfaceNormal(position, this._normal);
+ }
+ }
+
+ defineProperties(TerrainOffsetProperty.prototype, {
+ /**
+ * Gets a value indicating if this property is constant.
+ * @memberof TerrainOffsetProperty.prototype
+ *
+ * @type {Boolean}
+ * @readonly
+ */
+ isConstant : {
+ get : function() {
+ return false;
+ }
+ },
+ /**
+ * Gets the event that is raised whenever the definition of this property changes.
+ * @memberof TerrainOffsetProperty.prototype
+ *
+ * @type {Event}
+ * @readonly
+ */
+ definitionChanged : {
+ get : function() {
+ return this._definitionChanged;
+ }
+ }
+ });
+
+ /**
+ * @private
+ */
+ TerrainOffsetProperty.prototype._updateClamping = function() {
+ if (defined(this._removeCallbackFunc)) {
+ this._removeCallbackFunc();
+ }
+
+ var scene = this._scene;
+ var globe = scene.globe;
+ var position = this._position;
+
+ if (!defined(globe) || Cartesian3.equals(position, Cartesian3.ZERO)) {
+ this._terrainHeight = 0;
+ return;
+ }
+ var ellipsoid = globe.ellipsoid;
+ var surface = globe._surface;
+
+ var that = this;
+ var cartographicPosition = ellipsoid.cartesianToCartographic(position, this._cartographicPosition);
+ var height = globe.getHeight(cartographicPosition);
+ if (defined(height)) {
+ this._terrainHeight = height;
+ } else {
+ this._terrainHeight = 0;
+ }
+
+ function updateFunction(clampedPosition) {
+ if (scene.mode === SceneMode.SCENE3D) {
+ var carto = ellipsoid.cartesianToCartographic(clampedPosition, scratchCarto);
+ that._terrainHeight = carto.height;
+ } else {
+ that._terrainHeight = clampedPosition.x;
+ }
+ that.definitionChanged.raiseEvent();
+ }
+ this._removeCallbackFunc = surface.updateHeight(cartographicPosition, updateFunction);
+ };
+
+ /**
+ * Gets the height relative to the terrain based on the positions.
+ *
+ * @returns {Cartesian3} The offset
+ */
+ TerrainOffsetProperty.prototype.getValue = function(time, result) {
+ var heightReference = Property.getValueOrDefault(this._heightReference, time, HeightReference.NONE);
+ var extrudedHeightReference = Property.getValueOrDefault(this._extrudedHeightReference, time, HeightReference.NONE);
+
+ if (heightReference === HeightReference.NONE && extrudedHeightReference !== HeightReference.RELATIVE_TO_GROUND) {
+ this._position = Cartesian3.clone(Cartesian3.ZERO, this._position);
+ return Cartesian3.clone(Cartesian3.ZERO, result);
+ }
+
+ if (this._positionProperty.isConstant) {
+ return Cartesian3.multiplyByScalar(this._normal, this._terrainHeight, result);
+ }
+
+ var scene = this._scene;
+ var position = this._positionProperty.getValue(time, scratchPosition);
+ if (!defined(position) || Cartesian3.equals(position, Cartesian3.ZERO) || !defined(scene.globe)) {
+ return Cartesian3.clone(Cartesian3.ZERO, result);
+ }
+
+ if (Cartesian3.equalsEpsilon(this._position, position, CesiumMath.EPSILON10)) {
+ return Cartesian3.multiplyByScalar(this._normal, this._terrainHeight, result);
+ }
+
+ this._position = Cartesian3.clone(position, this._position);
+
+ this._updateClamping();
+
+ var normal = scene.globe.ellipsoid.geodeticSurfaceNormal(position, this._normal);
+ return Cartesian3.multiplyByScalar(normal, this._terrainHeight, result);
+ };
+
+ TerrainOffsetProperty.prototype.isDestroyed = function() {
+ return false;
+ };
+
+ TerrainOffsetProperty.prototype.destroy = function() {
+ if (defined(this._removeEventListener)) {
+ this._removeEventListener();
+ }
+ if (defined(this._removeModeListener)) {
+ this._removeModeListener();
+ }
+ if (defined(this._removeCallbackFunc)) {
+ this._removeCallbackFunc();
+ }
+ return destroyObject(this);
+ };
+
+ /**
+ * A function which creates one or more providers.
+ * @callback TerrainOffsetProperty~PositionFunction
+ * @param {JulianDate} time The clock time at which to retrieve the position
+ * @param {Cartesian3} result The result position
+ * @returns {Cartesian3} The position at which to do the terrain height check
+ */
+
+ return TerrainOffsetProperty;
+});
diff --git a/Specs/DataSources/CorridorGeometryUpdaterSpec.js b/Specs/DataSources/CorridorGeometryUpdaterSpec.js
index 940a2718d92b..1f4c23f2b3cc 100644
--- a/Specs/DataSources/CorridorGeometryUpdaterSpec.js
+++ b/Specs/DataSources/CorridorGeometryUpdaterSpec.js
@@ -1,8 +1,11 @@
defineSuite([
'DataSources/CorridorGeometryUpdater',
+ 'Core/ApproximateTerrainHeights',
'Core/Cartesian3',
'Core/CornerType',
+ 'Core/GeometryOffsetAttribute',
'Core/JulianDate',
+ 'Core/Math',
'Core/TimeInterval',
'Core/TimeIntervalCollection',
'DataSources/ConstantProperty',
@@ -20,9 +23,12 @@ defineSuite([
'Specs/createScene'
], function(
CorridorGeometryUpdater,
+ ApproximateTerrainHeights,
Cartesian3,
CornerType,
+ GeometryOffsetAttribute,
JulianDate,
+ CesiumMath,
TimeInterval,
TimeIntervalCollection,
ConstantProperty,
@@ -46,15 +52,20 @@ defineSuite([
beforeAll(function() {
scene = createScene();
time = JulianDate.now();
+
+ return ApproximateTerrainHeights.initialize();
});
afterAll(function() {
scene.destroyForSpecs();
+
+ ApproximateTerrainHeights._initPromise = undefined;
+ ApproximateTerrainHeights._terrainHeights = undefined;
});
function createBasicCorridor() {
var corridor = new CorridorGraphics();
- corridor.positions = new ConstantProperty(Cartesian3.fromRadiansArray([
+ corridor.positions = new ConstantProperty(Cartesian3.fromDegreesArray([
0, 0,
1, 0,
1, 1,
@@ -69,13 +80,13 @@ defineSuite([
function createDynamicCorridor() {
var entity = createBasicCorridor();
- entity.corridor.positions = createDynamicProperty(Cartesian3.fromRadiansArray([0, 0, 1, 0, 1, 1, 0, 1]));
+ entity.corridor.positions = createDynamicProperty(Cartesian3.fromDegreesArray([0, 0, 1, 0, 1, 1, 0, 1]));
return entity;
}
function createBasicCorridorWithoutHeight() {
var corridor = new CorridorGraphics();
- corridor.positions = new ConstantProperty(Cartesian3.fromRadiansArray([
+ corridor.positions = new ConstantProperty(Cartesian3.fromDegreesArray([
0, 0,
1, 0,
1, 1,
@@ -89,7 +100,7 @@ defineSuite([
function createDynamicCorridorWithoutHeight() {
var entity = createBasicCorridorWithoutHeight();
- entity.corridor.positions = createDynamicProperty(Cartesian3.fromRadiansArray([0, 0, 1, 0, 1, 1, 0, 1]));
+ entity.corridor.positions = createDynamicProperty(Cartesian3.fromDegreesArray([0, 0, 1, 0, 1, 1, 0, 1]));
return entity;
}
@@ -193,6 +204,7 @@ defineSuite([
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
expect(geometry._cornerType).toEqual(options.cornerType);
+ expect(geometry._offsetAttribute).toBeUndefined();
instance = updater.createOutlineGeometryInstance(time);
geometry = instance.geometry;
@@ -201,11 +213,12 @@ defineSuite([
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
expect(geometry._cornerType).toEqual(options.cornerType);
+ expect(geometry._offsetAttribute).toBeUndefined();
});
it('dynamic updater sets properties', function() {
var corridor = new CorridorGraphics();
- corridor.positions = createDynamicProperty(Cartesian3.fromRadiansArray([
+ corridor.positions = createDynamicProperty(Cartesian3.fromDegreesArray([
0, 0,
1, 0,
1, 1,
@@ -234,6 +247,7 @@ defineSuite([
expect(options.width).toEqual(corridor.width.getValue());
expect(options.granularity).toEqual(corridor.granularity.getValue());
expect(options.cornerType).toEqual(corridor.cornerType.getValue());
+ expect(options.offsetAttribute).toBeUndefined();
});
it('geometryChanged event is raised when expected', function() {
@@ -268,6 +282,13 @@ defineSuite([
expect(listener.calls.count()).toEqual(4);
});
+ it('computes center', function() {
+ var entity = createBasicCorridor();
+ var updater = new CorridorGeometryUpdater(entity, scene);
+
+ expect(updater._computeCenter(time)).toEqualEpsilon(Cartesian3.fromDegrees(1.0, 1.0), CesiumMath.EPSILON10);
+ });
+
function getScene() {
return scene;
}
diff --git a/Specs/DataSources/EllipseGeometryUpdaterSpec.js b/Specs/DataSources/EllipseGeometryUpdaterSpec.js
index a429a8dd859a..559020da2906 100644
--- a/Specs/DataSources/EllipseGeometryUpdaterSpec.js
+++ b/Specs/DataSources/EllipseGeometryUpdaterSpec.js
@@ -1,6 +1,8 @@
defineSuite([
'DataSources/EllipseGeometryUpdater',
+ 'Core/ApproximateTerrainHeights',
'Core/Cartesian3',
+ 'Core/GeometryOffsetAttribute',
'Core/JulianDate',
'Core/TimeIntervalCollection',
'DataSources/ConstantPositionProperty',
@@ -17,7 +19,9 @@ defineSuite([
'Specs/createScene'
], function(
EllipseGeometryUpdater,
+ ApproximateTerrainHeights,
Cartesian3,
+ GeometryOffsetAttribute,
JulianDate,
TimeIntervalCollection,
ConstantPositionProperty,
@@ -40,10 +44,15 @@ defineSuite([
beforeAll(function() {
scene = createScene();
time = JulianDate.now();
+
+ return ApproximateTerrainHeights.initialize();
});
afterAll(function() {
scene.destroyForSpecs();
+
+ ApproximateTerrainHeights._initPromise = undefined;
+ ApproximateTerrainHeights._terrainHeights = undefined;
});
function createBasicEllipse() {
@@ -234,6 +243,7 @@ defineSuite([
expect(geometry._height).toEqual(options.height);
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
+ expect(geometry._offsetAttribute).toBeUndefined();
instance = updater.createOutlineGeometryInstance(time);
geometry = instance.geometry;
@@ -245,6 +255,7 @@ defineSuite([
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
expect(geometry._numberOfVerticalLines).toEqual(options.numberOfVerticalLines);
+ expect(geometry._offsetAttribute).toBeUndefined();
});
it('dynamic updater sets properties', function() {
@@ -265,6 +276,7 @@ defineSuite([
expect(options.semiMajorAxis).toEqual(ellipse.semiMajorAxis.getValue());
expect(options.semiMinorAxis).toEqual(ellipse.semiMinorAxis.getValue());
expect(options.height).toEqual(ellipse.height.getValue());
+ expect(options.offsetAttribute).toBeUndefined();
});
it('geometryChanged event is raised when expected', function() {
@@ -304,6 +316,13 @@ defineSuite([
expect(listener.calls.count()).toEqual(5);
});
+ it('computes center', function() {
+ var entity = createBasicEllipse();
+ var updater = new EllipseGeometryUpdater(entity, scene);
+
+ expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time));
+ });
+
function getScene() {
return scene;
}
diff --git a/Specs/DataSources/GroundGeometryUpdaterSpec.js b/Specs/DataSources/GroundGeometryUpdaterSpec.js
new file mode 100644
index 000000000000..6974d335bd18
--- /dev/null
+++ b/Specs/DataSources/GroundGeometryUpdaterSpec.js
@@ -0,0 +1,115 @@
+defineSuite([
+ 'DataSources/GroundGeometryUpdater',
+ 'Core/ApproximateTerrainHeights',
+ 'Core/Event',
+ 'Core/GeometryOffsetAttribute',
+ 'Core/JulianDate',
+ 'Core/Rectangle',
+ 'Scene/HeightReference',
+ 'DataSources/ConstantProperty'
+], function(
+ GroundGeometryUpdater,
+ ApproximateTerrainHeights,
+ Event,
+ GeometryOffsetAttribute,
+ JulianDate,
+ Rectangle,
+ HeightReference,
+ ConstantProperty) {
+ 'use strict';
+
+ var time = JulianDate.now();
+
+ beforeAll(function() {
+ return ApproximateTerrainHeights.initialize();
+ });
+
+ afterAll(function() {
+ ApproximateTerrainHeights._initPromise = undefined;
+ ApproximateTerrainHeights._terrainHeights = undefined;
+ });
+
+ it('getGeometryHeight works for for height reference NONE and RELATIVE_TO_GROUND', function() {
+ var expected = 30;
+ var height = new ConstantProperty(expected);
+ var heightReference = new ConstantProperty(HeightReference.NONE);
+ expect(GroundGeometryUpdater.getGeometryHeight(height, heightReference, time)).toEqual(expected);
+
+ heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ expect(GroundGeometryUpdater.getGeometryHeight(height, heightReference, time)).toEqual(expected);
+ });
+
+ it('getGeometryHeight works for for height reference CLAMP_TO_GROUND', function() {
+ var height = new ConstantProperty(50);
+ var heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ expect(GroundGeometryUpdater.getGeometryHeight(height, heightReference, time)).toEqual(0);
+ });
+
+ it('getGeometryExtrudedHeight works for for height reference NONE and RELATIVE_TO_GROUND', function() {
+ var expected = 30;
+ var height = new ConstantProperty(expected);
+ var heightReference = new ConstantProperty(HeightReference.NONE);
+ expect(GroundGeometryUpdater.getGeometryExtrudedHeight(height, heightReference, time)).toEqual(expected);
+
+ heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ expect(GroundGeometryUpdater.getGeometryExtrudedHeight(height, heightReference, time)).toEqual(expected);
+ });
+
+ it('getGeometryExtrudedHeight works for for height reference CLAMP_TO_GROUND', function() {
+ var height = new ConstantProperty(50);
+ var heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ expect(GroundGeometryUpdater.getGeometryExtrudedHeight(height, heightReference, time)).toEqual(GroundGeometryUpdater.CLAMP_TO_GROUND);
+ });
+
+ it('computeGeometryOffsetAttribute works', function() {
+ var heightReference;
+ var extrudedHeightReference;
+ var result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBeUndefined();
+
+ heightReference = new ConstantProperty(HeightReference.NONE);
+ extrudedHeightReference = new ConstantProperty(HeightReference.NONE);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBeUndefined();
+
+ heightReference = new ConstantProperty(HeightReference.NONE);
+ extrudedHeightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBeUndefined();
+
+ heightReference = new ConstantProperty(HeightReference.NONE);
+ extrudedHeightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.TOP);
+
+ heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ extrudedHeightReference = new ConstantProperty(HeightReference.NONE);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.TOP);
+
+ heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ extrudedHeightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.TOP);
+
+ heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ extrudedHeightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.ALL);
+
+ heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ extrudedHeightReference = new ConstantProperty(HeightReference.NONE);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.TOP);
+
+ heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ extrudedHeightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.TOP);
+
+ heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ extrudedHeightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ result = GroundGeometryUpdater.computeGeometryOffsetAttribute(heightReference, extrudedHeightReference, time);
+ expect(result).toBe(GeometryOffsetAttribute.ALL);
+ });
+});
diff --git a/Specs/DataSources/PolygonGeometryUpdaterSpec.js b/Specs/DataSources/PolygonGeometryUpdaterSpec.js
index 1e87f87d4d5a..18d40f26e264 100644
--- a/Specs/DataSources/PolygonGeometryUpdaterSpec.js
+++ b/Specs/DataSources/PolygonGeometryUpdaterSpec.js
@@ -1,7 +1,11 @@
defineSuite([
'DataSources/PolygonGeometryUpdater',
+ 'Core/ApproximateTerrainHeights',
'Core/Cartesian3',
+ 'Core/Ellipsoid',
+ 'Core/GeometryOffsetAttribute',
'Core/JulianDate',
+ 'Core/Math',
'Core/PolygonHierarchy',
'Core/TimeIntervalCollection',
'DataSources/ConstantProperty',
@@ -19,8 +23,12 @@ defineSuite([
'Specs/createScene'
], function(
PolygonGeometryUpdater,
+ ApproximateTerrainHeights,
Cartesian3,
+ Ellipsoid,
+ GeometryOffsetAttribute,
JulianDate,
+ CesiumMath,
PolygonHierarchy,
TimeIntervalCollection,
ConstantProperty,
@@ -46,19 +54,23 @@ defineSuite([
scene = createScene();
time = JulianDate.now();
groundPrimitiveSupported = GroundPrimitive.isSupported(scene);
+ return ApproximateTerrainHeights.initialize();
});
afterAll(function() {
scene.destroyForSpecs();
+
+ ApproximateTerrainHeights._initPromise = undefined;
+ ApproximateTerrainHeights._terrainHeights = undefined;
});
function createBasicPolygon() {
var polygon = new PolygonGraphics();
polygon.hierarchy = new ConstantProperty(new PolygonHierarchy(Cartesian3.fromRadiansArray([
- 0, 0,
- 1, 0,
+ -1, -1,
+ 1, -1,
1, 1,
- 0, 1
+ -1, 1
])));
polygon.height = new ConstantProperty(0);
var entity = new Entity();
@@ -225,6 +237,7 @@ defineSuite([
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
expect(geometry._closeTop).toEqual(options.closeTop);
expect(geometry._closeBottom).toEqual(options.closeBottom);
+ expect(geometry._offsetAttribute).toBeUndefined();
instance = updater.createOutlineGeometryInstance(time);
geometry = instance.geometry;
@@ -232,6 +245,7 @@ defineSuite([
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
expect(geometry._perPositionHeight).toEqual(options.perPositionHeight);
+ expect(geometry._offsetAttribute).toBeUndefined();
});
it('Checks that a polygon with per position heights isn\'t on terrain', function() {
@@ -291,6 +305,7 @@ defineSuite([
expect(options.stRotation).toEqual(polygon.stRotation.getValue());
expect(options.closeTop).toEqual(polygon.closeTop.getValue());
expect(options.closeBottom).toEqual(polygon.closeBottom.getValue());
+ expect(options.offsetAttribute).toBeUndefined();
});
it('geometryChanged event is raised when expected', function() {
@@ -333,6 +348,14 @@ defineSuite([
expect(updater.onTerrain).toBe(false);
});
+ it('computes center', function() {
+ var entity = createBasicPolygon();
+ var updater = new PolygonGeometryUpdater(entity, scene);
+ var result = updater._computeCenter(time);
+ result = Ellipsoid.WGS84.scaleToGeodeticSurface(result, result);
+ expect(result).toEqualEpsilon(Cartesian3.fromDegrees(0.0, 0.0), CesiumMath.EPSILON10);
+ });
+
function getScene() {
return scene;
}
diff --git a/Specs/DataSources/PolylineGeometryUpdaterSpec.js b/Specs/DataSources/PolylineGeometryUpdaterSpec.js
index cc14250f3aef..67f2e43daff3 100644
--- a/Specs/DataSources/PolylineGeometryUpdaterSpec.js
+++ b/Specs/DataSources/PolylineGeometryUpdaterSpec.js
@@ -800,5 +800,7 @@ defineSuite([
var instance = updater.createFillGeometryInstance(time);
expect(instance.geometry instanceof GroundPolylineGeometry).toBe(false);
+
+ updater.destroy();
});
}, 'WebGL');
diff --git a/Specs/DataSources/RectangleGeometryUpdaterSpec.js b/Specs/DataSources/RectangleGeometryUpdaterSpec.js
index 2608b931511f..4f8c74175435 100644
--- a/Specs/DataSources/RectangleGeometryUpdaterSpec.js
+++ b/Specs/DataSources/RectangleGeometryUpdaterSpec.js
@@ -1,7 +1,10 @@
defineSuite([
'DataSources/RectangleGeometryUpdater',
+ 'Core/ApproximateTerrainHeights',
'Core/Cartesian3',
+ 'Core/GeometryOffsetAttribute',
'Core/JulianDate',
+ 'Core/Math',
'Core/Rectangle',
'Core/TimeIntervalCollection',
'DataSources/ConstantProperty',
@@ -16,8 +19,11 @@ defineSuite([
'Specs/createScene'
], function(
RectangleGeometryUpdater,
+ ApproximateTerrainHeights,
Cartesian3,
+ GeometryOffsetAttribute,
JulianDate,
+ CesiumMath,
Rectangle,
TimeIntervalCollection,
ConstantProperty,
@@ -38,17 +44,22 @@ defineSuite([
beforeAll(function() {
scene = createScene();
time = new JulianDate(0, 0);
+
+ return ApproximateTerrainHeights.initialize();
});
afterAll(function() {
scene.destroyForSpecs();
+
+ ApproximateTerrainHeights._initPromise = undefined;
+ ApproximateTerrainHeights._terrainHeights = undefined;
});
function createBasicRectangle() {
var rectangle = new RectangleGraphics();
var entity = new Entity();
entity.rectangle = rectangle;
- entity.rectangle.coordinates = new ConstantProperty(new Rectangle(0, 0, 1, 1));
+ entity.rectangle.coordinates = new ConstantProperty(new Rectangle(-1, -1, 1, 1));
entity.rectangle.height = new ConstantProperty(0);
return entity;
}
@@ -161,12 +172,14 @@ defineSuite([
expect(geometry._surfaceHeight).toEqual(options.height);
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
+ expect(geometry._offsetAttribute).toBeUndefined();
instance = updater.createOutlineGeometryInstance(time);
geometry = instance.geometry;
expect(geometry._surfaceHeight).toEqual(options.height);
expect(geometry._granularity).toEqual(options.granularity);
expect(geometry._extrudedHeight).toEqual(options.extrudedHeight);
+ expect(geometry._offsetAttribute).toBeUndefined();
});
it('dynamic updater sets properties', function() {
@@ -194,6 +207,7 @@ defineSuite([
expect(options.extrudedHeight).toEqual(rectangle.extrudedHeight.getValue());
expect(options.granularity).toEqual(rectangle.granularity.getValue());
expect(options.stRotation).toEqual(rectangle.stRotation.getValue());
+ expect(options.offsetAttribute).toBeUndefined();
});
it('geometryChanged event is raised when expected', function() {
@@ -224,6 +238,13 @@ defineSuite([
expect(listener.calls.count()).toEqual(3);
});
+ it('computes center', function() {
+ var entity = createBasicRectangle();
+ var updater = new RectangleGeometryUpdater(entity, scene);
+
+ expect(updater._computeCenter(time)).toEqualEpsilon(Cartesian3.fromDegrees(0.0, 0.0), CesiumMath.EPSILON10);
+ });
+
function getScene() {
return scene;
}
diff --git a/Specs/DataSources/TerrainOffsetPropertySpec.js b/Specs/DataSources/TerrainOffsetPropertySpec.js
new file mode 100644
index 000000000000..9a0b060c5e4f
--- /dev/null
+++ b/Specs/DataSources/TerrainOffsetPropertySpec.js
@@ -0,0 +1,63 @@
+defineSuite([
+ 'DataSources/TerrainOffsetProperty',
+ 'Core/Cartesian3',
+ 'Core/Event',
+ 'Core/JulianDate',
+ 'Core/Rectangle',
+ 'Scene/HeightReference',
+ 'DataSources/CallbackProperty',
+ 'DataSources/ConstantProperty',
+ 'Specs/createGlobe',
+ 'Specs/createScene'
+], function(
+ TerrainOffsetProperty,
+ Cartesian3,
+ Event,
+ JulianDate,
+ Rectangle,
+ HeightReference,
+ CallbackProperty,
+ ConstantProperty,
+ createGlobe,
+ createScene) {
+ 'use strict';
+
+ var scene;
+ var time = JulianDate.now();
+ beforeAll(function() {
+ scene = createScene();
+ scene.globe = createGlobe();
+ });
+
+ afterAll(function() {
+ scene.destroyForSpecs();
+ });
+
+ it('can construct and destroy', function() {
+ var position = new CallbackProperty(jasmine.createSpy(), false);
+ var height = new ConstantProperty(30);
+ var extrudedHeight = new ConstantProperty(0);
+ var property = new TerrainOffsetProperty(scene, height, extrudedHeight, position);
+ expect(property.isConstant).toBe(false);
+ expect(property.getValue(time)).toEqual(Cartesian3.ZERO);
+ property.destroy();
+ expect(property.isDestroyed()).toBe(true);
+ });
+
+ it('throws without scene', function() {
+ var position = new CallbackProperty(jasmine.createSpy(), false);
+ var height = new ConstantProperty(30);
+ var extrudedHeight = new ConstantProperty(0);
+ expect(function() {
+ return new TerrainOffsetProperty(undefined, height, extrudedHeight, position);
+ }).toThrowDeveloperError();
+ });
+
+ it('throws without position', function() {
+ var height = new ConstantProperty(30);
+ var extrudedHeight = new ConstantProperty(0);
+ expect(function() {
+ return new TerrainOffsetProperty(scene, height, extrudedHeight, undefined);
+ }).toThrowDeveloperError();
+ });
+});
diff --git a/Specs/createGeometryUpdaterGroundGeometrySpecs.js b/Specs/createGeometryUpdaterGroundGeometrySpecs.js
index b0ed38ab479c..9a7f3af4efb7 100644
--- a/Specs/createGeometryUpdaterGroundGeometrySpecs.js
+++ b/Specs/createGeometryUpdaterGroundGeometrySpecs.js
@@ -1,20 +1,24 @@
define([
'Core/Color',
+ 'Core/GeometryOffsetAttribute',
'Core/JulianDate',
'DataSources/ColorMaterialProperty',
'DataSources/ConstantProperty',
'DataSources/SampledProperty',
'Scene/ClassificationType',
'Scene/GroundPrimitive',
+ 'Scene/HeightReference',
'Scene/PrimitiveCollection'
], function(
Color,
+ GeometryOffsetAttribute,
JulianDate,
ColorMaterialProperty,
ConstantProperty,
SampledProperty,
ClassificationType,
GroundPrimitive,
+ HeightReference,
PrimitiveCollection) {
'use strict';
@@ -119,6 +123,108 @@ define([
expect(updater.onTerrain).toBe(false);
});
+ it('Creates geometry with no offsetAttribute when geometry is on terrain', function() {
+ var entity = createEntity();
+
+ var updater = new Updater(entity, getScene());
+
+ var instance;
+ var geometry;
+ instance = updater.createFillGeometryInstance(time);
+ geometry = instance.geometry;
+ expect(geometry._offsetAttribute).toBeUndefined();
+ });
+
+ it('Creates geometry with expected offsetAttribute based on height and extrudedHeight', function() {
+ var entity = createEntity();
+ var graphics = entity[geometryPropertyName];
+ graphics.outline = true;
+ graphics.outlineColor = Color.BLACK;
+ graphics.height = new ConstantProperty(20.0);
+ graphics.extrudedHeight = new ConstantProperty(0.0);
+ var updater = new Updater(entity, getScene());
+
+ var instance;
+
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toBeUndefined();
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toBeUndefined();
+
+ graphics.heightReference = new ConstantProperty(HeightReference.NONE);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.NONE);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toBeUndefined();
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toBeUndefined();
+
+ graphics.heightReference = new ConstantProperty(HeightReference.NONE);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toBeUndefined();
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toBeUndefined();
+
+ graphics.heightReference = new ConstantProperty(HeightReference.NONE);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+
+ graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.NONE);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+
+ graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+
+ graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL);
+
+ graphics.heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.NONE);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+
+ graphics.heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.TOP);
+
+ graphics.heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ graphics.extrudedHeightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND);
+ updater._onEntityPropertyChanged(entity, geometryPropertyName);
+ instance = updater.createFillGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL);
+ instance = updater.createOutlineGeometryInstance(time);
+ expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL);
+ });
+
it('color material sets onTerrain to true', function() {
var entity = createEntity();
var geometry = entity[geometryPropertyName];