From 19f8e3c8f3f613508e7d109eee6f44327df03746 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Sat, 21 Sep 2024 04:39:47 +0100 Subject: [PATCH] Add coordinate interpolation method + improve unit tests --- .../info/openrocket/core/util/Coordinate.java | 14 ++ .../openrocket/core/util/CoordinateTest.java | 148 ++++++++++++++---- 2 files changed, 133 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/info/openrocket/core/util/Coordinate.java b/core/src/main/java/info/openrocket/core/util/Coordinate.java index 59ef7d07d..2ea26dcd1 100644 --- a/core/src/main/java/info/openrocket/core/util/Coordinate.java +++ b/core/src/main/java/info/openrocket/core/util/Coordinate.java @@ -311,6 +311,20 @@ public final class Coordinate implements Cloneable, Serializable { } return new Coordinate(x1, y1, z1, w1); } + + /** + * Interpolate between two coordinates. The fraction is the weight of the other coordinate. + * @param other Coordinate to interpolate to. + * @param fraction Interpolation fraction (0 = this, 1 = other). + * @return Interpolated coordinate. + */ + public Coordinate interpolate(Coordinate other, double fraction) { + double x1 = this.x + (other.x - this.x) * fraction; + double y1 = this.y + (other.y - this.y) * fraction; + double z1 = this.z + (other.z - this.z) * fraction; + double w1 = this.weight + (other.weight - this.weight) * fraction; + return new Coordinate(x1, y1, z1, w1); + } /** diff --git a/core/src/test/java/info/openrocket/core/util/CoordinateTest.java b/core/src/test/java/info/openrocket/core/util/CoordinateTest.java index cc797bbe0..17ede794e 100644 --- a/core/src/test/java/info/openrocket/core/util/CoordinateTest.java +++ b/core/src/test/java/info/openrocket/core/util/CoordinateTest.java @@ -9,54 +9,144 @@ public class CoordinateTest { private static final double EPS = 0.0000000001; @Test - public void coordinateTest() { + public void testConstructors() { + Coordinate c1 = new Coordinate(); + assertCoordinateEquals(new Coordinate(0, 0, 0, 0), c1); + Coordinate c2 = new Coordinate(1); + assertCoordinateEquals(new Coordinate(1, 0, 0, 0), c2); + + Coordinate c3 = new Coordinate(1, 2); + assertCoordinateEquals(new Coordinate(1, 2, 0, 0), c3); + + Coordinate c4 = new Coordinate(1, 2, 3); + assertCoordinateEquals(new Coordinate(1, 2, 3, 0), c4); + + Coordinate c5 = new Coordinate(1, 2, 3, 4); + assertCoordinateEquals(new Coordinate(1, 2, 3, 4), c5); + } + + @Test + public void testSetters() { Coordinate x = new Coordinate(1, 1, 1, 1); - Coordinate y = new Coordinate(1, 2, 3, 4); assertCoordinateEquals(new Coordinate(2, 1, 1, 1), x.setX(2)); assertCoordinateEquals(new Coordinate(1, 2, 1, 1), x.setY(2)); assertCoordinateEquals(new Coordinate(1, 1, 2, 1), x.setZ(2)); assertCoordinateEquals(new Coordinate(1, 1, 1, 2), x.setWeight(2)); - assertCoordinateEquals(new Coordinate(2, 3, 4, 1), x.setXYZ(y).add(1, 1, 1)); - assertFalse(x.isNaN()); - assertTrue(x.setX(Double.NaN).isNaN()); + Coordinate y = new Coordinate(1, 2, 3, 4); + assertCoordinateEquals(new Coordinate(1, 2, 3, 1), x.setXYZ(y)); + } + + @Test + public void testIsWeighted() { + assertTrue(new Coordinate(1, 1, 1, 1).isWeighted()); + assertFalse(new Coordinate(1, 1, 1, 0).isWeighted()); + } + + @Test + public void testIsNaN() { + assertFalse(new Coordinate(1, 1, 1, 1).isNaN()); + assertTrue(new Coordinate(Double.NaN, 1, 1, 1).isNaN()); + assertTrue(new Coordinate(1, Double.NaN, 1, 1).isNaN()); + assertTrue(new Coordinate(1, 1, Double.NaN, 1).isNaN()); + assertTrue(new Coordinate(1, 1, 1, Double.NaN).isNaN()); assertTrue(Coordinate.NaN.isNaN()); + } - assertTrue(x.isWeighted()); - assertFalse(x.setWeight(0).isWeighted()); + @Test + public void testAdd() { + Coordinate x = new Coordinate(1, 1, 1, 1); + Coordinate y = new Coordinate(1, 2, 3, 4); - assertCoordinateEquals(x, x.add(Coordinate.NUL)); assertCoordinateEquals(new Coordinate(2, 3, 4, 5), x.add(y)); assertCoordinateEquals(new Coordinate(2, 3, 4, 1), x.add(1, 2, 3)); assertCoordinateEquals(new Coordinate(2, 3, 4, 5), x.add(1, 2, 3, 4)); + } + + @Test + public void testSub() { + Coordinate x = new Coordinate(1, 1, 1, 1); + Coordinate y = new Coordinate(1, 2, 3, 4); assertCoordinateEquals(new Coordinate(0, -1, -2, 1), x.sub(y)); assertCoordinateEquals(new Coordinate(0, -1, -2, 1), x.sub(1, 2, 3)); - - assertCoordinateEquals(new Coordinate(2, 4, 6, 8), y.multiply(2)); - - assertEquals(1 + 2 + 3, y.dot(x), EPS); - assertEquals(1 + 2 + 3, x.dot(y), EPS); - assertEquals(1 + 2 + 3, Coordinate.dot(x, y), EPS); - assertEquals(x.dot(x), x.length2(), EPS); - assertEquals(y.dot(y), y.length2(), EPS); - assertEquals(3.7416573867739413, y.length(), EPS); - assertEquals(1, y.normalize().length(), EPS); - - assertCoordinateEquals(new Coordinate(1.75, 1.75, 1.75, 4), - new Coordinate(1, 1, 1, 1).average(new Coordinate(2, 2, 2, 3))); - assertCoordinateEquals(new Coordinate(1, 1, 1, 1), - new Coordinate(1, 1, 1, 1).average(new Coordinate(2, 2, 2, 0))); - assertCoordinateEquals(new Coordinate(1.5, 1.5, 1.5, 0), - new Coordinate(1, 1, 1, 0).average(new Coordinate(2, 2, 2, 0))); - } - private void assertCoordinateEquals(Coordinate a, Coordinate b) { - assertEquals(a, b); - assertEquals(a.weight, b.weight, EPS); + @Test + public void testMultiply() { + Coordinate x = new Coordinate(1, 2, 3, 4); + + assertCoordinateEquals(new Coordinate(2, 4, 6, 8), x.multiply(2)); + assertCoordinateEquals(new Coordinate(1, 4, 9, 16), x.multiply(x)); } + @Test + public void testDot() { + Coordinate x = new Coordinate(1, 1, 1, 1); + Coordinate y = new Coordinate(1, 2, 3, 4); + + assertEquals(6, x.dot(y), EPS); + assertEquals(6, y.dot(x), EPS); + assertEquals(6, Coordinate.dot(x, y), EPS); + } + + @Test + public void testLength() { + Coordinate x = new Coordinate(3, 4, 0, 1); + + assertEquals(5, x.length(), EPS); + assertEquals(25, x.length2(), EPS); + } + + @Test + public void testMax() { + assertEquals(3, new Coordinate(1, -2, 3, 4).max(), EPS); + } + + @Test + public void testNormalize() { + Coordinate x = new Coordinate(3, 4, 0, 2); + Coordinate normalized = x.normalize(); + + assertEquals(1, normalized.length(), EPS); + assertEquals(2, normalized.weight, EPS); + } + + @Test + public void testCross() { + Coordinate x = new Coordinate(1, 0, 0); + Coordinate y = new Coordinate(0, 1, 0); + + assertCoordinateEquals(new Coordinate(0, 0, 1), x.cross(y)); + assertCoordinateEquals(new Coordinate(0, 0, 1), Coordinate.cross(x, y)); + } + + @Test + public void testAverage() { + Coordinate x = new Coordinate(1, 2, 4, 1); + Coordinate y = new Coordinate(3, 5, 9, 1); + + assertCoordinateEquals(new Coordinate(2, 3.5, 6.5, 2), x.average(y)); + + y = new Coordinate(3, 5, 9, 3); + + assertCoordinateEquals(new Coordinate(2.5, 4.25, 7.75, 4), x.average(y)); + } + + @Test + public void testInterpolate() { + Coordinate x = new Coordinate(0, 0, 0, 0); + Coordinate y = new Coordinate(10, 10, 10, 10); + + assertCoordinateEquals(new Coordinate(5, 5, 5, 5), x.interpolate(y, 0.5)); + } + + private void assertCoordinateEquals(Coordinate expected, Coordinate actual) { + assertEquals(expected.x, actual.x, EPS); + assertEquals(expected.y, actual.y, EPS); + assertEquals(expected.z, actual.z, EPS); + assertEquals(expected.weight, actual.weight, EPS); + } }