From 4677d0c5cfe446ccc96d3982ff4f442cddba5063 Mon Sep 17 00:00:00 2001 From: TimGurnett Date: Fri, 15 May 2020 14:31:27 +1000 Subject: [PATCH 1/3] Added getMeshWithSkirts function --- index.js | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/index.js b/index.js index e93a9f3..3c253cf 100644 --- a/index.js +++ b/index.js @@ -161,4 +161,179 @@ class Tile { return {vertices, triangles}; } + + getMeshWithSkirts(maxError = 0) { + const {gridSize: size, indices} = this.martini; + const {errors} = this; + let numVertices = 0; + let numTriangles = 0; + const max = size - 1; + let aIndex, bIndex, cIndex = 0; + // Skirt indices + let leftSkirtIndices = []; + let rightSkirtIndices = []; + let bottomSkirtIndices = []; + let topSkirtIndices = []; + // use an index grid to keep track of vertices that were already used to avoid duplication + indices.fill(0); + + // retrieve mesh in two stages that both traverse the error map: + // - countElements: find used vertices (and assign each an index), and count triangles (for minimum allocation) + // - processTriangle: fill the allocated vertices & triangles typed arrays + function countElements(ax, ay, bx, by, cx, cy) { + const mx = (ax + bx) >> 1; + const my = (ay + by) >> 1; + + if (Math.abs(ax - cx) + Math.abs(ay - cy) > 1 && errors[my * size + mx] > maxError) { + countElements(cx, cy, ax, ay, mx, my); + countElements(bx, by, cx, cy, mx, my); + } else { + aIndex = ay * size + ax; + bIndex = by * size + bx; + cIndex = cy * size + cx; + + if (indices[aIndex]===0) { + if (ax === 0) + leftSkirtIndices.push(numVertices); + else if (ax === max) { + rightSkirtIndices.push(numVertices); + } + if (ay === 0) + bottomSkirtIndices.push(numVertices); + else if (ay === max) + topSkirtIndices.push(numVertices); + indices[aIndex] = ++numVertices; + } + if (indices[bIndex]===0) { + if (bx === 0) + leftSkirtIndices.push(numVertices); + else if (bx === max) + rightSkirtIndices.push(numVertices); + if (by === 0) + bottomSkirtIndices.push(numVertices); + else if (by === max) + topSkirtIndices.push(numVertices); + indices[bIndex] = ++numVertices; + } + if (indices[cIndex]===0) { + if (cx === 0) + leftSkirtIndices.push(numVertices); + else if (cx === max) + rightSkirtIndices.push(numVertices); + if (cy === 0) + bottomSkirtIndices.push(numVertices); + else if (cy === max) + topSkirtIndices.push(numVertices); + indices[cIndex] = ++numVertices; + + } + numTriangles++; + } + } + countElements(0, 0, max, max, max, 0); + countElements(max, max, 0, 0, 0, max); + + const numTotalVertices = ( + numVertices + + leftSkirtIndices.length + + rightSkirtIndices.length + + bottomSkirtIndices.length + + topSkirtIndices.length) * 2; + const numTotalTriangles = ( + numTriangles + + ((leftSkirtIndices.length - 1) * 2) + + ((rightSkirtIndices.length - 1) * 2) + + ((bottomSkirtIndices.length - 1) * 2) + + ((topSkirtIndices.length - 1) * 2)) * 3; + + const vertices = new Uint16Array(numTotalVertices); + const triangles = new Uint32Array(numTotalTriangles); + + let triIndex = 0; + function processTriangle(ax, ay, bx, by, cx, cy) { + const mx = (ax + bx) >> 1; + const my = (ay + by) >> 1; + + if (Math.abs(ax - cx) + Math.abs(ay - cy) > 1 && errors[my * size + mx] > maxError) { + // triangle doesn't approximate the surface well enough; drill down further + processTriangle(cx, cy, ax, ay, mx, my); + processTriangle(bx, by, cx, cy, mx, my); + + } else { + // add a triangle + const a = indices[ay * size + ax] - 1; + const b = indices[by * size + bx] - 1; + const c = indices[cy * size + cx] - 1; + + vertices[2 * a] = ax; + vertices[2 * a + 1] = ay; + + vertices[2 * b] = bx; + vertices[2 * b + 1] = by; + + vertices[2 * c] = cx; + vertices[2 * c + 1] = cy; + triangles[triIndex++] = a; + triangles[triIndex++] = b; + triangles[triIndex++] = c; + } + } + processTriangle(0, 0, max, max, max, 0); + processTriangle(max, max, 0, 0, 0, max); + + // Sort skirt indices to create adjacent triangles + leftSkirtIndices.sort( (a, b) => { + return vertices[2 * a + 1] - vertices[2 * b + 1]; + }) + + rightSkirtIndices.sort( (a, b) => { + // Reverse (b - a) to match triangle winding + return vertices[2 * b + 1] - vertices[2 * a + 1]; + }) + + bottomSkirtIndices.sort( (a, b) => { + return vertices[2 * b] - vertices[2 * a]; + }) + + topSkirtIndices.sort( (a, b) => { + // Reverse (b - a) to match triangle winding + return vertices[2 * a] - vertices[2 * b]; + }) + + let skirtIndex = numVertices * 2; + let currIndex, nextIndex, currentSkirt, nextSkirt, skirtLength = 0; + + // Add skirt vertices from index of last mesh vertex + function constructSkirt(skirt) { + skirtLength = skirt.length; + // Loop through indices in groups of two to generate triangles + for (var i = 0; i < skirtLength - 1; i++) { + currIndex = skirt[i]; + nextIndex = skirt[i + 1]; + currentSkirt = skirtIndex/2; + nextSkirt = (skirtIndex + 2)/2; + vertices[skirtIndex++] = vertices[2 * currIndex]; + vertices[skirtIndex++] = vertices[2 * currIndex + 1]; + + triangles[triIndex++] = currIndex; + triangles[triIndex++] = currentSkirt; + triangles[triIndex++] = nextIndex; + + triangles[triIndex++] = currentSkirt; + triangles[triIndex++] = nextSkirt; + triangles[triIndex++] = nextIndex; + } + // Add vertices of last skirt not added above (i < skirtLength - 1) + vertices[skirtIndex++] = vertices[2 * skirt[skirtLength - 1]]; + vertices[skirtIndex++] = vertices[2 * skirt[skirtLength - 1] + 1]; + } + + constructSkirt(leftSkirtIndices); + constructSkirt(rightSkirtIndices); + constructSkirt(bottomSkirtIndices); + constructSkirt(topSkirtIndices); + + // Return vertices and triangles and index into vertices array where skirts start + return {vertices, triangles, numVerticesWithoutSkirts: numVertices}; + } } From e9765e973940fb2f6f0fad7de3d393d438d8418d Mon Sep 17 00:00:00 2001 From: TimGurnett Date: Fri, 15 May 2020 14:34:45 +1000 Subject: [PATCH 2/3] tidy up --- index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 3c253cf..9f2b368 100644 --- a/index.js +++ b/index.js @@ -195,9 +195,8 @@ class Tile { if (indices[aIndex]===0) { if (ax === 0) leftSkirtIndices.push(numVertices); - else if (ax === max) { + else if (ax === max) rightSkirtIndices.push(numVertices); - } if (ay === 0) bottomSkirtIndices.push(numVertices); else if (ay === max) @@ -224,8 +223,7 @@ class Tile { bottomSkirtIndices.push(numVertices); else if (cy === max) topSkirtIndices.push(numVertices); - indices[cIndex] = ++numVertices; - + indices[cIndex] = ++numVertices; } numTriangles++; } From 58e6d954f4b7651fb1161a45221995d92999656f Mon Sep 17 00:00:00 2001 From: TimGurnett Date: Fri, 15 May 2020 15:03:58 +1000 Subject: [PATCH 3/3] fixed linting --- index.js | 92 ++++++++++++++++++++++++++------------------------------ 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/index.js b/index.js index 9f2b368..d094421 100644 --- a/index.js +++ b/index.js @@ -167,13 +167,13 @@ class Tile { const {errors} = this; let numVertices = 0; let numTriangles = 0; - const max = size - 1; + const max = size - 1; let aIndex, bIndex, cIndex = 0; // Skirt indices - let leftSkirtIndices = []; - let rightSkirtIndices = []; - let bottomSkirtIndices = []; - let topSkirtIndices = []; + const leftSkirtIndices = []; + const rightSkirtIndices = []; + const bottomSkirtIndices = []; + const topSkirtIndices = []; // use an index grid to keep track of vertices that were already used to avoid duplication indices.fill(0); @@ -192,8 +192,8 @@ class Tile { bIndex = by * size + bx; cIndex = cy * size + cx; - if (indices[aIndex]===0) { - if (ax === 0) + if (indices[aIndex] === 0) { + if (ax === 0) leftSkirtIndices.push(numVertices); else if (ax === max) rightSkirtIndices.push(numVertices); @@ -201,10 +201,10 @@ class Tile { bottomSkirtIndices.push(numVertices); else if (ay === max) topSkirtIndices.push(numVertices); - indices[aIndex] = ++numVertices; + indices[aIndex] = ++numVertices; } - if (indices[bIndex]===0) { - if (bx === 0) + if (indices[bIndex] === 0) { + if (bx === 0) leftSkirtIndices.push(numVertices); else if (bx === max) rightSkirtIndices.push(numVertices); @@ -212,10 +212,10 @@ class Tile { bottomSkirtIndices.push(numVertices); else if (by === max) topSkirtIndices.push(numVertices); - indices[bIndex] = ++numVertices; + indices[bIndex] = ++numVertices; } - if (indices[cIndex]===0) { - if (cx === 0) + if (indices[cIndex] === 0) { + if (cx === 0) leftSkirtIndices.push(numVertices); else if (cx === max) rightSkirtIndices.push(numVertices); @@ -223,7 +223,7 @@ class Tile { bottomSkirtIndices.push(numVertices); else if (cy === max) topSkirtIndices.push(numVertices); - indices[cIndex] = ++numVertices; + indices[cIndex] = ++numVertices; } numTriangles++; } @@ -232,21 +232,21 @@ class Tile { countElements(max, max, 0, 0, 0, max); const numTotalVertices = ( - numVertices - + leftSkirtIndices.length - + rightSkirtIndices.length - + bottomSkirtIndices.length - + topSkirtIndices.length) * 2; + numVertices + + leftSkirtIndices.length + + rightSkirtIndices.length + + bottomSkirtIndices.length + + topSkirtIndices.length) * 2; const numTotalTriangles = ( - numTriangles - + ((leftSkirtIndices.length - 1) * 2) - + ((rightSkirtIndices.length - 1) * 2) - + ((bottomSkirtIndices.length - 1) * 2) - + ((topSkirtIndices.length - 1) * 2)) * 3; + numTriangles + + ((leftSkirtIndices.length - 1) * 2) + + ((rightSkirtIndices.length - 1) * 2) + + ((bottomSkirtIndices.length - 1) * 2) + + ((topSkirtIndices.length - 1) * 2)) * 3; const vertices = new Uint16Array(numTotalVertices); const triangles = new Uint32Array(numTotalTriangles); - + let triIndex = 0; function processTriangle(ax, ay, bx, by, cx, cy) { const mx = (ax + bx) >> 1; @@ -270,56 +270,48 @@ class Tile { vertices[2 * b + 1] = by; vertices[2 * c] = cx; - vertices[2 * c + 1] = cy; + vertices[2 * c + 1] = cy; triangles[triIndex++] = a; triangles[triIndex++] = b; triangles[triIndex++] = c; } } - processTriangle(0, 0, max, max, max, 0); - processTriangle(max, max, 0, 0, 0, max); + processTriangle(0, 0, max, max, max, 0); + processTriangle(max, max, 0, 0, 0, max); // Sort skirt indices to create adjacent triangles - leftSkirtIndices.sort( (a, b) => { - return vertices[2 * a + 1] - vertices[2 * b + 1]; - }) + leftSkirtIndices.sort((a, b) => vertices[2 * a + 1] - vertices[2 * b + 1]); - rightSkirtIndices.sort( (a, b) => { - // Reverse (b - a) to match triangle winding - return vertices[2 * b + 1] - vertices[2 * a + 1]; - }) + // Reverse (b - a) to match triangle winding + rightSkirtIndices.sort((a, b) => vertices[2 * b + 1] - vertices[2 * a + 1]); - bottomSkirtIndices.sort( (a, b) => { - return vertices[2 * b] - vertices[2 * a]; - }) + bottomSkirtIndices.sort((a, b) => vertices[2 * b] - vertices[2 * a]); - topSkirtIndices.sort( (a, b) => { - // Reverse (b - a) to match triangle winding - return vertices[2 * a] - vertices[2 * b]; - }) + // Reverse (b - a) to match triangle winding + topSkirtIndices.sort((a, b) => vertices[2 * a] - vertices[2 * b]); let skirtIndex = numVertices * 2; let currIndex, nextIndex, currentSkirt, nextSkirt, skirtLength = 0; - + // Add skirt vertices from index of last mesh vertex function constructSkirt(skirt) { skirtLength = skirt.length; // Loop through indices in groups of two to generate triangles - for (var i = 0; i < skirtLength - 1; i++) { + for (let i = 0; i < skirtLength - 1; i++) { currIndex = skirt[i]; nextIndex = skirt[i + 1]; - currentSkirt = skirtIndex/2; - nextSkirt = (skirtIndex + 2)/2; + currentSkirt = skirtIndex / 2; + nextSkirt = (skirtIndex + 2) / 2; vertices[skirtIndex++] = vertices[2 * currIndex]; vertices[skirtIndex++] = vertices[2 * currIndex + 1]; triangles[triIndex++] = currIndex; - triangles[triIndex++] = currentSkirt; - triangles[triIndex++] = nextIndex; - + triangles[triIndex++] = currentSkirt; + triangles[triIndex++] = nextIndex; + triangles[triIndex++] = currentSkirt; triangles[triIndex++] = nextSkirt; - triangles[triIndex++] = nextIndex; + triangles[triIndex++] = nextIndex; } // Add vertices of last skirt not added above (i < skirtLength - 1) vertices[skirtIndex++] = vertices[2 * skirt[skirtLength - 1]];