diff --git a/CHANGES.md b/CHANGES.md index c3891b1f8bcc..3703add5564f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,7 +21,7 @@ Beta Releases * Removed `Polygon.bufferUsage`. It is no longer needed. * Removed `height` and `textureRotationAngle` arguments from `Polygon` `setPositions` and `configureFromPolygonHierarchy` functions. Use `Polygon` `height` and `textureRotationAngle` properties. * Renamed `PolygonPipeline.cleanUp` to `PolygonPipeline.removeDuplicates`. - * Removed `PolygonPipeline.wrapLongitude`. It is no longer needed. + * Removed `PolygonPipeline.wrapLongitude`. Use `GeometryPipeline.wrapLongitude` instead. * Added `height` parameter to `BoundingSphere.fromExtent3D`. * Added `height` parameter to `Extent.subsample`. * Added `ExtentPrimitive`. @@ -42,11 +42,11 @@ Beta Releases * Added `GeometryPipeline.combine` to combine meshes for better batching. * Added `GeometryPipeline.computeNormal` to compute normals for a geometry. * Added `GeometryPipeline.computeBinormalAndTangent` to compute binormals and tangent vectors for a geometry. -* Added the following functions to `GeometryPipeline` to index non-indexed primitive types: `indexLines`, `indexLineLoop`, `indexLineStrip`, `indexTriangles`, `indexTriangleFan`, and `indexTriangleStrip`. * Added `GeometryPipeline.wrapLongitude` to split geometry across the International Date Line. * Added `PolylinePipeline.removeDuplicates`. * Added `barycentricCoordinates` to compute the barycentric coordinates of a point with respect to three vertices of a triangle. * Added `BoundingSphere.fromEllipsoid`. +* Added `BoundingSphere.projectTo2D`. * Added `Extent.fromDegrees`. * Added `czm_tangentToEyeSpaceMatrix` built-in GLSL function. * Improved the performance of drawing polygons created with `configureFromPolygonHierarchy`. diff --git a/Source/Core/BoundingSphere.js b/Source/Core/BoundingSphere.js index fd29f9655756..8215e08c2d41 100644 --- a/Source/Core/BoundingSphere.js +++ b/Source/Core/BoundingSphere.js @@ -761,6 +761,117 @@ define([ return result; }; + var projectTo2DNormal = new Cartesian3(); + var projectTo2DEast = new Cartesian3(); + var projectTo2DNorth = new Cartesian3(); + var projectTo2DWest = new Cartesian3(); + var projectTo2DSouth = new Cartesian3(); + var projectTo2DCartographic = new Cartographic(); + var projectTo2DPositions = new Array(8); + for (var n = 0; n < 8; ++n) { + projectTo2DPositions[n] = new Cartesian3(); + } + /** + * Creates a bounding sphere in 2D from a bounding sphere in 3D world coordinates. + * @memberof BoundingSphere + * + * @param {BoundingSphere} sphere The bounding sphere to transform to 2D. + * @param {Object} [projection=GeographicProjection] The projection to 2D. + * @param {BoundingSphere} [result] The object onto which to store the result. + * @return {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. + * + * @exception {DeveloperError} sphere is required. + */ + BoundingSphere.projectTo2D = function(sphere, projection, result) { + if (typeof sphere === 'undefined') { + throw new DeveloperError('sphere is required.'); + } + + projection = (typeof projection !== 'undefined') ? projection : new GeographicProjection(); + + var ellipsoid = projection.getEllipsoid(); + var center = sphere.center; + var radius = sphere.radius; + + var normal = ellipsoid.geodeticSurfaceNormal(center, projectTo2DNormal); + var east = Cartesian3.cross(Cartesian3.UNIT_Z, normal, projectTo2DEast); + Cartesian3.normalize(east, east); + var north = Cartesian3.cross(normal, east, projectTo2DNorth); + Cartesian3.normalize(north, north); + + Cartesian3.multiplyByScalar(normal, radius, normal); + Cartesian3.multiplyByScalar(north, radius, north); + Cartesian3.multiplyByScalar(east, radius, east); + + var south = Cartesian3.negate(north, projectTo2DSouth); + var west = Cartesian3.negate(east, projectTo2DWest); + + var positions = projectTo2DPositions; + + // top NE corner + var corner = positions[0]; + Cartesian3.add(normal, north, corner); + Cartesian3.add(corner, east, corner); + + // top NW corner + corner = positions[1]; + Cartesian3.add(normal, north, corner); + Cartesian3.add(corner, west, corner); + + // top SW corner + corner = positions[2]; + Cartesian3.add(normal, south, corner); + Cartesian3.add(corner, west, corner); + + // top SE corner + corner = positions[3]; + Cartesian3.add(normal, south, corner); + Cartesian3.add(corner, east, corner); + + Cartesian3.negate(normal, normal); + + // bottom NE corner + corner = positions[4]; + Cartesian3.add(normal, north, corner); + Cartesian3.add(corner, east, corner); + + // bottom NW corner + corner = positions[5]; + Cartesian3.add(normal, north, corner); + Cartesian3.add(corner, west, corner); + + // bottom SW corner + corner = positions[6]; + Cartesian3.add(normal, south, corner); + Cartesian3.add(corner, west, corner); + + // bottom SE corner + corner = positions[7]; + Cartesian3.add(normal, south, corner); + Cartesian3.add(corner, east, corner); + + var length = positions.length; + for (var i = 0; i < length; ++i) { + var position = positions[i]; + Cartesian3.add(center, position, position); + var cartographic = ellipsoid.cartesianToCartographic(position, projectTo2DCartographic); + projection.project(cartographic, position); + } + + result = BoundingSphere.fromPoints(positions, result); + + // swizzle center components + center = result.center; + var x = center.x; + var y = center.y; + var z = center.z; + center.x = z; + center.y = x; + center.z = y; + + return result; + }; + /** * Compares the provided BoundingSphere componentwise and returns * true if they are equal, false otherwise. @@ -868,6 +979,18 @@ define([ return BoundingSphere.getPlaneDistances(this, position, direction, result); }; + /** + * Creates a bounding sphere in 2D from this bounding sphere. This bounding sphere must be in 3D world coordinates. + * @memberof BoundingSphere + * + * @param {Object} [projection=GeographicProjection] The projection to 2D. + * @param {BoundingSphere} [result] The object onto which to store the result. + * @return {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. + */ + BoundingSphere.prototype.projectTo2D = function(projection, result) { + return BoundingSphere.projectTo2D(this, projection, result); + }; + /** * Compares this BoundingSphere against the provided BoundingSphere componentwise and returns * true if they are equal, false otherwise. diff --git a/Source/Core/GeometryPipeline.js b/Source/Core/GeometryPipeline.js index 99b31c9f9885..96b86150976e 100644 --- a/Source/Core/GeometryPipeline.js +++ b/Source/Core/GeometryPipeline.js @@ -1187,10 +1187,7 @@ define([ return geometry; }; - /** - * DOC_TBA - */ - GeometryPipeline.indexTriangles = function(geometry) { + function indexTriangles(geometry) { if (typeof geometry === 'undefined') { throw new DeveloperError('geometry is required.'); } @@ -1199,10 +1196,6 @@ define([ return geometry; } - if (geometry.primitiveType !== PrimitiveType.TRIANGLES) { - throw new DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLES.'); - } - var numberOfVertices = Geometry.computeNumberOfVertices(geometry); if (numberOfVertices < 3) { throw new DeveloperError('The number of vertices must be at least three.'); @@ -1219,20 +1212,13 @@ define([ geometry.indices = indices; return geometry; - }; + } - /** - * DOC_TBA - */ - GeometryPipeline.indexTriangleFan = function(geometry) { + function indexTriangleFan(geometry) { if (typeof geometry === 'undefined') { throw new DeveloperError('geometry is required.'); } - if (geometry.primitiveType !== PrimitiveType.TRIANGLE_FAN) { - throw new DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLE_FAN.'); - } - var numberOfVertices = Geometry.computeNumberOfVertices(geometry); if (numberOfVertices < 3) { throw new DeveloperError('The number of vertices must be at least three.'); @@ -1253,20 +1239,13 @@ define([ geometry.indices = indices; geometry.primitiveType = PrimitiveType.TRIANGLES; return geometry; - }; + } - /** - * DOC_TBA - */ - GeometryPipeline.indexTriangleStrip = function(geometry) { + function indexTriangleStrip(geometry) { if (typeof geometry === 'undefined') { throw new DeveloperError('geometry is required.'); } - if (geometry.primitiveType !== PrimitiveType.TRIANGLE_STRIP) { - throw new DeveloperError('geometry.primitiveType must be PrimitiveType.TRIANGLE_STRIP.'); - } - var numberOfVertices = Geometry.computeNumberOfVertices(geometry); if (numberOfVertices < 3) { throw new DeveloperError('The number of vertices must be at least 3.'); @@ -1299,12 +1278,9 @@ define([ geometry.indices = indices; geometry.primitiveType = PrimitiveType.TRIANGLES; return geometry; - }; + } - /** - * DOC_TBA - */ - GeometryPipeline.indexLines = function(geometry) { + function indexLines(geometry) { if (typeof geometry === 'undefined') { throw new DeveloperError('undefined'); } @@ -1313,10 +1289,6 @@ define([ return geometry; } - if (geometry.primitiveType !== PrimitiveType.LINES) { - throw new DeveloperError('geometry.primitiveType must be PrimitiveType.LINES.'); - } - var numberOfVertices = Geometry.computeNumberOfVertices(geometry); if (numberOfVertices < 2) { throw new DeveloperError('The number of vertices must be at least two.'); @@ -1333,20 +1305,13 @@ define([ geometry.indices = indices; return geometry; - }; + } - /** - * DOC_TBA - */ - GeometryPipeline.indexLineStrip = function(geometry) { + function indexLineStrip(geometry) { if (typeof geometry === 'undefined') { throw new DeveloperError('geometry is required.'); } - if (geometry.primitiveType !== PrimitiveType.LINE_STRIP) { - throw new DeveloperError('geometry.primitiveType must be PrimitiveType.LINE_STRIP.'); - } - var numberOfVertices = Geometry.computeNumberOfVertices(geometry); if (numberOfVertices < 2) { throw new DeveloperError('The number of vertices must be at least two.'); @@ -1365,20 +1330,13 @@ define([ geometry.indices = indices; geometry.primitiveType = PrimitiveType.LINES; return geometry; - }; + } - /** - * DOC_TBA - */ - GeometryPipeline.indexLineLoop = function(geometry) { + function indexLineLoop(geometry) { if (typeof geometry === 'undefined') { throw new DeveloperError('geometry is required.'); } - if (geometry.primitiveType !== PrimitiveType.LINE_LOOP) { - throw new DeveloperError('geometry.primitiveType must be PrimitiveType.LINE_LOOP.'); - } - var numberOfVertices = Geometry.computeNumberOfVertices(geometry); if (numberOfVertices < 2) { throw new DeveloperError('The number of vertices must be at least two.'); @@ -1401,7 +1359,26 @@ define([ geometry.indices = indices; geometry.primitiveType = PrimitiveType.LINES; return geometry; - }; + } + + function indexPrimitive(geometry) { + switch (geometry.primitiveType) { + case PrimitiveType.TRIANGLE_FAN: + return indexTriangleFan(geometry); + case PrimitiveType.TRIANGLE_STRIP: + return indexTriangleStrip(geometry); + case PrimitiveType.TRIANGLES: + return indexTriangles(geometry); + case PrimitiveType.LINE_STRIP: + return indexLineStrip(geometry); + case PrimitiveType.LINE_LOOP: + return indexLineLoop(geometry); + case PrimitiveType.LINES: + return indexLines(geometry); + } + + return geometry; + } function offsetPointFromXZPlane(p, isBehind) { if (Math.abs(p.y) < CesiumMath.EPSILON11){ @@ -1797,28 +1774,10 @@ define([ } } - var primitiveType = geometry.primitiveType; - if (primitiveType === PrimitiveType.TRIANGLE_FAN) { - GeometryPipeline.indexTriangleFan(primitiveType); + indexPrimitive(geometry); + if (geometry.primitiveType === PrimitiveType.TRIANGLES) { wrapLongitudeTriangles(geometry); - } else if (primitiveType === PrimitiveType.TRIANGLE_STRIP) { - GeometryPipeline.indexTriangleStrip(geometry); - wrapLongitudeTriangles(geometry); - } else if (primitiveType === PrimitiveType.TRIANGLES) { - if (typeof geometry.indices === 'undefined') { - GeometryPipeline.indexTriangles(geometry); - } - wrapLongitudeTriangles(geometry); - } else if (primitiveType === PrimitiveType.LINE_STRIP) { - GeometryPipeline.indexLineStrip(geometry); - wrapLongitudeLines(geometry); - } else if (primitiveType === PrimitiveType.LINE_LOOP) { - GeometryPipeline.indexLineLoop(geometry); - wrapLongitudeLines(geometry); - } else if (primitiveType === PrimitiveType.LINES) { - if (typeof geometry.indices === 'undefined') { - GeometryPipeline.indexLines(geometry); - } + } else if (geometry.primitiveType === PrimitiveType.LINES) { wrapLongitudeLines(geometry); } diff --git a/Source/Scene/Primitive.js b/Source/Scene/Primitive.js index 73e162a70053..b440e30fb433 100644 --- a/Source/Scene/Primitive.js +++ b/Source/Scene/Primitive.js @@ -306,17 +306,7 @@ define([ // PERFORMANCE_IDEA: Move pipeline to a web-worker. function geometryPipeline(primitive, instances, context, projection) { - // Copy instances first since most pipeline operations modify the geometry and instance in-place. var length = instances.length; - var insts = new Array(length); - for (var i = 0; i < length; ++i) { - insts[i] = instances[i].clone(); - } - - // Unify to world coordinates before combining. If there is only one geometry or all - // geometries are in the same (non-world) coordinate system, only combine if the user requested it. - transformToWorldCoordinates(primitive, insts); - var primitiveType = instances[0].geometry.primitiveType; for (var j = 1; j < length; ++j) { if (instances[j].geometry.primitiveType !== primitiveType) { @@ -324,6 +314,15 @@ define([ } } + // Copy instances first since most pipeline operations modify the geometry and instance in-place. + var insts = new Array(length); + for (var i = 0; i < length; ++i) { + insts[i] = instances[i].clone(); + } + + // Unify to world coordinates before combining. + transformToWorldCoordinates(primitive, insts); + // Clip to IDL if (primitive._allowColumbusView) { for (var k = 0; k < length; ++k) { @@ -439,96 +438,6 @@ define([ } - function updateBoundingSpheres(primitive, boundingSphere, projection) { - primitive._boundingSphere = boundingSphere; - - if (!primitive._allowColumbusView || typeof boundingSphere === 'undefined') { - return; - } - - var ellipsoid = projection.getEllipsoid(); - var center = boundingSphere.center; - var radius = boundingSphere.radius; - - var normal = ellipsoid.geodeticSurfaceNormal(center); - var east = Cartesian3.cross(Cartesian3.UNIT_Z, normal); - Cartesian3.normalize(east, east); - var north = Cartesian3.cross(normal, east); - Cartesian3.normalize(north, north); - - Cartesian3.multiplyByScalar(normal, radius, normal); - Cartesian3.multiplyByScalar(north, radius, north); - Cartesian3.multiplyByScalar(east, radius, east); - - var south = Cartesian3.negate(north); - var west = Cartesian3.negate(east); - - var positions = new Array(8); - - // top NE corner - var corner = positions[0] = new Cartesian3(); - Cartesian3.add(normal, north, corner); - Cartesian3.add(corner, east, corner); - - // top NW corner - corner = positions[1] = new Cartesian3(); - Cartesian3.add(normal, north, corner); - Cartesian3.add(corner, west, corner); - - // top SW corner - corner = positions[2] = new Cartesian3(); - Cartesian3.add(normal, south, corner); - Cartesian3.add(corner, west, corner); - - // top SE corner - corner = positions[3] = new Cartesian3(); - Cartesian3.add(normal, south, corner); - Cartesian3.add(corner, east, corner); - - Cartesian3.negate(normal, normal); - - // bottom NE corner - corner = positions[4] = new Cartesian3(); - Cartesian3.add(normal, north, corner); - Cartesian3.add(corner, east, corner); - - // bottom NW corner - corner = positions[5] = new Cartesian3(); - Cartesian3.add(normal, north, corner); - Cartesian3.add(corner, west, corner); - - // bottom SW corner - corner = positions[6] = new Cartesian3(); - Cartesian3.add(normal, south, corner); - Cartesian3.add(corner, west, corner); - - // bottom SE corner - corner = positions[7] = new Cartesian3(); - Cartesian3.add(normal, south, corner); - Cartesian3.add(corner, east, corner); - - var length = positions.length; - for (var i = 0; i < length; ++i) { - var position = positions[i]; - Cartesian3.add(center, position, position); - var cartographic = ellipsoid.cartesianToCartographic(position); - projection.project(cartographic, position); - } - - boundingSphere = BoundingSphere.fromPoints(positions); - - // swizzle center components - center = boundingSphere.center; - var x = center.x; - var y = center.y; - var z = center.z; - center.x = z; - center.y = x; - center.z = y; - - primitive._boundingSphere2D = boundingSphere; - } - /** * @private */ @@ -567,7 +476,11 @@ define([ } this._attributeIndices = GeometryPipeline.createAttributeIndices(geometries[0]); - updateBoundingSpheres(this, geometries[0].boundingSphere, projection); + + this._boundingSphere = geometries[0].boundingSphere; + if (this._allowColumbusView && typeof this._boundingSphere !== 'undefined') { + this._boundingSphere2D = BoundingSphere.projectTo2D(this._boundingSphere, projection); + } var va = []; for (i = 0; i < length; ++i) {