From 08b727d6124f5a5d0772b1403726bb320db89901 Mon Sep 17 00:00:00 2001 From: bao tran Date: Mon, 6 Jul 2020 10:00:42 -0400 Subject: [PATCH 01/10] remove check for wall height <= 0 --- Source/Core/WallGeometryLibrary.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Source/Core/WallGeometryLibrary.js b/Source/Core/WallGeometryLibrary.js index 8c77a5fb94ec..08eff8c4651b 100644 --- a/Source/Core/WallGeometryLibrary.js +++ b/Source/Core/WallGeometryLibrary.js @@ -29,7 +29,6 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { var hasBottomHeights = defined(bottomHeights); var hasTopHeights = defined(topHeights); - var hasAllZeroHeights = true; var cleanedPositions = new Array(length); var cleanedTopHeights = new Array(length); @@ -43,8 +42,6 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { c0.height = topHeights[0]; } - hasAllZeroHeights = hasAllZeroHeights && c0.height <= 0; - cleanedTopHeights[0] = c0.height; if (hasBottomHeights) { @@ -60,7 +57,6 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { if (hasTopHeights) { c1.height = topHeights[i]; } - hasAllZeroHeights = hasAllZeroHeights && c1.height <= 0; if (!latLonEquals(c0, c1)) { cleanedPositions[index] = v1; // Shallow copy! @@ -79,7 +75,7 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { } } - if (hasAllZeroHeights || index < 2) { + if (index < 2) { return; } From 1fcd3e531b7391d579d61765ee969d25249466e1 Mon Sep 17 00:00:00 2001 From: bao tran Date: Mon, 6 Jul 2020 11:11:29 -0400 Subject: [PATCH 02/10] calculate the normal for the wall using bottom position instead of surface position --- Source/Core/WallGeometry.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index cfa9b6b7fd34..f2b4bc6b00e6 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -437,22 +437,19 @@ WallGeometry.createGeometry = function (wallGeometry) { } if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) { - var nextPosition; + var nextBottomPosition = Cartesian3.clone( + Cartesian3.ZERO, + scratchCartesian3Position3 + ); 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 - ), + nextBottomPosition = Cartesian3.fromArray( + bottomPositions, + i3 + 3, scratchCartesian3Position3 ); nextTop = Cartesian3.fromArray( @@ -468,13 +465,13 @@ WallGeometry.createGeometry = function (wallGeometry) { topPosition, scratchCartesian3Position4 ); - var scaledGroundPosition = Cartesian3.subtract( - groundPosition, + var scaledBottomPosition = Cartesian3.subtract( + bottomPosition, topPosition, scratchCartesian3Position1 ); normal = Cartesian3.normalize( - Cartesian3.cross(scaledGroundPosition, scalednextPosition, normal), + Cartesian3.cross(scaledBottomPosition, scalednextPosition, normal), normal ); recomputeNormal = false; @@ -482,8 +479,8 @@ WallGeometry.createGeometry = function (wallGeometry) { if ( Cartesian3.equalsEpsilon( - nextPosition, - groundPosition, + bottomPosition, + nextBottomPosition, CesiumMath.EPSILON10 ) ) { @@ -492,7 +489,7 @@ WallGeometry.createGeometry = function (wallGeometry) { s += ds; if (vertexFormat.tangent) { tangent = Cartesian3.normalize( - Cartesian3.subtract(nextPosition, groundPosition, tangent), + Cartesian3.subtract(nextBottomPosition, bottomPosition, tangent), tangent ); } From 013817d47be551dea03665123553e9c711dd79c4 Mon Sep 17 00:00:00 2001 From: bao tran Date: Mon, 6 Jul 2020 15:05:09 -0400 Subject: [PATCH 03/10] add test for negative height wall --- Specs/Core/WallGeometrySpec.js | 79 ++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/Specs/Core/WallGeometrySpec.js b/Specs/Core/WallGeometrySpec.js index afb332c68283..dd0173982726 100644 --- a/Specs/Core/WallGeometrySpec.js +++ b/Specs/Core/WallGeometrySpec.js @@ -172,6 +172,85 @@ describe("Core/WallGeometry", function () { expect(cartographic.height).toEqualEpsilon(4000.0, CesiumMath.EPSILON8); }); + it("create positions with negative height", function () { + var w = WallGeometry.createGeometry( + new WallGeometry({ + positions: Cartesian3.fromDegreesArrayHeights([ + 49.0, + 18.0, + 1000.0, + 50.0, + 18.0, + 1000.0, + ]), + maximumHeights: [-300.0, -200.0], + minimumHeights: [-500.0, -600.0], + }) + ); + + var positions = w.attributes.position.values; + var normals = w.attributes.normal.values; + var indices = w.indices; + var numPositions = 4; + var numTriangles = 2; + expect(positions.length).toEqual(numPositions * 3); + expect(normals.length).toEqual(numPositions * 3); + expect(indices.length).toEqual(numTriangles * 3); + + var cartographic = ellipsoid.cartesianToCartographic( + Cartesian3.fromArray(positions, 0) + ); + expect(cartographic.height).toEqualEpsilon(-500.0, CesiumMath.EPSILON8); + + cartographic = ellipsoid.cartesianToCartographic( + Cartesian3.fromArray(positions, 3) + ); + expect(cartographic.height).toEqualEpsilon(-300.0, CesiumMath.EPSILON8); + + cartographic = ellipsoid.cartesianToCartographic( + Cartesian3.fromArray(positions, 6) + ); + expect(cartographic.height).toEqualEpsilon(-600.0, CesiumMath.EPSILON8); + + cartographic = ellipsoid.cartesianToCartographic( + Cartesian3.fromArray(positions, 9) + ); + expect(cartographic.height).toEqualEpsilon(-200.0, CesiumMath.EPSILON8); + + var bottomPosition = Cartesian3.fromArray(positions, 0); + var topPosition = Cartesian3.fromArray(positions, 3); + var nextTopPosition = Cartesian3.fromArray(positions, 9); + var topDiff = Cartesian3.subtract( + nextTopPosition, + topPosition, + new Cartesian3() + ); + var bottomDiff = Cartesian3.subtract( + bottomPosition, + topPosition, + new Cartesian3() + ); + var expectedNormal = Cartesian3.cross( + bottomDiff, + topDiff, + new Cartesian3() + ); + Cartesian3.normalize(expectedNormal, expectedNormal); + + for (var i = 0; i < normals.length; i += 3) { + console.log(normals); + expect(normals[i]).toEqualEpsilon(expectedNormal.x, CesiumMath.EPSILON7); + expect(normals[i + 1]).toEqualEpsilon( + expectedNormal.y, + CesiumMath.EPSILON7 + ); + expect(normals[i + 2]).toEqualEpsilon( + expectedNormal.z, + CesiumMath.EPSILON7 + ); + } + }); + it("cleans positions with duplicates", function () { var w = WallGeometry.createGeometry( new WallGeometry({ From e9966ef8e0f84fcc261a27bb7c04642c984d6a4a Mon Sep 17 00:00:00 2001 From: bao tran Date: Mon, 6 Jul 2020 16:37:14 -0400 Subject: [PATCH 04/10] prevent wall has all zero heights --- Source/Core/WallGeometryLibrary.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Core/WallGeometryLibrary.js b/Source/Core/WallGeometryLibrary.js index 08eff8c4651b..11303706f2c1 100644 --- a/Source/Core/WallGeometryLibrary.js +++ b/Source/Core/WallGeometryLibrary.js @@ -50,6 +50,8 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { cleanedBottomHeights[0] = 0.0; } + var wallHeight = Math.abs(cleanedTopHeights[0] - cleanedBottomHeights[0]); + var hasAllZeroHeights = wallHeight < CesiumMath.EPSILON10; var index = 1; for (var i = 1; i < length; ++i) { var v1 = positions[i]; @@ -68,14 +70,25 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { cleanedBottomHeights[index] = 0.0; } + wallHeight = Math.abs( + cleanedTopHeights[index] - cleanedBottomHeights[index] + ); + hasAllZeroHeights = + hasAllZeroHeights && wallHeight < CesiumMath.EPSILON10; + Cartographic.clone(c1, c0); ++index; } else if (c0.height < c1.height) { cleanedTopHeights[index - 1] = c1.height; + wallHeight = Math.abs( + cleanedTopHeights[index - 1] - cleanedBottomHeights[index - 1] + ); + hasAllZeroHeights = + hasAllZeroHeights && wallHeight < CesiumMath.EPSILON10; } } - if (index < 2) { + if (hasAllZeroHeights || index < 2) { return; } From 42ece5e8c689dd020fa02ddc6cfd7cdaf3cd746e Mon Sep 17 00:00:00 2001 From: bao tran Date: Tue, 7 Jul 2020 12:02:45 -0400 Subject: [PATCH 05/10] cleanup WallGeometry.createGeometry() func --- Source/Core/WallGeometry.js | 400 +++++++++++++++-------------- Source/Core/WallGeometryLibrary.js | 33 ++- Specs/Core/WallGeometrySpec.js | 48 +++- 3 files changed, 263 insertions(+), 218 deletions(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index f2b4bc6b00e6..8e6ba178320a 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -14,15 +14,6 @@ import PrimitiveType from "./PrimitiveType.js"; import VertexFormat from "./VertexFormat.js"; import WallGeometryLibrary from "./WallGeometryLibrary.js"; -var scratchCartesian3Position1 = new Cartesian3(); -var scratchCartesian3Position2 = new Cartesian3(); -var scratchCartesian3Position3 = new Cartesian3(); -var scratchCartesian3Position4 = new Cartesian3(); -var scratchCartesian3Position5 = new Cartesian3(); -var scratchBitangent = new Cartesian3(); -var scratchTangent = new Cartesian3(); -var scratchNormal = new Cartesian3(); - /** * A description of a wall, which is similar to a KML line string. A wall is defined by a series of points, * which extrude down to the ground. Optionally, they can extrude downwards to a specified height. @@ -347,192 +338,51 @@ WallGeometry.fromConstantHeights = function (options) { return new WallGeometry(newOptions); }; -/** - * Computes the geometric representation of a wall, including its vertices, indices, and a bounding sphere. - * - * @param {WallGeometry} wallGeometry A description of the wall. - * @returns {Geometry|undefined} The computed vertices and indices. - */ -WallGeometry.createGeometry = function (wallGeometry) { - var wallPositions = wallGeometry._positions; - var minimumHeights = wallGeometry._minimumHeights; - var maximumHeights = wallGeometry._maximumHeights; - var vertexFormat = wallGeometry._vertexFormat; - var granularity = wallGeometry._granularity; - var ellipsoid = wallGeometry._ellipsoid; - - var pos = WallGeometryLibrary.computePositions( - ellipsoid, - wallPositions, - maximumHeights, - minimumHeights, - granularity, - true - ); - if (!defined(pos)) { - return; +function calculateDirection(p0, p1, result) { + if (Cartesian3.equalsEpsilon(p0, p1, CesiumMath.EPSILON10)) { + return false; } - var bottomPositions = pos.bottomPositions; - var topPositions = pos.topPositions; - var numCorners = pos.numCorners; - - var length = topPositions.length; - var size = length * 2; - - var positions = vertexFormat.position ? new Float64Array(size) : undefined; - 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((size / 3) * 2) - : undefined; - - var positionIndex = 0; - var normalIndex = 0; - var bitangentIndex = 0; - var tangentIndex = 0; - var stIndex = 0; - - // add lower and upper points one after the other, lower - // points being even and upper points being odd - var normal = scratchNormal; - var tangent = scratchTangent; - var bitangent = scratchBitangent; - var recomputeNormal = true; - length /= 3; - var i; - var s = 0; - var ds = 1 / (length - wallPositions.length + 1); - for (i = 0; i < length; ++i) { - var i3 = i * 3; - var topPosition = Cartesian3.fromArray( - topPositions, - i3, - scratchCartesian3Position1 - ); - var bottomPosition = Cartesian3.fromArray( - bottomPositions, - i3, - scratchCartesian3Position2 - ); - if (vertexFormat.position) { - // insert the lower point - positions[positionIndex++] = bottomPosition.x; - positions[positionIndex++] = bottomPosition.y; - positions[positionIndex++] = bottomPosition.z; - - // insert the upper point - positions[positionIndex++] = topPosition.x; - positions[positionIndex++] = topPosition.y; - positions[positionIndex++] = topPosition.z; - } - - if (vertexFormat.st) { - textureCoordinates[stIndex++] = s; - textureCoordinates[stIndex++] = 0.0; - - textureCoordinates[stIndex++] = s; - textureCoordinates[stIndex++] = 1.0; - } - - if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) { - var nextBottomPosition = Cartesian3.clone( - Cartesian3.ZERO, - scratchCartesian3Position3 - ); - var nextTop = Cartesian3.clone( - Cartesian3.ZERO, - scratchCartesian3Position5 - ); - - if (i + 1 < length) { - nextBottomPosition = Cartesian3.fromArray( - bottomPositions, - i3 + 3, - scratchCartesian3Position3 - ); - nextTop = Cartesian3.fromArray( - topPositions, - i3 + 3, - scratchCartesian3Position5 - ); - } - - if (recomputeNormal) { - var scalednextPosition = Cartesian3.subtract( - nextTop, - topPosition, - scratchCartesian3Position4 - ); - var scaledBottomPosition = Cartesian3.subtract( - bottomPosition, - topPosition, - scratchCartesian3Position1 - ); - normal = Cartesian3.normalize( - Cartesian3.cross(scaledBottomPosition, scalednextPosition, normal), - normal - ); - recomputeNormal = false; - } - - if ( - Cartesian3.equalsEpsilon( - bottomPosition, - nextBottomPosition, - CesiumMath.EPSILON10 - ) - ) { - recomputeNormal = true; - } else { - s += ds; - if (vertexFormat.tangent) { - tangent = Cartesian3.normalize( - Cartesian3.subtract(nextBottomPosition, bottomPosition, tangent), - tangent - ); - } - if (vertexFormat.bitangent) { - bitangent = Cartesian3.normalize( - Cartesian3.cross(normal, tangent, bitangent), - bitangent - ); - } - } - - if (vertexFormat.normal) { - normals[normalIndex++] = normal.x; - normals[normalIndex++] = normal.y; - normals[normalIndex++] = normal.z; + result = Cartesian3.normalize(Cartesian3.subtract(p0, p1, result), result); + return true; +} - normals[normalIndex++] = normal.x; - normals[normalIndex++] = normal.y; - normals[normalIndex++] = normal.z; - } +function calculateNormal(p0, p1, p2, resultP10, resultP20, result) { + if (!calculateDirection(p1, p0, resultP10)) { + return false; + } - if (vertexFormat.tangent) { - tangents[tangentIndex++] = tangent.x; - tangents[tangentIndex++] = tangent.y; - tangents[tangentIndex++] = tangent.z; + if (!calculateDirection(p2, p0, resultP20)) { + return false; + } - tangents[tangentIndex++] = tangent.x; - tangents[tangentIndex++] = tangent.y; - tangents[tangentIndex++] = tangent.z; - } + var angle = Cartesian3.dot(resultP10, resultP20); + if (CesiumMath.equalsEpsilon(Math.abs(angle), 1.0, CesiumMath.EPSILON10)) { + return false; + } - if (vertexFormat.bitangent) { - bitangents[bitangentIndex++] = bitangent.x; - bitangents[bitangentIndex++] = bitangent.y; - bitangents[bitangentIndex++] = bitangent.z; + result = Cartesian3.normalize( + Cartesian3.cross(resultP10, resultP20, result), + result + ); + return true; +} - bitangents[bitangentIndex++] = bitangent.x; - bitangents[bitangentIndex++] = bitangent.y; - bitangents[bitangentIndex++] = bitangent.z; - } - } - } +function calculateBitangent(normal, tangent, result) { + result = Cartesian3.normalize( + Cartesian3.cross(normal, tangent, result), + result + ); +} +function createWallGeometryAttributes( + vertexFormat, + positions, + normals, + tangents, + bitangents, + textureCoordinates +) { var attributes = new GeometryAttributes(); if (vertexFormat.position) { @@ -575,6 +425,10 @@ WallGeometry.createGeometry = function (wallGeometry) { }); } + return attributes; +} + +function createWallGeometryIndices(positions, numCorners) { // prepare the side walls, two triangles for each wall // // A (i+1) B (i+3) E @@ -588,25 +442,19 @@ WallGeometry.createGeometry = function (wallGeometry) { // +--------+-------+ // C (i) D (i+2) F // - + var size = positions.length; var numVertices = size / 3; size -= 6 * (numCorners + 1); var indices = IndexDatatype.createTypedArray(numVertices, size); + var scratchPosition1 = new Cartesian3(); + var scratchPosition2 = new Cartesian3(); var edgeIndex = 0; - for (i = 0; i < numVertices - 2; i += 2) { + for (var i = 0; i < numVertices - 2; i += 2) { var LL = i; var LR = i + 2; - var pl = Cartesian3.fromArray( - positions, - LL * 3, - scratchCartesian3Position1 - ); - var pr = Cartesian3.fromArray( - positions, - LR * 3, - scratchCartesian3Position2 - ); + var pl = Cartesian3.fromArray(positions, LL * 3, scratchPosition1); + var pr = Cartesian3.fromArray(positions, LR * 3, scratchPosition2); if (Cartesian3.equalsEpsilon(pl, pr, CesiumMath.EPSILON10)) { continue; } @@ -621,6 +469,160 @@ WallGeometry.createGeometry = function (wallGeometry) { indices[edgeIndex++] = LR; } + return indices; +} + +/** + * Computes the geometric representation of a wall, including its vertices, indices, and a bounding sphere. + * + * @param {WallGeometry} wallGeometry A description of the wall. + * @returns {Geometry|undefined} The computed vertices and indices. + */ +WallGeometry.createGeometry = function (wallGeometry) { + var wallPositions = wallGeometry._positions; + var minimumHeights = wallGeometry._minimumHeights; + var maximumHeights = wallGeometry._maximumHeights; + var vertexFormat = wallGeometry._vertexFormat; + var granularity = wallGeometry._granularity; + var ellipsoid = wallGeometry._ellipsoid; + + var pos = WallGeometryLibrary.computePositions( + ellipsoid, + wallPositions, + maximumHeights, + minimumHeights, + granularity, + true + ); + if (!defined(pos)) { + return; + } + + var bottomPositions = pos.bottomPositions; + var topPositions = pos.topPositions; + var numCorners = pos.numCorners; + + var length = topPositions.length; + var size = length * 2; + + var positions = vertexFormat.position ? new Float64Array(size) : undefined; + 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((size / 3) * 2) + : undefined; + + var positionIndex = 0; + var normalIndex = 0; + var bitangentIndex = 0; + var tangentIndex = 0; + var stIndex = 0; + + // add lower and upper points one after the other, lower + // points being even and upper points being odd + var topPosition = new Cartesian3(); + var bottomPosition = new Cartesian3(); + var nextTopPosition = new Cartesian3(); + var nextBottomPosition = new Cartesian3(); + var topToBottom = new Cartesian3(); + var topToNextTop = new Cartesian3(); + + var normal = new Cartesian3(0.0, 1.0, 0.0); + var tangent = new Cartesian3(1.0, 0.0, 0.0); + var bitangent = new Cartesian3(0.0, 0.0, 1.0); + + var recomputeNormal = true; + var s = 0; + var ds = 1.0 / (length / 3.0 - wallPositions.length + 1.0); + for (var i = 0; i < length; i += 3) { + var curr = i; + var next = i + 3; + Cartesian3.fromArray(topPositions, curr, topPosition); + Cartesian3.fromArray(bottomPositions, curr, bottomPosition); + + if (next < length) { + Cartesian3.fromArray(topPositions, next, nextTopPosition); + Cartesian3.fromArray(bottomPositions, next, nextBottomPosition); + + if ( + recomputeNormal && + (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) + ) { + recomputeNormal = !calculateNormal( + topPosition, + bottomPosition, + nextTopPosition, + topToBottom, + topToNextTop, + normal + ); + } + + if ( + !recomputeNormal && + (vertexFormat.tangent || vertexFormat.bitangent) + ) { + recomputeNormal = !calculateDirection( + bottomPosition, + nextBottomPosition, + tangent + ); + } + + if (!recomputeNormal && vertexFormat.bitangent) { + calculateBitangent(normal, tangent, bitangent); + } + } + + if (vertexFormat.position) { + Cartesian3.pack(bottomPosition, positions, positionIndex); + Cartesian3.pack(topPosition, positions, positionIndex + 3); + positionIndex += 6; + } + + if (vertexFormat.normal) { + Cartesian3.pack(normal, normals, normalIndex); + Cartesian3.pack(normal, normals, normalIndex + 3); + normalIndex += 6; + } + + if (vertexFormat.tangent) { + Cartesian3.pack(tangent, tangents, tangentIndex); + Cartesian3.pack(tangent, tangents, tangentIndex + 3); + tangentIndex += 6; + } + + if (vertexFormat.bitangent) { + Cartesian3.pack(bitangent, bitangents, bitangentIndex); + Cartesian3.pack(bitangent, bitangents, bitangentIndex + 3); + bitangentIndex += 6; + } + + if (vertexFormat.st) { + textureCoordinates[stIndex++] = s; + textureCoordinates[stIndex++] = 0.0; + + textureCoordinates[stIndex++] = s; + textureCoordinates[stIndex++] = 1.0; + } + + if (!recomputeNormal && (vertexFormat.tangent || vertexFormat.bitangent)) { + s += ds; + } + } + + var indices = createWallGeometryIndices(positions, numCorners); + + var attributes = createWallGeometryAttributes( + vertexFormat, + positions, + normals, + tangents, + bitangents, + textureCoordinates + ); + return new Geometry({ attributes: attributes, indices: indices, diff --git a/Source/Core/WallGeometryLibrary.js b/Source/Core/WallGeometryLibrary.js index 11303706f2c1..47b50c21e2ec 100644 --- a/Source/Core/WallGeometryLibrary.js +++ b/Source/Core/WallGeometryLibrary.js @@ -26,7 +26,6 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { if (length < 2) { return; } - var hasBottomHeights = defined(bottomHeights); var hasTopHeights = defined(topHeights); @@ -35,13 +34,12 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { var cleanedBottomHeights = new Array(length); var v0 = positions[0]; - cleanedPositions[0] = v0; - var c0 = ellipsoid.cartesianToCartographic(v0, scratchCartographic1); if (hasTopHeights) { c0.height = topHeights[0]; } + cleanedPositions[0] = v0; cleanedTopHeights[0] = c0.height; if (hasBottomHeights) { @@ -50,10 +48,9 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { cleanedBottomHeights[0] = 0.0; } - var wallHeight = Math.abs(cleanedTopHeights[0] - cleanedBottomHeights[0]); - var hasAllZeroHeights = wallHeight < CesiumMath.EPSILON10; var index = 1; - for (var i = 1; i < length; ++i) { + var i; + for (i = 1; i < length; ++i) { var v1 = positions[i]; var c1 = ellipsoid.cartesianToCartographic(v1, scratchCartographic2); if (hasTopHeights) { @@ -70,25 +67,25 @@ function removeDuplicates(ellipsoid, positions, topHeights, bottomHeights) { cleanedBottomHeights[index] = 0.0; } - wallHeight = Math.abs( - cleanedTopHeights[index] - cleanedBottomHeights[index] - ); - hasAllZeroHeights = - hasAllZeroHeights && wallHeight < CesiumMath.EPSILON10; - Cartographic.clone(c1, c0); ++index; } else if (c0.height < c1.height) { cleanedTopHeights[index - 1] = c1.height; - wallHeight = Math.abs( - cleanedTopHeights[index - 1] - cleanedBottomHeights[index - 1] - ); - hasAllZeroHeights = - hasAllZeroHeights && wallHeight < CesiumMath.EPSILON10; } } - if (hasAllZeroHeights || index < 2) { + var zeroHeightCount = 0; + for (i = 0; i < index; ++i) { + var topHeight = cleanedTopHeights[i]; + var bottomHeight = cleanedBottomHeights[i]; + zeroHeightCount += CesiumMath.equalsEpsilon( + topHeight, + bottomHeight, + CesiumMath.EPSILON10 + ); + } + + if (zeroHeightCount === index || index < 2) { return; } diff --git a/Specs/Core/WallGeometrySpec.js b/Specs/Core/WallGeometrySpec.js index dd0173982726..fa89c560cfbb 100644 --- a/Specs/Core/WallGeometrySpec.js +++ b/Specs/Core/WallGeometrySpec.js @@ -82,6 +82,53 @@ describe("Core/WallGeometry", function () { expect(geometry).toBeUndefined(); }); + it("does not create when minimumHeights and maximumHeights are the same", function () { + var geometry = WallGeometry.createGeometry( + new WallGeometry({ + positions: Cartesian3.fromDegreesArrayHeights([ + -115.0, + 44.0, + 100000.0, + -90.0, + 44.0, + 200000.0, + -30.0, + 44.0, + 200000.0, + ]), + maximumHeights: [60000.0, 60000.0, 50000.0], + minimumHeights: [60000.0, 60000.0, 50000.0], + }) + ); + + expect(geometry).toBeUndefined(); + }); + + it("does not create when removing duplicated position results in minimumHeights and maximumHeights are the same", function () { + var geometry = WallGeometry.createGeometry( + new WallGeometry({ + positions: Cartesian3.fromDegreesArrayHeights([ + -115.0, + 44.0, + 200000.0, + -115.0, + 44.0, + 100000.0, + -90.0, + 44.0, + 200000.0, + -30.0, + 44.0, + 200000.0, + ]), + maximumHeights: [40000.0, 60000.0, 60000.0, 50000.0], + minimumHeights: [60000.0, 60000.0, 60000.0, 50000.0], + }) + ); + + expect(geometry).toBeUndefined(); + }); + it("does not throw when positions are unique but close", function () { WallGeometry.createGeometry( new WallGeometry({ @@ -238,7 +285,6 @@ describe("Core/WallGeometry", function () { Cartesian3.normalize(expectedNormal, expectedNormal); for (var i = 0; i < normals.length; i += 3) { - console.log(normals); expect(normals[i]).toEqualEpsilon(expectedNormal.x, CesiumMath.EPSILON7); expect(normals[i + 1]).toEqualEpsilon( expectedNormal.y, From 04bccab1017035302d277adac207d2d144af19ce Mon Sep 17 00:00:00 2001 From: bao tran Date: Tue, 7 Jul 2020 15:03:44 -0400 Subject: [PATCH 06/10] fix textureCoordinate for wall and some clean up --- Source/Core/WallGeometry.js | 64 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index 8e6ba178320a..b72a0ec7660a 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -368,13 +368,6 @@ function calculateNormal(p0, p1, p2, resultP10, resultP20, result) { return true; } -function calculateBitangent(normal, tangent, result) { - result = Cartesian3.normalize( - Cartesian3.cross(normal, tangent, result), - result - ); -} - function createWallGeometryAttributes( vertexFormat, positions, @@ -532,24 +525,30 @@ WallGeometry.createGeometry = function (wallGeometry) { var tangent = new Cartesian3(1.0, 0.0, 0.0); var bitangent = new Cartesian3(0.0, 0.0, 1.0); - var recomputeNormal = true; + var isWallCorner = false; + var needNormal = true; var s = 0; - var ds = 1.0 / (length / 3.0 - wallPositions.length + 1.0); + var ds = 1.0 / (length / 3.0 - numCorners - 1.0); for (var i = 0; i < length; i += 3) { var curr = i; var next = i + 3; Cartesian3.fromArray(topPositions, curr, topPosition); Cartesian3.fromArray(bottomPositions, curr, bottomPosition); - if (next < length) { + if ( + next < length && + (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) + ) { Cartesian3.fromArray(topPositions, next, nextTopPosition); Cartesian3.fromArray(bottomPositions, next, nextBottomPosition); - - if ( - recomputeNormal && - (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) - ) { - recomputeNormal = !calculateNormal( + isWallCorner = Cartesian3.equalsEpsilon( + bottomPosition, + nextBottomPosition, + CesiumMath.EPSILON10 + ); + + if (needNormal || isWallCorner) { + needNormal = !calculateNormal( topPosition, bottomPosition, nextTopPosition, @@ -559,19 +558,20 @@ WallGeometry.createGeometry = function (wallGeometry) { ); } - if ( - !recomputeNormal && - (vertexFormat.tangent || vertexFormat.bitangent) - ) { - recomputeNormal = !calculateDirection( - bottomPosition, - nextBottomPosition, - tangent - ); - } - - if (!recomputeNormal && vertexFormat.bitangent) { - calculateBitangent(normal, tangent, bitangent); + if (!needNormal && !isWallCorner) { + if (vertexFormat.tangent || vertexFormat.bitangent) { + tangent = Cartesian3.normalize( + Cartesian3.subtract(nextBottomPosition, bottomPosition, tangent), + tangent + ); + } + + if (vertexFormat.bitangent) { + bitangent = Cartesian3.normalize( + Cartesian3.cross(normal, tangent, bitangent), + bitangent + ); + } } } @@ -605,10 +605,10 @@ WallGeometry.createGeometry = function (wallGeometry) { textureCoordinates[stIndex++] = s; textureCoordinates[stIndex++] = 1.0; - } - if (!recomputeNormal && (vertexFormat.tangent || vertexFormat.bitangent)) { - s += ds; + if (!isWallCorner) { + s += ds; + } } } From 943ccb1548df470f967cd6a87f8b92de80a3f611 Mon Sep 17 00:00:00 2001 From: bao tran Date: Tue, 7 Jul 2020 16:04:49 -0400 Subject: [PATCH 07/10] add scratch variable back --- Source/Core/WallGeometry.js | 45 +++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index b72a0ec7660a..26d18890d22c 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -14,6 +14,16 @@ import PrimitiveType from "./PrimitiveType.js"; import VertexFormat from "./VertexFormat.js"; import WallGeometryLibrary from "./WallGeometryLibrary.js"; +var scratchCartesian3Position0 = new Cartesian3(); +var scratchCartesian3Position1 = new Cartesian3(); +var scratchCartesian3Position2 = new Cartesian3(); +var scratchCartesian3Position3 = new Cartesian3(); +var scratchCartesian3Position4 = new Cartesian3(); +var scratchCartesian3Position5 = new Cartesian3(); +var scratchBitangent = new Cartesian3(); +var scratchTangent = new Cartesian3(); +var scratchNormal = new Cartesian3(); + /** * A description of a wall, which is similar to a KML line string. A wall is defined by a series of points, * which extrude down to the ground. Optionally, they can extrude downwards to a specified height. @@ -338,6 +348,12 @@ WallGeometry.fromConstantHeights = function (options) { return new WallGeometry(newOptions); }; +function initNormalTangentBitangent(normal, tangent, bitangent) { + Cartesian3.clone(Cartesian3.UNIT_X, tangent); + Cartesian3.clone(Cartesian3.UNIT_Y, normal); + Cartesian3.clone(Cartesian3.UNIT_Z, bitangent); +} + function calculateDirection(p0, p1, result) { if (Cartesian3.equalsEpsilon(p0, p1, CesiumMath.EPSILON10)) { return false; @@ -514,19 +530,20 @@ WallGeometry.createGeometry = function (wallGeometry) { // add lower and upper points one after the other, lower // points being even and upper points being odd - var topPosition = new Cartesian3(); - var bottomPosition = new Cartesian3(); - var nextTopPosition = new Cartesian3(); - var nextBottomPosition = new Cartesian3(); - var topToBottom = new Cartesian3(); - var topToNextTop = new Cartesian3(); - - var normal = new Cartesian3(0.0, 1.0, 0.0); - var tangent = new Cartesian3(1.0, 0.0, 0.0); - var bitangent = new Cartesian3(0.0, 0.0, 1.0); + var topPosition = scratchCartesian3Position0; + var bottomPosition = scratchCartesian3Position1; + var nextTopPosition = scratchCartesian3Position2; + var nextBottomPosition = scratchCartesian3Position3; + var topToBottom = scratchCartesian3Position4; + var topToNextTop = scratchCartesian3Position5; + + var normal = scratchNormal; + var tangent = scratchTangent; + var bitangent = scratchBitangent; + initNormalTangentBitangent(normal, tangent, bitangent); var isWallCorner = false; - var needNormal = true; + var validNormal = false; var s = 0; var ds = 1.0 / (length / 3.0 - numCorners - 1.0); for (var i = 0; i < length; i += 3) { @@ -547,8 +564,8 @@ WallGeometry.createGeometry = function (wallGeometry) { CesiumMath.EPSILON10 ); - if (needNormal || isWallCorner) { - needNormal = !calculateNormal( + if (!validNormal || isWallCorner) { + validNormal = calculateNormal( topPosition, bottomPosition, nextTopPosition, @@ -558,7 +575,7 @@ WallGeometry.createGeometry = function (wallGeometry) { ); } - if (!needNormal && !isWallCorner) { + if (validNormal && !isWallCorner) { if (vertexFormat.tangent || vertexFormat.bitangent) { tangent = Cartesian3.normalize( Cartesian3.subtract(nextBottomPosition, bottomPosition, tangent), From 69fff7c3dcefb1248e82c3012e62ac1fd37d3784 Mon Sep 17 00:00:00 2001 From: bao tran Date: Tue, 7 Jul 2020 19:03:58 -0400 Subject: [PATCH 08/10] add test for normal, tangent, and bitangent --- Specs/Core/WallGeometrySpec.js | 68 +++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/Specs/Core/WallGeometrySpec.js b/Specs/Core/WallGeometrySpec.js index fa89c560cfbb..8c48d6f41263 100644 --- a/Specs/Core/WallGeometrySpec.js +++ b/Specs/Core/WallGeometrySpec.js @@ -284,7 +284,8 @@ describe("Core/WallGeometry", function () { ); Cartesian3.normalize(expectedNormal, expectedNormal); - for (var i = 0; i < normals.length; i += 3) { + var length = normals.length; + for (var i = 0; i < length; i += 3) { expect(normals[i]).toEqualEpsilon(expectedNormal.x, CesiumMath.EPSILON7); expect(normals[i + 1]).toEqualEpsilon( expectedNormal.y, @@ -297,6 +298,71 @@ describe("Core/WallGeometry", function () { } }); + it("No zero unit normals, tangent, or bitangent created when only part of minimumHeights and maximumHeights array are equal", function () { + var w = WallGeometry.createGeometry( + new WallGeometry({ + vertexFormat: VertexFormat.ALL, + positions: Cartesian3.fromDegreesArrayHeights([ + 49.0, + 18.0, + 1000.0, + 50.0, + 18.0, + 1000.0, + 51.0, + 18.0, + 1000.0, + 52.0, + 18.0, + 1000.0, + ]), + maximumHeights: [0.0, -300.0, 0.0, 10.0], + minimumHeights: [0.0, -300.0, -10.0, -20.0], + }) + ); + + var normals = w.attributes.normal.values; + var tangents = w.attributes.tangent.values; + var bitangents = w.attributes.bitangent.values; + var normal = Cartesian3.fromArray(normals, 0); + var tangent = Cartesian3.fromArray(tangents, 0); + var bitangent = Cartesian3.fromArray(bitangents, 0); + expect(Cartesian3.equalsEpsilon(normal, Cartesian3.UNIT_Y)).toEqual(true); + expect(Cartesian3.equalsEpsilon(tangent, Cartesian3.UNIT_X)).toEqual(true); + expect(Cartesian3.equalsEpsilon(bitangent, Cartesian3.UNIT_Z)).toEqual( + true + ); + + var length = normals.length; + for (var i = 3; i < length; i += 3) { + normal = Cartesian3.fromArray(normals, i, normal); + tangent = Cartesian3.fromArray(tangents, i, tangent); + bitangent = Cartesian3.fromArray(bitangents, i, bitangents); + var normalLength = Cartesian3.magnitude(normal); + var tangentLength = Cartesian3.magnitude(tangent); + var bitangentLength = Cartesian3.magnitude(bitangent); + var normalTangentAngle = Cartesian3.dot(normal, tangent); + var normalBitangentAngle = Cartesian3.dot(normal, bitangent); + var tangentBitangentAngle = Cartesian3.dot(tangent, bitangent); + + expect( + CesiumMath.equalsEpsilon(normalLength, 0.0, CesiumMath.EPSILON7) + ).toEqual(false); + + expect( + CesiumMath.equalsEpsilon(tangentLength, 0.0, CesiumMath.EPSILON7) + ).toEqual(false); + + expect( + CesiumMath.equalsEpsilon(bitangentLength, 0.0, CesiumMath.EPSILON7) + ).toEqual(false); + + expect(normalTangentAngle).toEqualEpsilon(0.0, CesiumMath.EPSILON7); + expect(normalBitangentAngle).toEqualEpsilon(0.0, CesiumMath.EPSILON7); + expect(tangentBitangentAngle).toEqualEpsilon(0.0, CesiumMath.EPSILON7); + } + }); + it("cleans positions with duplicates", function () { var w = WallGeometry.createGeometry( new WallGeometry({ From 17ee68caa7ab0edd426b8aea0e4e409d4cacfafd Mon Sep 17 00:00:00 2001 From: bao tran Date: Tue, 7 Jul 2020 19:43:41 -0400 Subject: [PATCH 09/10] remove initNormalTangentBitangent func --- Source/Core/WallGeometry.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index 26d18890d22c..1ec5275ec6b2 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -348,12 +348,6 @@ WallGeometry.fromConstantHeights = function (options) { return new WallGeometry(newOptions); }; -function initNormalTangentBitangent(normal, tangent, bitangent) { - Cartesian3.clone(Cartesian3.UNIT_X, tangent); - Cartesian3.clone(Cartesian3.UNIT_Y, normal); - Cartesian3.clone(Cartesian3.UNIT_Z, bitangent); -} - function calculateDirection(p0, p1, result) { if (Cartesian3.equalsEpsilon(p0, p1, CesiumMath.EPSILON10)) { return false; @@ -537,10 +531,9 @@ WallGeometry.createGeometry = function (wallGeometry) { var topToBottom = scratchCartesian3Position4; var topToNextTop = scratchCartesian3Position5; - var normal = scratchNormal; - var tangent = scratchTangent; - var bitangent = scratchBitangent; - initNormalTangentBitangent(normal, tangent, bitangent); + var normal = Cartesian3.clone(Cartesian3.UNIT_Y, scratchNormal); + var tangent = Cartesian3.clone(Cartesian3.UNIT_X, scratchTangent); + var bitangent = Cartesian3.clone(Cartesian3.UNIT_Z, scratchBitangent); var isWallCorner = false; var validNormal = false; From 62eabf8d2bab23dd6ae12a7ba35ad01ff3c8d95e Mon Sep 17 00:00:00 2001 From: bao tran Date: Tue, 7 Jul 2020 23:48:23 -0400 Subject: [PATCH 10/10] recompute normal when seeing corner wall --- Source/Core/WallGeometry.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/Core/WallGeometry.js b/Source/Core/WallGeometry.js index 1ec5275ec6b2..64a6eceff80a 100644 --- a/Source/Core/WallGeometry.js +++ b/Source/Core/WallGeometry.js @@ -557,7 +557,7 @@ WallGeometry.createGeometry = function (wallGeometry) { CesiumMath.EPSILON10 ); - if (!validNormal || isWallCorner) { + if (!validNormal) { validNormal = calculateNormal( topPosition, bottomPosition, @@ -568,13 +568,15 @@ WallGeometry.createGeometry = function (wallGeometry) { ); } - if (validNormal && !isWallCorner) { - if (vertexFormat.tangent || vertexFormat.bitangent) { - tangent = Cartesian3.normalize( - Cartesian3.subtract(nextBottomPosition, bottomPosition, tangent), - tangent - ); - } + if (isWallCorner) { + validNormal = false; + } + + if (validNormal && (vertexFormat.tangent || vertexFormat.bitangent)) { + tangent = Cartesian3.normalize( + Cartesian3.subtract(nextBottomPosition, bottomPosition, tangent), + tangent + ); if (vertexFormat.bitangent) { bitangent = Cartesian3.normalize(