diff --git a/Apps/Sandcastle/gallery/development/Coplanar Polygon Outline.html b/Apps/Sandcastle/gallery/development/Coplanar Polygon Outline.html new file mode 100644 index 000000000000..cd2422717461 --- /dev/null +++ b/Apps/Sandcastle/gallery/development/Coplanar Polygon Outline.html @@ -0,0 +1,69 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/development/Coplanar Polygon Outline.jpg b/Apps/Sandcastle/gallery/development/Coplanar Polygon Outline.jpg new file mode 100644 index 000000000000..af7488de9916 Binary files /dev/null and b/Apps/Sandcastle/gallery/development/Coplanar Polygon Outline.jpg differ diff --git a/Apps/Sandcastle/gallery/development/Coplanar Polygon.html b/Apps/Sandcastle/gallery/development/Coplanar Polygon.html new file mode 100644 index 000000000000..8cfce4882ae8 --- /dev/null +++ b/Apps/Sandcastle/gallery/development/Coplanar Polygon.html @@ -0,0 +1,69 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/development/Coplanar Polygon.jpg b/Apps/Sandcastle/gallery/development/Coplanar Polygon.jpg new file mode 100644 index 000000000000..2bb5ae4334dd Binary files /dev/null and b/Apps/Sandcastle/gallery/development/Coplanar Polygon.jpg differ diff --git a/CHANGES.md b/CHANGES.md index a91c2f588467..7414ce2bb570 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,13 +3,14 @@ Change Log ### 1.48 - 2018-08-01 -##### Additions :tada: -* Added support for loading Draco compressed Point Cloud tiles for 2-3x better compression. [#6559](https://github.com/AnalyticalGraphicsInc/cesium/pull/6559) - ##### Deprecated :hourglass_flowing_sand: * Support for 3D Tiles `content.url` is deprecated to reflect updates to the [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/pull/301). Use `content.uri instead`. Support for `content.url` will remain for backwards compatibility. [#6744](https://github.com/AnalyticalGraphicsInc/cesium/pull/6744) -##### Fixes :wrench: +##### Additions :tada: +* Added support for loading Draco compressed Point Cloud tiles for 2-3x better compression. [#6559](https://github.com/AnalyticalGraphicsInc/cesium/pull/6559) +* Added `CoplanarPolygonGeometry` and `CoplanarPolygonGeometryOutline` for drawing polygons composed of coplanar positions that are not necessarliy on the ellipsoid surface. [#6769](https://github.com/AnalyticalGraphicsInc/cesium/pull/6769) + +#### Fixes :wrench: * Fixed bug causing billboards and labels to appear the wrong size when switching scene modes [#6745](https://github.com/AnalyticalGraphicsInc/cesium/issues/6745) * Fixed a bug that was preventing 3D Tilesets on the opposite side of the globe from being occluded [#6714](https://github.com/AnalyticalGraphicsInc/cesium/issues/6714) diff --git a/Source/Core/CoplanarPolygonGeometry.js b/Source/Core/CoplanarPolygonGeometry.js new file mode 100644 index 000000000000..3957cb66e3c9 --- /dev/null +++ b/Source/Core/CoplanarPolygonGeometry.js @@ -0,0 +1,318 @@ +/*global define*/ +define([ + './arrayRemoveDuplicates', + './BoundingRectangle', + './BoundingSphere', + './Cartesian2', + './Cartesian3', + './Check', + './ComponentDatatype', + './CoplanarPolygonGeometryLibrary', + './defaultValue', + './defined', + './Geometry', + './GeometryAttribute', + './GeometryAttributes', + './IndexDatatype', + './Math', + './PolygonPipeline', + './PrimitiveType', + './VertexFormat', + './WindingOrder' + ], function( + arrayRemoveDuplicates, + BoundingRectangle, + BoundingSphere, + Cartesian2, + Cartesian3, + Check, + ComponentDatatype, + CoplanarPolygonGeometryLibrary, + defaultValue, + defined, + Geometry, + GeometryAttribute, + GeometryAttributes, + IndexDatatype, + CesiumMath, + PolygonPipeline, + PrimitiveType, + VertexFormat, + WindingOrder) { + 'use strict'; + + var scratchPositions2D = []; + var scratchBR = new BoundingRectangle(); + var textureCoordinatesOrigin = new Cartesian2(); + var scratchNormal = new Cartesian3(); + var scratchTangent = new Cartesian3(); + var scratchBitangent = new Cartesian3(); + + /** + * A description of a polygon composed of arbitrary coplanar positions. + * + * @alias CoplanarPolygonGeometry + * @constructor + * + * @param {Object} options Object with the following properties: + * @param {Cartesian3[]} options.positions The positions of the polygon + * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed. + * + * @example + * var polygon = new Cesium.CoplanarPolygonGeometry({ + * positions : Cesium.Cartesian3.fromDegreesArrayHeights([ + * -90.0, 30.0, 0.0, + * -90.0, 30.0, 1000.0, + * -80.0, 30.0, 1000.0, + * -80.0, 30.0, 0.0 + * ]) + * }); + * var geometry = Cesium.CoplanarPolygonGeometry.createGeometry(polygon); + * + * @see CoplanarPolygonGeometry.createGeometry + */ + function CoplanarPolygonGeometry(options) { + options = defaultValue(options, defaultValue.EMPTY_OBJECT); + var positions = options.positions; + //>>includeStart('debug', pragmas.debug); + Check.defined('options.positions', positions); + //>>includeEnd('debug'); + + var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT); + this._vertexFormat = VertexFormat.clone(vertexFormat); + this._positions = positions; + this._workerName = 'createCoplanarPolygonGeometry'; + + /** + * The number of elements used to pack the object into an array. + * @type {Number} + */ + this.packedLength = 1 + positions.length * Cartesian3.packedLength + VertexFormat.packedLength; + } + + /** + * Stores the provided instance into the provided array. + * + * @param {CoplanarPolygonGeometry} value The value to pack. + * @param {Number[]} array The array to pack into. + * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements. + * + * @returns {Number[]} The array that was packed into + */ + CoplanarPolygonGeometry.pack = function(value, array, startingIndex) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object('value', value); + Check.defined('array', array); + //>>includeEnd('debug'); + + startingIndex = defaultValue(startingIndex, 0); + + var positions = value._positions; + var length = positions.length; + array[startingIndex++] = length; + + for (var i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) { + Cartesian3.pack(positions[i], array, startingIndex); + } + + VertexFormat.pack(value._vertexFormat, array, startingIndex); + + return array; + }; + + var scratchVertexFormat = new VertexFormat(); + var scratchOptions = { + positions : undefined, + vertexFormat : scratchVertexFormat + }; + /** + * Retrieves an instance from a packed array. + * + * @param {Number[]} array The packed array. + * @param {Number} [startingIndex=0] The starting index of the element to be unpacked. + * @param {CoplanarPolygonGeometry} [result] The object into which to store the result. + * @returns {CoplanarPolygonGeometry} The modified result parameter or a new CoplanarPolygonGeometry instance if one was not provided. + */ + CoplanarPolygonGeometry.unpack = function(array, startingIndex, result) { + //>>includeStart('debug', pragmas.debug); + Check.defined('array', array); + //>>includeEnd('debug'); + + startingIndex = defaultValue(startingIndex, 0); + + var i; + + var length = array[startingIndex++]; + var positions = new Array(length); + + for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) { + positions[i] = Cartesian3.unpack(array, startingIndex); + } + + var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat); + + if (!defined(result)) { + scratchOptions.positions = positions; + scratchOptions.vertexFormat = vertexFormat; + return new CoplanarPolygonGeometry(scratchOptions); + } + + result._positions = positions; + result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat); + + return result; + }; + + /** + * Computes the geometric representation of an arbitrary coplanar polygon, including its vertices, indices, and a bounding sphere. + * + * @param {CoplanarPolygonGeometry} polygonGeometry A description of the polygon. + * @returns {Geometry|undefined} The computed vertices and indices. + */ + CoplanarPolygonGeometry.createGeometry = function(polygonGeometry) { + var vertexFormat = polygonGeometry._vertexFormat; + var positions = polygonGeometry._positions; + positions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon, true); + if (positions.length < 3) { + return; + } + var boundingSphere = BoundingSphere.fromPoints(positions); + + var normal; + var tangent; + var bitangent; + if (vertexFormat.normal) { + normal = scratchNormal; + } + if (vertexFormat.tangent) { + tangent = scratchTangent; + } + if (vertexFormat.bitangent) { + bitangent = scratchBitangent; + } + var positions2D = CoplanarPolygonGeometryLibrary.projectTo2D(positions, scratchPositions2D, normal, tangent, bitangent); + if (!defined(positions2D)) { + return; + } + + if (PolygonPipeline.computeWindingOrder2D(positions2D) === WindingOrder.CLOCKWISE) { + positions2D.reverse(); + positions = positions.slice().reverse(); + } + + var indices = PolygonPipeline.triangulate(positions2D); + if (indices.length < 3) { + return; + } + var newIndices = IndexDatatype.createTypedArray(positions.length, indices.length); + newIndices.set(indices); + + var boundingRectangle; + var stOrigin = textureCoordinatesOrigin; + if (vertexFormat.st) { + boundingRectangle = BoundingRectangle.fromPoints(positions2D, scratchBR); + stOrigin.x = boundingRectangle.x; + stOrigin.y = boundingRectangle.y; + } + + var length = positions.length; + var size = length * 3; + var flatPositions = new Float64Array(size); + var normals = vertexFormat.normal ? new Float32Array(size) : undefined; + var tangents = vertexFormat.tangent ? new Float32Array(size) : undefined; + var bitangents = vertexFormat.bitangent ? new Float32Array(size) : undefined; + var textureCoordinates = vertexFormat.st ? new Float32Array(length * 2) : undefined; + + var positionIndex = 0; + var normalIndex = 0; + var bitangentIndex = 0; + var tangentIndex = 0; + var stIndex = 0; + + for (var i = 0; i < length; i++) { + var position = positions[i]; + flatPositions[positionIndex++] = position.x; + flatPositions[positionIndex++] = position.y; + flatPositions[positionIndex++] = position.z; + + if (vertexFormat.st) { + var st = positions2D[i]; + st = Cartesian2.subtract(st, stOrigin, st); + + var stx = CesiumMath.clamp(st.x / boundingRectangle.width, 0, 1); + var sty = CesiumMath.clamp(st.y / boundingRectangle.height, 0, 1); + textureCoordinates[stIndex++] = stx; + textureCoordinates[stIndex++] = sty; + } + + if (vertexFormat.normal) { + normals[normalIndex++] = normal.x; + normals[normalIndex++] = normal.y; + normals[normalIndex++] = normal.z; + } + + if (vertexFormat.tangent) { + tangents[tangentIndex++] = tangent.x; + tangents[tangentIndex++] = tangent.y; + tangents[tangentIndex++] = tangent.z; + } + + if (vertexFormat.bitangent) { + bitangents[bitangentIndex++] = bitangent.x; + bitangents[bitangentIndex++] = bitangent.y; + bitangents[bitangentIndex++] = bitangent.z; + } + } + + var attributes = new GeometryAttributes(); + + if (vertexFormat.position) { + attributes.position = new GeometryAttribute({ + componentDatatype : ComponentDatatype.DOUBLE, + componentsPerAttribute : 3, + values : flatPositions + }); + } + + if (vertexFormat.normal) { + attributes.normal = new GeometryAttribute({ + componentDatatype : ComponentDatatype.FLOAT, + componentsPerAttribute : 3, + values : normals + }); + } + + if (vertexFormat.tangent) { + attributes.tangent = new GeometryAttribute({ + componentDatatype : ComponentDatatype.FLOAT, + componentsPerAttribute : 3, + values : tangents + }); + } + + if (vertexFormat.bitangent) { + attributes.bitangent = new GeometryAttribute({ + componentDatatype : ComponentDatatype.FLOAT, + componentsPerAttribute : 3, + values : bitangents + }); + } + + if (vertexFormat.st) { + attributes.st = new GeometryAttribute({ + componentDatatype : ComponentDatatype.FLOAT, + componentsPerAttribute : 2, + values : textureCoordinates + }); + } + + return new Geometry({ + attributes : attributes, + indices : newIndices, + primitiveType : PrimitiveType.TRIANGLES, + boundingSphere : boundingSphere + }); + }; + + return CoplanarPolygonGeometry; +}); diff --git a/Source/Core/CoplanarPolygonGeometryLibrary.js b/Source/Core/CoplanarPolygonGeometryLibrary.js new file mode 100644 index 000000000000..8942e138e4af --- /dev/null +++ b/Source/Core/CoplanarPolygonGeometryLibrary.js @@ -0,0 +1,100 @@ +define([ + './defined', + './Cartesian2', + './Cartesian3', + './Check', + './IntersectionTests', + './Math', + './Matrix3', + './OrientedBoundingBox' + ], function( + defined, + Cartesian2, + Cartesian3, + Check, + IntersectionTests, + CesiumMath, + Matrix3, + OrientedBoundingBox + ) { + 'use strict'; + + /** + * @private + */ + var PolygonGeometryLibrary = {}; + + var scratchIntersectionPoint = new Cartesian3(); + var scratchXAxis = new Cartesian3(); + var scratchYAxis = new Cartesian3(); + var scratchZAxis = new Cartesian3(); + var obbScratch = new OrientedBoundingBox(); + + // call after removeDuplicates + PolygonGeometryLibrary.projectTo2D = function(positions, positionsResult, normalResult, tangentResult, bitangentResult) { + //>>includeStart('debug', pragmas.debug); + Check.defined('positions', positions); + Check.defined('positionsResult', positionsResult); + //>>includeEnd('debug'); + + var orientedBoundingBox = OrientedBoundingBox.fromPoints(positions, obbScratch); + var halfAxes = orientedBoundingBox.halfAxes; + var xAxis = Matrix3.getColumn(halfAxes, 0, scratchXAxis); + var yAxis = Matrix3.getColumn(halfAxes, 1, scratchYAxis); + var zAxis = Matrix3.getColumn(halfAxes, 2, scratchZAxis); + + var xMag = Cartesian3.magnitude(xAxis); + var yMag = Cartesian3.magnitude(yAxis); + var zMag = Cartesian3.magnitude(zAxis); + var min = Math.min(xMag, yMag, zMag); + + // If all the points are on a line return undefined because we can't draw a polygon + if ((xMag === 0 && (yMag === 0 || zMag === 0)) || (yMag === 0 && zMag === 0)) { + return; + } + + var planeAxis1; + var planeAxis2; + + if (min === yMag || min === zMag) { + planeAxis1 = xAxis; + } + if (min === xMag) { + planeAxis1 = yAxis; + } else if (min === zMag) { + planeAxis2 = yAxis; + } + if (min === xMag || min === yMag) { + planeAxis2 = zAxis; + } + + planeAxis1 = Cartesian3.normalize(planeAxis1, planeAxis1); + planeAxis2 = Cartesian3.normalize(planeAxis2, planeAxis2); + + if (defined(normalResult)) { + normalResult = Cartesian3.cross(planeAxis1, planeAxis2, normalResult); + normalResult = Cartesian3.normalize(normalResult, normalResult); + } + if (defined(tangentResult)) { + Cartesian3.clone(planeAxis1, tangentResult); + } + if (defined(bitangentResult)) { + Cartesian3.clone(planeAxis2, bitangentResult); + } + + for (var i = 0; i < positions.length; i++) { + var position = positions[i]; + var v = Cartesian3.subtract(position, orientedBoundingBox.center, scratchIntersectionPoint); + var x = Cartesian3.dot(planeAxis1, v); + var y = Cartesian3.dot(planeAxis2, v); + + positionsResult[i] = Cartesian2.fromElements(x, y, positionsResult[i]); + } + + positionsResult.length = positions.length; + + return positionsResult; + }; + + return PolygonGeometryLibrary; +}); diff --git a/Source/Core/CoplanarPolygonOutlineGeometry.js b/Source/Core/CoplanarPolygonOutlineGeometry.js new file mode 100644 index 000000000000..1ea4495b59aa --- /dev/null +++ b/Source/Core/CoplanarPolygonOutlineGeometry.js @@ -0,0 +1,200 @@ +/*global define*/ +define([ + './arrayRemoveDuplicates', + './BoundingSphere', + './Cartesian3', + './Check', + './ComponentDatatype', + './CoplanarPolygonGeometryLibrary', + './defaultValue', + './defined', + './Geometry', + './GeometryAttribute', + './GeometryAttributes', + './IndexDatatype', + './PolygonPipeline', + './PrimitiveType', + './WindingOrder' +], function( + arrayRemoveDuplicates, + BoundingSphere, + Cartesian3, + Check, + ComponentDatatype, + CoplanarPolygonGeometryLibrary, + defaultValue, + defined, + Geometry, + GeometryAttribute, + GeometryAttributes, + IndexDatatype, + PolygonPipeline, + PrimitiveType, + WindingOrder) { + 'use strict'; + + var scratchPositions2D = []; + + /** + * A description of the outline of a polygon composed of arbitrary coplanar positions. + * + * @alias CoplanarPolygonOutlineGeometry + * @constructor + * + * @param {Object} options Object with the following properties: + * @param {Cartesian3[]} options.positions The positions of the polygon + * + * @see CoplanarPolygonOutlineGeometry.createGeometry + * + * @example + * var polygonOutline = new Cesium.CoplanarPolygonOutlineGeometry({ + * positions : Cesium.Cartesian3.fromDegreesArrayHeights([ + * -90.0, 30.0, 0.0, + * -90.0, 30.0, 1000.0, + * -80.0, 30.0, 1000.0, + * -80.0, 30.0, 0.0 + * ]) + * }); + * var geometry = Cesium.CoplanarPolygonOutlineGeometry.createGeometry(polygonOutline); + */ + function CoplanarPolygonOutlineGeometry(options) { + options = defaultValue(options, defaultValue.EMPTY_OBJECT); + var positions = options.positions; + //>>includeStart('debug', pragmas.debug); + Check.defined('options.positions', positions); + //>>includeEnd('debug'); + + this._positions = positions; + this._workerName = 'createCoplanarPolygonOutlineGeometry'; + + /** + * The number of elements used to pack the object into an array. + * @type {Number} + */ + this.packedLength = 1 + positions.length * Cartesian3.packedLength; + } + + /** + * Stores the provided instance into the provided array. + * + * @param {CoplanarPolygonOutlineGeometry} value The value to pack. + * @param {Number[]} array The array to pack into. + * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements. + * + * @returns {Number[]} The array that was packed into + */ + CoplanarPolygonOutlineGeometry.pack = function(value, array, startingIndex) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object('value', value); + Check.defined('array', array); + //>>includeEnd('debug'); + + startingIndex = defaultValue(startingIndex, 0); + + var positions = value._positions; + var length = positions.length; + array[startingIndex++] = length; + + for (var i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) { + Cartesian3.pack(positions[i], array, startingIndex); + } + + return array; + }; + + var scratchOptions = { + positions : undefined + }; + /** + * Retrieves an instance from a packed array. + * + * @param {Number[]} array The packed array. + * @param {Number} [startingIndex=0] The starting index of the element to be unpacked. + * @param {CoplanarPolygonOutlineGeometry} [result] The object into which to store the result. + * @returns {CoplanarPolygonOutlineGeometry} The modified result parameter or a new CoplanarPolygonOutlineGeometry instance if one was not provided. + */ + CoplanarPolygonOutlineGeometry.unpack = function(array, startingIndex, result) { + //>>includeStart('debug', pragmas.debug); + Check.defined('array', array); + //>>includeEnd('debug'); + + startingIndex = defaultValue(startingIndex, 0); + + var i; + + var length = array[startingIndex++]; + var positions = new Array(length); + + for (i = 0; i < length; ++i, startingIndex += Cartesian3.packedLength) { + positions[i] = Cartesian3.unpack(array, startingIndex); + } + + if (!defined(result)) { + scratchOptions.positions = positions; + return new CoplanarPolygonOutlineGeometry(scratchOptions); + } + + result._positions = positions; + + return result; + }; + + /** + * Computes the geometric representation of an arbitrary coplanar polygon, including its vertices, indices, and a bounding sphere. + * + * @param {CoplanarPolygonOutlineGeometry} polygonGeometry A description of the polygon. + * @returns {Geometry|undefined} The computed vertices and indices. + */ + CoplanarPolygonOutlineGeometry.createGeometry = function(polygonGeometry) { + var positions = polygonGeometry._positions; + positions = arrayRemoveDuplicates(positions, Cartesian3.equalsEpsilon, true); + if (positions.length < 3) { + return; + } + var boundingSphere = BoundingSphere.fromPoints(positions); + + var positions2D = CoplanarPolygonGeometryLibrary.projectTo2D(positions, scratchPositions2D); + if (!defined(positions2D)) { + return; + } + + if (PolygonPipeline.computeWindingOrder2D(positions2D) === WindingOrder.CLOCKWISE) { + positions2D.reverse(); + positions = positions.slice().reverse(); + } + + var length = positions.length; + var flatPositions = new Float64Array(length * 3); + var indices = IndexDatatype.createTypedArray(length, length * 2); + + var positionIndex = 0; + var index = 0; + + for (var i = 0; i < length; i++) { + var position = positions[i]; + flatPositions[positionIndex++] = position.x; + flatPositions[positionIndex++] = position.y; + flatPositions[positionIndex++] = position.z; + + indices[index++] = i; + indices[index++] = (i + 1) % length; + } + + var attributes = new GeometryAttributes({ + position: new GeometryAttribute({ + componentDatatype : ComponentDatatype.DOUBLE, + componentsPerAttribute : 3, + values : flatPositions + }) + }); + + return new Geometry({ + attributes : attributes, + indices : indices, + primitiveType : PrimitiveType.LINES, + boundingSphere : boundingSphere + }); + }; + + return CoplanarPolygonOutlineGeometry; +}); diff --git a/Source/Workers/createCoplanarPolygonGeometry.js b/Source/Workers/createCoplanarPolygonGeometry.js new file mode 100644 index 000000000000..1e76b76c23c8 --- /dev/null +++ b/Source/Workers/createCoplanarPolygonGeometry.js @@ -0,0 +1,17 @@ +define([ + '../Core/defined', + '../Core/CoplanarPolygonGeometry' +], function( + defined, + CoplanarPolygonGeometry) { + 'use strict'; + + function createCoplanarPolygonGeometry(polygonGeometry, offset) { + if (defined(offset)) { + polygonGeometry = CoplanarPolygonGeometry.unpack(polygonGeometry, offset); + } + return CoplanarPolygonGeometry.createGeometry(polygonGeometry); + } + + return createCoplanarPolygonGeometry; +}); diff --git a/Source/Workers/createCoplanarPolygonOutlineGeometry.js b/Source/Workers/createCoplanarPolygonOutlineGeometry.js new file mode 100644 index 000000000000..d989368e9e87 --- /dev/null +++ b/Source/Workers/createCoplanarPolygonOutlineGeometry.js @@ -0,0 +1,17 @@ +define([ + '../Core/defined', + '../Core/CoplanarPolygonOutlineGeometry' +], function( + defined, + CoplanarPolygonOutlineGeometry) { + 'use strict'; + + function createCoplanarPolygonOutlineGeometry(polygonGeometry, offset) { + if (defined(offset)) { + polygonGeometry = CoplanarPolygonOutlineGeometry.unpack(polygonGeometry, offset); + } + return CoplanarPolygonOutlineGeometry.createGeometry(polygonGeometry); + } + + return createCoplanarPolygonOutlineGeometry; +}); diff --git a/Specs/Core/CoplanarPolygonGeometrySpec.js b/Specs/Core/CoplanarPolygonGeometrySpec.js new file mode 100644 index 000000000000..6e69043fa18e --- /dev/null +++ b/Specs/Core/CoplanarPolygonGeometrySpec.js @@ -0,0 +1,90 @@ +defineSuite([ + 'Core/CoplanarPolygonGeometry', + 'Core/Cartesian3', + 'Core/Ellipsoid', + 'Core/Math', + 'Core/VertexFormat', + 'Specs/createPackableSpecs' +], function( + CoplanarPolygonGeometry, + Cartesian3, + Ellipsoid, + CesiumMath, + VertexFormat, + createPackableSpecs) { + 'use strict'; + + it('throws with no positions', function() { + expect(function() { + return new CoplanarPolygonGeometry(); + }).toThrowDeveloperError(); + }); + + it('returns undefined with less than 3 unique positions', function() { + var geometry = CoplanarPolygonGeometry.createGeometry(new CoplanarPolygonGeometry({ + positions : Cartesian3.fromDegreesArrayHeights([ + 49.0, 18.0, 1000.0, + 49.0, 18.0, 5000.0, + 49.0, 18.0, 5000.0, + 49.0, 18.0, 1000.0 + ]) + })); + expect(geometry).toBeUndefined(); + }); + + it('returns undefined when positions are linear', function() { + var geometry = CoplanarPolygonGeometry.createGeometry(new CoplanarPolygonGeometry({ + positions : Cartesian3.fromDegreesArrayHeights([ + 0.0, 0.0, 1.0, + 0.0, 0.0, 2.0, + 0.0, 0.0, 3.0 + ]) + })); + expect(geometry).toBeUndefined(); + }); + + it('computes positions', function() { + var p = CoplanarPolygonGeometry.createGeometry(new CoplanarPolygonGeometry({ + vertexFormat : VertexFormat.POSITION_ONLY, + positions : Cartesian3.fromDegreesArrayHeights([ + -1.0, -1.0, 0.0, + -1.0, 0.0, 1.0, + -1.0, 1.0, 1.0, + -1.0, 2.0, 0.0 + ]) + })); + + expect(p.attributes.position.values.length).toEqual(4 * 3); + expect(p.indices.length).toEqual(2 * 3); + }); + + it('computes all attributes', function() { + var p = CoplanarPolygonGeometry.createGeometry(new CoplanarPolygonGeometry({ + vertexFormat : VertexFormat.ALL, + positions : Cartesian3.fromDegreesArrayHeights([ + -1.0, -1.0, 0.0, + -1.0, 0.0, 1.0, + -1.0, 1.0, 1.0, + -1.0, 2.0, 0.0 + ]) + })); + + var numVertices = 4; + var numTriangles = 2; + expect(p.attributes.position.values.length).toEqual(numVertices * 3); + expect(p.attributes.st.values.length).toEqual(numVertices * 2); + expect(p.attributes.normal.values.length).toEqual(numVertices * 3); + expect(p.attributes.tangent.values.length).toEqual(numVertices * 3); + expect(p.attributes.bitangent.values.length).toEqual(numVertices * 3); + expect(p.indices.length).toEqual(numTriangles * 3); + }); + + var positions = [new Cartesian3(-1.0, 0.0, 0.0), new Cartesian3(0.0, 0.0, 1.0), new Cartesian3(-1.0, 0.0, 0.0)]; + var polygon = new CoplanarPolygonGeometry({ + positions : positions, + vertexFormat : VertexFormat.POSITION_ONLY + }); + var packedInstance = [3.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0]; + createPackableSpecs(CoplanarPolygonGeometry, polygon, packedInstance); +}); + diff --git a/Specs/Core/CoplanarPolygonOutlineGeometrySpec.js b/Specs/Core/CoplanarPolygonOutlineGeometrySpec.js new file mode 100644 index 000000000000..576be81b9fd0 --- /dev/null +++ b/Specs/Core/CoplanarPolygonOutlineGeometrySpec.js @@ -0,0 +1,64 @@ +defineSuite([ + 'Core/CoplanarPolygonOutlineGeometry', + 'Core/Cartesian3', + 'Core/Ellipsoid', + 'Core/Math', + 'Specs/createPackableSpecs' +], function( + CoplanarPolygonOutlineGeometry, + Cartesian3, + Ellipsoid, + CesiumMath, + createPackableSpecs) { + 'use strict'; + + it('throws with no positions', function() { + expect(function() { + return new CoplanarPolygonOutlineGeometry(); + }).toThrowDeveloperError(); + }); + + it('returns undefined with less than 3 unique positions', function() { + var geometry = CoplanarPolygonOutlineGeometry.createGeometry(new CoplanarPolygonOutlineGeometry({ + positions : Cartesian3.fromDegreesArrayHeights([ + 49.0, 18.0, 1000.0, + 49.0, 18.0, 5000.0, + 49.0, 18.0, 5000.0, + 49.0, 18.0, 1000.0 + ]) + })); + expect(geometry).toBeUndefined(); + }); + + it('returns undefined when positions are linear', function() { + var geometry = CoplanarPolygonOutlineGeometry.createGeometry(new CoplanarPolygonOutlineGeometry({ + positions : Cartesian3.fromDegreesArrayHeights([ + 0.0, 0.0, 1.0, + 0.0, 0.0, 2.0, + 0.0, 0.0, 3.0 + ]) + })); + expect(geometry).toBeUndefined(); + }); + + it('creates positions', function() { + var geometry = CoplanarPolygonOutlineGeometry.createGeometry(new CoplanarPolygonOutlineGeometry({ + positions : Cartesian3.fromDegreesArrayHeights([ + -1.0, -1.0, 0.0, + -1.0, 0.0, 1.0, + -1.0, 1.0, 1.0, + -1.0, 2.0, 0.0 + ]) + })); + + expect(geometry.attributes.position.values.length).toEqual(4 * 3); + expect(geometry.indices.length).toEqual(4 * 2); + }); + + var positions = [new Cartesian3(-1.0, 0.0, 0.0), new Cartesian3(0.0, 0.0, 1.0), new Cartesian3(-1.0, 0.0, 0.0)]; + var polygon = new CoplanarPolygonOutlineGeometry({ + positions : positions + }); + var packedInstance = [3.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0]; + createPackableSpecs(CoplanarPolygonOutlineGeometry, polygon, packedInstance); +}); diff --git a/Specs/Scene/GeometryRenderingSpec.js b/Specs/Scene/GeometryRenderingSpec.js index a066fdc64b1f..20dfedb08ea5 100644 --- a/Specs/Scene/GeometryRenderingSpec.js +++ b/Specs/Scene/GeometryRenderingSpec.js @@ -6,6 +6,7 @@ defineSuite([ 'Core/CircleGeometry', 'Core/Color', 'Core/ColorGeometryInstanceAttribute', + 'Core/CoplanarPolygonGeometry', 'Core/ComponentDatatype', 'Core/CornerType', 'Core/CorridorGeometry', @@ -46,6 +47,7 @@ defineSuite([ CircleGeometry, Color, ColorGeometryInstanceAttribute, + CoplanarPolygonGeometry, ComponentDatatype, CornerType, CorridorGeometry, @@ -332,6 +334,49 @@ defineSuite([ }); }, 'WebGL'); + describe('CoplanarPolygonGeometry', function() { + var instance; + beforeAll(function() { + instance = new GeometryInstance({ + geometry : new CoplanarPolygonGeometry({ + positions : Cartesian3.fromDegreesArrayHeights([ + 71.0, -10.0, 0.0, + 70.0, 0.0, 20000.0, + 69.0, 0.0, 20000.0, + 68.0, -10.0, 0.0 + ]), + vertexFormat : PerInstanceColorAppearance.FLAT_VERTEX_FORMAT + }), + id: 'coplanar polygon', + attributes : { + color : new ColorGeometryInstanceAttribute(Math.random(), Math.random(), Math.random(), 0.5) + } + }); + geometry = CoplanarPolygonGeometry.createGeometry(instance.geometry); + geometry.boundingSphereWC = BoundingSphere.transform(geometry.boundingSphere, instance.modelMatrix); + }); + + it('3D', function() { + render3D(instance); + }); + + it('Columbus view', function() { + renderCV(instance); + }); + + it('2D', function() { + render2D(instance); + }); + + it('pick', function() { + pickGeometry(instance); + }); + + it('async', function() { + return renderAsync(instance); + }); + }); + describe('CylinderGeometry', function() { var instance; beforeAll(function() {