From 1f0ec2e07e7c9bda7680480ace30bc461449af3c Mon Sep 17 00:00:00 2001 From: hpinkos Date: Fri, 17 Aug 2018 15:57:55 -0400 Subject: [PATCH 1/4] Height reference for Box, Cylinder and Ellipsoid entities --- .../gallery/Geometry Height Reference.html | 90 ++++++++++++-- Source/DataSources/BoxGeometryUpdater.js | 89 ++++++++++---- Source/DataSources/BoxGraphics.js | 12 ++ Source/DataSources/CylinderGeometryUpdater.js | 94 ++++++++++----- Source/DataSources/CylinderGraphics.js | 12 ++ .../DataSources/EllipsoidGeometryUpdater.js | 112 +++++++++++++----- Source/DataSources/EllipsoidGraphics.js | 12 ++ Source/DataSources/Entity.js | 41 +++++++ Source/DataSources/GroundGeometryUpdater.js | 8 +- Source/DataSources/TerrainOffsetProperty.js | 2 +- .../heightReferenceOnEntityPropertyChanged.js | 40 +++++++ Specs/DataSources/BoxGeometryUpdaterSpec.js | 55 +++++++++ .../CylinderGeometryUpdaterSpec.js | 55 +++++++++ .../EllipsoidGeometryUpdaterSpec.js | 52 ++++++++ .../DataSources/TerrainOffsetPropertySpec.js | 6 +- 15 files changed, 581 insertions(+), 99 deletions(-) create mode 100644 Source/DataSources/heightReferenceOnEntityPropertyChanged.js diff --git a/Apps/Sandcastle/gallery/Geometry Height Reference.html b/Apps/Sandcastle/gallery/Geometry Height Reference.html index d3202f476d38..743da3f2bf42 100644 --- a/Apps/Sandcastle/gallery/Geometry Height Reference.html +++ b/Apps/Sandcastle/gallery/Geometry Height Reference.html @@ -4,7 +4,7 @@ - + Cesium Demo @@ -41,6 +41,20 @@ // instead of showing through it from underground viewer.scene.globe.depthTestAgainstTerrain = true; +Sandcastle.addToolbarMenu([{ + text : 'Polygons', + onselect : function() { + viewer.entities.removeAll(); + addPolygons(); + } +}, { + text : 'Boxes, Cylinders and Ellipsoids', + onselect : function() { + viewer.entities.removeAll(); + addGeometries(); + } +}]); + Sandcastle.addToolbarMenu([{ text : 'Terrain Enabled', onselect : function() { @@ -53,11 +67,63 @@ } }]); -var longitude = 6.850615989890521; -var latitude = 45.89546589994886; +var longitude = 6.950615989890521; +var latitude = 45.79546589994886; var delta = 0.001; -function addEntity(i, j) { +function addGeometry(i, j) { + var west = longitude + delta * i; + var north = latitude + delta * j + delta; + + var type = Math.floor(Math.random() * 3); + if (type === 0) { + viewer.entities.add({ + position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), + box : { + dimensions : new Cesium.Cartesian3(40.0, 30.0, 50.0), + material : Cesium.Color.fromRandom({alpha : 1}), + outline : true, + outlineColor : Cesium.Color.BLACK, + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND + } + }); + } else if (type === 1) { + viewer.entities.add({ + position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), + cylinder : { + length :50.0, + topRadius : 20.0, + bottomRadius : 20.0, + material : Cesium.Color.fromRandom({alpha : 1}), + outline : true, + outlineColor : Cesium.Color.BLACK, + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND + } + }); + } else { + viewer.entities.add({ + position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), + ellipsoid : { + radii : new Cesium.Cartesian3(20.0, 15.0, 25.0), + material : Cesium.Color.fromRandom({alpha : 1}), + outline : true, + outlineColor : Cesium.Color.BLACK, + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND + } + }); + } +} + +function addGeometries(){ + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + addGeometry(i, j); + } + } + viewer.zoomTo(viewer.entities); +} + +function addPolygon(i, j) { var west = longitude + delta * i; var east = longitude + delta * i + delta; @@ -81,15 +147,17 @@ }); } -// create 16 polygons that are side-by-side -for (var i = 0; i < 4; i++) { - for (var j = 0; j < 4; j++) { - addEntity(i, j); +function addPolygons() { + // create 16 polygons that are side-by-side + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + addPolygon(i, j); + } } + viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(longitude, latitude, 1500), new Cesium.HeadingPitchRange(-Cesium.Math.PI/2, -Cesium.Math.PI_OVER_FOUR, 2000)); + viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); } - -viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(longitude, latitude, 500), new Cesium.HeadingPitchRange(Cesium.Math.PI, -Cesium.Math.PI_OVER_FOUR, 2000)); -viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);//Sandcastle_End +//Sandcastle_End Sandcastle.finishedLoading(); } if (typeof Cesium !== 'undefined') { diff --git a/Source/DataSources/BoxGeometryUpdater.js b/Source/DataSources/BoxGeometryUpdater.js index 65fc33687cb0..40b807d927d9 100644 --- a/Source/DataSources/BoxGeometryUpdater.js +++ b/Source/DataSources/BoxGeometryUpdater.js @@ -6,13 +6,18 @@ define([ '../Core/Color', '../Core/ColorGeometryInstanceAttribute', '../Core/defined', + '../Core/defineProperties', '../Core/DeveloperError', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/GeometryInstance', + '../Core/GeometryOffsetAttribute', '../Core/Iso8601', + '../Core/OffsetGeometryInstanceAttribute', '../Core/ShowGeometryInstanceAttribute', + '../Scene/HeightReference', '../Scene/MaterialAppearance', '../Scene/PerInstanceColorAppearance', + './heightReferenceOnEntityPropertyChanged', './ColorMaterialProperty', './DynamicGeometryUpdater', './GeometryUpdater', @@ -25,19 +30,27 @@ define([ Color, ColorGeometryInstanceAttribute, defined, + defineProperties, DeveloperError, DistanceDisplayConditionGeometryInstanceAttribute, GeometryInstance, + GeometryOffsetAttribute, Iso8601, + OffsetGeometryInstanceAttribute, ShowGeometryInstanceAttribute, + HeightReference, MaterialAppearance, PerInstanceColorAppearance, + heightReferenceOnEntityPropertyChanged, ColorMaterialProperty, DynamicGeometryUpdater, GeometryUpdater, Property) { 'use strict'; + var defaultOffset = Cartesian3.ZERO; + + var offsetScratch = new Cartesian3(); var positionScratch = new Cartesian3(); var scratchColor = new Color(); @@ -45,6 +58,7 @@ define([ this.id = entity; this.vertexFormat = undefined; this.dimensions = undefined; + this.offsetAttribute = undefined; } /** @@ -73,6 +87,20 @@ define([ BoxGeometryUpdater.prototype.constructor = BoxGeometryUpdater; } + defineProperties(BoxGeometryUpdater.prototype, { + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof BoxGeometryUpdater.prototype + * @readonly + */ + terrainOffsetProperty: { + get: function() { + return this._terrainOffsetProperty; + } + } + }); + /** * Creates the geometry instance which represents the fill of the geometry. * @@ -93,12 +121,16 @@ define([ var entity = this._entity; var isAvailable = entity.isAvailable(time); - var attributes; - - 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); + + var attributes = { + show : show, + distanceDisplayCondition : distanceDisplayConditionAttribute, + color : undefined, + offset: undefined + }; if (this._materialProperty instanceof ColorMaterialProperty) { var currentColor; if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { @@ -107,23 +139,16 @@ 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({ id : entity, geometry : BoxGeometry.fromDimensions(this._options), - modelMatrix : entity.computeModelMatrix(time), + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.box.heightReference, this._options.dimensions.z * 0.5, this._scene.mapProjection.ellipsoid), attributes : attributes }); }; @@ -150,18 +175,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 : BoxOutlineGeometry.fromDimensions(this._options), - modelMatrix : entity.computeModelMatrix(time), - attributes : { - show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), - color : ColorGeometryInstanceAttribute.fromColor(outlineColor), - distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition) - } + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.box.heightReference, this._options.dimensions.z * 0.5, this._scene.mapProjection.ellipsoid), + attributes : attributes }); }; + BoxGeometryUpdater.prototype._computeCenter = function(time, result) { + return Property.getValueOrUndefined(this._entity.position, time, result); + }; + BoxGeometryUpdater.prototype._isHidden = function(entity, box) { return !defined(box.dimensions) || !defined(entity.position) || GeometryUpdater.prototype._isHidden.call(this, entity, box); }; @@ -171,13 +206,16 @@ define([ }; BoxGeometryUpdater.prototype._setStaticOptions = function(entity, box) { - var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty; + var heightReference = Property.getValueOrDefault(box.heightReference, Iso8601.MINIMUM_VALUE, HeightReference.NONE); 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.dimensions = box.dimensions.getValue(Iso8601.MINIMUM_VALUE, options.dimensions); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; + BoxGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged; + BoxGeometryUpdater.DynamicGeometryUpdater = DynamicBoxGeometryUpdater; /** @@ -199,7 +237,10 @@ define([ }; DynamicBoxGeometryUpdater.prototype._setOptions = function(entity, box, time) { - this._options.dimensions = Property.getValueOrUndefined(box.dimensions, time, this._options.dimensions); + var heightReference = Property.getValueOrDefault(box.heightReference, time, HeightReference.NONE); + var options = this._options; + options.dimensions = Property.getValueOrUndefined(box.dimensions, time, options.dimensions); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; return BoxGeometryUpdater; diff --git a/Source/DataSources/BoxGraphics.js b/Source/DataSources/BoxGraphics.js index dd63aee52e21..69da519d55d6 100644 --- a/Source/DataSources/BoxGraphics.js +++ b/Source/DataSources/BoxGraphics.js @@ -23,6 +23,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: + * @param {Property} [options.heightReference] A Property specifying what the height from the entity position is relative to. * @param {Property} [options.dimensions] A {@link Cartesian3} Property specifying the length, width, and height of the box. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the box. * @param {Property} [options.fill=true] A boolean Property specifying whether the box is filled with the provided material. @@ -36,6 +37,7 @@ define([ * @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Box.html|Cesium Sandcastle Box Demo} */ function BoxGraphics(options) { + this._heightReference = undefined; this._dimensions = undefined; this._dimensionsSubscription = undefined; this._show = undefined; @@ -72,6 +74,14 @@ define([ } }, + /** + * Gets or sets the Property specifying the {@link HeightReference}. + * @memberof EllipsoidGraphics.prototype + * @type {Property} + * @default HeightReference.NONE + */ + heightReference : createPropertyDescriptor('heightReference'), + /** * Gets or sets the boolean Property specifying the visibility of the box. * @memberof BoxGraphics.prototype @@ -154,6 +164,7 @@ define([ if (!defined(result)) { return new BoxGraphics(this); } + result.heightReference = this.heightReference; result.dimensions = this.dimensions; result.show = this.show; result.material = this.material; @@ -179,6 +190,7 @@ define([ } //>>includeEnd('debug'); + this.heightReference = defaultValue(this.heightReference, source.heightReference); this.dimensions = defaultValue(this.dimensions, source.dimensions); this.show = defaultValue(this.show, source.show); this.material = defaultValue(this.material, source.material); diff --git a/Source/DataSources/CylinderGeometryUpdater.js b/Source/DataSources/CylinderGeometryUpdater.js index 90c863049ce3..0d5aad66a628 100644 --- a/Source/DataSources/CylinderGeometryUpdater.js +++ b/Source/DataSources/CylinderGeometryUpdater.js @@ -6,13 +6,18 @@ define([ '../Core/CylinderGeometry', '../Core/CylinderOutlineGeometry', '../Core/defined', + '../Core/defineProperties', '../Core/DeveloperError', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/GeometryInstance', + '../Core/GeometryOffsetAttribute', '../Core/Iso8601', + '../Core/OffsetGeometryInstanceAttribute', '../Core/ShowGeometryInstanceAttribute', + '../Scene/HeightReference', '../Scene/MaterialAppearance', '../Scene/PerInstanceColorAppearance', + './heightReferenceOnEntityPropertyChanged', './ColorMaterialProperty', './DynamicGeometryUpdater', './GeometryUpdater', @@ -25,19 +30,27 @@ define([ CylinderGeometry, CylinderOutlineGeometry, defined, + defineProperties, DeveloperError, DistanceDisplayConditionGeometryInstanceAttribute, GeometryInstance, + GeometryOffsetAttribute, Iso8601, + OffsetGeometryInstanceAttribute, ShowGeometryInstanceAttribute, + HeightReference, MaterialAppearance, PerInstanceColorAppearance, + heightReferenceOnEntityPropertyChanged, ColorMaterialProperty, DynamicGeometryUpdater, GeometryUpdater, Property) { 'use strict'; + var defaultOffset = Cartesian3.ZERO; + + var offsetScratch = new Cartesian3(); var positionScratch = new Cartesian3(); var scratchColor = new Color(); @@ -49,6 +62,7 @@ define([ this.bottomRadius = undefined; this.slices = undefined; this.numberOfVerticalLines = undefined; + this.offsetAttribute = undefined; } /** @@ -77,6 +91,20 @@ define([ CylinderGeometryUpdater.prototype.constructor = CylinderGeometryUpdater; } + defineProperties(CylinderGeometryUpdater.prototype, { + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof CylinderGeometryUpdater.prototype + * @readonly + */ + terrainOffsetProperty: { + get: function() { + return this._terrainOffsetProperty; + } + } + }); + /** * Creates the geometry instance which represents the fill of the geometry. * @@ -97,12 +125,16 @@ define([ var entity = this._entity; var isAvailable = entity.isAvailable(time); - var attributes; - - 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); + + var attributes = { + show : show, + distanceDisplayCondition : distanceDisplayConditionAttribute, + color : undefined, + offset: undefined + }; if (this._materialProperty instanceof ColorMaterialProperty) { var currentColor; if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { @@ -111,23 +143,17 @@ 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({ id : entity, geometry : new CylinderGeometry(this._options), - modelMatrix : entity.computeModelMatrix(time), + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.cylinder.heightReference, this._options.length * 0.5, this._scene.mapProjection.ellipsoid), attributes : attributes }); }; @@ -154,18 +180,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 CylinderOutlineGeometry(this._options), - modelMatrix : entity.computeModelMatrix(time), - attributes : { - show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), - color : ColorGeometryInstanceAttribute.fromColor(outlineColor), - distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition) - } + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.cylinder.heightReference, this._options.length * 0.5, this._scene.mapProjection.ellipsoid), + attributes : attributes }); }; + CylinderGeometryUpdater.prototype._computeCenter = function(time, result) { + return Property.getValueOrUndefined(this._entity.position, time, result); + }; + CylinderGeometryUpdater.prototype._isHidden = function(entity, cylinder) { return !defined(entity.position) || !defined(cylinder.length) || !defined(cylinder.topRadius) || !defined(cylinder.bottomRadius) || GeometryUpdater.prototype._isHidden.call(this, entity, cylinder); }; @@ -182,19 +218,19 @@ define([ }; CylinderGeometryUpdater.prototype._setStaticOptions = function(entity, cylinder) { - var slices = cylinder.slices; - var numberOfVerticalLines = cylinder.numberOfVerticalLines; - + var heightReference = Property.getValueOrDefault(cylinder.heightReference, Iso8601.MINIMUM_VALUE, HeightReference.NONE); var options = this._options; - var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty; - options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; + options.vertexFormat = this._materialProperty instanceof ColorMaterialProperty ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; options.length = cylinder.length.getValue(Iso8601.MINIMUM_VALUE); options.topRadius = cylinder.topRadius.getValue(Iso8601.MINIMUM_VALUE); options.bottomRadius = cylinder.bottomRadius.getValue(Iso8601.MINIMUM_VALUE); - options.slices = defined(slices) ? slices.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.numberOfVerticalLines = defined(numberOfVerticalLines) ? numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE) : undefined; + options.slices = Property.getValueOrUndefined(cylinder.slices, Iso8601.MINIMUM_VALUE); + options.numberOfVerticalLines = Property.getValueOrUndefined(cylinder.numberOfVerticalLines, Iso8601.MINIMUM_VALUE); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; + CylinderGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged; + CylinderGeometryUpdater.DynamicGeometryUpdater = DynamicCylinderGeometryUpdater; /** @@ -217,12 +253,14 @@ define([ }; DynamicCylinderGeometryUpdater.prototype._setOptions = function(entity, cylinder, time) { + var heightReference = Property.getValueOrDefault(cylinder.heightReference, time, HeightReference.NONE); var options = this._options; options.length = Property.getValueOrUndefined(cylinder.length, time); options.topRadius = Property.getValueOrUndefined(cylinder.topRadius, time); options.bottomRadius = Property.getValueOrUndefined(cylinder.bottomRadius, time); options.slices = Property.getValueOrUndefined(cylinder.slices, time); options.numberOfVerticalLines = Property.getValueOrUndefined(cylinder.numberOfVerticalLines, time); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; return CylinderGeometryUpdater; diff --git a/Source/DataSources/CylinderGraphics.js b/Source/DataSources/CylinderGraphics.js index 3b0deba5cedd..a27ee3b21dbc 100644 --- a/Source/DataSources/CylinderGraphics.js +++ b/Source/DataSources/CylinderGraphics.js @@ -24,6 +24,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: + * @param {Property} [options.heightReference] A Property specifying what the height from the entity position is relative to. * @param {Property} [options.length] A numeric Property specifying the length of the cylinder. * @param {Property} [options.topRadius] A numeric Property specifying the radius of the top of the cylinder. * @param {Property} [options.bottomRadius] A numeric Property specifying the radius of the bottom of the cylinder. @@ -39,6 +40,7 @@ define([ * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this cylinder will be displayed. */ function CylinderGraphics(options) { + this._heightReference = undefined; this._length = undefined; this._lengthSubscription = undefined; this._topRadius = undefined; @@ -84,6 +86,14 @@ define([ } }, + /** + * Gets or sets the Property specifying the {@link HeightReference}. + * @memberof EllipsoidGraphics.prototype + * @type {Property} + * @default HeightReference.NONE + */ + heightReference : createPropertyDescriptor('heightReference'), + /** * Gets or sets the numeric Property specifying the length of the cylinder. * @memberof CylinderGraphics.prototype @@ -196,6 +206,7 @@ define([ if (!defined(result)) { return new CylinderGraphics(this); } + result.heightReference = this.heightReference; result.bottomRadius = this.bottomRadius; result.length = this.length; result.topRadius = this.topRadius; @@ -225,6 +236,7 @@ define([ } //>>includeEnd('debug'); + this.heightReference = defaultValue(this.heightReference, source.heightReference); this.bottomRadius = defaultValue(this.bottomRadius, source.bottomRadius); this.length = defaultValue(this.length, source.length); this.topRadius = defaultValue(this.topRadius, source.topRadius); diff --git a/Source/DataSources/EllipsoidGeometryUpdater.js b/Source/DataSources/EllipsoidGeometryUpdater.js index 41f6b4052e27..a606fbc6ff5f 100644 --- a/Source/DataSources/EllipsoidGeometryUpdater.js +++ b/Source/DataSources/EllipsoidGeometryUpdater.js @@ -5,18 +5,23 @@ define([ '../Core/ColorGeometryInstanceAttribute', '../Core/defaultValue', '../Core/defined', + '../Core/defineProperties', '../Core/DistanceDisplayCondition', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/EllipsoidGeometry', '../Core/EllipsoidOutlineGeometry', '../Core/GeometryInstance', + '../Core/GeometryOffsetAttribute', '../Core/Iso8601', + '../Core/OffsetGeometryInstanceAttribute', '../Core/Matrix4', '../Core/ShowGeometryInstanceAttribute', + '../Scene/HeightReference', '../Scene/MaterialAppearance', '../Scene/PerInstanceColorAppearance', '../Scene/Primitive', '../Scene/SceneMode', + './heightReferenceOnEntityPropertyChanged', './ColorMaterialProperty', './DynamicGeometryUpdater', './GeometryUpdater', @@ -29,18 +34,23 @@ define([ ColorGeometryInstanceAttribute, defaultValue, defined, + defineProperties, DistanceDisplayCondition, DistanceDisplayConditionGeometryInstanceAttribute, EllipsoidGeometry, EllipsoidOutlineGeometry, GeometryInstance, + GeometryOffsetAttribute, Iso8601, + OffsetGeometryInstanceAttribute, Matrix4, ShowGeometryInstanceAttribute, + HeightReference, MaterialAppearance, PerInstanceColorAppearance, Primitive, SceneMode, + heightReferenceOnEntityPropertyChanged, ColorMaterialProperty, DynamicGeometryUpdater, GeometryUpdater, @@ -49,7 +59,9 @@ define([ 'use strict'; var defaultMaterial = new ColorMaterialProperty(Color.WHITE); + var defaultOffset = Cartesian3.ZERO; + var offsetScratch = new Cartesian3(); var radiiScratch = new Cartesian3(); var scratchColor = new Color(); var unitSphere = new Cartesian3(1, 1, 1); @@ -61,6 +73,7 @@ define([ this.stackPartitions = undefined; this.slicePartitions = undefined; this.subdivisions = undefined; + this.offsetAttribute = undefined; } /** @@ -89,6 +102,20 @@ define([ EllipsoidGeometryUpdater.prototype.constructor = EllipsoidGeometryUpdater; } + defineProperties(EllipsoidGeometryUpdater.prototype, { + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof EllipsoidGeometryUpdater.prototype + * @readonly + */ + terrainOffsetProperty: { + get: function() { + return this._terrainOffsetProperty; + } + } + }); + /** * Creates the geometry instance which represents the fill of the geometry. * @@ -107,12 +134,18 @@ define([ var entity = this._entity; var isAvailable = entity.isAvailable(time); - var attributes; - 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); + + var attributes = { + show : show, + distanceDisplayCondition : distanceDisplayConditionAttribute, + color : undefined, + offset: undefined + }; + if (this._materialProperty instanceof ColorMaterialProperty) { var currentColor; if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { @@ -122,22 +155,16 @@ define([ currentColor = Color.WHITE; } color = ColorGeometryInstanceAttribute.fromColor(currentColor); - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute, - color : color - }; - } else { - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute - }; + attributes.color = color; + } + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); } return new GeometryInstance({ id : entity, geometry : new EllipsoidGeometry(this._options), - modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrix(time, modelMatrixResult), + modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrixForHeightReference(time, entity.ellipsoid.heightReference, this._options.radii.z * 0.5, this._scene.mapProjection.ellipsoid, modelMatrixResult), attributes : attributes }); }; @@ -163,18 +190,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 EllipsoidOutlineGeometry(this._options), - modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrix(time, modelMatrixResult), - attributes : { - show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), - color : ColorGeometryInstanceAttribute.fromColor(outlineColor), - distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition) - } + modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrixForHeightReference(time, entity.ellipsoid.heightReference, this._options.radii.z * 0.5, this._scene.mapProjection.ellipsoid, modelMatrixResult), + attributes : attributes }); }; + EllipsoidGeometryUpdater.prototype._computeCenter = function(time, result) { + return Property.getValueOrUndefined(this._entity.position, time, result); + }; + EllipsoidGeometryUpdater.prototype._isHidden = function(entity, ellipsoid) { return !defined(entity.position) || !defined(ellipsoid.radii) || GeometryUpdater.prototype._isHidden.call(this, entity, ellipsoid); }; @@ -190,19 +227,18 @@ define([ }; EllipsoidGeometryUpdater.prototype._setStaticOptions = function(entity, ellipsoid) { - var stackPartitions = ellipsoid.stackPartitions; - var slicePartitions = ellipsoid.slicePartitions; - var subdivisions = ellipsoid.subdivisions; - var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty; - + var heightReference = Property.getValueOrDefault(ellipsoid.heightReference, Iso8601.MINIMUM_VALUE, HeightReference.NONE); 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.radii = ellipsoid.radii.getValue(Iso8601.MINIMUM_VALUE, options.radii); - options.stackPartitions = defined(stackPartitions) ? stackPartitions.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.slicePartitions = defined(slicePartitions) ? slicePartitions.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.subdivisions = defined(subdivisions) ? subdivisions.getValue(Iso8601.MINIMUM_VALUE) : undefined; + options.stackPartitions = Property.getValueOrUndefined(ellipsoid.stackPartitions, Iso8601.MINIMUM_VALUE); + options.slicePartitions = Property.getValueOrUndefined(ellipsoid.slicePartitions, Iso8601.MINIMUM_VALUE); + options.subdivisions = Property.getValueOrUndefined(ellipsoid.subdivisions, Iso8601.MINIMUM_VALUE); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; + EllipsoidGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged; + EllipsoidGeometryUpdater.DynamicGeometryUpdater = DynamicEllipsoidGeometryUpdater; /** @@ -220,6 +256,7 @@ define([ this._lastOutlineShow = undefined; this._lastOutlineWidth = undefined; this._lastOutlineColor = undefined; + this._lastOffset = new Cartesian3(); this._material = {}; } @@ -247,7 +284,7 @@ define([ } var radii = Property.getValueOrUndefined(ellipsoid.radii, time, radiiScratch); - var modelMatrix = entity.computeModelMatrix(time, this._modelMatrix); + var modelMatrix = entity.computeModelMatrixForHeightReference(time, ellipsoid.heightReference, radii.z * 0.5, this._scene.mapProjection.ellipsoid, this._modelMatrix); if (!defined(modelMatrix) || !defined(radii)) { if (defined(this._primitive)) { this._primitive.show = false; @@ -270,10 +307,13 @@ define([ var slicePartitions = Property.getValueOrUndefined(ellipsoid.slicePartitions, time); var subdivisions = Property.getValueOrUndefined(ellipsoid.subdivisions, time); var outlineWidth = Property.getValueOrDefault(ellipsoid.outlineWidth, time, 1.0); + var heightReference = Property.getValueOrDefault(ellipsoid.heightReference, time, HeightReference.NONE); + var offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; //In 3D we use a fast path by modifying Primitive.modelMatrix instead of regenerating the primitive every frame. + //Also check for height reference because this method doesn't work when the height is relative to terrain. var sceneMode = this._scene.mode; - var in3D = sceneMode === SceneMode.SCENE3D; + var in3D = sceneMode === SceneMode.SCENE3D && heightReference === HeightReference.NONE; var options = this._options; @@ -282,11 +322,13 @@ define([ var distanceDisplayConditionProperty = this._geometryUpdater.distanceDisplayConditionProperty; var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time); + var offset = Property.getValueOrDefault(this._geometryUpdater.terrainOffsetProperty, time, defaultOffset, offsetScratch); + //We only rebuild the primitive if something other than the radii has changed //For the radii, we use unit sphere and then deform it with a scale matrix. var rebuildPrimitives = !in3D || this._lastSceneMode !== sceneMode || !defined(this._primitive) || // options.stackPartitions !== stackPartitions || options.slicePartitions !== slicePartitions || // - options.subdivisions !== subdivisions || this._lastOutlineWidth !== outlineWidth; + options.subdivisions !== subdivisions || this._lastOutlineWidth !== outlineWidth || options.offsetAttribute !== offsetAttribute; if (rebuildPrimitives) { var primitives = this._primitives; @@ -300,6 +342,7 @@ define([ options.stackPartitions = stackPartitions; options.slicePartitions = slicePartitions; options.subdivisions = subdivisions; + options.offsetAttribute = offsetAttribute; options.radii = in3D ? unitSphere : radii; var appearance = new MaterialAppearance({ @@ -336,6 +379,7 @@ define([ this._lastOutlineShow = showOutline; this._lastOutlineColor = Color.clone(outlineColor, this._lastOutlineColor); this._lastDistanceDisplayCondition = distanceDisplayCondition; + this._lastOffset = Cartesian3.clone(offset, this._lastOffset); } else if (this._primitive.ready) { //Update attributes only. var primitive = this._primitive; @@ -377,6 +421,12 @@ define([ outlineAttributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, outlineAttributes.distanceDisplayCondition); DistanceDisplayCondition.clone(distanceDisplayCondition, this._lastDistanceDisplayCondition); } + + if (!Cartesian3.equals(offset, this._lastOffset)) { + attributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset); + outlineAttributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset); + Cartesian3.clone(offset, this._lastOffset); + } } if (in3D) { diff --git a/Source/DataSources/EllipsoidGraphics.js b/Source/DataSources/EllipsoidGraphics.js index 2199c61dec41..9f2894b09eed 100644 --- a/Source/DataSources/EllipsoidGraphics.js +++ b/Source/DataSources/EllipsoidGraphics.js @@ -23,6 +23,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: + * @param {Property} [options.heightReference] A Property specifying what the height from the entity position is relative to. * @param {Property} [options.radii] A {@link Cartesian3} Property specifying the radii of the ellipsoid. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the ellipsoid. * @param {Property} [options.fill=true] A boolean Property specifying whether the ellipsoid is filled with the provided material. @@ -39,6 +40,7 @@ define([ * @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Spheres%20and%20Ellipsoids.html|Cesium Sandcastle Spheres and Ellipsoids Demo} */ function EllipsoidGraphics(options) { + this._heightReference = undefined; this._show = undefined; this._showSubscription = undefined; this._radii = undefined; @@ -82,6 +84,14 @@ define([ } }, + /** + * Gets or sets the Property specifying the {@link HeightReference}. + * @memberof EllipsoidGraphics.prototype + * @type {Property} + * @default HeightReference.NONE + */ + heightReference : createPropertyDescriptor('heightReference'), + /** * Gets or sets the boolean Property specifying the visibility of the ellipsoid. * @memberof EllipsoidGraphics.prototype @@ -188,6 +198,7 @@ define([ if (!defined(result)) { return new EllipsoidGraphics(this); } + result.heightReference = this.heightReference; result.show = this.show; result.radii = this.radii; result.material = this.material; @@ -217,6 +228,7 @@ define([ } //>>includeEnd('debug'); + this.heightReference = defaultValue(this.heightReference, source.heightReference); this.show = defaultValue(this.show, source.show); this.radii = defaultValue(this.radii, source.radii); this.material = defaultValue(this.material, source.material); diff --git a/Source/DataSources/Entity.js b/Source/DataSources/Entity.js index 1996c6791872..b5170a14fa46 100644 --- a/Source/DataSources/Entity.js +++ b/Source/DataSources/Entity.js @@ -1,5 +1,6 @@ define([ '../Core/Cartesian3', + '../Core/Cartographic', '../Core/Check', '../Core/createGuid', '../Core/defaultValue', @@ -7,10 +8,12 @@ define([ '../Core/defineProperties', '../Core/DeveloperError', '../Core/Event', + '../Core/Math', '../Core/Matrix3', '../Core/Matrix4', '../Core/Quaternion', '../Core/Transforms', + '../Scene/HeightReference', '../Scene/GroundPrimitive', '../Scene/GroundPolylinePrimitive', './BillboardGraphics', @@ -36,6 +39,7 @@ define([ './WallGraphics' ], function( Cartesian3, + Cartographic, Check, createGuid, defaultValue, @@ -43,10 +47,12 @@ define([ defineProperties, DeveloperError, Event, + CesiumMath, Matrix3, Matrix4, Quaternion, Transforms, + HeightReference, GroundPrimitive, GroundPolylinePrimitive, BillboardGraphics, @@ -72,6 +78,8 @@ define([ WallGraphics) { 'use strict'; + var cartoScratch = new Cartographic(); + function createConstantPositionProperty(value) { return new ConstantPositionProperty(value); } @@ -608,11 +616,44 @@ define([ * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. Result is undefined if position or orientation are undefined. */ Entity.prototype.computeModelMatrix = function(time, result) { + //>>includeStart('debug', pragmas.debug); Check.typeOf.object('time', time); + //>>includeEnd('debug'); var position = Property.getValueOrUndefined(this._position, time, positionScratch); if (!defined(position)) { return undefined; } + + var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch); + if (!defined(orientation)) { + result = Transforms.eastNorthUpToFixedFrame(position, undefined, result); + } else { + result = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, result); + } + return result; + }; + + /** + * @private + */ + Entity.prototype.computeModelMatrixForHeightReference = function(time, heightReferenceProperty, heightOffset, ellipsoid, result) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object('time', time); + //>>includeEnd('debug'); + var heightReference = Property.getValueOrDefault(heightReferenceProperty, time, HeightReference.NONE); + var position = Property.getValueOrUndefined(this._position, time, positionScratch); + if (heightReference === HeightReference.NONE || !defined(position) || Cartesian3.equalsEpsilon(position, Cartesian3.ZERO, CesiumMath.EPSILON8)) { + return this.computeModelMatrix(time, result); + } + + var carto = ellipsoid.cartesianToCartographic(position, cartoScratch); + if (heightReference === HeightReference.CLAMP_TO_GROUND) { + carto.height = heightOffset; + } else { + carto.height += heightOffset; + } + position = ellipsoid.cartographicToCartesian(carto, position); + var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch); if (!defined(orientation)) { result = Transforms.eastNorthUpToFixedFrame(position, undefined, result); diff --git a/Source/DataSources/GroundGeometryUpdater.js b/Source/DataSources/GroundGeometryUpdater.js index 76c2c7b1810e..bcc22dd6b8b0 100644 --- a/Source/DataSources/GroundGeometryUpdater.js +++ b/Source/DataSources/GroundGeometryUpdater.js @@ -72,6 +72,12 @@ define([ } }, + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof GroundGeometryUpdater.prototype + * @readonly + */ terrainOffsetProperty: { get: function() { return this._terrainOffsetProperty; @@ -107,7 +113,7 @@ define([ if (defined(heightReferenceProperty) || defined(extrudedHeightReferenceProperty)) { var centerPosition = new CallbackProperty(this._computeCenter.bind(this), !this._dynamic); - this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, heightReferenceProperty, extrudedHeightReferenceProperty, centerPosition); + this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, centerPosition, heightReferenceProperty, extrudedHeightReferenceProperty); } }; diff --git a/Source/DataSources/TerrainOffsetProperty.js b/Source/DataSources/TerrainOffsetProperty.js index 7f9f740cf7d7..b7683f047778 100644 --- a/Source/DataSources/TerrainOffsetProperty.js +++ b/Source/DataSources/TerrainOffsetProperty.js @@ -32,7 +32,7 @@ define([ /** * @private */ - function TerrainOffsetProperty(scene, heightReferenceProperty, extrudedHeightReferenceProperty, positionProperty) { + function TerrainOffsetProperty(scene, positionProperty, heightReferenceProperty, extrudedHeightReferenceProperty) { //>>includeStart('debug', pragmas.debug); Check.defined('scene', scene); Check.defined('positionProperty', positionProperty); diff --git a/Source/DataSources/heightReferenceOnEntityPropertyChanged.js b/Source/DataSources/heightReferenceOnEntityPropertyChanged.js new file mode 100644 index 000000000000..95fae99fa390 --- /dev/null +++ b/Source/DataSources/heightReferenceOnEntityPropertyChanged.js @@ -0,0 +1,40 @@ +define([ + '../Core/defaultValue', + '../Core/defined', + './CallbackProperty', + './GeometryUpdater', + './TerrainOffsetProperty' + ], function( + defaultValue, + defined, + CallbackProperty, + GeometryUpdater, + TerrainOffsetProperty) { + 'use strict'; + + function heightReferenceOnEntityPropertyChanged(entity, propertyName, newValue, oldValue) { + GeometryUpdater.prototype._onEntityPropertyChanged.call(this, entity, propertyName, newValue, oldValue); + if (this._observedPropertyNames.indexOf(propertyName) === -1) { + return; + } + + var geometry = this._entity[this._geometryPropertyName]; + if (!defined(geometry)) { + return; + } + + if (defined(this._terrainOffsetProperty)) { + this._terrainOffsetProperty.destroy(); + this._terrainOffsetProperty = undefined; + } + + var heightReferenceProperty = geometry.heightReference; + + if (defined(heightReferenceProperty)) { + var centerPosition = new CallbackProperty(this._computeCenter.bind(this), !this._dynamic); + this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, centerPosition, heightReferenceProperty); + } + } + + return heightReferenceOnEntityPropertyChanged; +}); diff --git a/Specs/DataSources/BoxGeometryUpdaterSpec.js b/Specs/DataSources/BoxGeometryUpdaterSpec.js index 1a59fa76d025..c7e5dc8d09c3 100644 --- a/Specs/DataSources/BoxGeometryUpdaterSpec.js +++ b/Specs/DataSources/BoxGeometryUpdaterSpec.js @@ -1,12 +1,15 @@ defineSuite([ 'DataSources/BoxGeometryUpdater', 'Core/Cartesian3', + 'Core/Color', + 'Core/GeometryOffsetAttribute', 'Core/JulianDate', 'Core/TimeIntervalCollection', 'DataSources/BoxGraphics', 'DataSources/ConstantPositionProperty', 'DataSources/ConstantProperty', 'DataSources/Entity', + 'Scene/HeightReference', 'Scene/PrimitiveCollection', 'Specs/createDynamicGeometryUpdaterSpecs', 'Specs/createDynamicProperty', @@ -15,12 +18,15 @@ defineSuite([ ], function( BoxGeometryUpdater, Cartesian3, + Color, + GeometryOffsetAttribute, JulianDate, TimeIntervalCollection, BoxGraphics, ConstantPositionProperty, ConstantProperty, Entity, + HeightReference, PrimitiveCollection, createDynamicGeometryUpdaterSpecs, createDynamicProperty, @@ -79,10 +85,51 @@ defineSuite([ instance = updater.createFillGeometryInstance(time); geometry = instance.geometry; expect(geometry._maximum).toEqual(Cartesian3.multiplyByScalar(dimensions, 0.5, new Cartesian3())); + expect(geometry._offsetAttribute).toBeUndefined(); instance = updater.createOutlineGeometryInstance(time); geometry = instance.geometry; expect(geometry._max).toEqual(Cartesian3.multiplyByScalar(dimensions, 0.5, new Cartesian3())); + expect(geometry._offsetAttribute).toBeUndefined(); + }); + + it('Creates geometry with expected offsetAttribute', function() { + var entity = createBasicBox(); + var graphics = entity.box; + graphics.outline = true; + graphics.outlineColor = Color.BLACK; + graphics.height = new ConstantProperty(20.0); + graphics.extrudedHeight = new ConstantProperty(0.0); + var updater = new BoxGeometryUpdater(entity, getScene()); + + var instance; + + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.NONE); + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'box'); + 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); + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); }); it('dynamic updater sets properties', function() { @@ -93,6 +140,7 @@ defineSuite([ dynamicUpdater.update(JulianDate.now()); expect(dynamicUpdater._options.dimensions).toEqual(entity.box.dimensions.getValue()); + expect(dynamicUpdater._options.offsetAttribute).toBeUndefined(); }); it('geometryChanged event is raised when expected', function() { @@ -123,6 +171,13 @@ defineSuite([ expect(listener.calls.count()).toEqual(3); }); + it('computes center', function() { + var entity = createBasicBox(); + var updater = new BoxGeometryUpdater(entity, scene); + + expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time)); + }); + function getScene() { return scene; } diff --git a/Specs/DataSources/CylinderGeometryUpdaterSpec.js b/Specs/DataSources/CylinderGeometryUpdaterSpec.js index df9e36764088..07dcd008431e 100644 --- a/Specs/DataSources/CylinderGeometryUpdaterSpec.js +++ b/Specs/DataSources/CylinderGeometryUpdaterSpec.js @@ -1,6 +1,8 @@ defineSuite([ 'DataSources/CylinderGeometryUpdater', 'Core/Cartesian3', + 'Core/Color', + 'Core/GeometryOffsetAttribute', 'Core/JulianDate', 'Core/Quaternion', 'Core/TimeIntervalCollection', @@ -10,6 +12,7 @@ defineSuite([ 'DataSources/Entity', 'DataSources/SampledPositionProperty', 'DataSources/SampledProperty', + 'Scene/HeightReference', 'Scene/PrimitiveCollection', 'Specs/createDynamicGeometryUpdaterSpecs', 'Specs/createDynamicProperty', @@ -18,6 +21,8 @@ defineSuite([ ], function( CylinderGeometryUpdater, Cartesian3, + Color, + GeometryOffsetAttribute, JulianDate, Quaternion, TimeIntervalCollection, @@ -27,6 +32,7 @@ defineSuite([ Entity, SampledPositionProperty, SampledProperty, + HeightReference, PrimitiveCollection, createDynamicGeometryUpdaterSpecs, createDynamicProperty, @@ -164,6 +170,7 @@ defineSuite([ expect(geometry._topRadius).toEqual(options.topRadius); expect(geometry._bottomRadius).toEqual(options.bottomRadius); expect(geometry._length).toEqual(options.length); + expect(geometry._offsetAttribute).toBeUndefined(); instance = updater.createOutlineGeometryInstance(time); geometry = instance.geometry; @@ -171,6 +178,46 @@ defineSuite([ expect(geometry._bottomRadius).toEqual(options.bottomRadius); expect(geometry._length).toEqual(options.length); expect(geometry._numberOfVerticalLines).toEqual(options.numberOfVerticalLines); + expect(geometry._offsetAttribute).toBeUndefined(); + }); + + it('Creates geometry with expected offsetAttribute', function() { + var entity = createBasicCylinder(); + var graphics = entity.cylinder; + graphics.outline = true; + graphics.outlineColor = Color.BLACK; + graphics.height = new ConstantProperty(20.0); + graphics.extrudedHeight = new ConstantProperty(0.0); + var updater = new CylinderGeometryUpdater(entity, getScene()); + + var instance; + + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.NONE); + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'cylinder'); + 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); + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); }); it('dynamic updater sets properties', function() { @@ -191,6 +238,7 @@ defineSuite([ expect(options.topRadius).toEqual(cylinder.topRadius.getValue()); expect(options.bottomRadius).toEqual(cylinder.bottomRadius.getValue()); expect(options.length).toEqual(cylinder.length.getValue()); + expect(options.offsetAttribute).toBeUndefined(); }); it('geometryChanged event is raised when expected', function() { @@ -230,6 +278,13 @@ defineSuite([ expect(listener.calls.count()).toEqual(5); }); + it('computes center', function() { + var entity = createBasicCylinder(); + var updater = new CylinderGeometryUpdater(entity, scene); + + expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time)); + }); + function getScene() { return scene; } diff --git a/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js b/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js index e149aeadb9eb..828536582552 100644 --- a/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js +++ b/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js @@ -3,6 +3,7 @@ defineSuite([ 'Core/Cartesian3', 'Core/Color', 'Core/ColorGeometryInstanceAttribute', + 'Core/GeometryOffsetAttribute', 'Core/JulianDate', 'Core/Math', 'Core/Quaternion', @@ -14,6 +15,7 @@ defineSuite([ 'DataSources/Entity', 'DataSources/SampledPositionProperty', 'DataSources/SampledProperty', + 'Scene/HeightReference', 'Scene/PrimitiveCollection', 'Specs/createDynamicGeometryUpdaterSpecs', 'Specs/createDynamicProperty', @@ -24,6 +26,7 @@ defineSuite([ Cartesian3, Color, ColorGeometryInstanceAttribute, + GeometryOffsetAttribute, JulianDate, CesiumMath, Quaternion, @@ -35,6 +38,7 @@ defineSuite([ Entity, SampledPositionProperty, SampledProperty, + HeightReference, PrimitiveCollection, createDynamicGeometryUpdaterSpecs, createDynamicProperty, @@ -160,6 +164,7 @@ defineSuite([ expect(geometry._radii).toEqual(options.radii); expect(geometry._stackPartitions).toEqual(options.stackPartitions); expect(geometry._slicePartitions).toEqual(options.slicePartitions); + expect(geometry._offsetAttribute).toBeUndefined(); instance = updater.createOutlineGeometryInstance(time); geometry = instance.geometry; @@ -168,6 +173,53 @@ defineSuite([ expect(geometry._stackPartitions).toEqual(options.stackPartitions); expect(geometry._slicePartitions).toEqual(options.slicePartitions); expect(geometry._subdivisions).toEqual(options.subdivisions); + expect(geometry._offsetAttribute).toBeUndefined(); + }); + + it('Creates geometry with expected offsetAttribute', function() { + var entity = createBasicEllipsoid(); + var graphics = entity.ellipsoid; + graphics.outline = true; + graphics.outlineColor = Color.BLACK; + graphics.height = new ConstantProperty(20.0); + graphics.extrudedHeight = new ConstantProperty(0.0); + var updater = new EllipsoidGeometryUpdater(entity, getScene()); + + var instance; + + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.NONE); + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + 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); + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + }); + + it('computes center', function() { + var entity = createBasicEllipsoid(); + var updater = new EllipsoidGeometryUpdater(entity, scene); + + expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time)); }); it('dynamic ellipsoid creates and updates', function() { diff --git a/Specs/DataSources/TerrainOffsetPropertySpec.js b/Specs/DataSources/TerrainOffsetPropertySpec.js index 9a0b060c5e4f..671434a11126 100644 --- a/Specs/DataSources/TerrainOffsetPropertySpec.js +++ b/Specs/DataSources/TerrainOffsetPropertySpec.js @@ -37,7 +37,7 @@ defineSuite([ 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); + var property = new TerrainOffsetProperty(scene, position, height, extrudedHeight); expect(property.isConstant).toBe(false); expect(property.getValue(time)).toEqual(Cartesian3.ZERO); property.destroy(); @@ -49,7 +49,7 @@ defineSuite([ var height = new ConstantProperty(30); var extrudedHeight = new ConstantProperty(0); expect(function() { - return new TerrainOffsetProperty(undefined, height, extrudedHeight, position); + return new TerrainOffsetProperty(undefined, position, height, extrudedHeight); }).toThrowDeveloperError(); }); @@ -57,7 +57,7 @@ defineSuite([ var height = new ConstantProperty(30); var extrudedHeight = new ConstantProperty(0); expect(function() { - return new TerrainOffsetProperty(scene, height, extrudedHeight, undefined); + return new TerrainOffsetProperty(scene, undefined, height, extrudedHeight); }).toThrowDeveloperError(); }); }); From f6febae5c09c8915ca517e7589184010d1650153 Mon Sep 17 00:00:00 2001 From: hpinkos Date: Fri, 17 Aug 2018 17:04:18 -0400 Subject: [PATCH 2/4] cleanup --- Apps/Sandcastle/gallery/Geometry Height Reference.html | 6 +++--- CHANGES.md | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Apps/Sandcastle/gallery/Geometry Height Reference.html b/Apps/Sandcastle/gallery/Geometry Height Reference.html index 743da3f2bf42..752a02a7a72c 100644 --- a/Apps/Sandcastle/gallery/Geometry Height Reference.html +++ b/Apps/Sandcastle/gallery/Geometry Height Reference.html @@ -4,7 +4,7 @@ - + Cesium Demo @@ -74,7 +74,7 @@ function addGeometry(i, j) { var west = longitude + delta * i; var north = latitude + delta * j + delta; - + var type = Math.floor(Math.random() * 3); if (type === 0) { viewer.entities.add({ @@ -111,7 +111,7 @@ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND } }); - } + } } function addGeometries(){ diff --git a/CHANGES.md b/CHANGES.md index bf63de04f06b..1c2874f580bd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ Change Log * Added `Matrix4.setScale` for setting the scale on an affine transformation matrix [#6888](https://github.com/AnalyticalGraphicsInc/cesium/pull/6888) * Added `GeocoderViewModel.destinationFound` for specifying a function that is called upon a successful geocode. The default behavior is to fly to the destination found by the geocoder. [#6915](https://github.com/AnalyticalGraphicsInc/cesium/pull/6915) * Added optional `width` and `height` to `Scene.drillPick` for specifying a search area. +* Added `heightReference` to `BoxGraphics`, `CylinderGraphics` and `EllipsoidGraphics`, which can be used to clamp these entity types to terrain [#6932](https://github.com/AnalyticalGraphicsInc/cesium/pull/6932) ##### Fixes :wrench: * Several performance improvements and fixes to the 3D Tiles traversal code. [#6390](https://github.com/AnalyticalGraphicsInc/cesium/pull/6390) From ed753621257a586c6bc9309f0c90abd0f5b0883f Mon Sep 17 00:00:00 2001 From: hpinkos Date: Mon, 20 Aug 2018 09:16:13 -0400 Subject: [PATCH 3/4] fix specs --- Source/DataSources/EllipsoidGeometryUpdater.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/DataSources/EllipsoidGeometryUpdater.js b/Source/DataSources/EllipsoidGeometryUpdater.js index a606fbc6ff5f..52b1facb8fd1 100644 --- a/Source/DataSources/EllipsoidGeometryUpdater.js +++ b/Source/DataSources/EllipsoidGeometryUpdater.js @@ -284,7 +284,7 @@ define([ } var radii = Property.getValueOrUndefined(ellipsoid.radii, time, radiiScratch); - var modelMatrix = entity.computeModelMatrixForHeightReference(time, ellipsoid.heightReference, radii.z * 0.5, this._scene.mapProjection.ellipsoid, this._modelMatrix); + var modelMatrix = defined(radii) ? entity.computeModelMatrixForHeightReference(time, ellipsoid.heightReference, radii.z * 0.5, this._scene.mapProjection.ellipsoid, this._modelMatrix) : undefined; if (!defined(modelMatrix) || !defined(radii)) { if (defined(this._primitive)) { this._primitive.show = false; From 5ac289f4653ce12dd78f97aef79d593da1e2b5df Mon Sep 17 00:00:00 2001 From: hpinkos Date: Wed, 22 Aug 2018 14:18:26 -0400 Subject: [PATCH 4/4] cleanup --- .../gallery/Geometry Height Reference.html | 12 +++--------- Source/DataSources/BoxGraphics.js | 2 +- Source/DataSources/CylinderGraphics.js | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Apps/Sandcastle/gallery/Geometry Height Reference.html b/Apps/Sandcastle/gallery/Geometry Height Reference.html index 752a02a7a72c..76b33542fcf2 100644 --- a/Apps/Sandcastle/gallery/Geometry Height Reference.html +++ b/Apps/Sandcastle/gallery/Geometry Height Reference.html @@ -81,9 +81,7 @@ position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), box : { dimensions : new Cesium.Cartesian3(40.0, 30.0, 50.0), - material : Cesium.Color.fromRandom({alpha : 1}), - outline : true, - outlineColor : Cesium.Color.BLACK, + material : Cesium.Color.fromRandom({alpha : 1.0}), heightReference: Cesium.HeightReference.CLAMP_TO_GROUND } }); @@ -94,9 +92,7 @@ length :50.0, topRadius : 20.0, bottomRadius : 20.0, - material : Cesium.Color.fromRandom({alpha : 1}), - outline : true, - outlineColor : Cesium.Color.BLACK, + material : Cesium.Color.fromRandom({alpha : 1.0}), heightReference: Cesium.HeightReference.CLAMP_TO_GROUND } }); @@ -105,9 +101,7 @@ position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), ellipsoid : { radii : new Cesium.Cartesian3(20.0, 15.0, 25.0), - material : Cesium.Color.fromRandom({alpha : 1}), - outline : true, - outlineColor : Cesium.Color.BLACK, + material : Cesium.Color.fromRandom({alpha : 1.0}), heightReference: Cesium.HeightReference.CLAMP_TO_GROUND } }); diff --git a/Source/DataSources/BoxGraphics.js b/Source/DataSources/BoxGraphics.js index 69da519d55d6..d9b96a63f493 100644 --- a/Source/DataSources/BoxGraphics.js +++ b/Source/DataSources/BoxGraphics.js @@ -76,7 +76,7 @@ define([ /** * Gets or sets the Property specifying the {@link HeightReference}. - * @memberof EllipsoidGraphics.prototype + * @memberof BoxGraphics.prototype * @type {Property} * @default HeightReference.NONE */ diff --git a/Source/DataSources/CylinderGraphics.js b/Source/DataSources/CylinderGraphics.js index a27ee3b21dbc..fb74a8ff0cb3 100644 --- a/Source/DataSources/CylinderGraphics.js +++ b/Source/DataSources/CylinderGraphics.js @@ -88,7 +88,7 @@ define([ /** * Gets or sets the Property specifying the {@link HeightReference}. - * @memberof EllipsoidGraphics.prototype + * @memberof CylinderGraphics.prototype * @type {Property} * @default HeightReference.NONE */