From 7ce5950963068f4a797da805f895842adad38a3e Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 29 Jan 2014 20:18:32 +0000 Subject: [PATCH] Added ball generation from support points in 3D. This can be used for applying Emo Welzl smallest enclosing ball algorithm in the Euclidean 3D case. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1562571 13f79535-47bb-0310-9956-ffa450edef68 --- .../euclidean/threed/SphereGenerator.java | 154 ++++++++++++++++++ .../euclidean/twod/BallGenerator.java | 69 -------- .../euclidean/twod/DiskGenerator.java | 107 ++++++++++++ .../euclidean/threed/SphereGeneratorTest.java | 153 +++++++++++++++++ .../euclidean/twod/BallGeneratorTest.java | 96 ----------- .../euclidean/twod/DiskGeneratorTest.java | 118 ++++++++++++++ 6 files changed, 532 insertions(+), 165 deletions(-) create mode 100644 src/main/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGenerator.java delete mode 100644 src/main/java/org/apache/commons/math3/geometry/euclidean/twod/BallGenerator.java create mode 100644 src/main/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGenerator.java create mode 100644 src/test/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGeneratorTest.java delete mode 100644 src/test/java/org/apache/commons/math3/geometry/euclidean/twod/BallGeneratorTest.java create mode 100644 src/test/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGeneratorTest.java diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGenerator.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGenerator.java new file mode 100644 index 000000000..03e445089 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGenerator.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.geometry.euclidean.threed; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.math3.geometry.enclosing.EnclosingBall; +import org.apache.commons.math3.geometry.enclosing.SupportBallGenerator; +import org.apache.commons.math3.geometry.euclidean.twod.DiskGenerator; +import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; +import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; +import org.apache.commons.math3.util.MathArrays; + +/** Class generating an enclosing ball from its support points. + * @version $Id$ + * @since 3.3 + */ +public class SphereGenerator implements SupportBallGenerator { + + /** {@inheritDoc} */ + public EnclosingBall ballOnSupport(final List support) { + + if (support.size() < 1) { + return new EnclosingBall(Vector3D.ZERO, -1.0); + } else { + final Vector3D vA = support.get(0); + if (support.size() < 2) { + return new EnclosingBall(vA, 0, vA); + } else { + final Vector3D vB = support.get(1); + if (support.size() < 3) { + return new EnclosingBall(new Vector3D(0.5, vA, 0.5, vB), + 0.5 * vA.distance(vB), + vA, vB); + } else { + final Vector3D vC = support.get(2); + if (support.size() < 4) { + + // delegate to 2D disk generator + final Plane p = new Plane(vA, vB, vC, + 1.0e-10 * (vA.getNorm1() + vB.getNorm1() + vC.getNorm1())); + final EnclosingBall disk = + new DiskGenerator().ballOnSupport(Arrays.asList(p.toSubSpace(vA), + p.toSubSpace(vB), + p.toSubSpace(vC))); + + // convert back to 3D + return new EnclosingBall(p.toSpace(disk.getCenter()), + disk.getRadius(), vA, vB, vC); + + } else { + final Vector3D vD = support.get(3); + // a sphere is 3D can be defined as: + // (1) (x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 = r^2 + // which can be written: + // (2) (x^2 + y^2 + z^2) - 2 x_0 x - 2 y_0 y - 2 z_0 z + (x_0^2 + y_0^2 + z_0^2 - r^2) = 0 + // or simply: + // (3) (x^2 + y^2 + z^2) + a x + b y + c z + d = 0 + // with sphere center coordinates -a/2, -b/2, -c/2 + // If the sphere exists, a b, c and d are a non zero solution to + // [ (x^2 + y^2 + z^2) x y z 1 ] [ 1 ] [ 0 ] + // [ (xA^2 + yA^2 + zA^2) xA yA zA 1 ] [ a ] [ 0 ] + // [ (xB^2 + yB^2 + zB^2) xB yB zB 1 ] * [ b ] = [ 0 ] + // [ (xC^2 + yC^2 + zC^2) xC yC zC 1 ] [ c ] [ 0 ] + // [ (xD^2 + yD^2 + zD^2) xD yD zD 1 ] [ d ] [ 0 ] + // So the determinant of the matrix is zero. Computing this determinant + // by expanding it using the minors m_ij of first row leads to + // (4) m_11 (x^2 + y^2 + z^2) - m_12 x + m_13 y - m_14 z + m_15 = 0 + // So by identifying equations (2) and (4) we get the coordinates + // of center as: + // x_0 = +m_12 / (2 m_11) + // y_0 = -m_13 / (2 m_11) + // z_0 = +m_14 / (2 m_11) + // Note that the minors m_11, m_12, m_13 and m_14 all have the last column + // filled with 1.0, hence simplifying the computation + final double[] c1 = new double[] { + vA.getNormSq(), vB.getNormSq(), vC.getNormSq(), vD.getNormSq() + }; + final double[] c2 = new double[] { + vA.getX(), vB.getX(), vC.getX(), vD.getX() + }; + final double[] c3 = new double[] { + vA.getY(), vB.getY(), vC.getY(), vD.getY() + }; + final double[] c4 = new double[] { + vA.getZ(), vB.getZ(), vC.getZ(), vD.getZ() + }; + final double m11 = minor(c2, c3, c4); + final double m12 = minor(c1, c3, c4); + final double m13 = minor(c1, c2, c4); + final double m14 = minor(c1, c2, c3); + final Vector3D center = new Vector3D(0.5 * m12 / m11, -0.5 * m13 / m11, 0.5 * m14 / m11); + return new EnclosingBall(center, center.distance(vA), + vA, vB, vC, vD); + } + } + } + } + } + + /** Compute a dimension 4 minor, when 4th column is known to be filled with 1.0. + *

+ * The computation is performed using {@link MathArrays#linearCombination(double[], double[]) + * high accuracy sum of products}, trying to avoid cancellations effect. This should reduce + * risks in case of near co-planar points. + *

+ * @param c1 first column + * @param c2 second column + * @param c3 third column + * @return value of the minor computed to high accuracy + */ + private double minor(final double[] c1, final double[] c2, final double[] c3) { + final double m01 = c2[0] * c3[1]; + final double m02 = c2[0] * c3[2]; + final double m03 = c2[0] * c3[3]; + final double m10 = c2[1] * c3[0]; + final double m12 = c2[1] * c3[2]; + final double m13 = c2[1] * c3[3]; + final double m20 = c2[2] * c3[0]; + final double m21 = c2[2] * c3[1]; + final double m23 = c2[2] * c3[3]; + final double m30 = c2[3] * c3[0]; + final double m31 = c2[3] * c3[1]; + final double m32 = c2[3] * c3[2]; + return MathArrays.linearCombination(new double[] { + c1[2], c1[1], c1[3], -c1[1], -c1[3], -c1[2], + c1[0], c1[3], c1[2], -c1[3], -c1[0], -c1[2], + c1[1], c1[0], c1[3], -c1[0], -c1[3], -c1[1], + c1[0], c1[2], c1[1], -c1[2], -c1[0], -c1[1] + }, + new double[] { + m13, m32, m21, m23, m12, m31, + m23, m02, m30, m20, m32, m03, + m03, m31, m10, m13, m01, m30, + m12, m01, m20, m10, m21, m02 + }); + } + +} diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/BallGenerator.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/BallGenerator.java deleted file mode 100644 index a0c30dd14..000000000 --- a/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/BallGenerator.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math3.geometry.euclidean.twod; - -import java.util.List; - -import org.apache.commons.math3.geometry.enclosing.EnclosingBall; -import org.apache.commons.math3.geometry.enclosing.SupportBallGenerator; -import org.apache.commons.math3.util.MathArrays; - -/** Class generating an enclosing ball from its support points. - * @version $Id$ - * @since 3.3 - */ -public class BallGenerator implements SupportBallGenerator { - - /** {@inheritDoc} */ - public EnclosingBall ballOnSupport(final List support) { - - if (support.size() < 1) { - return new EnclosingBall(Vector2D.ZERO, -1.0); - } else { - final Vector2D vA = support.get(0); - if (support.size() < 2) { - return new EnclosingBall(vA, 0, vA); - } else { - final Vector2D vB = support.get(1); - if (support.size() < 3) { - return new EnclosingBall(new Vector2D(0.5, vA, 0.5, vB), - 0.5 * vA.distance(vB), - vA, vB); - } else { - final Vector2D vC = support.get(2); - final Vector2D bc = vB.subtract(vC); - final Vector2D ca = vC.subtract(vA); - final Vector2D ab = vA.subtract(vB); - final double vA2 = vA.getNormSq(); - final double vB2 = vB.getNormSq(); - final double vC2 = vC.getNormSq(); - final double d = 2 * MathArrays.linearCombination(vA.getX(), bc.getY(), - vB.getX(), ca.getY(), - vC.getX(), ab.getY()); - final Vector2D center = new Vector2D( MathArrays.linearCombination(vA2, bc.getY(), - vB2, ca.getY(), - vC2, ab.getY()) / d, - -MathArrays.linearCombination(vA2, bc.getX(), - vB2, ca.getX(), - vC2, ab.getX()) / d); - return new EnclosingBall(center, center.distance(vA), vA, vB, vC); - } - } - } - } - -} diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGenerator.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGenerator.java new file mode 100644 index 000000000..514df1458 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGenerator.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.geometry.euclidean.twod; + +import java.util.List; + +import org.apache.commons.math3.geometry.enclosing.EnclosingBall; +import org.apache.commons.math3.geometry.enclosing.SupportBallGenerator; +import org.apache.commons.math3.util.MathArrays; + +/** Class generating an enclosing ball from its support points. + * @version $Id$ + * @since 3.3 + */ +public class DiskGenerator implements SupportBallGenerator { + + /** {@inheritDoc} */ + public EnclosingBall ballOnSupport(final List support) { + + if (support.size() < 1) { + return new EnclosingBall(Vector2D.ZERO, -1.0); + } else { + final Vector2D vA = support.get(0); + if (support.size() < 2) { + return new EnclosingBall(vA, 0, vA); + } else { + final Vector2D vB = support.get(1); + if (support.size() < 3) { + return new EnclosingBall(new Vector2D(0.5, vA, 0.5, vB), + 0.5 * vA.distance(vB), + vA, vB); + } else { + final Vector2D vC = support.get(2); + // a disk is 2D can be defined as: + // (1) (x - x_0)^2 + (y - y_0)^2 = r^2 + // which can be written: + // (2) (x^2 + y^2) - 2 x_0 x - 2 y_0 y + (x_0^2 + y_0^2 - r^2) = 0 + // or simply: + // (3) (x^2 + y^2) + a x + b y + c= 0 + // with disk center coordinates -a/2, -b/2 + // If the sphere exists, a, b and c are a non zero solution to + // [ (x^2 + y^2 ) x y 1 ] [ 1 ] [ 0 ] + // [ (xA^2 + yA^2) xA yA 1 ] [ a ] [ 0 ] + // [ (xB^2 + yB^2) xB yB 1 ] * [ b ] = [ 0 ] + // [ (xC^2 + yC^2) xC yC 1 ] [ c ] [ 0 ] + // So the determinant of the matrix is zero. Computing this determinant + // by expanding it using the minors m_ij of first row leads to + // (4) m_11 (x^2 + y^2) - m_12 x + m_13 y - m_14 = 0 + // So by identifying equations (2) and (4) we get the coordinates + // of center as: + // x_0 = +m_12 / (2 m_11) + // y_0 = -m_13 / (2 m_11) + // Note that the minors m_11, m_12 and m_13 all have the last column + // filled with 1.0, hence simplifying the computation + final double[] c1 = new double[] { + vA.getNormSq(), vB.getNormSq(), vC.getNormSq() + }; + final double[] c2 = new double[] { + vA.getX(), vB.getX(), vC.getX() + }; + final double[] c3 = new double[] { + vA.getY(), vB.getY(), vC.getY() + }; + final double m11 = minor(c2, c3); + final double m12 = minor(c1, c3); + final double m13 = minor(c1, c2); + final Vector2D center = new Vector2D(0.5 * m12 / m11, -0.5 * m13 / m11); + return new EnclosingBall(center, center.distance(vA), vA, vB, vC); + } + } + } + } + + /** Compute a dimension 3 minor, when 3d column is known to be filled with 1.0. + *

+ * The computation is performed using {@link MathArrays#linearCombination(double[], double[]) + * high accuracy sum of products}, trying to avoid cancellations effect. This should reduce + * risks in case of near co-planar points. + *

+ * @param c1 first column + * @param c2 second column + * @return value of the minor computed to high accuracy + */ + private double minor(final double[] c1, final double[] c2) { + return MathArrays.linearCombination(new double[] { + c1[0], c1[2], c1[1], -c1[2], -c1[0], -c1[1] + }, + new double[] { + c2[1], c2[0], c2[2], c2[1], c2[2], c2[0] + }); + } + +} diff --git a/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGeneratorTest.java b/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGeneratorTest.java new file mode 100644 index 000000000..877d7d415 --- /dev/null +++ b/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/SphereGeneratorTest.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.geometry.euclidean.threed; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.math3.geometry.enclosing.EnclosingBall; +import org.apache.commons.math3.random.RandomGenerator; +import org.apache.commons.math3.random.UnitSphereRandomVectorGenerator; +import org.apache.commons.math3.random.Well1024a; +import org.junit.Assert; +import org.junit.Test; + + +public class SphereGeneratorTest { + + @Test + public void testSupport0Point() { + List support = Arrays.asList(new Vector3D[0]); + EnclosingBall sphere = new SphereGenerator().ballOnSupport(support); + Assert.assertTrue(sphere.getRadius() < 0); + Assert.assertEquals(0, sphere.getSupportSize()); + Assert.assertEquals(0, sphere.getSupport().length); + } + + @Test + public void testSupport1Point() { + List support = Arrays.asList(new Vector3D(1, 2, 3)); + EnclosingBall sphere = new SphereGenerator().ballOnSupport(support); + Assert.assertEquals(0.0, sphere.getRadius(), 1.0e-10); + Assert.assertTrue(sphere.contains(support.get(0))); + Assert.assertTrue(sphere.contains(support.get(0), 0.5)); + Assert.assertFalse(sphere.contains(new Vector3D(support.get(0).getX() + 0.1, + support.get(0).getY() + 0.1, + support.get(0).getZ() + 0.1), + 0.001)); + Assert.assertTrue(sphere.contains(new Vector3D(support.get(0).getX() + 0.1, + support.get(0).getY() + 0.1, + support.get(0).getZ() + 0.1), + 0.5)); + Assert.assertEquals(0, support.get(0).distance(sphere.getCenter()), 1.0e-10); + Assert.assertEquals(1, sphere.getSupportSize()); + Assert.assertTrue(support.get(0) == sphere.getSupport()[0]); + } + + @Test + public void testSupport2Points() { + List support = Arrays.asList(new Vector3D(1, 0, 0), + new Vector3D(3, 0, 0)); + EnclosingBall sphere = new SphereGenerator().ballOnSupport(support); + Assert.assertEquals(1.0, sphere.getRadius(), 1.0e-10); + int i = 0; + for (Vector3D v : support) { + Assert.assertTrue(sphere.contains(v)); + Assert.assertEquals(1.0, v.distance(sphere.getCenter()), 1.0e-10); + Assert.assertTrue(v == sphere.getSupport()[i++]); + } + Assert.assertTrue(sphere.contains(new Vector3D(2, 0.9, 0))); + Assert.assertFalse(sphere.contains(Vector3D.ZERO)); + Assert.assertEquals(0.0, new Vector3D(2, 0, 0).distance(sphere.getCenter()), 1.0e-10); + Assert.assertEquals(2, sphere.getSupportSize()); + } + + @Test + public void testSupport3Points() { + List support = Arrays.asList(new Vector3D(1, 0, 0), + new Vector3D(3, 0, 0), + new Vector3D(2, 2, 0)); + EnclosingBall sphere = new SphereGenerator().ballOnSupport(support); + Assert.assertEquals(5.0 / 4.0, sphere.getRadius(), 1.0e-10); + int i = 0; + for (Vector3D v : support) { + Assert.assertTrue(sphere.contains(v)); + Assert.assertEquals(5.0 / 4.0, v.distance(sphere.getCenter()), 1.0e-10); + Assert.assertTrue(v == sphere.getSupport()[i++]); + } + Assert.assertTrue(sphere.contains(new Vector3D(2, 0.9, 0))); + Assert.assertFalse(sphere.contains(new Vector3D(0.9, 0, 0))); + Assert.assertFalse(sphere.contains(new Vector3D(3.1, 0, 0))); + Assert.assertTrue(sphere.contains(new Vector3D(2.0, -0.499, 0))); + Assert.assertFalse(sphere.contains(new Vector3D(2.0, -0.501, 0))); + Assert.assertTrue(sphere.contains(new Vector3D(2.0, 3.0 / 4.0, -1.249))); + Assert.assertFalse(sphere.contains(new Vector3D(2.0, 3.0 / 4.0, -1.251))); + Assert.assertEquals(0.0, new Vector3D(2.0, 3.0 / 4.0, 0).distance(sphere.getCenter()), 1.0e-10); + Assert.assertEquals(3, sphere.getSupportSize()); + } + + @Test + public void testSupport4Points() { + List support = Arrays.asList(new Vector3D(17, 14, 18), + new Vector3D(11, 14, 22), + new Vector3D( 2, 22, 17), + new Vector3D(22, 11, -10)); + EnclosingBall sphere = new SphereGenerator().ballOnSupport(support); + Assert.assertEquals(25.0, sphere.getRadius(), 1.0e-10); + int i = 0; + for (Vector3D v : support) { + Assert.assertTrue(sphere.contains(v)); + Assert.assertEquals(25.0, v.distance(sphere.getCenter()), 1.0e-10); + Assert.assertTrue(v == sphere.getSupport()[i++]); + } + Assert.assertTrue(sphere.contains (new Vector3D(-22.999, 2, 2))); + Assert.assertFalse(sphere.contains(new Vector3D(-23.001, 2, 2))); + Assert.assertTrue(sphere.contains (new Vector3D( 26.999, 2, 2))); + Assert.assertFalse(sphere.contains(new Vector3D( 27.001, 2, 2))); + Assert.assertTrue(sphere.contains (new Vector3D(2, -22.999, 2))); + Assert.assertFalse(sphere.contains(new Vector3D(2, -23.001, 2))); + Assert.assertTrue(sphere.contains (new Vector3D(2, 26.999, 2))); + Assert.assertFalse(sphere.contains(new Vector3D(2, 27.001, 2))); + Assert.assertTrue(sphere.contains (new Vector3D(2, 2, -22.999))); + Assert.assertFalse(sphere.contains(new Vector3D(2, 2, -23.001))); + Assert.assertTrue(sphere.contains (new Vector3D(2, 2, 26.999))); + Assert.assertFalse(sphere.contains(new Vector3D(2, 2, 27.001))); + Assert.assertEquals(0.0, new Vector3D(2.0, 2.0, 2.0).distance(sphere.getCenter()), 1.0e-10); + Assert.assertEquals(4, sphere.getSupportSize()); + } + + @Test + public void testRandom() { + final RandomGenerator random = new Well1024a(0xd015982e9f31ee04l); + final UnitSphereRandomVectorGenerator sr = new UnitSphereRandomVectorGenerator(3, random); + for (int i = 0; i < 500; ++i) { + double d = 25 * random.nextDouble(); + double refRadius = 10 * random.nextDouble(); + Vector3D refCenter = new Vector3D(d, new Vector3D(sr.nextVector())); + List support = new ArrayList(); + for (int j = 0; j < 5; ++j) { + support.add(new Vector3D(1.0, refCenter, refRadius, new Vector3D(sr.nextVector()))); + } + EnclosingBall sphere = new SphereGenerator().ballOnSupport(support); + Assert.assertEquals(0.0, refCenter.distance(sphere.getCenter()), 4e-7 * refRadius); + Assert.assertEquals(refRadius, sphere.getRadius(), 1e-7 * refRadius); + } + + } + +} diff --git a/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/BallGeneratorTest.java b/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/BallGeneratorTest.java deleted file mode 100644 index 688ad6e82..000000000 --- a/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/BallGeneratorTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math3.geometry.euclidean.twod; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.math3.geometry.enclosing.EnclosingBall; -import org.junit.Assert; -import org.junit.Test; - - -public class BallGeneratorTest { - - @Test - public void testSupport0Point() { - List support = Arrays.asList(new Vector2D[0]); - EnclosingBall ball = new BallGenerator().ballOnSupport(support); - Assert.assertTrue(ball.getRadius() < 0); - Assert.assertEquals(0, ball.getSupportSize()); - Assert.assertEquals(0, ball.getSupport().length); - } - - @Test - public void testSupport1Point() { - List support = Arrays.asList(new Vector2D(1, 2)); - EnclosingBall ball = new BallGenerator().ballOnSupport(support); - Assert.assertEquals(0.0, ball.getRadius(), 1.0e-10); - Assert.assertTrue(ball.contains(support.get(0))); - Assert.assertTrue(ball.contains(support.get(0), 0.5)); - Assert.assertFalse(ball.contains(new Vector2D(support.get(0).getX() + 0.1, - support.get(0).getY() - 0.1), - 0.001)); - Assert.assertTrue(ball.contains(new Vector2D(support.get(0).getX() + 0.1, - support.get(0).getY() - 0.1), - 0.5)); - Assert.assertEquals(0, support.get(0).distance(ball.getCenter()), 1.0e-10); - Assert.assertEquals(1, ball.getSupportSize()); - Assert.assertTrue(support.get(0) == ball.getSupport()[0]); - } - - @Test - public void testSupport2Points() { - List support = Arrays.asList(new Vector2D(1, 0), - new Vector2D(3, 0)); - EnclosingBall ball = new BallGenerator().ballOnSupport(support); - Assert.assertEquals(1.0, ball.getRadius(), 1.0e-10); - int i = 0; - for (Vector2D v : support) { - Assert.assertTrue(ball.contains(v)); - Assert.assertEquals(1.0, v.distance(ball.getCenter()), 1.0e-10); - Assert.assertTrue(v == ball.getSupport()[i++]); - } - Assert.assertTrue(ball.contains(new Vector2D(2, 0.9))); - Assert.assertFalse(ball.contains(Vector2D.ZERO)); - Assert.assertEquals(0.0, new Vector2D(2, 0).distance(ball.getCenter()), 1.0e-10); - Assert.assertEquals(2, ball.getSupportSize()); - } - - @Test - public void testSupport3Points() { - List support = Arrays.asList(new Vector2D(1, 0), - new Vector2D(3, 0), - new Vector2D(2, 2)); - EnclosingBall ball = new BallGenerator().ballOnSupport(support); - Assert.assertEquals(5.0 / 4.0, ball.getRadius(), 1.0e-10); - int i = 0; - for (Vector2D v : support) { - Assert.assertTrue(ball.contains(v)); - Assert.assertEquals(5.0 / 4.0, v.distance(ball.getCenter()), 1.0e-10); - Assert.assertTrue(v == ball.getSupport()[i++]); - } - Assert.assertTrue(ball.contains(new Vector2D(2, 0.9))); - Assert.assertFalse(ball.contains(new Vector2D(0.9, 0))); - Assert.assertFalse(ball.contains(new Vector2D(3.1, 0))); - Assert.assertTrue(ball.contains(new Vector2D(2.0, -0.499))); - Assert.assertFalse(ball.contains(new Vector2D(2.0, -0.501))); - Assert.assertEquals(0.0, new Vector2D(2.0, 3.0 / 4.0).distance(ball.getCenter()), 1.0e-10); - Assert.assertEquals(3, ball.getSupportSize()); - } - -} diff --git a/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGeneratorTest.java b/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGeneratorTest.java new file mode 100644 index 000000000..f4452fbfc --- /dev/null +++ b/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/DiskGeneratorTest.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.geometry.euclidean.twod; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.math3.geometry.enclosing.EnclosingBall; +import org.apache.commons.math3.random.RandomGenerator; +import org.apache.commons.math3.random.UnitSphereRandomVectorGenerator; +import org.apache.commons.math3.random.Well1024a; +import org.junit.Assert; +import org.junit.Test; + + +public class DiskGeneratorTest { + + @Test + public void testSupport0Point() { + List support = Arrays.asList(new Vector2D[0]); + EnclosingBall disk = new DiskGenerator().ballOnSupport(support); + Assert.assertTrue(disk.getRadius() < 0); + Assert.assertEquals(0, disk.getSupportSize()); + Assert.assertEquals(0, disk.getSupport().length); + } + + @Test + public void testSupport1Point() { + List support = Arrays.asList(new Vector2D(1, 2)); + EnclosingBall disk = new DiskGenerator().ballOnSupport(support); + Assert.assertEquals(0.0, disk.getRadius(), 1.0e-10); + Assert.assertTrue(disk.contains(support.get(0))); + Assert.assertTrue(disk.contains(support.get(0), 0.5)); + Assert.assertFalse(disk.contains(new Vector2D(support.get(0).getX() + 0.1, + support.get(0).getY() - 0.1), + 0.001)); + Assert.assertTrue(disk.contains(new Vector2D(support.get(0).getX() + 0.1, + support.get(0).getY() - 0.1), + 0.5)); + Assert.assertEquals(0, support.get(0).distance(disk.getCenter()), 1.0e-10); + Assert.assertEquals(1, disk.getSupportSize()); + Assert.assertTrue(support.get(0) == disk.getSupport()[0]); + } + + @Test + public void testSupport2Points() { + List support = Arrays.asList(new Vector2D(1, 0), + new Vector2D(3, 0)); + EnclosingBall disk = new DiskGenerator().ballOnSupport(support); + Assert.assertEquals(1.0, disk.getRadius(), 1.0e-10); + int i = 0; + for (Vector2D v : support) { + Assert.assertTrue(disk.contains(v)); + Assert.assertEquals(1.0, v.distance(disk.getCenter()), 1.0e-10); + Assert.assertTrue(v == disk.getSupport()[i++]); + } + Assert.assertTrue(disk.contains(new Vector2D(2, 0.9))); + Assert.assertFalse(disk.contains(Vector2D.ZERO)); + Assert.assertEquals(0.0, new Vector2D(2, 0).distance(disk.getCenter()), 1.0e-10); + Assert.assertEquals(2, disk.getSupportSize()); + } + + @Test + public void testSupport3Points() { + List support = Arrays.asList(new Vector2D(1, 0), + new Vector2D(3, 0), + new Vector2D(2, 2)); + EnclosingBall disk = new DiskGenerator().ballOnSupport(support); + Assert.assertEquals(5.0 / 4.0, disk.getRadius(), 1.0e-10); + int i = 0; + for (Vector2D v : support) { + Assert.assertTrue(disk.contains(v)); + Assert.assertEquals(5.0 / 4.0, v.distance(disk.getCenter()), 1.0e-10); + Assert.assertTrue(v == disk.getSupport()[i++]); + } + Assert.assertTrue(disk.contains(new Vector2D(2, 0.9))); + Assert.assertFalse(disk.contains(new Vector2D(0.9, 0))); + Assert.assertFalse(disk.contains(new Vector2D(3.1, 0))); + Assert.assertTrue(disk.contains(new Vector2D(2.0, -0.499))); + Assert.assertFalse(disk.contains(new Vector2D(2.0, -0.501))); + Assert.assertEquals(0.0, new Vector2D(2.0, 3.0 / 4.0).distance(disk.getCenter()), 1.0e-10); + Assert.assertEquals(3, disk.getSupportSize()); + } + + @Test + public void testRandom() { + final RandomGenerator random = new Well1024a(0x12faa818373ffe90l); + final UnitSphereRandomVectorGenerator sr = new UnitSphereRandomVectorGenerator(2, random); + for (int i = 0; i < 500; ++i) { + double d = 25 * random.nextDouble(); + double refRadius = 10 * random.nextDouble(); + Vector2D refCenter = new Vector2D(d, new Vector2D(sr.nextVector())); + List support = new ArrayList(); + for (int j = 0; j < 4; ++j) { + support.add(new Vector2D(1.0, refCenter, refRadius, new Vector2D(sr.nextVector()))); + } + EnclosingBall sphere = new DiskGenerator().ballOnSupport(support); + Assert.assertEquals(0.0, refCenter.distance(sphere.getCenter()), 3e-9 * refRadius); + Assert.assertEquals(refRadius, sphere.getRadius(), 7e-10 * refRadius); + } + + } +}