From 2921f4b1f4e6a9dc0fe5b58c068dda1c30700ec3 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 12 Dec 2014 16:25:24 -0500 Subject: [PATCH 1/7] Improved extruded polygon performance and slightly improve combining geometries. Also reduce memory allocations. --- Source/Core/GeometryPipeline.js | 88 +++++++++++++++-------------- Source/Core/PolygonGeometry.js | 99 +++++++++++++++++++++------------ 2 files changed, 111 insertions(+), 76 deletions(-) diff --git a/Source/Core/GeometryPipeline.js b/Source/Core/GeometryPipeline.js index 53d31294f60f..15dc5f108eee 100644 --- a/Source/Core/GeometryPipeline.js +++ b/Source/Core/GeometryPipeline.js @@ -877,6 +877,11 @@ define([ } var tempScratch = new Cartesian3(); + var centerScratch = new Cartesian3(); + var geometryScratch = new Geometry({ + attributes : {}, + primitiveType : PrimitiveType.POINTS + }); function combineGeometries(instances, propertyName) { var length = instances.length; @@ -927,41 +932,10 @@ define([ } } - // Combine index lists - var indices; - - if (haveIndices) { - var numberOfIndices = 0; - for (i = 0; i < length; ++i) { - numberOfIndices += instances[i][propertyName].indices.length; - } - - var numberOfVertices = Geometry.computeNumberOfVertices(new Geometry({ - attributes : attributes, - primitiveType : PrimitiveType.POINTS - })); - var destIndices = IndexDatatype.createTypedArray(numberOfVertices, numberOfIndices); - - var destOffset = 0; - var offset = 0; - - for (i = 0; i < length; ++i) { - var sourceIndices = instances[i][propertyName].indices; - var sourceIndicesLen = sourceIndices.length; - - for (k = 0; k < sourceIndicesLen; ++k) { - destIndices[destOffset++] = offset + sourceIndices[k]; - } - - offset += Geometry.computeNumberOfVertices(instances[i][propertyName]); - } - - indices = destIndices; - } - - // Create bounding sphere that includes all instances - var center = new Cartesian3(); + // Create bounding sphere that includes all instances and combine index lists + var center = centerScratch; var radius = 0.0; + var numberOfIndices = 0; var bs; for (i = 0; i < length; ++i) { @@ -969,28 +943,60 @@ define([ if (!defined(bs)) { // If any geometries have an undefined bounding sphere, then so does the combined geometry center = undefined; - break; } - Cartesian3.add(bs.center, center, center); + if (defined(center)) { + Cartesian3.add(bs.center, center, center); + } + + if (haveIndices) { + numberOfIndices += instances[i][propertyName].indices.length; + } + } + + var numberOfVertices; + var destIndices; + var destOffset = 0; + var offset = 0; + + if (haveIndices) { + var geometry = geometryScratch; + geometry.attributes = attributes; + numberOfVertices = Geometry.computeNumberOfVertices(geometry); + destIndices = IndexDatatype.createTypedArray(numberOfVertices, numberOfIndices); } if (defined(center)) { Cartesian3.divideByScalar(center, length, center); + } + if (defined(center) || haveIndices) { for (i = 0; i < length; ++i) { - bs = instances[i][propertyName].boundingSphere; - var tempRadius = Cartesian3.magnitude(Cartesian3.subtract(bs.center, center, tempScratch)) + bs.radius; + if (defined(center)) { + bs = instances[i][propertyName].boundingSphere; + var tempRadius = Cartesian3.magnitude(Cartesian3.subtract(bs.center, center, tempScratch)) + bs.radius; + + if (tempRadius > radius) { + radius = tempRadius; + } + } + + if (haveIndices) { + var sourceIndices = instances[i][propertyName].indices; + var sourceIndicesLen = sourceIndices.length; + + for (k = 0; k < sourceIndicesLen; ++k) { + destIndices[destOffset++] = offset + sourceIndices[k]; + } - if (tempRadius > radius) { - radius = tempRadius; + offset += Geometry.computeNumberOfVertices(instances[i][propertyName]); } } } return new Geometry({ attributes : attributes, - indices : indices, + indices : haveIndices ? destIndices : undefined, primitiveType : primitiveType, boundingSphere : (defined(center)) ? new BoundingSphere(center, radius) : undefined }); diff --git a/Source/Core/PolygonGeometry.js b/Source/Core/PolygonGeometry.js index 19a2376df389..f1170447cd14 100644 --- a/Source/Core/PolygonGeometry.js +++ b/Source/Core/PolygonGeometry.js @@ -329,51 +329,78 @@ define([ return geometry; } + var computeWallIndicesSubdivided = []; + function computeWallIndices(positions, ellipsoid, granularity, perPositionHeight){ - var edgePositions = []; - var subdividedEdge; - var edgeIndex; - var UL, UR, LL, LR; + var edgePositions; var i; - - var length = positions.length; var p1; var p2; + + var length = positions.length; + var index = 0; + if (!perPositionHeight) { var radius = ellipsoid.maximumRadius; var minDistance = 2.0 * radius * Math.sin(granularity * 0.5); + var numVertices = 0; + for (i = 0; i < length; i++) { + numVertices += PolygonGeometryLibrary.subdivideLineCount(positions[i], positions[(i + 1) % length], minDistance); + } + + var topEdgeLength = (numVertices + length) * 3; + edgePositions = new Array(topEdgeLength * 2); for (i = 0; i < length; i++) { p1 = positions[i]; p2 = positions[(i + 1) % length]; - subdividedEdge = PolygonGeometryLibrary.subdivideLine(p1, p2, minDistance); - subdividedEdge.push(p2.x, p2.y, p2.z); - edgePositions = edgePositions.concat(subdividedEdge); + + var tempPositions = PolygonGeometryLibrary.subdivideLine(p1, p2, minDistance, computeWallIndicesSubdivided); + var tempPositionsLength = tempPositions.length; + for (var j = 0; j < tempPositionsLength; ++j, ++index) { + edgePositions[index] = tempPositions[j]; + edgePositions[index + topEdgeLength] = tempPositions[j]; + } + + edgePositions[index] = p2.x; + edgePositions[index + topEdgeLength] = p2.x; + ++index; + + edgePositions[index] = p2.y; + edgePositions[index + topEdgeLength] = p2.y; + ++index; + + edgePositions[index] = p2.z; + edgePositions[index + topEdgeLength] = p2.z; + ++index; } } else { + edgePositions = []; for (i = 0; i < length; i++) { p1 = positions[i]; p2 = positions[(i + 1) % length]; edgePositions.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z); } + edgePositions = edgePositions.concat(edgePositions); } - edgePositions = edgePositions.concat(edgePositions); length = edgePositions.length; var indices = IndexDatatype.createTypedArray(length / 3, length - positions.length * 6); - edgeIndex = 0; + var edgeIndex = 0; length /= 6; for (i = 0; i < length; i++) { - UL = i; - UR = UL + 1; + var UL = i; + var UR = UL + 1; + var LL = UL + length; + var LR = LL + 1; + p1 = Cartesian3.fromArray(edgePositions, UL * 3, p1Scratch); p2 = Cartesian3.fromArray(edgePositions, UR * 3, p2Scratch); if (Cartesian3.equalsEpsilon(p1, p2, CesiumMath.EPSILON6)) { continue; } - LL = UL + length; - LR = LL + 1; + indices[edgeIndex++] = UL; indices[edgeIndex++] = LL; indices[edgeIndex++] = UR; @@ -399,15 +426,20 @@ define([ function createGeometryFromPositionsExtruded(ellipsoid, positions, granularity, hierarchy, perPositionHeight) { var topGeo = createGeometryFromPositions(ellipsoid, positions, granularity, perPositionHeight).geometry; + var edgePoints = topGeo.attributes.position.values; var indices = topGeo.indices; + var topBottomPositions = edgePoints.concat(edgePoints); var numPositions = topBottomPositions.length / 3; + var newIndices = IndexDatatype.createTypedArray(numPositions, indices.length * 2); newIndices.set(indices); var ilength = indices.length; + var i; var length = numPositions / 2; + for (i = 0; i < ilength; i += 3) { var i0 = newIndices[i] + length; var i1 = newIndices[i + 1] + length; @@ -417,6 +449,7 @@ define([ newIndices[i + 1 + ilength] = i1; newIndices[i + 2 + ilength] = i0; } + var topAndBottomGeo = new Geometry({ attributes : new GeometryAttributes({ position : new GeometryAttribute({ @@ -432,10 +465,10 @@ define([ var geos = { topAndBottom : new GeometryInstance({ geometry : topAndBottomGeo - }) + }), + walls : [] }; - geos.walls = []; var outerRing = hierarchy.outerRing; var tangentPlane = EllipsoidTangentPlane.fromPoints(outerRing, ellipsoid); var positions2D = tangentPlane.projectPointsOntoPlane(outerRing, createGeometryFromPositionsExtrudedPositions); @@ -732,29 +765,25 @@ define([ if (extrude) { for (i = 0; i < polygons.length; i++) { geometry = createGeometryFromPositionsExtruded(ellipsoid, polygons[i], granularity, polygonHierarchy[i], perPositionHeight); - if (defined(geometry)) { - topAndBottom = geometry.topAndBottom; - topAndBottom.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight); - topAndBottom.geometry = computeAttributes(vertexFormat, topAndBottom.geometry, outerPositions, ellipsoid, stRotation, true, false); - geometries.push(topAndBottom); - - walls = geometry.walls; - for ( var k = 0; k < walls.length; k++) { - var wall = walls[k]; - wall.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(wall.geometry, height, extrudedHeight, ellipsoid, perPositionHeight); - wall.geometry = computeAttributes(vertexFormat, wall.geometry, outerPositions, ellipsoid, stRotation, true, true); - geometries.push(wall); - } + topAndBottom = geometry.topAndBottom; + topAndBottom.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight); + topAndBottom.geometry = computeAttributes(vertexFormat, topAndBottom.geometry, outerPositions, ellipsoid, stRotation, true, false); + geometries.push(topAndBottom); + + walls = geometry.walls; + for ( var k = 0; k < walls.length; k++) { + var wall = walls[k]; + wall.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(wall.geometry, height, extrudedHeight, ellipsoid, perPositionHeight); + wall.geometry = computeAttributes(vertexFormat, wall.geometry, outerPositions, ellipsoid, stRotation, true, true); + geometries.push(wall); } } } else { for (i = 0; i < polygons.length; i++) { geometry = createGeometryFromPositions(ellipsoid, polygons[i], granularity, perPositionHeight); - if (defined(geometry)) { - geometry.geometry = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry, height, ellipsoid, !perPositionHeight); - geometry.geometry = computeAttributes(vertexFormat, geometry.geometry, outerPositions, ellipsoid, stRotation, false, false); - geometries.push(geometry); - } + geometry.geometry = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry, height, ellipsoid, !perPositionHeight); + geometry.geometry = computeAttributes(vertexFormat, geometry.geometry, outerPositions, ellipsoid, stRotation, false, false); + geometries.push(geometry); } } From c75966d6326f11766305328877b9c426f9976ab6 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 12 Dec 2014 17:55:02 -0500 Subject: [PATCH 2/7] More extruded polygon optimizations. --- Source/Core/PolygonGeometry.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Source/Core/PolygonGeometry.js b/Source/Core/PolygonGeometry.js index f1170447cd14..26760846ba9e 100644 --- a/Source/Core/PolygonGeometry.js +++ b/Source/Core/PolygonGeometry.js @@ -333,6 +333,7 @@ define([ function computeWallIndices(positions, ellipsoid, granularity, perPositionHeight){ var edgePositions; + var topEdgeLength; var i; var p1; var p2; @@ -349,7 +350,7 @@ define([ numVertices += PolygonGeometryLibrary.subdivideLineCount(positions[i], positions[(i + 1) % length], minDistance); } - var topEdgeLength = (numVertices + length) * 3; + topEdgeLength = (numVertices + length) * 3; edgePositions = new Array(topEdgeLength * 2); for (i = 0; i < length; i++) { p1 = positions[i]; @@ -375,13 +376,24 @@ define([ ++index; } } else { - edgePositions = []; + topEdgeLength = length * 3 * 2; + edgePositions = new Array(topEdgeLength * 2); for (i = 0; i < length; i++) { p1 = positions[i]; p2 = positions[(i + 1) % length]; - edgePositions.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z); + edgePositions[index] = edgePositions[index + topEdgeLength] = p1.x; + ++index; + edgePositions[index] = edgePositions[index + topEdgeLength] = p1.y; + ++index; + edgePositions[index] = edgePositions[index + topEdgeLength] = p1.z; + ++index; + edgePositions[index] = edgePositions[index + topEdgeLength] = p2.x; + ++index; + edgePositions[index] = edgePositions[index + topEdgeLength] = p2.y; + ++index; + edgePositions[index] = edgePositions[index + topEdgeLength] = p2.z; + ++index; } - edgePositions = edgePositions.concat(edgePositions); } length = edgePositions.length; From 99dca29e7751700c329f1caf78d3863b98ef10b2 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 15 Dec 2014 16:53:05 -0500 Subject: [PATCH 3/7] Revert GeometryPipeline changes and slightly reduce memory allocations. --- Source/Core/GeometryPipeline.js | 90 ++++++++++----------- Source/Core/IntersectionTests.js | 10 +-- Source/Scene/Globe.js | 17 +++- Source/Scene/PolylineCollection.js | 6 +- Source/Scene/ScreenSpaceCameraController.js | 8 +- 5 files changed, 72 insertions(+), 59 deletions(-) diff --git a/Source/Core/GeometryPipeline.js b/Source/Core/GeometryPipeline.js index 15dc5f108eee..4ddc14d3f65c 100644 --- a/Source/Core/GeometryPipeline.js +++ b/Source/Core/GeometryPipeline.js @@ -877,11 +877,6 @@ define([ } var tempScratch = new Cartesian3(); - var centerScratch = new Cartesian3(); - var geometryScratch = new Geometry({ - attributes : {}, - primitiveType : PrimitiveType.POINTS - }); function combineGeometries(instances, propertyName) { var length = instances.length; @@ -932,10 +927,41 @@ define([ } } - // Create bounding sphere that includes all instances and combine index lists - var center = centerScratch; + // Combine index lists + var indices; + + if (haveIndices) { + var numberOfIndices = 0; + for (i = 0; i < length; ++i) { + numberOfIndices += instances[i][propertyName].indices.length; + } + + var numberOfVertices = Geometry.computeNumberOfVertices(new Geometry({ + attributes : attributes, + primitiveType : PrimitiveType.POINTS + })); + var destIndices = IndexDatatype.createTypedArray(numberOfVertices, numberOfIndices); + + var destOffset = 0; + var offset = 0; + + for (i = 0; i < length; ++i) { + var sourceIndices = instances[i][propertyName].indices; + var sourceIndicesLen = sourceIndices.length; + + for (k = 0; k < sourceIndicesLen; ++k) { + destIndices[destOffset++] = offset + sourceIndices[k]; + } + + offset += Geometry.computeNumberOfVertices(instances[i][propertyName]); + } + + indices = destIndices; + } + + // Create bounding sphere that includes all instances + var center = new Cartesian3(); var radius = 0.0; - var numberOfIndices = 0; var bs; for (i = 0; i < length; ++i) { @@ -943,60 +969,28 @@ define([ if (!defined(bs)) { // If any geometries have an undefined bounding sphere, then so does the combined geometry center = undefined; + break; } - if (defined(center)) { - Cartesian3.add(bs.center, center, center); - } - - if (haveIndices) { - numberOfIndices += instances[i][propertyName].indices.length; - } - } - - var numberOfVertices; - var destIndices; - var destOffset = 0; - var offset = 0; - - if (haveIndices) { - var geometry = geometryScratch; - geometry.attributes = attributes; - numberOfVertices = Geometry.computeNumberOfVertices(geometry); - destIndices = IndexDatatype.createTypedArray(numberOfVertices, numberOfIndices); + Cartesian3.add(bs.center, center, center); } if (defined(center)) { Cartesian3.divideByScalar(center, length, center); - } - if (defined(center) || haveIndices) { for (i = 0; i < length; ++i) { - if (defined(center)) { - bs = instances[i][propertyName].boundingSphere; - var tempRadius = Cartesian3.magnitude(Cartesian3.subtract(bs.center, center, tempScratch)) + bs.radius; - - if (tempRadius > radius) { - radius = tempRadius; - } - } - - if (haveIndices) { - var sourceIndices = instances[i][propertyName].indices; - var sourceIndicesLen = sourceIndices.length; - - for (k = 0; k < sourceIndicesLen; ++k) { - destIndices[destOffset++] = offset + sourceIndices[k]; - } + bs = instances[i][propertyName].boundingSphere; + var tempRadius = Cartesian3.magnitude(Cartesian3.subtract(bs.center, center, tempScratch)) + bs.radius; - offset += Geometry.computeNumberOfVertices(instances[i][propertyName]); + if (tempRadius > radius) { + radius = tempRadius; } } } return new Geometry({ attributes : attributes, - indices : haveIndices ? destIndices : undefined, + indices : indices, primitiveType : primitiveType, boundingSphere : (defined(center)) ? new BoundingSphere(center, radius) : undefined }); @@ -2547,4 +2541,4 @@ define([ }; return GeometryPipeline; -}); +}); \ No newline at end of file diff --git a/Source/Core/IntersectionTests.js b/Source/Core/IntersectionTests.js index fbf4bb761f26..e45b261b18e2 100644 --- a/Source/Core/IntersectionTests.js +++ b/Source/Core/IntersectionTests.js @@ -573,6 +573,7 @@ define([ var sScratch = new Cartesian3(); var closestScratch = new Cartesian3(); var surfPointScratch = new Cartographic(); + /** * Provides the point along the ray which is nearest to the ellipsoid. * @@ -593,8 +594,7 @@ define([ var position = ray.origin; var direction = ray.direction; - var normal = ellipsoid.geodeticSurfaceNormal(position); - + var normal = ellipsoid.geodeticSurfaceNormal(position, firstAxisScratch); if (Cartesian3.dot(direction, normal) >= 0.0) { // The location provided is the closest point in altitude return position; } @@ -602,10 +602,10 @@ define([ var intersects = defined(this.rayEllipsoid(ray, ellipsoid)); // Compute the scaled direction vector. - var f = ellipsoid.transformPositionToScaledSpace(direction); + var f = ellipsoid.transformPositionToScaledSpace(direction, firstAxisScratch); // Constructs a basis from the unit scaled direction vector. Construct its rotation and transpose. - var firstAxis = Cartesian3.normalize(f, firstAxisScratch); + var firstAxis = Cartesian3.normalize(f, f); var reference = Cartesian3.mostOrthogonalAxis(f, referenceScratch); var secondAxis = Cartesian3.normalize(Cartesian3.cross(reference, firstAxis, secondAxisScratch), secondAxisScratch); var thirdAxis = Cartesian3.normalize(Cartesian3.cross(firstAxis, secondAxis, thirdAxisScratch), thirdAxisScratch); @@ -667,7 +667,7 @@ define([ altitude = Cartesian3.magnitude(Cartesian3.subtract(closest, position, referenceScratch)) * Math.sqrt(1.0 - maximumValue * maximumValue); altitude = intersects ? -altitude : altitude; surfacePoint.height = altitude; - return ellipsoid.cartographicToCartesian(surfacePoint); + return ellipsoid.cartographicToCartesian(surfacePoint, new Cartesian3()); } return undefined; diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js index 26c87ca60ac2..4ce3394a5d02 100644 --- a/Source/Scene/Globe.js +++ b/Source/Scene/Globe.js @@ -540,12 +540,23 @@ define([ var rightScratch = new Cartesian3(); var upScratch = new Cartesian3(); var negativeZ = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()); + var cartographicScratch = new Cartographic(0.0, 0.0); + var pt1Scratch = new Cartesian3(); + var pt2Scratch = new Cartesian3(); + function computePoleQuad(globe, frameState, maxLat, maxGivenLat, viewProjMatrix, viewportTransformation) { - var pt1 = globe._ellipsoid.cartographicToCartesian(new Cartographic(0.0, maxGivenLat)); - var pt2 = globe._ellipsoid.cartographicToCartesian(new Cartographic(Math.PI, maxGivenLat)); + cartographicScratch.longitude = 0.0; + cartographicScratch.latitude = maxGivenLat; + var pt1 = globe._ellipsoid.cartographicToCartesian(cartographicScratch, pt1Scratch); + + cartographicScratch.longitude = Math.PI; + var pt2 = globe._ellipsoid.cartographicToCartesian(cartographicScratch, pt2Scratch); + var radius = Cartesian3.magnitude(Cartesian3.subtract(pt1, pt2, rightScratch), rightScratch) * 0.5; - var center = globe._ellipsoid.cartographicToCartesian(new Cartographic(0.0, maxLat)); + cartographicScratch.longitude = 0.0; + cartographicScratch.latitude = maxLat; + var center = globe._ellipsoid.cartographicToCartesian(cartographicScratch, pt1Scratch); var right; var dir = frameState.camera.direction; diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index 08224a3b3686..65c30b3ca70f 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -3,6 +3,7 @@ define([ '../Core/BoundingSphere', '../Core/Cartesian3', '../Core/Cartesian4', + '../Core/Cartographic', '../Core/Color', '../Core/ComponentDatatype', '../Core/defaultValue', @@ -30,6 +31,7 @@ define([ BoundingSphere, Cartesian3, Cartesian4, + Cartographic, Color, ComponentDatatype, defaultValue, @@ -1344,6 +1346,8 @@ define([ }; var scratchLengths = new Array(1); var pscratch = new Cartesian3(); + var scratchCartographic = new Cartographic(); + PolylineBucket.prototype.getSegments = function(polyline, projection) { var positions = polyline._actualPositions; @@ -1368,7 +1372,7 @@ define([ for ( var n = 0; n < length; ++n) { position = positions[n]; p = Matrix4.multiplyByPoint(modelMatrix, position, p); - newPositions.push(projection.project(ellipsoid.cartesianToCartographic(p))); + newPositions.push(projection.project(ellipsoid.cartesianToCartographic(p, scratchCartographic))); } if (newPositions.length > 0) { diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js index 9e107f9759da..cf91f0d74fa8 100644 --- a/Source/Scene/ScreenSpaceCameraController.js +++ b/Source/Scene/ScreenSpaceCameraController.js @@ -1183,6 +1183,8 @@ define([ } var zoom3DUnitPosition = new Cartesian3(); + var zoom3DCartographic = new Cartographic(); + function zoom3D(controller, startPosition, movement) { if (defined(movement.distance)) { movement = movement.distance; @@ -1199,7 +1201,7 @@ define([ var ray = camera.getPickRay(windowPosition, zoomCVWindowRay); var intersection; - var height = ellipsoid.cartesianToCartographic(camera.position).height; + var height = ellipsoid.cartesianToCartographic(camera.position, zoom3DCartographic).height; if (defined(controller._globe) && height < controller.minimumPickingTerrainHeight) { intersection = controller._globe.pick(ray, scene, zoomCVIntersection); } @@ -1262,12 +1264,14 @@ define([ } } + var tilt3DOnEllipsoidCartographic = new Cartographic(); + function tilt3DOnEllipsoid(controller, startPosition, movement) { var ellipsoid = controller._ellipsoid; var scene = controller._scene; var camera = scene.camera; var minHeight = controller.minimumZoomDistance * 0.25; - var height = ellipsoid.cartesianToCartographic(camera.positionWC).height; + var height = ellipsoid.cartesianToCartographic(camera.positionWC, tilt3DOnEllipsoidCartographic).height; if (height - minHeight - 1.0 < CesiumMath.EPSILON3 && movement.endPosition.y - movement.startPosition.y < 0) { return; From 2e30db6d26db779fbf221c42938546ace092787b Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 16 Dec 2014 17:05:51 -0500 Subject: [PATCH 4/7] Reduce garbage collection in WallGeometryLibrary. --- Apps/Sandcastle/gallery/Wall.html | 1 - Source/Core/WallGeometryLibrary.js | 130 ++++++++++++++++------------- 2 files changed, 73 insertions(+), 58 deletions(-) diff --git a/Apps/Sandcastle/gallery/Wall.html b/Apps/Sandcastle/gallery/Wall.html index d4138fca32bf..d00207d510ad 100644 --- a/Apps/Sandcastle/gallery/Wall.html +++ b/Apps/Sandcastle/gallery/Wall.html @@ -97,7 +97,6 @@ maximumHeights: maximumHeights, minimumHeights: minimumHeights, vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT - }), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE) diff --git a/Source/Core/WallGeometryLibrary.js b/Source/Core/WallGeometryLibrary.js index 11536015012f..62b08b8782e5 100644 --- a/Source/Core/WallGeometryLibrary.js +++ b/Source/Core/WallGeometryLibrary.js @@ -31,51 +31,63 @@ define([ var scratchCartographic1 = new Cartographic(); var scratchCartographic2 = new Cartographic(); function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { - var hasBottomHeights = (defined(bottomHeights)); - var hasTopHeights = (defined(topHeights)); - var cleanedPositions = []; - var cleanedTopHeights = []; - var cleanedBottomHeights = []; - var length = positions.length; if (length < 2) { return { positions: positions }; } + var hasBottomHeights = (defined(bottomHeights)); + var hasTopHeights = (defined(topHeights)); + + var cleanedPositions = new Array(length); + var cleanedTopHeights = new Array(length); + var cleanedBottomHeights = new Array(length); + var v0 = positions[0]; - cleanedPositions.push(v0); + cleanedPositions[0] = v0; + var c0 = ellipsoid.cartesianToCartographic(v0, scratchCartographic1); if (hasTopHeights) { c0.height = topHeights[0]; } - cleanedTopHeights.push(c0.height); + cleanedTopHeights[0] = c0.height; + if (hasBottomHeights) { - cleanedBottomHeights.push(bottomHeights[0]); + cleanedBottomHeights[0] = bottomHeights[0]; } else { - cleanedBottomHeights.push(0); + cleanedBottomHeights[0] = 0.0; } + var index = 1; for (var i = 1; i < length; ++i) { var v1 = positions[i]; var c1 = ellipsoid.cartesianToCartographic(v1, scratchCartographic2); if (hasTopHeights) { c1.height = topHeights[i]; } + if (!latLonEquals(c0, c1)) { - cleanedPositions.push(v1); // Shallow copy! - cleanedTopHeights.push(c1.height); + cleanedPositions[index] = v1; // Shallow copy! + cleanedTopHeights[index] = c1.height; + if (hasBottomHeights) { - cleanedBottomHeights.push(bottomHeights[i]); + cleanedBottomHeights[index] = bottomHeights[i]; } else { - cleanedBottomHeights.push(0); + cleanedBottomHeights[index] = 0.0; } + + ++index; } else if (c0.height < c1.height) { - cleanedTopHeights[cleanedTopHeights.length-1] = c1.height; + cleanedTopHeights[index - 1] = c1.height; } Cartographic.clone(c1, c0); } + cleanedPositions.length = index; + cleanedTopHeights.length = index; + cleanedBottomHeights.length = index; + return { positions: cleanedPositions, topHeights: cleanedTopHeights, @@ -83,6 +95,15 @@ define([ }; } + var positionsArrayScratch = new Array(2); + var heightsArrayScratch = new Array(2); + var generateArcOptionsScratch = { + positions : undefined, + height : undefined, + granularity : undefined, + ellipsoid : undefined + }; + /** * @private */ @@ -111,64 +132,59 @@ define([ } } - var i; var length = wallPositions.length; var topPositions; var bottomPositions; - var p0; - var p1; + var generateArcOptions; + if (duplicateCorners) { - var l = 0; - for (i = 0; i < length-1; i++) { - p0 = wallPositions[i]; - p1 = wallPositions[i+1]; + var count = 0; + var i; - l += PolylinePipeline.numberOfPoints(p0, p1, granularity); - l++; + for (i = 0; i < length - 1; i++) { + count += PolylinePipeline.numberOfPoints(wallPositions[i], wallPositions[i+1], granularity) + 1; } - topPositions = new Float64Array(l*3); - bottomPositions = new Float64Array(l*3); + topPositions = new Float64Array(count * 3); + bottomPositions = new Float64Array(count * 3); + + var generateArcPositions = positionsArrayScratch; + var generateArcHeights = heightsArrayScratch; + generateArcOptions = generateArcOptionsScratch; + generateArcOptions.positions = generateArcPositions; + generateArcOptions.height = generateArcHeights; + generateArcOptions.granularity = granularity; + generateArcOptions.ellipsoid = ellipsoid; var offset = 0; - for (i = 0; i < length-1; i++) { - p0 = wallPositions[i]; - p1 = wallPositions[i + 1]; - var h0 = maximumHeights[i]; - var h1 = maximumHeights[i + 1]; - var pos = PolylinePipeline.generateArc({ - positions: [p0, p1], - height: [h0, h1], - granularity: granularity, - ellipsoid: ellipsoid - }); + for (i = 0; i < length - 1; i++) { + generateArcPositions[0] = wallPositions[i]; + generateArcPositions[1] = wallPositions[i + 1]; + + generateArcHeights[0] = maximumHeights[i]; + generateArcHeights[1] = maximumHeights[i + 1]; + + var pos = PolylinePipeline.generateArc(generateArcOptions); topPositions.set(pos, offset); + generateArcHeights[0] = minimumHeights[i]; + generateArcHeights[1] = minimumHeights[i + 1]; - h0 = minimumHeights[i]; - h1 = minimumHeights[i + 1]; + bottomPositions.set(PolylinePipeline.generateArc(generateArcOptions), offset); - bottomPositions.set(PolylinePipeline.generateArc({ - positions: [p0, p1], - height: [h0, h1], - granularity: granularity, - ellipsoid: ellipsoid - }), offset); offset += pos.length; } } else { - topPositions = new Float64Array(PolylinePipeline.generateArc({ - positions: wallPositions, - height: maximumHeights, - granularity: granularity, - ellipsoid: ellipsoid - })); - bottomPositions = new Float64Array(PolylinePipeline.generateArc({ - positions: wallPositions, - height: minimumHeights, - granularity: granularity, - ellipsoid: ellipsoid - })); + generateArcOptions = generateArcOptionsScratch; + generateArcOptions.positions = wallPositions; + generateArcOptions.granularity = granularity; + generateArcOptions.ellipsoid = ellipsoid; + + generateArcOptions.height = maximumHeights; + topPositions = new Float64Array(PolylinePipeline.generateArc(generateArcOptions)); + + generateArcOptions.height = minimumHeights; + bottomPositions = new Float64Array(PolylinePipeline.generateArc(generateArcOptions)); } return { From 925dc45a6ce234ce5a465b259b1965c653273684 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 16 Dec 2014 19:32:49 -0500 Subject: [PATCH 5/7] Minor performance improvement by removing inverse trig calls in a loop and remove more temporary object creation. --- Source/Core/Math.js | 23 +++++++--- Source/Core/PolygonGeometry.js | 3 +- Source/Core/PolygonOutlineGeometry.js | 4 +- Source/Core/PolygonPipeline.js | 2 +- Source/Core/PolylineGeometry.js | 12 ++--- Source/Core/PolylinePipeline.js | 63 +++++++++++++-------------- Source/Core/SimplePolylineGeometry.js | 14 +++--- Source/Core/WallGeometryLibrary.js | 16 +++---- 8 files changed, 73 insertions(+), 64 deletions(-) diff --git a/Source/Core/Math.js b/Source/Core/Math.js index 053353bc5dcd..b3dff7e61b28 100644 --- a/Source/Core/Math.js +++ b/Source/Core/Math.js @@ -679,7 +679,7 @@ define([ * @param {Number} value The value to constrain. * @param {Number} min The minimum value. * @param {Number} max The maximum value. - * @returns The value clamped so that min <= value <= max. + * @returns {Number} The value clamped so that min <= value <= max. */ CesiumMath.clamp = function(value, min, max) { //>>includeStart('debug', pragmas.debug); @@ -718,7 +718,7 @@ define([ * Generates a random number in the range of [0.0, 1.0) * using a Mersenne twister. * - * @returns A random number in the range of [0.0, 1.0). + * @returns {Number} A random number in the range of [0.0, 1.0). * * @see CesiumMath.setRandomNumberSeed * @see {@link http://en.wikipedia.org/wiki/Mersenne_twister|Mersenne twister on Wikipedia} @@ -731,8 +731,8 @@ define([ * Computes Math.acos(value), but first clamps value to the range [-1.0, 1.0] * so that the function will never return NaN. * - * @param value The value for which to compute acos. - * @returns {number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0, + * @param {Number} value The value for which to compute acos. + * @returns {Number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0, * whichever is closer, if the value is outside the range. */ CesiumMath.acosClamped = function(value) { @@ -743,13 +743,24 @@ define([ * Computes Math.asin(value), but first clamps value to the range [-1.0, 1.0] * so that the function will never return NaN. * - * @param value The value for which to compute asin. - * @returns {number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0, + * @param {Number} value The value for which to compute asin. + * @returns {Number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0, * whichever is closer, if the value is outside the range. */ CesiumMath.asinClamped = function(value) { return Math.asin(CesiumMath.clamp(value, -1.0, 1.0)); }; + /** + * Finds the chord length between two points given the circle's radius and the angle between the points. + * + * @param {Number} angle The angle between the two points. + * @param {Number} radius The radius of the circle. + * @returns {Number} The chord length. + */ + CesiumMath.chordLength = function(angle, radius) { + return 2.0 * radius * Math.sin(angle * 0.5); + }; + return CesiumMath; }); diff --git a/Source/Core/PolygonGeometry.js b/Source/Core/PolygonGeometry.js index 26760846ba9e..c672daca3c5b 100644 --- a/Source/Core/PolygonGeometry.js +++ b/Source/Core/PolygonGeometry.js @@ -342,8 +342,7 @@ define([ var index = 0; if (!perPositionHeight) { - var radius = ellipsoid.maximumRadius; - var minDistance = 2.0 * radius * Math.sin(granularity * 0.5); + var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius); var numVertices = 0; for (i = 0; i < length; i++) { diff --git a/Source/Core/PolygonOutlineGeometry.js b/Source/Core/PolygonOutlineGeometry.js index e19bcd174783..a229073d71a6 100644 --- a/Source/Core/PolygonOutlineGeometry.js +++ b/Source/Core/PolygonOutlineGeometry.js @@ -431,9 +431,7 @@ define([ var geometry; var geometries = []; - - var radius = ellipsoid.maximumRadius; - var minDistance = 2.0 * radius * Math.sin(granularity * 0.5); + var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius); if (extrude) { for (i = 0; i < polygons.length; i++) { diff --git a/Source/Core/PolygonPipeline.js b/Source/Core/PolygonPipeline.js index 9224410ebc80..070a346f5413 100644 --- a/Source/Core/PolygonPipeline.js +++ b/Source/Core/PolygonPipeline.js @@ -870,7 +870,7 @@ define([ var edges = {}; var radius = ellipsoid.maximumRadius; - var minDistance = 2.0 * radius * Math.sin(granularity * 0.5); + var minDistance = CesiumMath.chordLength(granularity, radius); var minDistanceSqrd = minDistance * minDistance; while (triangles.length > 0) { diff --git a/Source/Core/PolylineGeometry.js b/Source/Core/PolylineGeometry.js index bca9b1b27955..ef07a5332ada 100644 --- a/Source/Core/PolylineGeometry.js +++ b/Source/Core/PolylineGeometry.js @@ -37,8 +37,8 @@ define([ VertexFormat) { "use strict"; - function interpolateColors(p0, p1, color0, color1, granularity) { - var numPoints = PolylinePipeline.numberOfPoints(p0, p1, granularity); + function interpolateColors(p0, p1, color0, color1, minDistance) { + var numPoints = PolylinePipeline.numberOfPoints(p0, p1, minDistance); var colors = new Array(numPoints); var i; @@ -157,6 +157,8 @@ define([ var granularity = polylineGeometry._granularity; var ellipsoid = polylineGeometry._ellipsoid; + var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius); + var i; var j; var k; @@ -183,9 +185,9 @@ define([ if (perVertex && i < colors.length) { c1 = colors[i+1]; - newColors = newColors.concat(interpolateColors(p0, p1, c0, c1, granularity)); + newColors = newColors.concat(interpolateColors(p0, p1, c0, c1, minDistance)); } else { - var l = PolylinePipeline.numberOfPoints(p0, p1, granularity); + var l = PolylinePipeline.numberOfPoints(p0, p1, minDistance); for (j = 0; j < l; j++) { newColors.push(Color.clone(c0)); } @@ -197,7 +199,7 @@ define([ positions = PolylinePipeline.generateCartesianArc({ positions: positions, - granularity: granularity, + minDistance: minDistance, ellipsoid: ellipsoid, height: heights }); diff --git a/Source/Core/PolylinePipeline.js b/Source/Core/PolylinePipeline.js index f6e5dff5c556..0eecea11e090 100644 --- a/Source/Core/PolylinePipeline.js +++ b/Source/Core/PolylinePipeline.js @@ -32,9 +32,9 @@ define([ */ var PolylinePipeline = {}; - PolylinePipeline.numberOfPoints = function(p0, p1, granularity) { - var angleBetween = Cartesian3.angleBetween(p0, p1); - return Math.ceil(angleBetween / granularity); + PolylinePipeline.numberOfPoints = function(p0, p1, minDistance) { + var distance = Cartesian3.distance(p0, p1); + return Math.ceil(distance / minDistance); }; var cartoScratch = new Cartographic(); @@ -57,8 +57,12 @@ define([ var wrapLongitudeIntersection = new Cartesian3(); var wrapLongitudeOffset = new Cartesian3(); + var subdivideHeightsScratchArray = []; + function subdivideHeights(numPoints, h0, h1) { - var heights = new Array(numPoints); + var heights = subdivideHeightsScratchArray; + heights.length = numPoints; + var i; if (h0 === h1) { for (i = 0; i < numPoints; i++) { @@ -68,14 +72,13 @@ define([ } var dHeight = h1 - h0; - var heightPerVertex = dHeight / (numPoints); + var heightPerVertex = dHeight / numPoints; - for (i = 1; i < numPoints; i++) { + for (i = 0; i < numPoints; i++) { var h = h0 + i*heightPerVertex; heights[i] = h; } - heights[0] = h0; return heights; } @@ -85,13 +88,14 @@ define([ var scaleFirst = new Cartesian3(); var scaleLast = new Cartesian3(); var ellipsoidGeodesic = new EllipsoidGeodesic(); + //Returns subdivided line scaled to ellipsoid surface starting at p1 and ending at p2. //Result includes p1, but not include p2. This function is called for a sequence of line segments, //and this prevents duplication of end point. - function generateCartesianArc(p0, p1, granularity, ellipsoid, h0, h1, array, offset) { + function generateCartesianArc(p0, p1, minDistance, ellipsoid, h0, h1, array, offset) { var first = ellipsoid.scaleToGeodeticSurface(p0, scaleFirst); var last = ellipsoid.scaleToGeodeticSurface(p1, scaleLast); - var numPoints = PolylinePipeline.numberOfPoints(p0, p1, granularity); + var numPoints = PolylinePipeline.numberOfPoints(p0, p1, minDistance); var start = ellipsoid.cartesianToCartographic(first, carto1); var end = ellipsoid.cartesianToCartographic(last, carto2); var heights = subdivideHeights(numPoints, h0, h1); @@ -283,43 +287,38 @@ define([ var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84); var height = defaultValue(options.height, 0); - var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE); + var minDistance = options.minDistance; + if (!defined(minDistance)) { + var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE); + minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius); + } var length = positions.length; var numPoints = 0; var i; - var p0; - var p1; - for (i = 0; i < length-1; i++) { - p0 = positions[i]; - p1 = positions[i+1]; - numPoints += PolylinePipeline.numberOfPoints(p0, p1, granularity); + for (i = 0; i < length -1; i++) { + numPoints += PolylinePipeline.numberOfPoints(positions[i], positions[i+1], minDistance); } - numPoints++; - var arrayLength = numPoints * 3; + + var arrayLength = (numPoints + 1) * 3; var newPositions = new Array(arrayLength); var offset = 0; + var hasHeightArray = isArray(height); + for (i = 0; i < length - 1; i++) { - p0 = positions[i]; - p1 = positions[i + 1]; - - var h0; - var h1; - if (isArray(height)) { - h0 = height[i]; - h1 = height[i + 1]; - } else { - h0 = height; - h1 = height; - } + var p0 = positions[i]; + var p1 = positions[i + 1]; + + var h0 = hasHeightArray ? height[i] : height; + var h1 = hasHeightArray ? height[i + 1] : height; - offset = generateCartesianArc(p0, p1, granularity, ellipsoid, h0, h1, newPositions, offset); + offset = generateCartesianArc(p0, p1, minDistance, ellipsoid, h0, h1, newPositions, offset); } var lastPoint = positions[length - 1]; var carto = ellipsoid.cartesianToCartographic(lastPoint, carto1); - carto.height = isArray(height) ? height[length - 1] : height; + carto.height = hasHeightArray ? height[length - 1] : height; var cart = ellipsoid.cartographicToCartesian(carto, cartesian); Cartesian3.pack(cart, newPositions, arrayLength - 3); diff --git a/Source/Core/SimplePolylineGeometry.js b/Source/Core/SimplePolylineGeometry.js index 8e83c40e693c..c4dd90aac9b2 100644 --- a/Source/Core/SimplePolylineGeometry.js +++ b/Source/Core/SimplePolylineGeometry.js @@ -33,8 +33,8 @@ define([ PrimitiveType) { "use strict"; - function interpolateColors(p0, p1, color0, color1, granularity, array, offset) { - var numPoints = PolylinePipeline.numberOfPoints(p0, p1, granularity); + function interpolateColors(p0, p1, color0, color1, minDistance, array, offset) { + var numPoints = PolylinePipeline.numberOfPoints(p0, p1, minDistance); var i; var r0 = color0.red; @@ -147,6 +147,8 @@ define([ var granularity = simplePolylineGeometry._granularity; var ellipsoid = simplePolylineGeometry._ellipsoid; + var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius); + var perSegmentColors = defined(colors) && !perVertex; var i; @@ -169,7 +171,7 @@ define([ p0 = positions[i]; p1 = positions[i+1]; - l += PolylinePipeline.numberOfPoints(p0, p1, granularity); + l += PolylinePipeline.numberOfPoints(p0, p1, minDistance); l++; } @@ -186,7 +188,7 @@ define([ var pos = PolylinePipeline.generateArc({ positions : scratchArray1, - granularity : granularity, + minDistance : minDistance, ellipsoid: ellipsoid, height: scratchArray2 }); @@ -208,7 +210,7 @@ define([ } else { positionValues = new Float64Array(PolylinePipeline.generateArc({ positions: positions, - granularity: granularity, + minDistance: minDistance, ellipsoid: ellipsoid, height: heights })); @@ -221,7 +223,7 @@ define([ p1 = positions[i+1]; c0 = colors[i]; c1 = colors[i+1]; - offset = interpolateColors(p0, p1, c0, c1, granularity, colorValues, offset); + offset = interpolateColors(p0, p1, c0, c1, minDistance, colorValues, offset); } colorValues[offset++] = Color.floatToByte(c1.red); colorValues[offset++] = Color.floatToByte(c1.green); diff --git a/Source/Core/WallGeometryLibrary.js b/Source/Core/WallGeometryLibrary.js index 62b08b8782e5..e98408ded1bf 100644 --- a/Source/Core/WallGeometryLibrary.js +++ b/Source/Core/WallGeometryLibrary.js @@ -135,14 +135,19 @@ define([ var length = wallPositions.length; var topPositions; var bottomPositions; - var generateArcOptions; + + var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius); + + var generateArcOptions = generateArcOptionsScratch; + generateArcOptions.minDistance = minDistance; + generateArcOptions.ellipsoid = ellipsoid; if (duplicateCorners) { var count = 0; var i; for (i = 0; i < length - 1; i++) { - count += PolylinePipeline.numberOfPoints(wallPositions[i], wallPositions[i+1], granularity) + 1; + count += PolylinePipeline.numberOfPoints(wallPositions[i], wallPositions[i+1], minDistance) + 1; } topPositions = new Float64Array(count * 3); @@ -150,11 +155,8 @@ define([ var generateArcPositions = positionsArrayScratch; var generateArcHeights = heightsArrayScratch; - generateArcOptions = generateArcOptionsScratch; generateArcOptions.positions = generateArcPositions; generateArcOptions.height = generateArcHeights; - generateArcOptions.granularity = granularity; - generateArcOptions.ellipsoid = ellipsoid; var offset = 0; for (i = 0; i < length - 1; i++) { @@ -175,11 +177,7 @@ define([ offset += pos.length; } } else { - generateArcOptions = generateArcOptionsScratch; generateArcOptions.positions = wallPositions; - generateArcOptions.granularity = granularity; - generateArcOptions.ellipsoid = ellipsoid; - generateArcOptions.height = maximumHeights; topPositions = new Float64Array(PolylinePipeline.generateArc(generateArcOptions)); From 8604ba2706aee19825bd3bff0d3c90147e72e329 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 16 Dec 2014 19:46:48 -0500 Subject: [PATCH 6/7] Remove missing cartesian allocation that could be a scratch. --- Source/Core/WallGeometry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index a27d30fc3f64..b3626d02e8a7 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -246,7 +246,7 @@ define([ if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) { var nextPosition; - var nextTop = new Cartesian3(); + var nextTop = Cartesian3.clone(Cartesian3.ZERO, scratchCartesian3Position5); var groundPosition = ellipsoid.scaleToGeodeticSurface(Cartesian3.fromArray(topPositions, i3, scratchCartesian3Position2), scratchCartesian3Position2); if (i + 1 < length) { nextPosition = ellipsoid.scaleToGeodeticSurface(Cartesian3.fromArray(topPositions, i3 + 3, scratchCartesian3Position3), scratchCartesian3Position3); From d0b128c8c66a8d30478e785bfc9e91e0bc6e938e Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 17 Dec 2014 15:47:15 -0500 Subject: [PATCH 7/7] Updates from review. --- Source/Core/Math.js | 18 ++++++++++++++++++ Source/Core/PolylinePipeline.js | 2 ++ Specs/Core/MathSpec.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/Source/Core/Math.js b/Source/Core/Math.js index b3dff7e61b28..a123df193d25 100644 --- a/Source/Core/Math.js +++ b/Source/Core/Math.js @@ -736,6 +736,11 @@ define([ * whichever is closer, if the value is outside the range. */ CesiumMath.acosClamped = function(value) { + //>>includeStart('debug', pragmas.debug); + if (!defined(value)) { + throw new DeveloperError('value is required.'); + } + //>>includeEnd('debug'); return Math.acos(CesiumMath.clamp(value, -1.0, 1.0)); }; @@ -748,6 +753,11 @@ define([ * whichever is closer, if the value is outside the range. */ CesiumMath.asinClamped = function(value) { + //>>includeStart('debug', pragmas.debug); + if (!defined(value)) { + throw new DeveloperError('value is required.'); + } + //>>includeEnd('debug'); return Math.asin(CesiumMath.clamp(value, -1.0, 1.0)); }; @@ -759,6 +769,14 @@ define([ * @returns {Number} The chord length. */ CesiumMath.chordLength = function(angle, radius) { + //>>includeStart('debug', pragmas.debug); + if (!defined(angle)) { + throw new DeveloperError('angle is required.'); + } + if (!defined(radius)) { + throw new DeveloperError('radius is required.'); + } + //>>includeEnd('debug'); return 2.0 * radius * Math.sin(angle * 0.5); }; diff --git a/Source/Core/PolylinePipeline.js b/Source/Core/PolylinePipeline.js index 0eecea11e090..c0ed77868e6c 100644 --- a/Source/Core/PolylinePipeline.js +++ b/Source/Core/PolylinePipeline.js @@ -316,6 +316,8 @@ define([ offset = generateCartesianArc(p0, p1, minDistance, ellipsoid, h0, h1, newPositions, offset); } + subdivideHeightsScratchArray.length = 0; + var lastPoint = positions[length - 1]; var carto = ellipsoid.cartesianToCartographic(lastPoint, carto1); carto.height = hasHeightArray ? height[length - 1] : height; diff --git a/Specs/Core/MathSpec.js b/Specs/Core/MathSpec.js index 41b1838c63df..480a1d53c64d 100644 --- a/Specs/Core/MathSpec.js +++ b/Specs/Core/MathSpec.js @@ -350,6 +350,12 @@ defineSuite([ expect(CesiumMath.acosClamped(1.01)).toBe(Math.acos(1.0)); }); + it('acosClamped throws without value', function() { + expect(function() { + CesiumMath.acosClamped(); + }).toThrowDeveloperError(); + }); + it('asinClamped returns asin for normal values', function() { expect(CesiumMath.asinClamped(0.5)).toBe(Math.asin(0.5)); expect(CesiumMath.asinClamped(0.123)).toBe(Math.asin(0.123)); @@ -362,4 +368,30 @@ defineSuite([ expect(CesiumMath.asinClamped(-1.01)).toBe(Math.asin(-1.0)); expect(CesiumMath.asinClamped(1.01)).toBe(Math.asin(1.0)); }); + + it('asinClamped throws without value', function() { + expect(function() { + CesiumMath.asinClamped(); + }).toThrowDeveloperError(); + }); + + it('chordLength finds the chord length', function() { + expect(CesiumMath.chordLength(CesiumMath.PI_OVER_THREE, 1.0)).toEqualEpsilon(1.0, CesiumMath.EPSILON14); + expect(CesiumMath.chordLength(CesiumMath.PI_OVER_THREE, 5.0)).toEqualEpsilon(5.0, CesiumMath.EPSILON14); + expect(CesiumMath.chordLength(2.0 * CesiumMath.PI_OVER_THREE, 1.0)).toEqualEpsilon(Math.sqrt(3.0), CesiumMath.EPSILON14); + expect(CesiumMath.chordLength(2.0 * CesiumMath.PI_OVER_THREE, 5.0)).toEqualEpsilon(5.0 * Math.sqrt(3.0), CesiumMath.EPSILON14); + expect(CesiumMath.chordLength(CesiumMath.PI, 10.0)).toEqualEpsilon(2.0 * 10.0, CesiumMath.EPSILON14); + }); + + it('chordLength throws without angle', function() { + expect(function() { + CesiumMath.chordLength(undefined, 1.0); + }).toThrowDeveloperError(); + }); + + it('chordLength throws without radius', function() { + expect(function() { + CesiumMath.chordLength(0.0, undefined); + }).toThrowDeveloperError(); + }); });