diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope index c9e73cd6b2d7..a94373c9de99 100644 --- a/.settings/.jsdtscope +++ b/.settings/.jsdtscope @@ -1,6 +1,6 @@ - + diff --git a/Apps/Sandcastle/gallery/CZML Polygon.html b/Apps/Sandcastle/gallery/CZML Polygon.html index f1a22a65f027..e8d819ad0ba3 100644 --- a/Apps/Sandcastle/gallery/CZML Polygon.html +++ b/Apps/Sandcastle/gallery/CZML Polygon.html @@ -72,7 +72,9 @@ } } }, - "extrudedHeight" : 500000.0 + "extrudedHeight" : 500000.0, + "closeTop" : false, + "closeBottom" : false } }, { "id" : "orangePolygon", diff --git a/Apps/Sandcastle/gallery/Polygon.html b/Apps/Sandcastle/gallery/Polygon.html index fcd13e32abde..2d094d77f01c 100644 --- a/Apps/Sandcastle/gallery/Polygon.html +++ b/Apps/Sandcastle/gallery/Polygon.html @@ -48,7 +48,9 @@ -100.0, 42.0, -104.0, 40.0]), extrudedHeight: 500000.0, - material : Cesium.Color.GREEN + material : Cesium.Color.GREEN, + closeTop : false, + closeBottom : false } }); diff --git a/CHANGES.md b/CHANGES.md index cb7d9d8571a3..841992dbd69e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,20 +1,30 @@ Change Log ========== +### 1.22 - 2016-06-01 + +* Breaking changes + * +* Deprecated + * +* Improved KML NetworkLink compatibility by supporting the `Url` tag. [#3895](https://github.com/AnalyticalGraphicsInc/cesium/pull/3895). +* Fixed exaggerated terrain tiles disappearing. [#3676](https://github.com/AnalyticalGraphicsInc/cesium/issues/3676) +* Fixed infinite horizontal 2D scrolling in IE/Edge. [#3893](https://github.com/AnalyticalGraphicsInc/cesium/issues/3893) +* Fixed a bug that could cause incorrect normals to be computed for exaggerated terrain, especially for low-detail tiles. [#3904](https://github.com/AnalyticalGraphicsInc/cesium/pull/3904) + ### 1.21 - 2016-05-02 * Breaking changes * Removed `ImageryMaterialProperty.alpha`. Use `ImageryMaterialProperty.color.alpha` instead. * Removed `OpenStreetMapImageryProvider`. Use `createOpenStreetMapImageryProvider` instead. -* Deprecated - * -* Fixed issue causing the sun not to render. [#3801](https://github.com/AnalyticalGraphicsInc/cesium/pull/3801) * Added ability to import and export Sandcastle example using GitHub Gists. [#3795](https://github.com/AnalyticalGraphicsInc/cesium/pull/3795) -* Fixed issue where `Camera.flyTo` does not go to the rectangle. [#3688](https://github.com/AnalyticalGraphicsInc/cesium/issues/3688) +* Added `PolygonGraphics.closeTop`, `PolygonGraphics.closeBottom`, and `PolygonGeometry` options for creating an extruded polygon without a top or bottom. [#3879](https://github.com/AnalyticalGraphicsInc/cesium/pull/3879) +* Added support for polyline arrow material to `CzmlDataSource` [#3860](https://github.com/AnalyticalGraphicsInc/cesium/pull/3860) +* Fixed issue causing the sun not to render. [#3801](https://github.com/AnalyticalGraphicsInc/cesium/pull/3801) +* Fixed issue where `Camera.flyTo` would not work with a rectangle in 2D. [#3688](https://github.com/AnalyticalGraphicsInc/cesium/issues/3688) * Fixed issue causing the fog to go dark and the atmosphere to flicker when the camera clips the globe. [#3178](https://github.com/AnalyticalGraphicsInc/cesium/issues/3178) * Fixed a bug that caused an exception and rendering to stop when using `ArcGisMapServerImageryProvider` to connect to a MapServer specifying the Web Mercator projection and a fullExtent bigger than the valid extent of the projection. [#3854](https://github.com/AnalyticalGraphicsInc/cesium/pull/3854) * Fixed issue causing an exception when switching scene modes with an active KML network link. [#3865](https://github.com/AnalyticalGraphicsInc/cesium/issues/3865) -* Added support for polyline arrow material to `CzmlDataSource` [#3860](https://github.com/AnalyticalGraphicsInc/cesium/pull/3860) * Fixed issue where labels were disappearing. [3730](https://github.com/AnalyticalGraphicsInc/cesium/issues/3730) ### 1.20 - 2016-04-01 diff --git a/Source/Core/EllipsoidalOccluder.js b/Source/Core/EllipsoidalOccluder.js index 1f95bad9631b..ae0d355c4fe1 100644 --- a/Source/Core/EllipsoidalOccluder.js +++ b/Source/Core/EllipsoidalOccluder.js @@ -238,48 +238,6 @@ define([ return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result); }; - /** - * Computes a point that can be used for horizon culling from a list of positions. If the point is below - * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point - * is expressed in the ellipsoid-scaled space and is suitable for use with - * {@link EllipsoidalOccluder#isScaledSpacePointVisible}. - * - * @param {Cartesian3} directionToPoint The direction that the computed point will lie along. - * A reasonable direction to use is the direction from the center of the ellipsoid to - * the center of the bounding sphere computed from the positions. The direction need not - * be normalized. - * @param {Cartesian3[]} points The vertices from which to compute the horizon culling point. The positions - * must be expressed in a reference frame centered at the ellipsoid and aligned with the - * ellipsoid's axes. - * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance. - * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space. - */ - EllipsoidalOccluder.prototype.computeHorizonCullingPointFromPoints = function(directionToPoint, points, result) { - //>>includeStart('debug', pragmas.debug); - if (!defined(directionToPoint)) { - throw new DeveloperError('directionToPoint is required'); - } - if (!defined(points)) { - throw new DeveloperError('points is required'); - } - //>>includeEnd('debug'); - - if (!defined(result)) { - result = new Cartesian3(); - } - - var ellipsoid = this._ellipsoid; - var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint); - var resultMagnitude = 0.0; - - for (var i = 0, len = points.length; i < len; ++i) { - var candidateMagnitude = computeMagnitude(ellipsoid, points[i], scaledSpaceDirectionToPoint); - resultMagnitude = Math.max(resultMagnitude, candidateMagnitude); - } - - return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result); - }; - var subsampleScratch = []; /** diff --git a/Source/Core/HeightmapTessellator.js b/Source/Core/HeightmapTessellator.js index f2a5f62f7450..fbb28c43ebb7 100644 --- a/Source/Core/HeightmapTessellator.js +++ b/Source/Core/HeightmapTessellator.js @@ -365,7 +365,7 @@ define([ var center = options.relativetoCenter; if (defined(center)) { var occluder = new EllipsoidalOccluder(ellipsoid); - occludeePointInScaledSpace = occluder.computeHorizonCullingPointFromPoints(center, positions); + occludeePointInScaledSpace = occluder.computeHorizonCullingPoint(center, positions); } var aaBox = new AxisAlignedBoundingBox(minimum, maximum, relativeToCenter); diff --git a/Source/Core/PolygonGeometry.js b/Source/Core/PolygonGeometry.js index 4b8558179edd..f3c79ac32f4d 100644 --- a/Source/Core/PolygonGeometry.js +++ b/Source/Core/PolygonGeometry.js @@ -4,6 +4,7 @@ define([ './BoundingSphere', './Cartesian2', './Cartesian3', + './Cartographic', './ComponentDatatype', './defaultValue', './defined', @@ -28,6 +29,7 @@ define([ BoundingSphere, Cartesian2, Cartesian3, + Cartographic, ComponentDatatype, defaultValue, defined, @@ -85,6 +87,20 @@ define([ return result; } + var scratchCarto1 = new Cartographic(); + var scratchCarto2 = new Cartographic(); + function adjustPosHeightsForNormal(position, p1, p2, ellipsoid) { + var carto1 = ellipsoid.cartesianToCartographic(position, scratchCarto1); + var height = carto1.height; + var p1Carto = ellipsoid.cartesianToCartographic(p1, scratchCarto2); + p1Carto.height = height; + ellipsoid.cartographicToCartesian(p1Carto, p1); + + var p2Carto = ellipsoid.cartesianToCartographic(p2, scratchCarto2); + p2Carto.height = height - 100; + ellipsoid.cartographicToCartesian(p2Carto, p2); + } + var scratchBoundingRectangle = new BoundingRectangle(); var scratchPosition = new Cartesian3(); var scratchNormal = new Cartesian3(); @@ -92,6 +108,9 @@ define([ var scratchBinormal = new Cartesian3(); var p1Scratch = new Cartesian3(); var p2Scratch = new Cartesian3(); + var scratchPerPosNormal = new Cartesian3(); + var scratchPerPosTangent = new Cartesian3(); + var scratchPerPosBinormal = new Cartesian3(); var appendTextureCoordinatesOrigin = new Cartesian2(); var appendTextureCoordinatesCartesian2 = new Cartesian2(); @@ -109,8 +128,10 @@ define([ var tangentPlane = options.tangentPlane; var ellipsoid = options.ellipsoid; var stRotation = options.stRotation; - var bottom = options.bottom; var wall = options.wall; + var top = options.top || wall; + var bottom = options.bottom || wall; + var perPositionHeight = options.perPositionHeight; var origin = appendTextureCoordinatesOrigin; origin.x = boundingRectangle.x; @@ -120,7 +141,14 @@ define([ var length = flatPositions.length; var textureCoordinates = vertexFormat.st ? new Float32Array(2 * (length / 3)) : undefined; - var normals = vertexFormat.normal ? new Float32Array(length) : undefined; + var normals; + if (vertexFormat.normal) { + if (perPositionHeight && top && !wall) { + normals = geometry.attributes.normal.values; + } else { + normals = new Float32Array(length); + } + } var tangents = vertexFormat.tangent ? new Float32Array(length) : undefined; var binormals = vertexFormat.binormal ? new Float32Array(length) : undefined; @@ -135,10 +163,13 @@ define([ var rotation = Quaternion.fromAxisAngle(tangentPlane._plane.normal, stRotation, appendTextureCoordinatesQuaternion); var textureMatrix = Matrix3.fromQuaternion(rotation, appendTextureCoordinatesMatrix3); - var bottomOffset = length / 2; - var bottomOffset2 = length / 3; + var bottomOffset = 0; + var bottomOffset2 = 0; + + if (top && bottom) { + bottomOffset = length / 2; + bottomOffset2 = length / 3; - if (bottom) { length /= 2; } @@ -157,9 +188,10 @@ define([ textureCoordinates[textureCoordIndex + bottomOffset2] = stx; textureCoordinates[textureCoordIndex + 1 + bottomOffset2] = sty; } - - textureCoordinates[textureCoordIndex] = stx; - textureCoordinates[textureCoordIndex + 1] = sty; + if (top) { + textureCoordinates[textureCoordIndex] = stx; + textureCoordinates[textureCoordIndex + 1] = sty; + } textureCoordIndex += 2; } @@ -174,6 +206,9 @@ define([ if (recomputeNormal) { var p2 = Cartesian3.fromArray(flatPositions, i + length, p2Scratch); + if (perPositionHeight) { + adjustPosHeightsForNormal(position, p1, p2, ellipsoid); + } Cartesian3.subtract(p1, position, p1); Cartesian3.subtract(p2, position, p2); normal = Cartesian3.normalize(Cartesian3.cross(p2, p1, normal), normal); @@ -191,10 +226,18 @@ define([ tangent = Cartesian3.normalize(Cartesian3.cross(binormal, normal, tangent), tangent); } } - } else { normal = ellipsoid.geodeticSurfaceNormal(position, normal); if (vertexFormat.tangent || vertexFormat.binormal) { + if (perPositionHeight) { + scratchPerPosNormal = Cartesian3.fromArray(normals, attrIndex, scratchPerPosNormal); + scratchPerPosTangent = Cartesian3.cross(Cartesian3.UNIT_Z, scratchPerPosNormal, scratchPerPosTangent); + scratchPerPosTangent = Cartesian3.normalize(Matrix3.multiplyByVector(textureMatrix, scratchPerPosTangent, scratchPerPosTangent), scratchPerPosTangent); + if (vertexFormat.binormal) { + scratchPerPosBinormal = Cartesian3.normalize(Cartesian3.cross(scratchPerPosNormal, scratchPerPosTangent, scratchPerPosBinormal), scratchPerPosBinormal); + } + } + tangent = Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent); tangent = Cartesian3.normalize(Matrix3.multiplyByVector(textureMatrix, tangent, tangent), tangent); if (vertexFormat.binormal) { @@ -204,35 +247,45 @@ define([ } if (vertexFormat.normal) { - if (bottom && !wall) { - normals[attrIndex + bottomOffset] = -normal.x; - normals[attrIndex1 + bottomOffset] = -normal.y; - normals[attrIndex2 + bottomOffset] = -normal.z; - } else { + if (options.wall) { normals[attrIndex + bottomOffset] = normal.x; normals[attrIndex1 + bottomOffset] = normal.y; normals[attrIndex2 + bottomOffset] = normal.z; + } else if (bottom){ + normals[attrIndex + bottomOffset] = -normal.x; + normals[attrIndex1 + bottomOffset] = -normal.y; + normals[attrIndex2 + bottomOffset] = -normal.z; } - normals[attrIndex] = normal.x; - normals[attrIndex1] = normal.y; - normals[attrIndex2] = normal.z; + if ((top && !perPositionHeight) || wall) { + normals[attrIndex] = normal.x; + normals[attrIndex1] = normal.y; + normals[attrIndex2] = normal.z; + } } if (vertexFormat.tangent) { - if (bottom && !wall) { - tangents[attrIndex + bottomOffset] = -tangent.x; - tangents[attrIndex1 + bottomOffset] = -tangent.y; - tangents[attrIndex2 + bottomOffset] = -tangent.z; - } else { + if (options.wall) { tangents[attrIndex + bottomOffset] = tangent.x; tangents[attrIndex1 + bottomOffset] = tangent.y; tangents[attrIndex2 + bottomOffset] = tangent.z; + } else if (bottom) { + tangents[attrIndex + bottomOffset] = -tangent.x; + tangents[attrIndex1 + bottomOffset] = -tangent.y; + tangents[attrIndex2 + bottomOffset] = -tangent.z; } - tangents[attrIndex] = tangent.x; - tangents[attrIndex1] = tangent.y; - tangents[attrIndex2] = tangent.z; + if(top) { + if (perPositionHeight) { + tangents[attrIndex] = scratchPerPosTangent.x; + tangents[attrIndex1] = scratchPerPosTangent.y; + tangents[attrIndex2] = scratchPerPosTangent.z; + } else { + tangents[attrIndex] = tangent.x; + tangents[attrIndex1] = tangent.y; + tangents[attrIndex2] = tangent.z; + } + } } if (vertexFormat.binormal) { @@ -241,10 +294,17 @@ define([ binormals[attrIndex1 + bottomOffset] = binormal.y; binormals[attrIndex2 + bottomOffset] = binormal.z; } - - binormals[attrIndex] = binormal.x; - binormals[attrIndex1] = binormal.y; - binormals[attrIndex2] = binormal.z; + if (top) { + if (perPositionHeight) { + binormals[attrIndex] = scratchPerPosBinormal.x; + binormals[attrIndex1] = scratchPerPosBinormal.y; + binormals[attrIndex2] = scratchPerPosBinormal.z; + } else { + binormals[attrIndex] = binormal.x; + binormals[attrIndex1] = binormal.y; + binormals[attrIndex2] = binormal.z; + } + } } attrIndex += 3; } @@ -287,50 +347,66 @@ define([ var createGeometryFromPositionsExtrudedPositions = []; - function createGeometryFromPositionsExtruded(ellipsoid, positions, granularity, hierarchy, perPositionHeight) { - var topGeo = PolygonGeometryLibrary.createGeometryFromPositions(ellipsoid, positions, granularity, perPositionHeight); + function createGeometryFromPositionsExtruded(ellipsoid, positions, granularity, hierarchy, perPositionHeight, closeTop, closeBottom, vertexFormat) { + var geos = { + walls : [] + }; + var i; - var edgePoints = topGeo.attributes.position.values; - var indices = topGeo.indices; + if (closeTop || closeBottom) { + var topGeo = PolygonGeometryLibrary.createGeometryFromPositions(ellipsoid, positions, granularity, perPositionHeight, vertexFormat); - var topBottomPositions = edgePoints.concat(edgePoints); - var numPositions = topBottomPositions.length / 3; + var edgePoints = topGeo.attributes.position.values; + var indices = topGeo.indices; + var numPositions; + var newIndices; - var newIndices = IndexDatatype.createTypedArray(numPositions, indices.length * 2); - newIndices.set(indices); - var ilength = indices.length; + if (closeTop && closeBottom) { + var topBottomPositions = edgePoints.concat(edgePoints); + numPositions = topBottomPositions.length / 3; - var i; - var length = numPositions / 2; + newIndices = IndexDatatype.createTypedArray(numPositions, indices.length * 2); + newIndices.set(indices); + var ilength = indices.length; - for (i = 0; i < ilength; i += 3) { - var i0 = newIndices[i] + length; - var i1 = newIndices[i + 1] + length; - var i2 = newIndices[i + 2] + length; - newIndices[i + ilength] = i2; - newIndices[i + 1 + ilength] = i1; - newIndices[i + 2 + ilength] = i0; - } + var length = numPositions / 2; - var topAndBottomGeo = new Geometry({ - attributes : new GeometryAttributes({ - position : new GeometryAttribute({ - componentDatatype : ComponentDatatype.DOUBLE, - componentsPerAttribute : 3, - values : topBottomPositions - }) - }), - indices : newIndices, - primitiveType : topGeo.primitiveType - }); + for (i = 0; i < ilength; i += 3) { + var i0 = newIndices[i] + length; + var i1 = newIndices[i + 1] + length; + var i2 = newIndices[i + 2] + length; - var geos = { - topAndBottom : new GeometryInstance({ - geometry : topAndBottomGeo - }), - walls : [] - }; + newIndices[i + ilength] = i2; + newIndices[i + 1 + ilength] = i1; + newIndices[i + 2 + ilength] = i0; + } + + topGeo.attributes.position.values = topBottomPositions; + if (perPositionHeight) { + var normals = topGeo.attributes.normal.values; + topGeo.attributes.normal.values = new Float32Array(topBottomPositions.length); + topGeo.attributes.normal.values.set(normals); + } + topGeo.indices = newIndices; + } else if (closeBottom) { + numPositions = edgePoints.length / 3; + newIndices = IndexDatatype.createTypedArray(numPositions, indices.length); + + for (i = 0; i < indices.length; i += 3) { + newIndices[i] = indices[i + 2]; + newIndices[i + 1] = indices[i + 1]; + newIndices[i + 2] = indices[i]; + } + + topGeo.indices = newIndices; + } + + geos.topAndBottom = new GeometryInstance({ + geometry : topGeo + }); + + } var outerRing = hierarchy.outerRing; var tangentPlane = EllipsoidTangentPlane.fromPoints(outerRing, ellipsoid); @@ -382,6 +458,8 @@ define([ * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height. + * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open. + * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open. * * @see PolygonGeometry#createGeometry * @see PolygonGeometry#fromPositions @@ -460,6 +538,9 @@ define([ if (!defined(options) || !defined(options.polygonHierarchy)) { throw new DeveloperError('options.polygonHierarchy is required.'); } + if (defined(options.perPositionHeight) && options.perPositionHeight && defined(options.height)) { + throw new DeveloperError('Cannot use both options.perPositionHeight and options.height'); + } //>>includeEnd('debug'); var polygonHierarchy = options.polygonHierarchy; @@ -492,6 +573,8 @@ define([ this._height = height; this._extrudedHeight = defaultValue(extrudedHeight, 0.0); this._extrude = extrude; + this._closeTop = defaultValue(options.closeTop, true); + this._closeBottom = defaultValue(options.closeBottom, true); this._polygonHierarchy = polygonHierarchy; this._perPositionHeight = perPositionHeight; this._workerName = 'createPolygonGeometry'; @@ -500,7 +583,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - this.packedLength = PolygonGeometryLibrary.computeHierarchyPackedLength(polygonHierarchy) + Ellipsoid.packedLength + VertexFormat.packedLength + 7; + this.packedLength = PolygonGeometryLibrary.computeHierarchyPackedLength(polygonHierarchy) + Ellipsoid.packedLength + VertexFormat.packedLength + 9; } /** @@ -515,6 +598,8 @@ define([ * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height. + * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open. + * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open. * @returns {PolygonGeometry} * * @@ -552,7 +637,9 @@ define([ stRotation : options.stRotation, ellipsoid : options.ellipsoid, granularity : options.granularity, - perPositionHeight : options.perPositionHeight + perPositionHeight : options.perPositionHeight, + closeTop : options.closeTop, + closeBottom: options.closeBottom }; return new PolygonGeometry(newOptions); }; @@ -590,6 +677,8 @@ define([ array[startingIndex++] = value._stRotation; array[startingIndex++] = value._extrude ? 1.0 : 0.0; array[startingIndex++] = value._perPositionHeight ? 1.0 : 0.0; + array[startingIndex++] = value._closeTop ? 1.0 : 0.0; + array[startingIndex++] = value._closeBottom ? 1.0 : 0.0; array[startingIndex] = value.packedLength; }; @@ -633,6 +722,8 @@ define([ var stRotation = array[startingIndex++]; var extrude = array[startingIndex++] === 1.0; var perPositionHeight = array[startingIndex++] === 1.0; + var closeTop = array[startingIndex++] === 1.0; + var closeBottom = array[startingIndex++] === 1.0; var packedLength = array[startingIndex]; if (!defined(result)) { @@ -648,6 +739,8 @@ define([ result._stRotation = stRotation; result._extrude = extrude; result._perPositionHeight = perPositionHeight; + result._closeTop = closeTop; + result._closeBottom = closeBottom; result.packedLength = packedLength; return result; }; @@ -668,6 +761,8 @@ define([ var extrude = polygonGeometry._extrude; var polygonHierarchy = polygonGeometry._polygonHierarchy; var perPositionHeight = polygonGeometry._perPositionHeight; + var closeTop = polygonGeometry._closeTop; + var closeBottom = polygonGeometry._closeBottom; var walls; var topAndBottom; @@ -698,6 +793,7 @@ define([ var geometries = []; var options = { + perPositionHeight: perPositionHeight, vertexFormat: vertexFormat, geometry: undefined, tangentPlane: tangentPlane, @@ -705,16 +801,31 @@ define([ ellipsoid: ellipsoid, stRotation: stRotation, bottom: false, + top: true, wall: false }; if (extrude) { - options.bottom = true; + options.top = closeTop; + options.bottom = closeBottom; for (i = 0; i < polygons.length; i++) { - geometry = createGeometryFromPositionsExtruded(ellipsoid, polygons[i], granularity, hierarchy[i], perPositionHeight); - topAndBottom = geometry.topAndBottom; - options.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight); - topAndBottom.geometry = computeAttributes(options); - geometries.push(topAndBottom); + geometry = createGeometryFromPositionsExtruded(ellipsoid, polygons[i], granularity, hierarchy[i], perPositionHeight, closeTop, closeBottom, vertexFormat); + if (closeTop && closeBottom) { + topAndBottom = geometry.topAndBottom; + options.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight); + } else if (closeTop) { + topAndBottom = geometry.topAndBottom; + topAndBottom.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(topAndBottom.geometry.attributes.position.values, height, ellipsoid, !perPositionHeight); + options.geometry = topAndBottom.geometry; + } else if (closeBottom) { + topAndBottom = geometry.topAndBottom; + topAndBottom.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(topAndBottom.geometry.attributes.position.values, extrudedHeight, ellipsoid, true); + options.geometry = topAndBottom.geometry; + } + if (closeTop || closeBottom) { + options.wall = false; + topAndBottom.geometry = computeAttributes(options); + geometries.push(topAndBottom); + } walls = geometry.walls; options.wall = true; @@ -728,7 +839,7 @@ define([ } else { for (i = 0; i < polygons.length; i++) { geometry = new GeometryInstance({ - geometry : PolygonGeometryLibrary.createGeometryFromPositions(ellipsoid, polygons[i], granularity, perPositionHeight) + geometry : PolygonGeometryLibrary.createGeometryFromPositions(ellipsoid, polygons[i], granularity, perPositionHeight, vertexFormat) }); geometry.geometry.attributes.position.values = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry.attributes.position.values, height, ellipsoid, !perPositionHeight); options.geometry = geometry.geometry; diff --git a/Source/Core/PolygonGeometryLibrary.js b/Source/Core/PolygonGeometryLibrary.js index 90ad0d34f920..13df0addd53b 100644 --- a/Source/Core/PolygonGeometryLibrary.js +++ b/Source/Core/PolygonGeometryLibrary.js @@ -10,6 +10,7 @@ define([ './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryPipeline', './IndexDatatype', './Math', './PolygonPipeline', @@ -27,6 +28,7 @@ define([ Geometry, GeometryAttribute, GeometryAttributes, + GeometryPipeline, IndexDatatype, CesiumMath, PolygonPipeline, @@ -269,7 +271,7 @@ define([ var createGeometryFromPositionsPositions = []; - PolygonGeometryLibrary.createGeometryFromPositions = function(ellipsoid, positions, granularity, perPositionHeight) { + PolygonGeometryLibrary.createGeometryFromPositions = function(ellipsoid, positions, granularity, perPositionHeight, vertexFormat) { var tangentPlane = EllipsoidTangentPlane.fromPoints(positions, ellipsoid); var positions2D = tangentPlane.projectPointsOntoPlane(positions, createGeometryFromPositionsPositions); @@ -295,8 +297,7 @@ define([ flattenedPositions[index++] = p.y; flattenedPositions[index++] = p.z; } - - return new Geometry({ + var geometry = new Geometry({ attributes : { position : new GeometryAttribute({ componentDatatype : ComponentDatatype.DOUBLE, @@ -307,6 +308,12 @@ define([ indices : indices, primitiveType : PrimitiveType.TRIANGLES }); + + if (vertexFormat.normal) { + return GeometryPipeline.computeNormal(geometry); + } + + return geometry; } return PolygonPipeline.computeSubdivision(ellipsoid, positions, indices, granularity); diff --git a/Source/Core/PolygonOutlineGeometry.js b/Source/Core/PolygonOutlineGeometry.js index 9146f8db4d0f..834743e6bb2c 100644 --- a/Source/Core/PolygonOutlineGeometry.js +++ b/Source/Core/PolygonOutlineGeometry.js @@ -289,6 +289,9 @@ define([ if (!defined(options) || !defined(options.polygonHierarchy)) { throw new DeveloperError('options.polygonHierarchy is required.'); } + if (defined(options.perPositionHeight) && options.perPositionHeight && defined(options.height)) { + throw new DeveloperError('Cannot use both options.perPositionHeight and options.height'); + } //>>includeEnd('debug'); var polygonHierarchy = options.polygonHierarchy; diff --git a/Source/Core/QuantizedMeshTerrainData.js b/Source/Core/QuantizedMeshTerrainData.js index 7e6d741d9d16..43c85f7c2a8c 100644 --- a/Source/Core/QuantizedMeshTerrainData.js +++ b/Source/Core/QuantizedMeshTerrainData.js @@ -305,7 +305,7 @@ define([ var maximumHeight = result.maximumHeight; var boundingSphere = defaultValue(result.boundingSphere, that._boundingSphere); var obb = defaultValue(result.orientedBoundingBox, that._orientedBoundingBox); - var occlusionPoint = defaultValue(result.occludeePointInScaledSpace, that._horizonOcclusionPoint); + var occlusionPoint = that._horizonOcclusionPoint; var stride = result.vertexStride; var terrainEncoding = TerrainEncoding.clone(result.encoding); diff --git a/Source/DataSources/CzmlDataSource.js b/Source/DataSources/CzmlDataSource.js index 7cbbd159573c..b78d41a39189 100644 --- a/Source/DataSources/CzmlDataSource.js +++ b/Source/DataSources/CzmlDataSource.js @@ -1327,6 +1327,8 @@ define([ processPacketData(Color, polygon, 'outlineColor', polygonData.outlineColor, interval, sourceUri, entityCollection); processPacketData(Number, polygon, 'outlineWidth', polygonData.outlineWidth, interval, sourceUri, entityCollection); processPacketData(Boolean, polygon, 'perPositionHeight', polygonData.perPositionHeight, interval, sourceUri, entityCollection); + processPacketData(Boolean, polygon, 'closeTop', polygonData.closeTop, interval, sourceUri, entityCollection); + processPacketData(Boolean, polygon, 'closeBottom', polygonData.closeBottom, interval, sourceUri, entityCollection); processPositions(polygon, 'hierarchy', polygonData.positions, entityCollection); } diff --git a/Source/DataSources/KmlDataSource.js b/Source/DataSources/KmlDataSource.js index 930ecb3d6e98..31ae7448e2a9 100644 --- a/Source/DataSources/KmlDataSource.js +++ b/Source/DataSources/KmlDataSource.js @@ -835,7 +835,7 @@ define([ } id = uri + '#' + tokens[1]; } - + styleEntity = styleCollection.getById(id); if (!defined(styleEntity)) { styleEntity = styleCollection.getById('#' + id); @@ -1827,6 +1827,10 @@ define([ var networkEntity = r.entity; var link = queryFirstNode(node, 'Link', namespaces.kml); + + if(!defined(link)){ + link = queryFirstNode(node, 'Url', namespaces.kml); + } if (defined(link)) { var href = queryStringValue(link, 'href', namespaces.kml); if (defined(href)) { @@ -2138,7 +2142,7 @@ define([ } if (showWarning) { - deprecationWarning('KmlDataSource', 'KmlDataSource now longer takes a proxy object. It takes an options object with camera and canvas as required properties. This will throw in Cesium 1.21.'); + deprecationWarning('KmlDataSource', 'KmlDataSource now longer takes a proxy object. It takes an options object with camera and canvas as required properties. This will throw in Cesium 1.22.'); } this._changed = new Event(); diff --git a/Source/DataSources/PolygonGeometryUpdater.js b/Source/DataSources/PolygonGeometryUpdater.js index 7bc0615ffbca..8bb71ebcb9bf 100644 --- a/Source/DataSources/PolygonGeometryUpdater.js +++ b/Source/DataSources/PolygonGeometryUpdater.js @@ -61,6 +61,8 @@ define([ this.vertexFormat = undefined; this.polygonHierarchy = undefined; this.perPositionHeight = undefined; + this.closeTop = undefined; + this.closeBottom = undefined; this.height = undefined; this.extrudedHeight = undefined; this.granularity = undefined; @@ -453,6 +455,8 @@ define([ var stRotation = polygon.stRotation; var outlineWidth = polygon.outlineWidth; var perPositionHeight = polygon.perPositionHeight; + var closeTop = polygon.closeTop; + var closeBottom = polygon.closeBottom; this._fillEnabled = fillEnabled; this._outlineEnabled = outlineEnabled; @@ -463,7 +467,9 @@ define([ !Property.isConstant(granularity) || // !Property.isConstant(stRotation) || // !Property.isConstant(outlineWidth) || // - !Property.isConstant(perPositionHeight)) { + !Property.isConstant(perPositionHeight) || // + !Property.isConstant(closeTop) || // + !Property.isConstant(closeBottom)) { if (!this._dynamic) { this._dynamic = true; this._geometryChanged.raiseEvent(this); @@ -477,17 +483,21 @@ define([ hierarchyValue = new PolygonHierarchy(hierarchyValue); } - var heightValue = defined(height) ? height.getValue(Iso8601.MINIMUM_VALUE) : undefined; - var extrudedHeightValue = defined(extrudedHeight) ? extrudedHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined; + var heightValue = Property.getValueOrUndefined(height, Iso8601.MINIMUM_VALUE); + var closeTopValue = Property.getValueOrDefault(closeTop, Iso8601.MINIMUM_VALUE, true); + var closeBottomValue = Property.getValueOrDefault(closeBottom, Iso8601.MINIMUM_VALUE, true); + var extrudedHeightValue = Property.getValueOrUndefined(extrudedHeight, Iso8601.MINIMUM_VALUE); options.polygonHierarchy = hierarchyValue; options.height = heightValue; options.extrudedHeight = extrudedHeightValue; - options.granularity = defined(granularity) ? granularity.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.stRotation = defined(stRotation) ? stRotation.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.perPositionHeight = defined(perPositionHeight) ? perPositionHeight.getValue(Iso8601.MINIMUM_VALUE) : undefined; - this._outlineWidth = defined(outlineWidth) ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE) : 1.0; - this._isClosed = defined(extrudedHeightValue) && extrudedHeightValue !== heightValue; + options.granularity = Property.getValueOrUndefined(granularity, Iso8601.MINIMUM_VALUE); + options.stRotation = Property.getValueOrUndefined(stRotation, Iso8601.MINIMUM_VALUE); + options.perPositionHeight = Property.getValueOrUndefined(perPositionHeight, Iso8601.MINIMUM_VALUE); + options.closeTop = closeTopValue; + options.closeBottom = closeBottomValue; + this._outlineWidth = Property.getValueOrDefault(outlineWidth, Iso8601.MINIMUM_VALUE, 1.0); + this._isClosed = defined(extrudedHeightValue) && extrudedHeightValue !== heightValue && closeTopValue && closeBottomValue; this._dynamic = false; this._geometryChanged.raiseEvent(this); } @@ -525,6 +535,7 @@ define([ this._geometryUpdater = geometryUpdater; this._options = new GeometryOptions(geometryUpdater._entity); } + DynamicGeometryUpdater.prototype.update = function(time) { //>>includeStart('debug', pragmas.debug); if (!defined(time)) { @@ -557,11 +568,16 @@ define([ options.polygonHierarchy = hierarchy; } + var closeTopValue = Property.getValueOrDefault(polygon.closeTop, time, true); + var closeBottomValue = Property.getValueOrDefault(polygon.closeBottom, time, true); + options.height = Property.getValueOrUndefined(polygon.height, time); options.extrudedHeight = Property.getValueOrUndefined(polygon.extrudedHeight, time); options.granularity = Property.getValueOrUndefined(polygon.granularity, time); options.stRotation = Property.getValueOrUndefined(polygon.stRotation, time); options.perPositionHeight = Property.getValueOrUndefined(polygon.perPositionHeight, time); + options.closeTop = closeTopValue; + options.closeBottom = closeBottomValue; if (Property.getValueOrDefault(polygon.fill, time, true)) { var material = MaterialProperty.getValue(time, geometryUpdater.fillMaterialProperty, this._material); @@ -570,7 +586,7 @@ define([ var appearance = new MaterialAppearance({ material : material, translucent : material.isTranslucent(), - closed : defined(options.extrudedHeight) && options.extrudedHeight !== options.height + closed : defined(options.extrudedHeight) && options.extrudedHeight !== options.height && closeTopValue && closeBottomValue }); options.vertexFormat = appearance.vertexFormat; diff --git a/Source/DataSources/PolygonGraphics.js b/Source/DataSources/PolygonGraphics.js index 13d6d196596b..bf0e6f6562d9 100644 --- a/Source/DataSources/PolygonGraphics.js +++ b/Source/DataSources/PolygonGraphics.js @@ -38,6 +38,8 @@ define([ * @param {Property} [options.stRotation=0.0] A numeric property specifying the rotation of the polygon texture counter-clockwise from north. * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude point. * @param {Property} [options.perPositionHeight=false] A boolean specifying whether or not the the height of each position is used. + * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open. + * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open. * * @see Entity * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polygon.html|Cesium Sandcastle Polygon Demo} @@ -68,6 +70,10 @@ define([ this._definitionChanged = new Event(); this._fill = undefined; this._fillSubscription = undefined; + this._closeTop = undefined; + this._closeTopSubscription = undefined; + this._closeBottom = undefined; + this._closeBottomSubscription = undefined; this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT)); } @@ -181,7 +187,21 @@ define([ * @memberof PolygonGraphics.prototype * @type {Property} */ - perPositionHeight : createPropertyDescriptor('perPositionHeight') + perPositionHeight : createPropertyDescriptor('perPositionHeight'), + + /** + * Gets or sets a boolean specifying whether or not the top of an extruded polygon is included. + * @memberof PolygonGraphics.prototype + * @type {Property} + */ + closeTop : createPropertyDescriptor('closeTop'), + + /** + * Gets or sets a boolean specifying whether or not the bottom of an extruded polygon is included. + * @memberof PolygonGraphics.prototype + * @type {Property} + */ + closeBottom : createPropertyDescriptor('closeBottom') }); /** @@ -206,6 +226,8 @@ define([ result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.perPositionHeight = this.perPositionHeight; + result.closeTop = this.closeTop; + result.closeBottom = this.closeBottom; return result; }; @@ -234,6 +256,8 @@ define([ this.outlineColor = defaultValue(this.outlineColor, source.outlineColor); this.outlineWidth = defaultValue(this.outlineWidth, source.outlineWidth); this.perPositionHeight = defaultValue(this.perPositionHeight, source.perPositionHeight); + this.closeTop = defaultValue(this.closeTop, source.closeTop); + this.closeBottom = defaultValue(this.closeBottom, source.closeBottom); }; return PolygonGraphics; diff --git a/Source/Scene/DeviceOrientationCameraController.js b/Source/Scene/DeviceOrientationCameraController.js index 3a2de93919c0..189c125f42b9 100644 --- a/Source/Scene/DeviceOrientationCameraController.js +++ b/Source/Scene/DeviceOrientationCameraController.js @@ -38,10 +38,19 @@ define([ this._gamma = undefined; var that = this; + function callback(e) { - that._alpha = CesiumMath.toRadians(defaultValue(e.alpha, 0.0)); - that._beta = CesiumMath.toRadians(defaultValue(e.beta, 0.0)); - that._gamma = CesiumMath.toRadians(defaultValue(e.gamma, 0.0)); + var alpha = e.alpha; + if (!defined(alpha)) { + that._alpha = undefined; + that._beta = undefined; + that._gamma = undefined; + return; + } + + that._alpha = CesiumMath.toRadians(alpha); + that._beta = CesiumMath.toRadians(e.beta); + that._gamma = CesiumMath.toRadians(e.gamma); } window.addEventListener('deviceorientation', callback, false); @@ -124,4 +133,4 @@ define([ }; return DeviceOrientationCameraController; -}); \ No newline at end of file +}); diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index 750f812da421..8796ce7de157 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -1763,37 +1763,40 @@ define([ } else if (windowCoordinates.x > context.drawingBufferWidth * 0.5) { viewport.width = windowCoordinates.x; + var right = camera.frustum.right; camera.frustum.right = maxCoord.x - x; executeCommandsInViewport(true, scene, passState, backgroundColor, picking); viewport.x += windowCoordinates.x; + viewport.width = context.drawingBufferWidth - windowCoordinates.x; camera.position.x = -camera.position.x; - var right = camera.frustum.right; - camera.frustum.right = -camera.frustum.left; - camera.frustum.left = -right; + camera.frustum.left = -camera.frustum.right; + camera.frustum.right = camera.frustum.left + (right - camera.frustum.right); frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); executeCommandsInViewport(false, scene, passState, backgroundColor, picking); } else { - viewport.x += windowCoordinates.x; - viewport.width -= windowCoordinates.x; + viewport.x = windowCoordinates.x; + viewport.width = context.drawingBufferWidth - windowCoordinates.x; + var left = camera.frustum.left; camera.frustum.left = -maxCoord.x - x; executeCommandsInViewport(true, scene, passState, backgroundColor, picking); - viewport.x = viewport.x - viewport.width; + viewport.x = 0; + viewport.width = windowCoordinates.x; camera.position.x = -camera.position.x; - var left = camera.frustum.left; - camera.frustum.left = -camera.frustum.right; - camera.frustum.right = -left; + camera.frustum.right = -camera.frustum.left; + camera.frustum.left = camera.frustum.right + (left - camera.frustum.left); + frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); diff --git a/Source/Scene/Sun.js b/Source/Scene/Sun.js index 6837cc21e2db..f1dfe1e0d18b 100644 --- a/Source/Scene/Sun.js +++ b/Source/Scene/Sun.js @@ -180,6 +180,11 @@ define([ var size = Math.max(drawingBufferWidth, drawingBufferHeight); size = Math.pow(2.0, Math.ceil(Math.log(size) / Math.log(2.0)) - 2.0); + // The size computed above can be less than 1.0 if size < 4.0. This will probably + // never happen in practice, but does in the tests. Clamp to 1.0 to prevent WebGL + // errors in the tests. + size = Math.max(1.0, size); + this._texture = new Texture({ context : context, width : size, diff --git a/Source/Scene/SunPostProcess.js b/Source/Scene/SunPostProcess.js index 1dd0304ef198..f26c7fc5575f 100644 --- a/Source/Scene/SunPostProcess.js +++ b/Source/Scene/SunPostProcess.js @@ -215,7 +215,11 @@ define([ var downSampleWidth = Math.pow(2.0, Math.ceil(Math.log(width) / Math.log(2)) - 2.0); var downSampleHeight = Math.pow(2.0, Math.ceil(Math.log(height) / Math.log(2)) - 2.0); - var downSampleSize = Math.max(downSampleWidth, downSampleHeight); + + // The size computed above can be less than 1.0 if size < 4.0. This will probably + // never happen in practice, but does in the tests. Clamp to 1.0 to prevent WebGL + // errors in the tests. + var downSampleSize = Math.max(1.0, downSampleWidth, downSampleHeight); var downSampleViewport = downSampleViewportBoundingRectangle; downSampleViewport.width = downSampleSize; diff --git a/Source/Workers/createVerticesFromQuantizedTerrainMesh.js b/Source/Workers/createVerticesFromQuantizedTerrainMesh.js index 73450be748fd..b32ed7d2521a 100644 --- a/Source/Workers/createVerticesFromQuantizedTerrainMesh.js +++ b/Source/Workers/createVerticesFromQuantizedTerrainMesh.js @@ -8,7 +8,6 @@ define([ '../Core/Cartographic', '../Core/defined', '../Core/Ellipsoid', - '../Core/EllipsoidalOccluder', '../Core/IndexDatatype', '../Core/Math', '../Core/Matrix3', @@ -26,7 +25,6 @@ define([ Cartographic, defined, Ellipsoid, - EllipsoidalOccluder, IndexDatatype, CesiumMath, Matrix3, @@ -111,7 +109,6 @@ define([ Cartesian3.maximumByComponent(cartesian3Scratch, maximum, maximum); } - var occludeePointInScaledSpace; var orientedBoundingBox; var boundingSphere; @@ -119,9 +116,6 @@ define([ // Bounding volumes and horizon culling point need to be recomputed since the tile payload assumes no exaggeration. boundingSphere = BoundingSphere.fromPoints(positions); orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid); - - var occluder = new EllipsoidalOccluder(ellipsoid); - occludeePointInScaledSpace = occluder.computeHorizonCullingPointFromPoints(center, positions); } var hMin = minimumHeight; @@ -145,7 +139,7 @@ define([ if (exaggeration !== 1.0) { var normal = AttributeCompression.octDecode(toPack.x, toPack.y, scratchNormal); - var fromENUNormal = Transforms.eastNorthUpToFixedFrame(cartesian3Scratch, ellipsoid, scratchFromENU); + var fromENUNormal = Transforms.eastNorthUpToFixedFrame(positions[j], ellipsoid, scratchFromENU); var toENUNormal = Matrix4.inverseTransformation(fromENUNormal, scratchToENU); Matrix4.multiplyByPointAsVector(toENUNormal, normal, normal); @@ -189,7 +183,6 @@ define([ maximumHeight : maximumHeight, boundingSphere : boundingSphere, orientedBoundingBox : orientedBoundingBox, - occludeePointInScaledSpace : occludeePointInScaledSpace, encoding : encoding, skirtIndex : parameters.indices.length }; diff --git a/Specs/Core/EllipsoidalOccluderSpec.js b/Specs/Core/EllipsoidalOccluderSpec.js index 72ee15ffa258..5e803dbd1858 100644 --- a/Specs/Core/EllipsoidalOccluderSpec.js +++ b/Specs/Core/EllipsoidalOccluderSpec.js @@ -255,41 +255,6 @@ defineSuite([ }); }); - describe('computeHorizonCullingPointFromPoints', function() { - it('requires directionToPointand points', function() { - var ellipsoid = new Ellipsoid(12345.0, 12345.0, 12345.0); - var ellipsoidalOccluder = new EllipsoidalOccluder(ellipsoid); - - var positions = [new Cartesian3(-12345.0, 12345.0, 12345.0), new Cartesian3(-12346.0, 12345.0, 12345.0), new Cartesian3(-12446.0, 12445.0, 12445.0)]; - var boundingSphere = BoundingSphere.fromPoints(positions); - - ellipsoidalOccluder.computeHorizonCullingPointFromPoints(boundingSphere.center, positions); - - expect(function() { - ellipsoidalOccluder.computeHorizonCullingPointFromPoints(undefined, positions); - }).toThrowDeveloperError(); - - expect(function() { - ellipsoidalOccluder.computeHorizonCullingPointFromPoints(boundingSphere.center, undefined); - }).toThrowDeveloperError(); - }); - - it('produces same answers as computeHorizonCullingPoint', function() { - var ellipsoid = new Ellipsoid(12345.0, 12345.0, 12345.0); - var ellipsoidalOccluder = new EllipsoidalOccluder(ellipsoid); - - var positions = [new Cartesian3(-12345.0, 12345.0, 12345.0), new Cartesian3(-12346.0, 12345.0, 12345.0), new Cartesian3(-12446.0, 12445.0, 12445.0)]; - var boundingSphere = BoundingSphere.fromPoints(positions); - - var result1 = ellipsoidalOccluder.computeHorizonCullingPoint(boundingSphere.center, positions); - var result2 = ellipsoidalOccluder.computeHorizonCullingPointFromPoints(boundingSphere.center, positions); - - expect(result1.x).toEqualEpsilon(result2.x, CesiumMath.EPSILON14); - expect(result1.y).toEqualEpsilon(result2.y, CesiumMath.EPSILON14); - expect(result1.z).toEqualEpsilon(result2.z, CesiumMath.EPSILON14); - }); - }); - describe('computeHorizonCullingPointFromRectangle', function() { it('returns undefined for global rectangle', function() { var ellipsoid = new Ellipsoid(12345.0, 12345.0, 12345.0); diff --git a/Specs/Core/PolygonGeometrySpec.js b/Specs/Core/PolygonGeometrySpec.js index 985df7e98fe1..86dff702a7af 100644 --- a/Specs/Core/PolygonGeometrySpec.js +++ b/Specs/Core/PolygonGeometrySpec.js @@ -4,6 +4,7 @@ defineSuite([ 'Core/BoundingSphere', 'Core/Cartesian3', 'Core/Ellipsoid', + 'Core/GeometryPipeline', 'Core/Math', 'Core/VertexFormat', 'Specs/createPackableSpecs' @@ -12,6 +13,7 @@ defineSuite([ BoundingSphere, Cartesian3, Ellipsoid, + GeometryPipeline, CesiumMath, VertexFormat, createPackableSpecs) { @@ -23,6 +25,15 @@ defineSuite([ }).toThrowDeveloperError(); }); + it('throws with height when perPositionHeight is true', function() { + expect(function() { + return new PolygonGeometry({ + height: 30, + perPositionHeight: true + }); + }).toThrowDeveloperError(); + }); + it('throws without positions', function() { expect(function() { return PolygonGeometry.fromPositions(); @@ -378,6 +389,64 @@ defineSuite([ expect(p.indices.length).toEqual(numTriangles * 3); }); + it('computes positions extruded and not closeTop', function() { + var p = PolygonGeometry.createGeometry(PolygonGeometry.fromPositions({ + vertexFormat : VertexFormat.POSITION_ONLY, + positions : Cartesian3.fromDegreesArray([ + -1.0, -1.0, + 1.0, -1.0, + 1.0, 1.0, + -1.0, 1.0 + ]), + extrudedHeight: 30000, + closeTop: false + })); + + var numVertices = 37; // 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner + var numTriangles = 32; // 16 bottom fill + 2 triangles * 4 sides + expect(p.attributes.position.values.length).toEqual(numVertices * 3); + expect(p.indices.length).toEqual(numTriangles * 3); + }); + + it('computes positions extruded and not closeBottom', function() { + var p = PolygonGeometry.createGeometry(PolygonGeometry.fromPositions({ + vertexFormat : VertexFormat.POSITION_ONLY, + positions : Cartesian3.fromDegreesArray([ + -1.0, -1.0, + 1.0, -1.0, + 1.0, 1.0, + -1.0, 1.0 + ]), + extrudedHeight: 30000, + closeBottom: false + })); + + var numVertices = 37; // 13 top + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner + var numTriangles = 32; // 16 top fill + 2 triangles * 4 sides + expect(p.attributes.position.values.length).toEqual(numVertices * 3); + expect(p.indices.length).toEqual(numTriangles * 3); + }); + + it('computes positions extruded and not closeBottom or closeTop', function() { + var p = PolygonGeometry.createGeometry(PolygonGeometry.fromPositions({ + vertexFormat : VertexFormat.POSITION_ONLY, + positions : Cartesian3.fromDegreesArray([ + -1.0, -1.0, + 1.0, -1.0, + 1.0, 1.0, + -1.0, 1.0 + ]), + extrudedHeight: 30000, + closeTop: false, + closeBottom: false + })); + + var numVertices = 24; // 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner + var numTriangles = 16; // 2 triangles * 4 sides + expect(p.attributes.position.values.length).toEqual(numVertices * 3); + expect(p.indices.length).toEqual(numTriangles * 3); + }); + it('removes duplicates extruded', function() { var p = PolygonGeometry.createGeometry(PolygonGeometry.fromPositions({ vertexFormat : VertexFormat.POSITION_ONLY, @@ -529,6 +598,35 @@ defineSuite([ expect(geometry).toBeUndefined(); }); + it('computes normals for perPositionHeight', function() { + var geometry = PolygonGeometry.createGeometry(PolygonGeometry.fromPositions({ + positions: [new Cartesian3(1333485.211963876, -4654510.505548239, 4138557.5850382405), + new Cartesian3(1333441.3994441305, -4654261.147368878, 4138322.784348336), + new Cartesian3(1333521.9333286814, -4654490.298890729, 4138567.564118971)], + extrudedHeight: 56, + vertexFormat: VertexFormat.POSITION_AND_NORMAL, + perPositionHeight: true, + closeBottom: false + }) + ); + + var normals = geometry.attributes.normal.values; + + geometry = GeometryPipeline.computeNormal(geometry); + var expectedNormals = geometry.attributes.normal.values; + + var notEqualCount = 0; + for (var i = 0; i < expectedNormals.length; i++) { + if (!CesiumMath.equalsEpsilon(normals[i], expectedNormals[i], CesiumMath.EPSILON6)) { + notEqualCount++; + } + } + + //Exactly 2 normals will be different due to weird triangles on the walls of the extrusion + //PolygonGeometry needs major changes to how extruded walls are computed with perPositionHeight in order to improve this + expect(notEqualCount).toEqual(6); + }); + var positions = Cartesian3.fromDegreesArray([ -124.0, 35.0, -110.0, 35.0, @@ -559,7 +657,9 @@ defineSuite([ vertexFormat : VertexFormat.POSITION_ONLY, polygonHierarchy : hierarchy, granularity : CesiumMath.PI_OVER_THREE, - perPositionHeight : true + perPositionHeight : true, + closeTop : false, + closeBottom : true }); function addPositions(array, positions) { @@ -574,6 +674,6 @@ defineSuite([ packedInstance.push(3.0, 0.0); addPositions(packedInstance, holePositions1); packedInstance.push(Ellipsoid.WGS84.radii.x, Ellipsoid.WGS84.radii.y, Ellipsoid.WGS84.radii.z); - packedInstance.push(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CesiumMath.PI_OVER_THREE, 0.0, 0.0, 1.0, 49); + packedInstance.push(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CesiumMath.PI_OVER_THREE, 0.0, 0.0, 1.0, 0, 1, 51); createPackableSpecs(PolygonGeometry, polygon, packedInstance); }); diff --git a/Specs/Core/PolygonOutlineGeometrySpec.js b/Specs/Core/PolygonOutlineGeometrySpec.js index 9bcd0e871081..cf8c631eea4e 100644 --- a/Specs/Core/PolygonOutlineGeometrySpec.js +++ b/Specs/Core/PolygonOutlineGeometrySpec.js @@ -21,6 +21,15 @@ defineSuite([ }).toThrowDeveloperError(); }); + it('throws with height when perPositionHeight is true', function() { + expect(function() { + return new PolygonOutlineGeometry({ + height: 30, + perPositionHeight: true + }); + }).toThrowDeveloperError(); + }); + it('throws without positions', function() { expect(function() { return PolygonOutlineGeometry.fromPositions(); diff --git a/Specs/DataSources/CzmlDataSourceSpec.js b/Specs/DataSources/CzmlDataSourceSpec.js index 6cf5f5f78ac5..821a5ee5e1aa 100644 --- a/Specs/DataSources/CzmlDataSourceSpec.js +++ b/Specs/DataSources/CzmlDataSourceSpec.js @@ -1403,7 +1403,9 @@ defineSuite([ outlineColor : { rgbaf : [0.2, 0.2, 0.2, 0.2] }, - outlineWidth : 6 + outlineWidth : 6, + closeTop : false, + closeBottom : false } }; @@ -1421,6 +1423,8 @@ defineSuite([ expect(entity.polygon.outline.getValue(Iso8601.MINIMUM_VALUE)).toEqual(true); expect(entity.polygon.outlineColor.getValue(Iso8601.MINIMUM_VALUE)).toEqual(new Color(0.2, 0.2, 0.2, 0.2)); expect(entity.polygon.outlineWidth.getValue(Iso8601.MINIMUM_VALUE)).toEqual(6); + expect(entity.polygon.closeTop.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); + expect(entity.polygon.closeBottom.getValue(Iso8601.MINIMUM_VALUE)).toEqual(false); }); it('CZML adds data for constrained polygon.', function() { diff --git a/Specs/DataSources/KmlDataSourceSpec.js b/Specs/DataSources/KmlDataSourceSpec.js index 861b8f7f0256..f8ce25ac154d 100644 --- a/Specs/DataSources/KmlDataSourceSpec.js +++ b/Specs/DataSources/KmlDataSourceSpec.js @@ -3116,6 +3116,27 @@ defineSuite([ }); }); + it('NetworkLink can accept invalid but common URL tag instead of Link', function(){ + var kml = '\ + \ + \ + ./Data/KML/refresh.kml\ + \ + '; + + var requestNetworkLink = when.defer(); + spyOn(loadWithXhr, 'load').and.callFake(function(url, responseType, method, data, headers, deferred, overrideMimeType) { + requestNetworkLink.resolve(url); + deferred.reject(); + }); + + KmlDataSource.load(parser.parseFromString(kml, "text/xml"), options); + + return requestNetworkLink.promise.then(function(url) { + expect(url).toEqual('./Data/KML/refresh.kml'); + }); + }); + it('NetworkLink: Url is correct on initial load with onStop defaults', function() { var kml = '\ \ diff --git a/Specs/DataSources/PolygonGeometryUpdaterSpec.js b/Specs/DataSources/PolygonGeometryUpdaterSpec.js index e2e5b3e074fe..0bf7cace26c5 100644 --- a/Specs/DataSources/PolygonGeometryUpdaterSpec.js +++ b/Specs/DataSources/PolygonGeometryUpdaterSpec.js @@ -143,6 +143,22 @@ defineSuite([ expect(updater.isClosed).toBe(true); }); + it('Settings extrudedHeight and closeTop false causes geometry to be open.', function() { + var entity = createBasicPolygon(); + var updater = new PolygonGeometryUpdater(entity, scene); + entity.polygon.extrudedHeight = new ConstantProperty(1000); + entity.polygon.closeTop = false; + expect(updater.isClosed).toBe(false); + }); + + it('Settings extrudedHeight and closeBottom false causes geometry to be open.', function() { + var entity = createBasicPolygon(); + var updater = new PolygonGeometryUpdater(entity, scene); + entity.polygon.extrudedHeight = new ConstantProperty(1000); + entity.polygon.closeBottom = false; + expect(updater.isClosed).toBe(false); + }); + it('A time-varying outlineWidth causes geometry to be dynamic', function() { var entity = createBasicPolygon(); var updater = new PolygonGeometryUpdater(entity, scene); @@ -216,6 +232,8 @@ defineSuite([ polygon.outline = new ConstantProperty(options.outline); polygon.outlineColor = new ConstantProperty(options.outlineColor); polygon.perPositionHeight = new ConstantProperty(options.perPositionHeight); + polygon.closeTop = new ConstantProperty(options.closeTop); + polygon.closeBottom = new ConstantProperty(options.closeBottom); polygon.stRotation = new ConstantProperty(options.stRotation); polygon.height = new ConstantProperty(options.height); @@ -234,6 +252,8 @@ defineSuite([ expect(geometry._height).toEqual(options.height); expect(geometry._granularity).toEqual(options.granularity); expect(geometry._extrudedHeight).toEqual(options.extrudedHeight); + expect(geometry._closeTop).toEqual(options.closeTop); + expect(geometry._closeBottom).toEqual(options.closeBottom); attributes = instance.attributes; if (options.material instanceof ColorMaterialProperty) { @@ -269,7 +289,9 @@ defineSuite([ fill : true, outline : true, outlineColor : Color.BLUE, - perPositionHeight : true + perPositionHeight : false, + closeTop: true, + closeBottom: false }); }); @@ -284,7 +306,9 @@ defineSuite([ fill : true, outline : true, outlineColor : Color.BLUE, - perPositionHeight : false + perPositionHeight : false, + closeTop: false, + closeBottom: true }); }); @@ -392,6 +416,8 @@ defineSuite([ polygon.perPositionHeight = createDynamicProperty(false); polygon.granularity = createDynamicProperty(2); polygon.stRotation = createDynamicProperty(1); + polygon.closeTop = createDynamicProperty(false); + polygon.closeBottom = createDynamicProperty(false); var entity = new Entity(); entity.polygon = polygon; @@ -413,6 +439,8 @@ defineSuite([ expect(options.perPositionHeight).toEqual(polygon.perPositionHeight.getValue()); expect(options.granularity).toEqual(polygon.granularity.getValue()); expect(options.stRotation).toEqual(polygon.stRotation.getValue()); + expect(options.closeTop).toEqual(polygon.closeTop.getValue()); + expect(options.closeBottom).toEqual(polygon.closeBottom.getValue()); entity.show = false; dynamicUpdater.update(JulianDate.now()); diff --git a/Specs/DataSources/PolygonGraphicsSpec.js b/Specs/DataSources/PolygonGraphicsSpec.js index 9e2ef7e1186b..1e6632fe2199 100644 --- a/Specs/DataSources/PolygonGraphicsSpec.js +++ b/Specs/DataSources/PolygonGraphicsSpec.js @@ -30,7 +30,9 @@ defineSuite([ fill : false, outline : false, outlineColor : Color.RED, - outlineWidth : 7 + outlineWidth : 7, + closeTop : true, + closeBottom : true }; var polygon = new PolygonGraphics(options); @@ -46,6 +48,8 @@ defineSuite([ expect(polygon.outline).toBeInstanceOf(ConstantProperty); expect(polygon.outlineColor).toBeInstanceOf(ConstantProperty); expect(polygon.outlineWidth).toBeInstanceOf(ConstantProperty); + expect(polygon.closeTop).toBeInstanceOf(ConstantProperty); + expect(polygon.closeBottom).toBeInstanceOf(ConstantProperty); expect(polygon.material.color.getValue()).toEqual(options.material); expect(polygon.show.getValue()).toEqual(options.show); @@ -59,6 +63,8 @@ defineSuite([ expect(polygon.outline.getValue()).toEqual(options.outline); expect(polygon.outlineColor.getValue()).toEqual(options.outlineColor); expect(polygon.outlineWidth.getValue()).toEqual(options.outlineWidth); + expect(polygon.closeTop.getValue()).toEqual(options.closeTop); + expect(polygon.closeBottom.getValue()).toEqual(options.closeBottom); }); it('merge assigns unassigned properties', function() { @@ -75,6 +81,8 @@ defineSuite([ source.outlineColor = new ConstantProperty(); source.outlineWidth = new ConstantProperty(); source.perPositionHeight = new ConstantProperty(); + source.closeTop = new ConstantProperty(); + source.closeBottom = new ConstantProperty(); var target = new PolygonGraphics(); target.merge(source); @@ -91,6 +99,8 @@ defineSuite([ expect(target.outlineColor).toBe(source.outlineColor); expect(target.outlineWidth).toBe(source.outlineWidth); expect(target.perPositionHeight).toBe(source.perPositionHeight); + expect(target.closeTop).toBe(source.closeTop); + expect(target.closeBottom).toBe(source.closeBottom); }); it('merge does not assign assigned properties', function() { @@ -108,6 +118,8 @@ defineSuite([ var outlineColor = new ConstantProperty(); var outlineWidth = new ConstantProperty(); var perPositionHeight = new ConstantProperty(); + var closeTop = new ConstantProperty(); + var closeBottom = new ConstantProperty(); var target = new PolygonGraphics(); target.material = material; @@ -122,6 +134,8 @@ defineSuite([ target.outlineColor = outlineColor; target.outlineWidth = outlineWidth; target.perPositionHeight = perPositionHeight; + target.closeTop = closeTop; + target.closeBottom = closeBottom; target.merge(source); @@ -137,6 +151,8 @@ defineSuite([ expect(target.outlineColor).toBe(outlineColor); expect(target.outlineWidth).toBe(outlineWidth); expect(target.perPositionHeight).toBe(perPositionHeight); + expect(target.closeTop).toBe(closeTop); + expect(target.closeBottom).toBe(closeBottom); }); it('clone works', function() { @@ -153,6 +169,8 @@ defineSuite([ source.outlineColor = new ConstantProperty(); source.outlineWidth = new ConstantProperty(); source.perPositionHeight = new ConstantProperty(); + source.closeTop = new ConstantProperty(); + source.closeBottom = new ConstantProperty(); var result = source.clone(); expect(result.material).toBe(source.material); @@ -167,6 +185,8 @@ defineSuite([ expect(result.outlineColor).toBe(source.outlineColor); expect(result.outlineWidth).toBe(source.outlineWidth); expect(result.perPositionHeight).toBe(source.perPositionHeight); + expect(result.closeTop).toBe(source.closeTop); + expect(result.closeBottom).toBe(source.closeBottom); }); it('merge throws if source undefined', function() { @@ -190,5 +210,7 @@ defineSuite([ testDefinitionChanged(property, 'outlineColor', Color.RED, Color.BLUE); testDefinitionChanged(property, 'outlineWidth', 2, 3); testDefinitionChanged(property, 'perPositionHeight', false, true); + testDefinitionChanged(property, 'closeTop', true, false); + testDefinitionChanged(property, 'closeBottom', true, false); }); }); diff --git a/package.json b/package.json index bf0c1058ed1e..266b4208cbd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "1.20.0", + "version": "1.21.0", "description": "Cesium is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "homepage": "http://cesiumjs.org", "license": "Apache-2.0",