From f9c1bcf113003f9c8d400fc921fa885a8213f448 Mon Sep 17 00:00:00 2001 From: Kevin Nowaczyk Date: Wed, 15 May 2024 08:11:33 -0400 Subject: [PATCH] Longest side (#50) * created tests * simplified findlongestside function --- src/extras/BuildingShapeUtils.js | 60 +++++++++++++------------------- test/utils.test.js | 32 +++++++++++++---- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/extras/BuildingShapeUtils.js b/src/extras/BuildingShapeUtils.js index 7ce3afe..c0f889a 100644 --- a/src/extras/BuildingShapeUtils.js +++ b/src/extras/BuildingShapeUtils.js @@ -195,6 +195,10 @@ class BuildingShapeUtils extends ShapeUtils { /** * Calculate the length of each of a shape's edge + * + * @param {THREE.Shape} shape - the shape + * + * @return {[number, ...]} the esge lwngths. */ static edgeLength(shape) { const points = shape.extractPoints().shape; @@ -240,6 +244,10 @@ class BuildingShapeUtils extends ShapeUtils { /** * Calculate the angle of each of a shape's edge + * + * @param {THREE.Shape} shape - the shape + * + * @return {[number, ...]} the angles in radians. */ static edgeDirection(shape) { const points = shape.extractPoints().shape; @@ -251,6 +259,9 @@ class BuildingShapeUtils extends ShapeUtils { p2 = points[i + 1]; angles.push(Math.atan((p2.y - p1.y) / (p2.x - p1.x))); } + p1 = points[points.length - 1]; + p2 = points[0]; + angles.push(Math.atan((p2.y - p1.y) / (p2.x - p1.x))); return angles; } @@ -298,45 +309,24 @@ class BuildingShapeUtils extends ShapeUtils { * @return {number} */ static longestSideAngle(shape) { - const newVecs = []; - const newShape = new Shape(); const vecs = shape.extractPoints().shape; - var p0 = vecs[vecs.length - 2]; - var p1; - var p2; - for (let i = 0; i < vecs.length - 1; i++) { - p1 = vecs[i]; - p2 = vecs[i + 1]; - // Calculate angle - const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x) - Math.atan2(p0.y - p1.y, p0.x - p1.x); - - // Discard the point if within half a degree of 180. - if (Math.abs(angle - Math.PI) > Math.PI / 360 / 2 ) { - newVecs.push(p1); + const lengths = BuildingShapeUtils.edgeLength(shape); + const directions = BuildingShapeUtils.edgeDirection(shape); + var index; + var maxLength = 0; + for (let i = 0; i < lengths.length; i++) { + if (lengths[i] > maxLength) { + index = i; + maxLength = lengths[i]; } - p0 = p1; } - if (newVecs.length > 0) { - // convert newVecs into newShape - newShape.setFromPoints(newVecs); - const lengths = BuildingShapeUtils.edgeLength(newShape); - const directions = BuildingShapeUtils.edgeDirection(newShape); - var index; - var maxLength = 0; - for (let i = 0; i < lengths.length; i++) { - if (lengths[i] > maxLength) { - index = i; - maxLength = lengths[i]; - } - } - var angle = directions[index]; - const extents = BuildingShapeUtils.extents(newShape, Math.PI * 2 - angle); - // If the shape is taller than it is wide after rotation, we are off by 90 degrees. - if ((extents[3] - extents[1]) > (extents[2] - extents[0])) { - angle = angle > Math.PI / 2 ? angle - Math.PI / 2 : angle + Math.PI / 2; - } - return angle; + var angle = directions[index]; + const extents = BuildingShapeUtils.extents(shape, -angle); + // If the shape is taller than it is wide after rotation, we are off by 90 degrees. + if ((extents[3] - extents[1]) > (extents[2] - extents[0])) { + angle = angle > 0 ? angle - Math.PI / 2 : angle + Math.PI / 2; } + return angle; } } export {BuildingShapeUtils}; diff --git a/test/utils.test.js b/test/utils.test.js index 1c4c4e6..f4fee52 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -51,13 +51,31 @@ test('Test combining 2 ways', () => { expect(result[0].outerHTML).toBe(way3); }); -test('Extents no rotation', () => { - const shape = new Shape(); - shape.moveTo(1, 1); - shape.lineTo(1, -1); - shape.lineTo(-1, 1); - expect(BuildingShapeUtils.extents(shape)).toStrictEqual([-1, -1, 1, 1]); +const rightTriangle = new Shape(); +rightTriangle.moveTo(1, 1); +rightTriangle.lineTo(1, -1); +rightTriangle.lineTo(-1, 1); + +test('Extents no Rotation', () => { + expect(BuildingShapeUtils.extents(rightTriangle)).toStrictEqual([-1, -1, 1, 1]); +}); + +test('Extents Rotation', () => { const angle = 45 / 360 * 2 * 3.1415926535; const sqrt2 = Math.sqrt(2); - expect(BuildingShapeUtils.extents(shape, angle)).toBeDeepCloseTo([-sqrt2, 0, sqrt2, sqrt2], 10); + expect(BuildingShapeUtils.extents(rightTriangle, angle)).toBeDeepCloseTo([-sqrt2, 0, sqrt2, sqrt2], 10); +}); + +test('Edge Lengths', () => { + expect(BuildingShapeUtils.edgeLength(rightTriangle)).toBeDeepCloseTo([2, Math.sqrt(2) * 2, 2]); +}); + +test('Edge Direction', () => { + expect(BuildingShapeUtils.edgeDirection(rightTriangle)).toBeDeepCloseTo([-Math.PI / 2, -Math.PI / 4, 0]); +}); + +test('Longest side angle', () => { + // A three.Shape object does not repeat the fist and last nodes. + expect(rightTriangle.extractPoints().shape.length).toBe(3); + expect(BuildingShapeUtils.longestSideAngle(rightTriangle)).toBe(-Math.PI / 4); });