This is an automated email from the ASF dual-hosted git repository. erans pushed a commit to branch GEOMETRY-3__TBR in repository https://gitbox.apache.org/repos/asf/commons-geometry.git
commit aaf6960e0d7ac9b9cfd616c3e8e4dedaaf080bd6 Author: Matt Juntunen <[email protected]> AuthorDate: Sat Jun 2 23:12:40 2018 -0400 GEOMETRY-3: adding euclidean parse methods; converting S1Point and S2Point to valjos; addressing some checkstyle issues --- .../core/util/AbstractCoordinateParser.java | 46 +++++--- .../commons/geometry/core/util/Coordinates.java | 30 ++--- .../geometry/core/util/SimpleCoordinateFormat.java | 61 +++++++--- .../commons/geometry/core/util/package-info.java | 23 ++++ .../core/util/SimpleCoordinateFormatTest.java | 127 ++++++++++++-------- .../commons/geometry/euclidean/oned/Point1D.java | 31 ++++- .../commons/geometry/euclidean/oned/Vector1D.java | 31 ++++- .../commons/geometry/euclidean/threed/Point3D.java | 31 ++++- .../geometry/euclidean/threed/Vector3D.java | 33 +++++- .../commons/geometry/euclidean/twod/Point2D.java | 31 ++++- .../commons/geometry/euclidean/twod/Vector2D.java | 31 ++++- .../geometry/euclidean/oned/Point1DTest.java | 32 +++++ .../geometry/euclidean/oned/Vector1DTest.java | 32 +++++ .../geometry/euclidean/threed/Point3DTest.java | 32 ++++- .../geometry/euclidean/threed/Vector3DTest.java | 33 +++++- .../geometry/euclidean/twod/Point2DTest.java | 32 ++++- .../geometry/euclidean/twod/Vector2DTest.java | 33 +++++- .../commons/geometry/spherical/oned/ArcsSet.java | 33 +++--- .../commons/geometry/spherical/oned/S1Point.java | 63 +++++++--- .../commons/geometry/spherical/package-info.java | 23 ++++ .../commons/geometry/spherical/twod/Circle.java | 7 +- .../commons/geometry/spherical/twod/Edge.java | 6 +- .../geometry/spherical/twod/EdgesBuilder.java | 4 +- .../spherical/twod/PropertiesComputer.java | 2 +- .../commons/geometry/spherical/twod/S2Point.java | 126 ++++++++++++-------- .../spherical/twod/SphericalPolygonsSet.java | 16 +-- .../geometry/spherical/SphericalTestUtils.java | 2 +- .../geometry/spherical/oned/ArcsSetTest.java | 130 ++++++++++----------- .../geometry/spherical/oned/LimitAngleTest.java | 2 +- .../geometry/spherical/oned/S1PointTest.java | 56 +++++++-- .../geometry/spherical/twod/CircleTest.java | 34 +++--- .../geometry/spherical/twod/S2PointTest.java | 67 ++++++++--- .../spherical/twod/SphericalPolygonsSetTest.java | 106 ++++++++--------- 33 files changed, 984 insertions(+), 362 deletions(-) diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java index ec906bc..ceb8527 100644 --- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java +++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/AbstractCoordinateParser.java @@ -114,7 +114,8 @@ public abstract class AbstractCoordinateParser { return value; } catch (NumberFormatException exc) { - throw new CoordinateParseException("Failed to parse number from string at index " + startIdx + ": " + substr, exc); + fail(String.format("unable to parse number from string \"%s\"", substr), str, pos, exc); + return 0.0; // for the compiler } } @@ -133,8 +134,8 @@ public abstract class AbstractCoordinateParser { } } - /** Ends a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An exception - * is thrown if extra content is found. + /** Ends a parse operation by ensuring that all non-whitespace characters in the string have been parsed. An + * exception is thrown if extra content is found. * @param str the string being parsed * @param pos the current parsing position * @throws IllegalArgumentException if extra non-whitespace content is found past the current parsing position @@ -142,7 +143,7 @@ public abstract class AbstractCoordinateParser { protected void endParse(String str, ParsePosition pos) throws IllegalArgumentException { consumeWhitespace(str, pos); if (pos.getIndex() != str.length()) { - throw new CoordinateParseException("Failed to parse string: unexpected content at index " + pos.getIndex()); + fail("unexpected content", str, pos); } } @@ -209,11 +210,35 @@ public abstract class AbstractCoordinateParser { final int idx = pos.getIndex(); final String actualSeq = str.substring(idx, Math.min(str.length(), idx + seq.length())); - throw new CoordinateParseException("Failed to parse string: expected \"" + seq + - "\" but found \"" + actualSeq + "\" at index " + idx); + fail(String.format("expected \"%s\" but found \"%s\"", seq, actualSeq), str, pos); } } + /** Aborts the current parsing operation by throwing an {@link IllegalArgumentException} with an informative + * error message. + * @param msg the error message + * @param str the string being parsed + * @param pos the current parse position + * @throws IllegalArgumentException the exception signaling a parse failure + */ + protected void fail(String msg, String str, ParsePosition pos) throws IllegalArgumentException { + fail(msg, str, pos, null); + } + + /** Aborts the current parsing operation by throwing an {@link IllegalArgumentException} with an informative + * error message. + * @param msg the error message + * @param str the string being parsed + * @param pos the current parse position + * @param cause the original cause of the error + * @throws IllegalArgumentException the exception signaling a parse failure + */ + protected void fail(String msg, String str, ParsePosition pos, Throwable cause) throws IllegalArgumentException { + String fullMsg = String.format("Failed to parse string \"%s\" at index %d: %s", str, pos.getIndex(), msg); + + throw new CoordinateParseException(fullMsg, cause); + } + /** Exception class for errors occurring during coordinate parsing. */ private static class CoordinateParseException extends IllegalArgumentException { @@ -222,17 +247,10 @@ public abstract class AbstractCoordinateParser { private static final long serialVersionUID = 1494716029613981959L; /** Simple constructor. - * @param msg the exception message. - */ - public CoordinateParseException(String msg) { - super(msg); - } - - /** Simple constructor with cause. * @param msg the exception message * @param cause the exception root cause */ - public CoordinateParseException(String msg, Throwable cause) { + CoordinateParseException(String msg, Throwable cause) { super(msg, cause); } } diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java index fcafd4f..8ea6c77 100644 --- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java +++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/Coordinates.java @@ -20,43 +20,43 @@ package org.apache.commons.geometry.core.util; */ public class Coordinates { - /** Interface for classes that create new instances of a type from a single coordinate value. + /** Interface for classes that create objects from a single coordinate value. * @param <T> The type created by this factory. */ - public static interface Factory1D<T> { + public interface Factory1D<T> { /** Creates a new instance of type T from the given coordinate value. - * @param v the first coordinate value + * @param a the coordinate value * @return a new instance of type T */ - T create(double v); + T create(double a); } - /** Interface for classes that create new instances of a type from two coordinate values. + /** Interface for classes that create objects from two coordinate values. * @param <T> The type created by this factory. */ - public static interface Factory2D<T> { + public interface Factory2D<T> { /** Creates a new instance of type T from the given coordinate values. - * @param v1 the first coordinate value - * @param v2 the second coordinate value + * @param a1 the first coordinate value + * @param a2 the second coordinate value * @return a new instance of type T */ - T create(double v1, double v2); + T create(double a1, double a2); } - /** Interface for classes that create new instances of a type from three coordinate values. + /** Interface for classes that create objects from three coordinate values. * @param <T> The type created by this factory. */ - public static interface Factory3D<T> { + public interface Factory3D<T> { /** Creates a new instance of type T from the given coordinate values. - * @param v1 the first coordinate value - * @param v2 the second coordinate value - * @param v3 the third coordinate value + * @param a1 the first coordinate value + * @param a2 the second coordinate value + * @param a3 the third coordinate value * @return a new instance of type T */ - T create(double v1, double v2, double v3); + T create(double a1, double a2, double a3); } /** Private constructor. */ diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java index fd66e45..6a4eb09 100644 --- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java +++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormat.java @@ -28,6 +28,14 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { /** Space character */ private static final String SPACE = " "; + /** Static instance configured with default values for working with points. */ + private static final SimpleCoordinateFormat DEFAULT_POINT_FORMAT = + new SimpleCoordinateFormat(DEFAULT_SEPARATOR, "(", ")"); + + /** Static instance configured with default values for working with vectors. */ + private static final SimpleCoordinateFormat DEFAULT_VECTOR_FORMAT = + new SimpleCoordinateFormat(DEFAULT_SEPARATOR, "{", "}"); + /** Creates a new format instance with the default separator value and the given * tuple prefix and suffix. * @param prefix coordinate tuple prefix; may be null @@ -47,17 +55,17 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { } /** Returns a 1D coordinate tuple string with the given value. - * @param v coordinate value + * @param a coordinate value * @return 1D coordinate tuple string */ - public String format1D(double v) { + public String format(double a) { StringBuilder sb = new StringBuilder(); if (getPrefix() != null) { sb.append(getPrefix()); } - sb.append(v); + sb.append(a); if (getSuffix() != null) { sb.append(getSuffix()); @@ -67,21 +75,21 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { } /** Returns a 2D coordinate tuple string with the given values. - * @param v1 first coordinate value - * @param v2 second coordinate value + * @param a1 first coordinate value + * @param a2 second coordinate value * @return 2D coordinate tuple string */ - public String format2D(double v1, double v2) { + public String format(double a1, double a2) { StringBuilder sb = new StringBuilder(); if (getPrefix() != null) { sb.append(getPrefix()); } - sb.append(v1); + sb.append(a1); sb.append(getSeparator()); sb.append(SPACE); - sb.append(v2); + sb.append(a2); if (getSuffix() != null) { sb.append(getSuffix()); @@ -91,25 +99,25 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { } /** Returns a 3D coordinate tuple string with the given values. - * @param v1 first coordinate value - * @param v2 second coordinate value - * @param v3 third coordinate value + * @param a1 first coordinate value + * @param a2 second coordinate value + * @param a3 third coordinate value * @return 3D coordinate tuple string */ - public String format3D(double v1, double v2, double v3) { + public String format(double a1, double a2, double a3) { StringBuilder sb = new StringBuilder(); if (getPrefix() != null) { sb.append(getPrefix()); } - sb.append(v1); + sb.append(a1); sb.append(getSeparator()); sb.append(SPACE); - sb.append(v2); + sb.append(a2); sb.append(getSeparator()); sb.append(SPACE); - sb.append(v3); + sb.append(a3); if (getSuffix() != null) { sb.append(getSuffix()); @@ -120,12 +128,13 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { /** Parses the given string as a 1D coordinate tuple and passes the coordinate value to the * given factory. The object created by the factory is returned. + * @param <T> The type created by {@code factory} * @param str the string to be parsed * @param factory object that will be passed the parsed coordinate value * @return object created by {@code factory} * @throws IllegalArgumentException if the input string format is invalid */ - public <T> T parse1D(String str, Coordinates.Factory1D<T> factory) throws IllegalArgumentException { + public <T> T parse(String str, Coordinates.Factory1D<T> factory) throws IllegalArgumentException { final ParsePosition pos = new ParsePosition(0); readPrefix(str, pos); @@ -138,12 +147,13 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { /** Parses the given string as a 2D coordinate tuple and passes the coordinate values to the * given factory. The object created by the factory is returned. + * @param <T> The type created by {@code factory} * @param str the string to be parsed * @param factory object that will be passed the parsed coordinate values * @return object created by {@code factory} * @throws IllegalArgumentException if the input string format is invalid */ - public <T> T parse2D(String str, Coordinates.Factory2D<T> factory) throws IllegalArgumentException { + public <T> T parse(String str, Coordinates.Factory2D<T> factory) throws IllegalArgumentException { final ParsePosition pos = new ParsePosition(0); readPrefix(str, pos); @@ -157,12 +167,13 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { /** Parses the given string as a 3D coordinate tuple and passes the coordinate values to the * given factory. The object created by the factory is returned. + * @param <T> The type created by {@code factory} * @param str the string to be parsed * @param factory object that will be passed the parsed coordinate values * @return object created by {@code factory} * @throws IllegalArgumentException if the input string format is invalid */ - public <T> T parse3D(String str, Coordinates.Factory3D<T> factory) throws IllegalArgumentException { + public <T> T parse(String str, Coordinates.Factory3D<T> factory) throws IllegalArgumentException { ParsePosition pos = new ParsePosition(0); readPrefix(str, pos); @@ -174,4 +185,18 @@ public class SimpleCoordinateFormat extends AbstractCoordinateParser { return factory.create(v1, v2, v3); } + + /** Returns a default instance for working with points. + * @return instance configured with default values for points + */ + public static SimpleCoordinateFormat getPointFormat() { + return DEFAULT_POINT_FORMAT; + } + + /** Returns a default instance for working with vectors. + * @return instance configured with default values for vectors. + */ + public static SimpleCoordinateFormat getVectorFormat() { + return DEFAULT_VECTOR_FORMAT; + } } diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/package-info.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/package-info.java new file mode 100644 index 0000000..526cca0 --- /dev/null +++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/util/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +/** + * + * <p> + * This package contains common geometry utilities. + * </p> + */ +package org.apache.commons.geometry.core.util; diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java index 820d3f6..23202d7 100644 --- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java +++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/util/SimpleCoordinateFormatTest.java @@ -23,7 +23,6 @@ public class SimpleCoordinateFormatTest { private static final double EPS = 1e-10; - private static final String COMMA = ","; private static final String OPEN_PAREN = "("; private static final String CLOSE_PAREN = ")"; @@ -80,7 +79,7 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("{", "}"); // assert - Assert.assertEquals(COMMA, formatter.getSeparator()); + Assert.assertEquals(",", formatter.getSeparator()); Assert.assertEquals("{", formatter.getPrefix()); Assert.assertEquals("}", formatter.getSuffix()); } @@ -91,11 +90,11 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN); // act/assert - Assert.assertEquals("(1.0)", formatter.format1D(1.0)); - Assert.assertEquals("(-1.0)", formatter.format1D(-1.0)); - Assert.assertEquals("(NaN)", formatter.format1D(Double.NaN)); - Assert.assertEquals("(-Infinity)", formatter.format1D(Double.NEGATIVE_INFINITY)); - Assert.assertEquals("(Infinity)", formatter.format1D(Double.POSITIVE_INFINITY)); + Assert.assertEquals("(1.0)", formatter.format(1.0)); + Assert.assertEquals("(-1.0)", formatter.format(-1.0)); + Assert.assertEquals("(NaN)", formatter.format(Double.NaN)); + Assert.assertEquals("(-Infinity)", formatter.format(Double.NEGATIVE_INFINITY)); + Assert.assertEquals("(Infinity)", formatter.format(Double.POSITIVE_INFINITY)); } @Test @@ -104,11 +103,11 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null); // act/assert - Assert.assertEquals("1.0", formatter.format1D(1.0)); - Assert.assertEquals("-1.0", formatter.format1D(-1.0)); - Assert.assertEquals("NaN", formatter.format1D(Double.NaN)); - Assert.assertEquals("-Infinity", formatter.format1D(Double.NEGATIVE_INFINITY)); - Assert.assertEquals("Infinity", formatter.format1D(Double.POSITIVE_INFINITY)); + Assert.assertEquals("1.0", formatter.format(1.0)); + Assert.assertEquals("-1.0", formatter.format(-1.0)); + Assert.assertEquals("NaN", formatter.format(Double.NaN)); + Assert.assertEquals("-Infinity", formatter.format(Double.NEGATIVE_INFINITY)); + Assert.assertEquals("Infinity", formatter.format(Double.POSITIVE_INFINITY)); } @Test @@ -117,10 +116,10 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN); // act/assert - Assert.assertEquals("(1.0, -1.0)", formatter.format2D(1.0, -1.0)); - Assert.assertEquals("(-1.0, 1.0)", formatter.format2D(-1.0, 1.0)); - Assert.assertEquals("(NaN, -Infinity)", formatter.format2D(Double.NaN, Double.NEGATIVE_INFINITY)); - Assert.assertEquals("(-Infinity, Infinity)", formatter.format2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + Assert.assertEquals("(1.0, -1.0)", formatter.format(1.0, -1.0)); + Assert.assertEquals("(-1.0, 1.0)", formatter.format(-1.0, 1.0)); + Assert.assertEquals("(NaN, -Infinity)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY)); + Assert.assertEquals("(-Infinity, Infinity)", formatter.format(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); } @Test @@ -129,10 +128,10 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null); // act/assert - Assert.assertEquals("1.0, -1.0", formatter.format2D(1.0, -1.0)); - Assert.assertEquals("-1.0, 1.0", formatter.format2D(-1.0, 1.0)); - Assert.assertEquals("NaN, -Infinity", formatter.format2D(Double.NaN, Double.NEGATIVE_INFINITY)); - Assert.assertEquals("-Infinity, Infinity", formatter.format2D(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + Assert.assertEquals("1.0, -1.0", formatter.format(1.0, -1.0)); + Assert.assertEquals("-1.0, 1.0", formatter.format(-1.0, 1.0)); + Assert.assertEquals("NaN, -Infinity", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY)); + Assert.assertEquals("-Infinity, Infinity", formatter.format(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); } @Test @@ -141,9 +140,9 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN); // act/assert - Assert.assertEquals("(1.0, 0.0, -1.0)", formatter.format3D(1.0, 0.0, -1.0)); - Assert.assertEquals("(-1.0, 1.0, 0.0)", formatter.format3D(-1.0, 1.0, 0.0)); - Assert.assertEquals("(NaN, -Infinity, Infinity)", formatter.format3D(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + Assert.assertEquals("(1.0, 0.0, -1.0)", formatter.format(1.0, 0.0, -1.0)); + Assert.assertEquals("(-1.0, 1.0, 0.0)", formatter.format(-1.0, 1.0, 0.0)); + Assert.assertEquals("(NaN, -Infinity, Infinity)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); } @Test @@ -152,9 +151,9 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(null, null); // act/assert - Assert.assertEquals("1.0, 0.0, -1.0", formatter.format3D(1.0, 0.0, -1.0)); - Assert.assertEquals("-1.0, 1.0, 0.0", formatter.format3D(-1.0, 1.0, 0.0)); - Assert.assertEquals("NaN, -Infinity, Infinity", formatter.format3D(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + Assert.assertEquals("1.0, 0.0, -1.0", formatter.format(1.0, 0.0, -1.0)); + Assert.assertEquals("-1.0, 1.0, 0.0", formatter.format(-1.0, 1.0, 0.0)); + Assert.assertEquals("NaN, -Infinity, Infinity", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); } @Test @@ -163,9 +162,9 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>"); // act/assert - Assert.assertEquals("<<1.0>>", formatter.format1D(1.0)); - Assert.assertEquals("<<1.0|| 2.0>>", formatter.format2D(1.0, 2.0)); - Assert.assertEquals("<<1.0|| 2.0|| 3.0>>", formatter.format3D(1.0, 2.0, 3.0)); + Assert.assertEquals("<<1.0>>", formatter.format(1.0)); + Assert.assertEquals("<<1.0|| 2.0>>", formatter.format(1.0, 2.0)); + Assert.assertEquals("<<1.0|| 2.0|| 3.0>>", formatter.format(1.0, 2.0, 3.0)); } @Test @@ -226,12 +225,12 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN); // act/assert - checkParse1DFailure(formatter, "", "expected \"(\" but found \"\" at index 0"); - checkParse1DFailure(formatter, "(1 ", "expected \")\" but found \"\" at index 3"); + checkParse1DFailure(formatter, "", "index 0: expected \"(\" but found \"\""); + checkParse1DFailure(formatter, "(1 ", "index 3: expected \")\" but found \"\""); - checkParse1DFailure(formatter, "(abc)", "Failed to parse number from string at index 1: abc"); + checkParse1DFailure(formatter, "(abc)", "unable to parse number from string \"abc\""); - checkParse1DFailure(formatter, "(1) 1", "unexpected content at index 4"); + checkParse1DFailure(formatter, "(1) 1", "index 4: unexpected content"); } @Test @@ -288,12 +287,12 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN); // act/assert - checkParse2DFailure(formatter, "", "expected \"(\" but found \"\" at index 0"); - checkParse2DFailure(formatter, "(1, 2 ", "expected \")\" but found \"\" at index 6"); + checkParse2DFailure(formatter, "", "index 0: expected \"(\" but found \"\""); + checkParse2DFailure(formatter, "(1, 2 ", "index 6: expected \")\" but found \"\""); - checkParse2DFailure(formatter, "(0,abc)", "Failed to parse number from string at index 3: abc"); + checkParse2DFailure(formatter, "(0,abc)", "index 3: unable to parse number from string \"abc\""); - checkParse2DFailure(formatter, "(1, 2) 1", "unexpected content at index 7"); + checkParse2DFailure(formatter, "(1, 2) 1", "index 7: unexpected content"); } @Test @@ -348,12 +347,12 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat(OPEN_PAREN, CLOSE_PAREN); // act/assert - checkParse3DFailure(formatter, "", "expected \"(\" but found \"\" at index 0"); - checkParse3DFailure(formatter, "(1, 2, 3", "expected \")\" but found \"\" at index 8"); + checkParse3DFailure(formatter, "", "index 0: expected \"(\" but found \"\""); + checkParse3DFailure(formatter, "(1, 2, 3", "index 8: expected \")\" but found \"\""); - checkParse3DFailure(formatter, "(0,0,abc)", "Failed to parse number from string at index 5: abc"); + checkParse3DFailure(formatter, "(0,0,abc)", "index 5: unable to parse number from string \"abc\""); - checkParse3DFailure(formatter, "(1, 2, 3) 1", "unexpected content at index 10"); + checkParse3DFailure(formatter, "(1, 2, 3) 1", "index 10: unexpected content"); } @Test @@ -373,21 +372,47 @@ public class SimpleCoordinateFormatTest { SimpleCoordinateFormat formatter = new SimpleCoordinateFormat("||", "<<", ">>"); // act/assert - checkParse1DFailure(formatter, "<", "expected \"<<\" but found \"<\" at index 0"); - checkParse1DFailure(formatter, "<1.0>>", "expected \"<<\" but found \"<1\" at index 0"); - checkParse2DFailure(formatter, "<<1.0| 2.0>>", "Failed to parse number from string at index 2: 1.0| 2.0"); - checkParse3DFailure(formatter, "<<1.0|| 2.0|| 3.0>", "Failed to parse number from string at index 13: 3.0>"); + checkParse1DFailure(formatter, "<", "index 0: expected \"<<\" but found \"<\""); + checkParse1DFailure(formatter, "<1.0>>", "index 0: expected \"<<\" but found \"<1\""); + checkParse2DFailure(formatter, "<<1.0| 2.0>>", "index 2: unable to parse number from string \"1.0| 2.0\""); + checkParse3DFailure(formatter, "<<1.0|| 2.0|| 3.0>", "index 13: unable to parse number from string \" 3.0>\""); + } + + @Test + public void testDefaultPointFormat() { + // act + SimpleCoordinateFormat formatter = SimpleCoordinateFormat.getPointFormat(); + + // assert + Assert.assertEquals(",", formatter.getSeparator()); + Assert.assertEquals("(", formatter.getPrefix()); + Assert.assertEquals(")", formatter.getSuffix()); + + Assert.assertEquals("(1.0, 2.0)", formatter.format(1, 2)); + } + + @Test + public void testDefaultVectorFormat() { + // act + SimpleCoordinateFormat formatter = SimpleCoordinateFormat.getVectorFormat(); + + // assert + Assert.assertEquals(",", formatter.getSeparator()); + Assert.assertEquals("{", formatter.getPrefix()); + Assert.assertEquals("}", formatter.getSuffix()); + + Assert.assertEquals("{1.0, 2.0}", formatter.format(1, 2)); } private void checkParse1D(SimpleCoordinateFormat formatter, String str, double v) { - Stub1D result = formatter.parse1D(str, FACTORY_1D); + Stub1D result = formatter.parse(str, FACTORY_1D); Assert.assertEquals(v, result.v, EPS); } private void checkParse1DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) { try { - formatter.parse1D(str, FACTORY_1D); + formatter.parse(str, FACTORY_1D); Assert.fail("Operation should have failed"); } catch (IllegalArgumentException exc) { @@ -398,7 +423,7 @@ public class SimpleCoordinateFormatTest { } private void checkParse2D(SimpleCoordinateFormat formatter, String str, double v1, double v2) { - Stub2D result = formatter.parse2D(str, FACTORY_2D); + Stub2D result = formatter.parse(str, FACTORY_2D); Assert.assertEquals(v1, result.v1, EPS); Assert.assertEquals(v2, result.v2, EPS); @@ -406,7 +431,7 @@ public class SimpleCoordinateFormatTest { private void checkParse2DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) { try { - formatter.parse2D(str, FACTORY_2D); + formatter.parse(str, FACTORY_2D); Assert.fail("Operation should have failed"); } catch (IllegalArgumentException exc) { @@ -417,7 +442,7 @@ public class SimpleCoordinateFormatTest { } private void checkParse3D(SimpleCoordinateFormat formatter, String str, double v1, double v2, double v3) { - Stub3D result = formatter.parse3D(str, FACTORY_3D); + Stub3D result = formatter.parse(str, FACTORY_3D); Assert.assertEquals(v1, result.v1, EPS); Assert.assertEquals(v2, result.v2, EPS); @@ -426,7 +451,7 @@ public class SimpleCoordinateFormatTest { private void checkParse3DFailure(SimpleCoordinateFormat formatter, String str, String msgSubstr) { try { - formatter.parse3D(str, FACTORY_3D); + formatter.parse(str, FACTORY_3D); Assert.fail("Operation should have failed"); } catch (IllegalArgumentException exc) { diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java index 75f4cb8..c6e6910 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java @@ -16,6 +16,8 @@ */ package org.apache.commons.geometry.euclidean.oned; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.EuclideanPoint; import org.apache.commons.numbers.arrays.LinearCombination; @@ -46,6 +48,16 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D /** Serializable UID. */ private static final long serialVersionUID = 7556674948671647925L; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory1D<Point1D> FACTORY = new Coordinates.Factory1D<Point1D>() { + + /** {@inheritDoc} */ + @Override + public Point1D create(double a) { + return new Point1D(a); + } + }; + /** Simple constructor. * @param x abscissa (coordinate value) */ @@ -136,7 +148,7 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D /** {@inheritDoc} */ @Override public String toString() { - return "(" + getX() + ")"; + return SimpleCoordinateFormat.getPointFormat().format(getX()); } /** Returns a point with the given coordinate value. @@ -155,6 +167,23 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D return new Point1D(value.getX()); } + /** Parses the given string and returns a new point instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return point instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static Point1D parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new point instances. + * @return point factory instance + */ + public static Coordinates.Factory1D<Point1D> getFactory() { + return FACTORY; + } + /** Returns a point with coordinates calculated by multiplying each input coordinate * with its corresponding factor and adding the results. * diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java index 8455441..5d79379 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java @@ -16,6 +16,8 @@ */ package org.apache.commons.geometry.euclidean.oned; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.EuclideanVector; import org.apache.commons.numbers.arrays.LinearCombination; @@ -46,6 +48,16 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point /** Serializable UID. */ private static final long serialVersionUID = 1582116020164328846L; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory1D<Vector1D> FACTORY = new Coordinates.Factory1D<Vector1D>() { + + /** {@inheritDoc} */ + @Override + public Vector1D create(double a) { + return new Vector1D(a); + } + }; + /** Simple constructor. * @param x abscissa (coordinate value) */ @@ -220,7 +232,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point /** {@inheritDoc} */ @Override public String toString() { - return "{" + getX() + "}"; + return SimpleCoordinateFormat.getVectorFormat().format(getX()); } /** Returns a vector with the given coordinate value. @@ -239,6 +251,23 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point return new Vector1D(value.getX()); } + /** Parses the given string and returns a new vector instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return vector instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static Vector1D parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new vector instances. + * @return vector factory instance + */ + public static Coordinates.Factory1D<Vector1D> getFactory() { + return FACTORY; + } + /** Returns a vector consisting of the linear combination of the inputs. * <p> * A linear combination is the sum of all of the inputs multiplied by their diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java index 05af242..2093292 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java @@ -17,6 +17,8 @@ package org.apache.commons.geometry.euclidean.threed; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.EuclideanPoint; import org.apache.commons.numbers.arrays.LinearCombination; @@ -44,6 +46,16 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D /** Serializable version identifier. */ private static final long serialVersionUID = 1313493323784566947L; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory3D<Point3D> FACTORY = new Coordinates.Factory3D<Point3D>() { + + /** {@inheritDoc} */ + @Override + public Point3D create(double a1, double a2, double a3) { + return new Point3D(a1, a2, a3); + } + }; + /** Simple constructor. * Build a point from its coordinates * @param x abscissa @@ -145,7 +157,7 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D /** {@inheritDoc} */ @Override public String toString() { - return "(" + getX() + "; " + getY() + "; " + getZ() + ")"; + return SimpleCoordinateFormat.getPointFormat().format(getX(), getY(), getZ()); } /** Returns a point with the given coordinate values @@ -178,6 +190,23 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D return new Point3D(p[0], p[1], p[2]); } + /** Parses the given string and returns a new point instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return point instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static Point3D parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new point instances. + * @return point factory instance + */ + public static Coordinates.Factory3D<Point3D> getFactory() { + return FACTORY; + } + /** Returns a point with coordinates calculated by multiplying each input coordinate * with its corresponding factor and adding the results. * diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java index f50816a..85246ab 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java @@ -16,13 +16,15 @@ */ package org.apache.commons.geometry.euclidean.threed; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.EuclideanVector; import org.apache.commons.numbers.arrays.LinearCombination; /** This class represents a vector in three-dimensional Euclidean space. * Instances of this class are guaranteed to be immutable. */ -public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Vector3D> { +public final class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Vector3D> { /** Zero (null) vector (coordinates: 0, 0, 0). */ public static final Vector3D ZERO = Vector3D.of(0, 0, 0); @@ -64,6 +66,16 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve /** Error message when norms are zero. */ private static final String ZERO_NORM_MSG = "Norm is zero"; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory3D<Vector3D> FACTORY = new Coordinates.Factory3D<Vector3D>() { + + /** {@inheritDoc} */ + @Override + public Vector3D create(double a1, double a2, double a3) { + return new Vector3D(a1, a2, a3); + } + }; + /** Simple constructor. * Build a vector from its coordinates * @param x abscissa @@ -373,7 +385,7 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve /** {@inheritDoc} */ @Override public String toString() { - return "{" + getX() + "; " + getY() + "; " + getZ() + "}"; + return SimpleCoordinateFormat.getVectorFormat().format(getX(), getY(), getZ()); } /** Computes the dot product between to vectors. This method simply @@ -458,6 +470,23 @@ public class Vector3D extends Cartesian3D implements EuclideanVector<Point3D, Ve return new Vector3D(x, y, z); } + /** Parses the given string and returns a new vector instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return vector instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static Vector3D parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new vector instances. + * @return vector factory instance + */ + public static Coordinates.Factory3D<Vector3D> getFactory() { + return FACTORY; + } + /** Returns a vector consisting of the linear combination of the inputs. * <p> * A linear combination is the sum of all of the inputs multiplied by their diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java index 376d970..4175d11 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java @@ -16,6 +16,8 @@ */ package org.apache.commons.geometry.euclidean.twod; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.EuclideanPoint; import org.apache.commons.numbers.arrays.LinearCombination; @@ -43,6 +45,16 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D /** Serializable UID. */ private static final long serialVersionUID = 266938651998679754L; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory2D<Point2D> FACTORY = new Coordinates.Factory2D<Point2D>() { + + /** {@inheritDoc} */ + @Override + public Point2D create(double a1, double a2) { + return new Point2D(a1, a2); + } + }; + /** Simple constructor. * Build a point from its coordinates * @param x abscissa @@ -134,7 +146,7 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D /** {@inheritDoc} */ @Override public String toString() { - return "(" + getX() + "; " + getY() + ")"; + return SimpleCoordinateFormat.getPointFormat().format(getX(), getY()); } /** Returns a point with the given coordinate values @@ -166,6 +178,23 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D return new Point2D(p[0], p[1]); } + /** Parses the given string and returns a new point instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return point instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static Point2D parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new point instances. + * @return point factory instance + */ + public static Coordinates.Factory2D<Point2D> getFactory() { + return FACTORY; + } + /** Returns a point with coordinates calculated by multiplying each input coordinate * with its corresponding factor and adding the results. * diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java index 98ac4bc..e6285b1 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java @@ -16,6 +16,8 @@ */ package org.apache.commons.geometry.euclidean.twod; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.EuclideanVector; import org.apache.commons.numbers.arrays.LinearCombination; @@ -58,6 +60,16 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point /** Error message when norms are zero. */ private static final String ZERO_NORM_MSG = "Norm is zero"; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory2D<Vector2D> FACTORY = new Coordinates.Factory2D<Vector2D>() { + + /** {@inheritDoc} */ + @Override + public Vector2D create(double a1, double a2) { + return new Vector2D(a1, a2); + } + }; + /** Simple constructor. * @param x abscissa (first coordinate) * @param y ordinate (second coordinate) @@ -311,7 +323,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point /** {@inheritDoc} */ @Override public String toString() { - return "{" + getX() + "; " + getY() + "}"; + return SimpleCoordinateFormat.getVectorFormat().format(getX(), getY()); } /** Computes the dot product between to vectors. This method simply @@ -365,6 +377,23 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point return new Vector2D(v[0], v[1]); } + /** Parses the given string and returns a new vector instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return vector instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static Vector2D parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getVectorFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new vector instances. + * @return vector factory instance + */ + public static Coordinates.Factory2D<Vector2D> getFactory() { + return FACTORY; + } + /** Returns a vector consisting of the linear combination of the inputs. * <p> * A linear combination is the sum of all of the inputs multiplied by their diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java index f17af96..bcde081 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java @@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.oned; import java.util.regex.Pattern; +import org.apache.commons.geometry.core.util.Coordinates; import org.apache.commons.numbers.core.Precision; import org.junit.Assert; import org.junit.Test; @@ -183,6 +184,27 @@ public class Point1DTest { } @Test + public void testParse() { + // act/assert + checkPoint(Point1D.parse("(1)"), 1); + checkPoint(Point1D.parse("(-1)"), -1); + + checkPoint(Point1D.parse("(0.01)"), 1e-2); + checkPoint(Point1D.parse("(-1e-3)"), -1e-3); + + checkPoint(Point1D.parse("(NaN)"), Double.NaN); + + checkPoint(Point1D.parse(Point1D.ZERO.toString()), 0); + checkPoint(Point1D.parse(Point1D.ONE.toString()), 1); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + Point1D.parse("abc"); + } + + @Test public void testOf() { // act/assert checkPoint(Point1D.of(0), 0.0); @@ -207,6 +229,16 @@ public class Point1DTest { } @Test + public void testGetFactory() { + // act + Coordinates.Factory1D<Point1D> factory = Point1D.getFactory(); + + // assert + checkPoint(factory.create(1), 1); + checkPoint(factory.create(-1), -1); + } + + @Test public void testVectorCombination() { // act/assert checkPoint(Point1D.vectorCombination(2, Point1D.of(3)), 6); diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java index fa757ab..7184476 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java @@ -2,6 +2,7 @@ package org.apache.commons.geometry.euclidean.oned; import java.util.regex.Pattern; +import org.apache.commons.geometry.core.util.Coordinates; import org.apache.commons.numbers.core.Precision; import org.junit.Assert; import org.junit.Test; @@ -291,6 +292,27 @@ public class Vector1DTest { } @Test + public void testParse() { + // act/assert + checkVector(Vector1D.parse("{1}"), 1); + checkVector(Vector1D.parse("{-1}"), -1); + + checkVector(Vector1D.parse("{0.01}"), 1e-2); + checkVector(Vector1D.parse("{-1e-3}"), -1e-3); + + checkVector(Vector1D.parse("{NaN}"), Double.NaN); + + checkVector(Vector1D.parse(Vector1D.ZERO.toString()), 0); + checkVector(Vector1D.parse(Vector1D.ONE.toString()), 1); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + Vector1D.parse("abc"); + } + + @Test public void testOf() { // act/assert checkVector(Vector1D.of(0), 0.0); @@ -315,6 +337,16 @@ public class Vector1DTest { } @Test + public void testGetFactory() { + // act + Coordinates.Factory1D<Vector1D> factory = Vector1D.getFactory(); + + // assert + checkVector(factory.create(1), 1); + checkVector(factory.create(-1), -1); + } + + @Test public void testLinearCombination() { // act/assert checkVector(Vector1D.linearCombination(2, Vector1D.of(3)), 6); diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java index fa4cf3f..d20d918 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java @@ -18,6 +18,7 @@ package org.apache.commons.geometry.euclidean.threed; import java.util.regex.Pattern; +import org.apache.commons.geometry.core.util.Coordinates; import org.apache.commons.numbers.core.Precision; import org.junit.Assert; import org.junit.Test; @@ -173,7 +174,7 @@ public class Point3DTest { public void testToString() { // arrange Point3D p = Point3D.of(1, 2, 3); - Pattern pattern = Pattern.compile("\\(1.{0,2}; 2.{0,2}; 3.{0,2}\\)"); + Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}, 3.{0,2}\\)"); // act String str = p.toString(); @@ -184,6 +185,25 @@ public class Point3DTest { } @Test + public void testParse() { + // act/assert + checkPoint(Point3D.parse("(1, 2, 0)"), 1, 2, 0); + checkPoint(Point3D.parse("(-1, -2, 0)"), -1, -2, 0); + + checkPoint(Point3D.parse("(0.01, -1e-3, 1e3)"), 1e-2, -1e-3, 1e3); + + checkPoint(Point3D.parse("(NaN, -Infinity, Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + + checkPoint(Point3D.parse(Point3D.ZERO.toString()), 0, 0, 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + Point3D.parse("abc"); + } + + @Test public void testOf() { // act/assert checkPoint(Point3D.of(1, 2, 3), 1, 2, 3); @@ -223,6 +243,16 @@ public class Point3DTest { } @Test + public void testGetFactory() { + // act + Coordinates.Factory3D<Point3D> factory = Point3D.getFactory(); + + // assert + checkPoint(factory.create(1, 2, 3), 1, 2, 3); + checkPoint(factory.create(-1, -2, -3), -1, -2, -3); + } + + @Test public void testVectorCombination1() { // arrange Point3D p1 = Point3D.of(1, 2, 3); diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java index f2b4fcc..c9b3cf9 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java @@ -20,6 +20,7 @@ package org.apache.commons.geometry.euclidean.threed; import java.util.regex.Pattern; import org.apache.commons.geometry.core.Geometry; +import org.apache.commons.geometry.core.util.Coordinates; import org.apache.commons.numbers.core.Precision; import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.simple.RandomSource; @@ -618,7 +619,7 @@ public class Vector3DTest { public void testToString() { // arrange Vector3D v = Vector3D.of(1, 2, 3); - Pattern pattern = Pattern.compile("\\{1.{0,2}; 2.{0,2}; 3.{0,2}\\}"); + Pattern pattern = Pattern.compile("\\{1.{0,2}, 2.{0,2}, 3.{0,2}\\}"); // act String str = v.toString(); @@ -629,6 +630,26 @@ public class Vector3DTest { } @Test + public void testParse() { + // act/assert + checkVector(Vector3D.parse("{1, 2, 3}"), 1, 2, 3); + checkVector(Vector3D.parse("{-1, -2, -3}"), -1, -2, -3); + + checkVector(Vector3D.parse("{0.01, -1e-3, 0}"), 1e-2, -1e-3, 0); + + checkVector(Vector3D.parse("{NaN, -Infinity, Infinity}"), Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + + checkVector(Vector3D.parse(Vector3D.ZERO.toString()), 0, 0, 0); + checkVector(Vector3D.parse(Vector3D.MINUS_X.toString()), -1, 0, 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + Vector3D.parse("abc"); + } + + @Test public void testOf() { // act/assert checkVector(Vector3D.of(1, 2, 3), 1, 2, 3); @@ -668,6 +689,16 @@ public class Vector3DTest { } @Test + public void testGetFactory() { + // act + Coordinates.Factory3D<Vector3D> factory = Vector3D.getFactory(); + + // assert + checkVector(factory.create(1, 2, 3), 1, 2, 3); + checkVector(factory.create(-1, -2, -3), -1, -2, -3); + } + + @Test public void testLinearCombination1() { // arrange Vector3D p1 = Vector3D.of(1, 2, 3); diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java index 6892198..20d95ad 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java @@ -18,6 +18,7 @@ package org.apache.commons.geometry.euclidean.twod; import java.util.regex.Pattern; +import org.apache.commons.geometry.core.util.Coordinates; import org.apache.commons.numbers.core.Precision; import org.junit.Assert; import org.junit.Test; @@ -156,7 +157,7 @@ public class Point2DTest { public void testToString() { // arrange Point2D p = Point2D.of(1, 2); - Pattern pattern = Pattern.compile("\\(1.{0,2}; 2.{0,2}\\)"); + Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)"); // act String str = p.toString(); @@ -167,6 +168,25 @@ public class Point2DTest { } @Test + public void testParse() { + // act/assert + checkPoint(Point2D.parse("(1, 2)"), 1, 2); + checkPoint(Point2D.parse("(-1, -2)"), -1, -2); + + checkPoint(Point2D.parse("(0.01, -1e-3)"), 1e-2, -1e-3); + + checkPoint(Point2D.parse("(NaN, -Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY); + + checkPoint(Point2D.parse(Point2D.ZERO.toString()), 0, 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + Point2D.parse("abc"); + } + + @Test public void testOf() { // act/assert checkPoint(Point2D.of(0, 1), 0, 1); @@ -200,6 +220,16 @@ public class Point2DTest { } @Test + public void testGetFactory() { + // act + Coordinates.Factory2D<Point2D> factory = Point2D.getFactory(); + + // assert + checkPoint(factory.create(1, 2), 1, 2); + checkPoint(factory.create(-1, -2), -1, -2); + } + + @Test public void testVectorCombination1() { // arrange Point2D p1 = Point2D.of(1, 2); diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java index 7882e7d..13208c0 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java @@ -3,6 +3,7 @@ package org.apache.commons.geometry.euclidean.twod; import java.util.regex.Pattern; import org.apache.commons.geometry.core.Geometry; +import org.apache.commons.geometry.core.util.Coordinates; import org.apache.commons.numbers.core.Precision; import org.junit.Assert; import org.junit.Test; @@ -420,7 +421,7 @@ public class Vector2DTest { public void testToString() { // arrange Vector2D v = Vector2D.of(1, 2); - Pattern pattern = Pattern.compile("\\{1.{0,2}; 2.{0,2}\\}"); + Pattern pattern = Pattern.compile("\\{1.{0,2}, 2.{0,2}\\}"); // act String str = v.toString(); @@ -431,6 +432,26 @@ public class Vector2DTest { } @Test + public void testParse() { + // act/assert + checkVector(Vector2D.parse("{1, 2}"), 1, 2); + checkVector(Vector2D.parse("{-1, -2}"), -1, -2); + + checkVector(Vector2D.parse("{0.01, -1e-3}"), 1e-2, -1e-3); + + checkVector(Vector2D.parse("{NaN, -Infinity}"), Double.NaN, Double.NEGATIVE_INFINITY); + + checkVector(Vector2D.parse(Vector2D.ZERO.toString()), 0, 0); + checkVector(Vector2D.parse(Vector2D.MINUS_X.toString()), -1, 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + Vector2D.parse("abc"); + } + + @Test public void testOf() { // act/assert checkVector(Vector2D.of(0, 1), 0, 1); @@ -464,6 +485,16 @@ public class Vector2DTest { } @Test + public void testGetFactory() { + // act + Coordinates.Factory2D<Vector2D> factory = Vector2D.getFactory(); + + // assert + checkVector(factory.create(1, 2), 1, 2); + checkVector(factory.create(-1, -2), -1, -2); + } + + @Test public void testLinearCombination1() { // arrange Vector2D p1 = Vector2D.of(1, 2); diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java index 2445857..676a88b 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java @@ -42,6 +42,9 @@ import org.apache.commons.numbers.core.Precision; */ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterable<double[]> { + /** Message used for internal errors. */ + private static final String INTERNAL_ERROR_MESSAGE = "Please file a bug report"; + /** Build an arcs set representing the whole circle. * @param tolerance tolerance below which close sub-arcs are merged together */ @@ -135,12 +138,12 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl final double normalizedLower = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(lower); final double normalizedUpper = normalizedLower + (upper - lower); final SubHyperplane<S1Point> lowerCut = - new LimitAngle(new S1Point(normalizedLower), false, tolerance).wholeHyperplane(); + new LimitAngle(S1Point.of(normalizedLower), false, tolerance).wholeHyperplane(); if (normalizedUpper <= Geometry.TWO_PI) { // simple arc starting after 0 and ending before 2 \pi final SubHyperplane<S1Point> upperCut = - new LimitAngle(new S1Point(normalizedUpper), true, tolerance).wholeHyperplane(); + new LimitAngle(S1Point.of(normalizedUpper), true, tolerance).wholeHyperplane(); return new BSPTree<>(lowerCut, new BSPTree<S1Point>(Boolean.FALSE), new BSPTree<>(upperCut, @@ -151,7 +154,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl } else { // arc wrapping around 2 \pi final SubHyperplane<S1Point> upperCut = - new LimitAngle(new S1Point(normalizedUpper - Geometry.TWO_PI), true, tolerance).wholeHyperplane(); + new LimitAngle(S1Point.of(normalizedUpper - Geometry.TWO_PI), true, tolerance).wholeHyperplane(); return new BSPTree<>(lowerCut, new BSPTree<>(upperCut, new BSPTree<S1Point>(Boolean.FALSE), @@ -459,7 +462,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl if (Precision.equals(size, Geometry.TWO_PI, 0)) { setBarycenter(S1Point.NaN); } else if (size >= Precision.SAFE_MIN) { - setBarycenter(new S1Point(sum / (2 * size))); + setBarycenter(S1Point.of(sum / (2 * size))); } else { final LimitAngle limit = (LimitAngle) getTree(false).getCut().getHyperplane(); setBarycenter(limit.getLocation()); @@ -495,9 +498,9 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl final double previousOffset = alpha - previous; final double currentOffset = a[0] - alpha; if (previousOffset < currentOffset) { - return new BoundaryProjection<>(point, new S1Point(previous), previousOffset); + return new BoundaryProjection<>(point, S1Point.of(previous), previousOffset); } else { - return new BoundaryProjection<>(point, new S1Point(a[0]), currentOffset); + return new BoundaryProjection<>(point, S1Point.of(a[0]), currentOffset); } } } else if (alpha <= a[1]) { @@ -506,9 +509,9 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl final double offset0 = a[0] - alpha; final double offset1 = alpha - a[1]; if (offset0 < offset1) { - return new BoundaryProjection<>(point, new S1Point(a[1]), offset1); + return new BoundaryProjection<>(point, S1Point.of(a[1]), offset1); } else { - return new BoundaryProjection<>(point, new S1Point(a[0]), offset0); + return new BoundaryProjection<>(point, S1Point.of(a[0]), offset0); } } } @@ -529,18 +532,18 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl final double previousOffset = alpha - (previous - Geometry.TWO_PI); final double currentOffset = first - alpha; if (previousOffset < currentOffset) { - return new BoundaryProjection<>(point, new S1Point(previous), previousOffset); + return new BoundaryProjection<>(point, S1Point.of(previous), previousOffset); } else { - return new BoundaryProjection<>(point, new S1Point(first), currentOffset); + return new BoundaryProjection<>(point, S1Point.of(first), currentOffset); } } else { // the test point is between last and 2\pi final double previousOffset = alpha - previous; final double currentOffset = first + Geometry.TWO_PI - alpha; if (previousOffset < currentOffset) { - return new BoundaryProjection<>(point, new S1Point(previous), previousOffset); + return new BoundaryProjection<>(point, S1Point.of(previous), previousOffset); } else { - return new BoundaryProjection<>(point, new S1Point(first), currentOffset); + return new BoundaryProjection<>(point, S1Point.of(first), currentOffset); } } @@ -652,7 +655,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl } if (end == null) { // this should never happen - throw new IllegalStateException("Please file a bug report"); + throw new IllegalStateException(INTERNAL_ERROR_MESSAGE); } // we have identified the last arc @@ -787,11 +790,11 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl */ private void addArcLimit(final BSPTree<S1Point> tree, final double alpha, final boolean isStart) { - final LimitAngle limit = new LimitAngle(new S1Point(alpha), !isStart, getTolerance()); + final LimitAngle limit = new LimitAngle(S1Point.of(alpha), !isStart, getTolerance()); final BSPTree<S1Point> node = tree.getCell(limit.getLocation(), getTolerance()); if (node.getCut() != null) { // this should never happen - throw new IllegalStateException("Please file a bug report"); + throw new IllegalStateException(INTERNAL_ERROR_MESSAGE); } node.insertCut(limit); diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java index 8f7b19c..c2f6d86 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/S1Point.java @@ -17,13 +17,15 @@ package org.apache.commons.geometry.spherical.oned; import org.apache.commons.geometry.core.Point; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.twod.Vector2D; import org.apache.commons.numbers.angle.PlaneAngleRadians; /** This class represents a point on the 1-sphere. * <p>Instances of this class are guaranteed to be immutable.</p> */ -public class S1Point implements Point<S1Point> { +public final class S1Point implements Point<S1Point> { // CHECKSTYLE: stop ConstantName /** A vector with all coordinates set to NaN. */ @@ -33,22 +35,22 @@ public class S1Point implements Point<S1Point> { /** Serializable UID. */ private static final long serialVersionUID = 20131218L; - /** Azimuthal angle \( \alpha \). */ + /** Factory for delegating instance creation. */ + private static Coordinates.Factory1D<S1Point> FACTORY = new Coordinates.Factory1D<S1Point>() { + + /** {@inheritDoc} */ + @Override + public S1Point create(double a) { + return S1Point.of(a); + } + }; + + /** Azimuthal angle in radians \( \alpha \). */ private final double alpha; /** Corresponding 2D normalized vector. */ private final Vector2D vector; - /** Simple constructor. - * Build a vector from its coordinates - * @param alpha azimuthal angle \( \alpha \) - * @see #getAlpha() - */ - public S1Point(final double alpha) { - this(PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(alpha), - Vector2D.of(Math.cos(alpha), Math.sin(alpha))); - } - /** Build a point from its internal components. * @param alpha azimuthal angle \( \alpha \) * @param vector corresponding vector @@ -58,7 +60,7 @@ public class S1Point implements Point<S1Point> { this.vector = vector; } - /** Get the azimuthal angle \( \alpha \). + /** Get the azimuthal angle in radians \( \alpha \). * @return azimuthal angle \( \alpha \) * @see #S1Point(double) */ @@ -159,4 +161,39 @@ public class S1Point implements Point<S1Point> { } return 1759 * Double.hashCode(alpha); } + + /** {@inheritDoc} */ + @Override + public String toString() { + return SimpleCoordinateFormat.getPointFormat().format(getAlpha()); + } + + /** Creates a new point instance from the given azimuthal coordinate value. + * @param alpha azimuthal angle in radians \( \alpha \) + * @return point instance with the given azimuth coordinate value + * @see #getAlpha() + */ + public static S1Point of(double alpha) { + double normalizedAlpha = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(alpha); + Vector2D vector = Vector2D.of(Math.cos(normalizedAlpha), Math.sin(normalizedAlpha)); + + return new S1Point(normalizedAlpha, vector); + } + + /** Parses the given string and returns a new point instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return point instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static S1Point parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new point instances. + * @return point factory instance + */ + public static Coordinates.Factory1D<S1Point> getFactory() { + return FACTORY; + } } diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java new file mode 100644 index 0000000..020a968 --- /dev/null +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +/** + * + * <p> + * Base package for spherical geometry components. + * </p> + */ +package org.apache.commons.geometry.spherical; diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java index 28d4e02..3b017ca 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java @@ -16,7 +16,6 @@ */ package org.apache.commons.geometry.spherical.twod; -import org.apache.commons.geometry.core.Point; import org.apache.commons.geometry.core.partitioning.Embedding; import org.apache.commons.geometry.core.partitioning.Hyperplane; import org.apache.commons.geometry.core.partitioning.SubHyperplane; @@ -147,7 +146,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point> */ @Override public S1Point toSubSpace(final S2Point point) { - return new S1Point(getPhase(point.getVector())); + return S1Point.of(getPhase(point.getVector())); } /** Get the phase angle of a direction. @@ -169,7 +168,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point> */ @Override public S2Point toSpace(final S1Point point) { - return new S2Point(getPointAt(point.getAlpha())); + return S2Point.of(getPointAt(point.getAlpha())); } /** Get a circle point from its phase around the circle. @@ -307,7 +306,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point> /** {@inheritDoc} */ @Override public S2Point apply(final S2Point point) { - return new S2Point(rotation.applyTo(point.getVector())); + return S2Point.of(rotation.applyTo(point.getVector())); } /** {@inheritDoc} */ diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java index 997d051..609408a 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java @@ -148,7 +148,7 @@ public class Edge { if (unwrappedEnd >= 0) { // the start of the edge is inside the circle previousVertex = addSubEdge(previousVertex, - new Vertex(new S2Point(circle.getPointAt(edgeStart + unwrappedEnd))), + new Vertex(S2Point.of(circle.getPointAt(edgeStart + unwrappedEnd))), unwrappedEnd, insideList, splitCircle); alreadyManagedLength = unwrappedEnd; } @@ -166,7 +166,7 @@ public class Edge { } else { // the edge is long enough to enter inside the circle previousVertex = addSubEdge(previousVertex, - new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))), + new Vertex(S2Point.of(circle.getPointAt(edgeStart + arcRelativeStart))), arcRelativeStart - alreadyManagedLength, outsideList, splitCircle); alreadyManagedLength = arcRelativeStart; @@ -177,7 +177,7 @@ public class Edge { } else { // the edge is long enough to exit outside of the circle previousVertex = addSubEdge(previousVertex, - new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))), + new Vertex(S2Point.of(circle.getPointAt(edgeStart + arcRelativeStart))), arcRelativeStart - alreadyManagedLength, insideList, splitCircle); alreadyManagedLength = arcRelativeStart; previousVertex = addSubEdge(previousVertex, end, diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java index 47b6d39..085f9c5 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java @@ -91,8 +91,8 @@ class EdgesBuilder implements BSPTreeVisitor<S2Point> { final Circle circle = (Circle) sub.getHyperplane(); final List<Arc> arcs = ((ArcsSet) sub.getRemainingRegion()).asList(); for (final Arc a : arcs) { - final Vertex start = new Vertex(circle.toSpace(new S1Point(a.getInf()))); - final Vertex end = new Vertex(circle.toSpace(new S1Point(a.getSup()))); + final Vertex start = new Vertex(circle.toSpace(S1Point.of(a.getInf()))); + final Vertex end = new Vertex(circle.toSpace(S1Point.of(a.getSup()))); start.bindWith(circle); end.bindWith(circle); final Edge edge; diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java index 2cbcb03..258b17e 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java @@ -160,7 +160,7 @@ class PropertiesComputer implements BSPTreeVisitor<S2Point> { if (summedBarycenter.getNormSq() == 0) { return S2Point.NaN; } else { - return new S2Point(summedBarycenter); + return S2Point.of(summedBarycenter); } } diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java index 567e666..a0c7499 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/S2Point.java @@ -17,6 +17,8 @@ package org.apache.commons.geometry.spherical.twod; import org.apache.commons.geometry.core.Point; +import org.apache.commons.geometry.core.util.Coordinates; +import org.apache.commons.geometry.core.util.SimpleCoordinateFormat; import org.apache.commons.geometry.euclidean.threed.Vector3D; /** This class represents a point on the 2-sphere. @@ -29,7 +31,7 @@ import org.apache.commons.geometry.euclidean.threed.Vector3D; * </p> * <p>Instances of this class are guaranteed to be immutable.</p> */ -public class S2Point implements Point<S2Point> { +public final class S2Point implements Point<S2Point> { /** +I (coordinates: \( \theta = 0, \varphi = \pi/2 \)). */ public static final S2Point PLUS_I = new S2Point(0, 0.5 * Math.PI, Vector3D.PLUS_X); @@ -57,6 +59,16 @@ public class S2Point implements Point<S2Point> { /** Serializable UID. */ private static final long serialVersionUID = 20131218L; + /** Factory for delegating instance creation. */ + private static Coordinates.Factory2D<S2Point> FACTORY = new Coordinates.Factory2D<S2Point>() { + + /** {@inheritDoc} */ + @Override + public S2Point create(double a1, double a2) { + return S2Point.of(a1, a2); + } + }; + /** Azimuthal angle \( \theta \) in the x-y plane. */ private final double theta; @@ -66,29 +78,6 @@ public class S2Point implements Point<S2Point> { /** Corresponding 3D normalized vector. */ private final Vector3D vector; - /** Simple constructor. - * Build a vector from its spherical coordinates - * @param theta azimuthal angle \( \theta \) in the x-y plane - * @param phi polar angle \( \varphi \) - * @see #getTheta() - * @see #getPhi() - * @exception IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range - */ - public S2Point(final double theta, final double phi) - throws IllegalArgumentException { - this(theta, phi, vector(theta, phi)); - } - - /** Simple constructor. - * Build a vector from its underlying 3D vector - * @param vector 3D vector - * @exception IllegalArgumentException if vector norm is zero - */ - public S2Point(final Vector3D vector) throws IllegalArgumentException { - this(Math.atan2(vector.getY(), vector.getX()), Vector3D.PLUS_Z.angle(vector), - vector.normalize()); - } - /** Build a point from its internal components. * @param theta azimuthal angle \( \theta \) in the x-y plane * @param phi polar angle \( \varphi \) @@ -100,28 +89,6 @@ public class S2Point implements Point<S2Point> { this.vector = vector; } - /** Build the normalized vector corresponding to spherical coordinates. - * @param theta azimuthal angle \( \theta \) in the x-y plane - * @param phi polar angle \( \varphi \) - * @return normalized vector - * @exception IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range - */ - private static Vector3D vector(final double theta, final double phi) - throws IllegalArgumentException { - - if (phi < 0 || phi > Math.PI) { - throw new IllegalArgumentException(phi + " is out of [" + 0 + ", " + Math.PI + "] range"); - } - - final double cosTheta = Math.cos(theta); - final double sinTheta = Math.sin(theta); - final double cosPhi = Math.cos(phi); - final double sinPhi = Math.sin(phi); - - return Vector3D.of(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi); - - } - /** Get the azimuthal angle \( \theta \) in the x-y plane. * @return azimuthal angle \( \theta \) in the x-y plane * @see #S2Point(double, double) @@ -236,4 +203,71 @@ public class S2Point implements Point<S2Point> { } return 134 * (37 * Double.hashCode(theta) + Double.hashCode(phi)); } + + /** {@inheritDoc} */ + @Override + public String toString() { + return SimpleCoordinateFormat.getPointFormat().format(getTheta(), getPhi()); + } + + /** Build a vector from its spherical coordinates + * @param theta azimuthal angle \( \theta \) in the x-y plane + * @param phi polar angle \( \varphi \) + * @return point instance with the given coordinates + * @see #getTheta() + * @see #getPhi() + * @exception IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range + */ + public static S2Point of(final double theta, final double phi) { + return new S2Point(theta, phi, vector(theta, phi)); + } + + /** Build a point from its underlying 3D vector + * @param vector 3D vector + * @return point instance with the coordinates determined by the given 3D vector + * @exception IllegalArgumentException if vector norm is zero + */ + public static S2Point of(final Vector3D vector) { + return new S2Point(Math.atan2(vector.getY(), vector.getX()), + Vector3D.PLUS_Z.angle(vector), + vector.normalize()); + } + + /** Build the normalized vector corresponding to spherical coordinates. + * @param theta azimuthal angle \( \theta \) in the x-y plane + * @param phi polar angle \( \varphi \) + * @return normalized vector + * @exception IllegalArgumentException if \( \varphi \) is not in the [\( 0; \pi \)] range + */ + private static Vector3D vector(final double theta, final double phi) + throws IllegalArgumentException { + + if (phi < 0 || phi > Math.PI) { + throw new IllegalArgumentException(phi + " is out of [" + 0 + ", " + Math.PI + "] range"); + } + + final double cosTheta = Math.cos(theta); + final double sinTheta = Math.sin(theta); + final double cosPhi = Math.cos(phi); + final double sinPhi = Math.sin(phi); + + return Vector3D.of(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi); + } + + /** Parses the given string and returns a new point instance. The expected string + * format is the same as that returned by {@link #toString()}. + * @param str the string to parse + * @return point instance represented by the string + * @throws IllegalArgumentException if the given string has an invalid format + */ + public static S2Point parse(String str) throws IllegalArgumentException { + return SimpleCoordinateFormat.getPointFormat().parse(str, FACTORY); + } + + /** Returns a factory object that can be used to created new point instances. + * @return point factory instance + */ + public static Coordinates.Factory2D<S2Point> getFactory() { + return FACTORY; + } } diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java index fd22d6b..d9e3eeb 100644 --- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java +++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java @@ -161,11 +161,11 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> { final S2Point[] array = new S2Point[n]; final Rotation r0 = new Rotation(Vector3D.crossProduct(center, meridian), outsideRadius, RotationConvention.VECTOR_OPERATOR); - array[0] = new S2Point(r0.applyTo(center)); + array[0] = S2Point.of(r0.applyTo(center)); final Rotation r = new Rotation(center, Geometry.TWO_PI / n, RotationConvention.VECTOR_OPERATOR); for (int i = 1; i < n; ++i) { - array[i] = new S2Point(r.applyTo(array[i - 1].getVector())); + array[i] = S2Point.of(r.applyTo(array[i - 1].getVector())); } return array; @@ -325,7 +325,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> { if (tree.getCut() == null && (Boolean) tree.getAttribute()) { // the instance covers the whole space setSize(4 * Math.PI); - setBarycenter(new S2Point(0, 0)); + setBarycenter(S2Point.of(0, 0)); } else { setSize(0); setBarycenter(S2Point.NaN); @@ -478,13 +478,13 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> { if (isEmpty(root.getMinus()) && isFull(root.getPlus())) { // the polygon covers an hemisphere, and its boundary is one 2π long edge final Circle circle = (Circle) root.getCut().getHyperplane(); - return new EnclosingBall<>(new S2Point(circle.getPole()).negate(), + return new EnclosingBall<>(S2Point.of(circle.getPole()).negate(), 0.5 * Math.PI); } if (isFull(root.getMinus()) && isEmpty(root.getPlus())) { // the polygon covers an hemisphere, and its boundary is one 2π long edge final Circle circle = (Circle) root.getCut().getHyperplane(); - return new EnclosingBall<>(new S2Point(circle.getPole()), + return new EnclosingBall<>(S2Point.of(circle.getPole()), 0.5 * Math.PI); } @@ -517,7 +517,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> { EnclosingBall<S2Point> enclosingS2 = new EnclosingBall<>(S2Point.PLUS_K, Double.POSITIVE_INFINITY); for (Point3D outsidePoint : getOutsidePoints()) { - final S2Point outsideS2 = new S2Point(outsidePoint.asVector()); + final S2Point outsideS2 = S2Point.of(outsidePoint.asVector()); final BoundaryProjection<S2Point> projection = projectToBoundary(outsideS2); if (Math.PI - projection.getOffset() < enclosingS2.getRadius()) { enclosingS2 = new EnclosingBall<>(outsideS2.negate(), @@ -529,11 +529,11 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> { } final S2Point[] support = new S2Point[support3D.length]; for (int i = 0; i < support3D.length; ++i) { - support[i] = new S2Point(support3D[i].asVector()); + support[i] = S2Point.of(support3D[i].asVector()); } final EnclosingBall<S2Point> enclosingS2 = - new EnclosingBall<>(new S2Point(enclosing3D.getCenter().asVector()), + new EnclosingBall<>(S2Point.of(enclosing3D.getCenter().asVector()), Math.acos((1 + h * h - r * r) / (2 * h)), support); diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java index b5a1211..a43bc3d 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java @@ -89,7 +89,7 @@ public class SphericalTestUtils { @Override protected LimitAngle parseHyperplane() throws IOException, ParseException { - return new LimitAngle(new S1Point(getNumber()), getBoolean(), getNumber()); + return new LimitAngle(S1Point.of(getNumber()), getBoolean(), getNumber()); } }; diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java index 3b59551..a6bab1a 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java @@ -39,12 +39,12 @@ public class ArcsSetTest { ArcsSet set = new ArcsSet(2.3, 5.7, 1.0e-10); Assert.assertEquals(3.4, set.getSize(), 1.0e-10); Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(1.2))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(8.5))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(8.7))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(3.0))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(2.3))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.7))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(1.2))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(8.5))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(8.7))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(3.0))); Assert.assertEquals(1, set.asList().size()); Assert.assertEquals(2.3, set.asList().get(0).getInf(), 1.0e-10); Assert.assertEquals(5.7, set.asList().get(0).getSup(), 1.0e-10); @@ -55,12 +55,12 @@ public class ArcsSetTest { ArcsSet set = new ArcsSet(5.7 - Geometry.TWO_PI, 2.3, 1.0e-10); Assert.assertEquals(Geometry.TWO_PI - 3.4, set.getSize(), 1.0e-10); Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(1.2))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(8.5))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(8.7))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(3.0))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(2.3))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.7))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(1.2))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(8.5))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(8.7))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(3.0))); Assert.assertEquals(1, set.asList().size()); Assert.assertEquals(5.7, set.asList().get(0).getInf(), 1.0e-10); Assert.assertEquals(2.3 + Geometry.TWO_PI, set.asList().get(0).getSup(), 1.0e-10); @@ -72,7 +72,7 @@ public class ArcsSetTest { Arc arc = new Arc(1.5 * Math.PI, 2.5 * Math.PI, 1.0e-10); ArcsSet.Split split = set.split(arc); for (double alpha = 0.0; alpha <= Geometry.TWO_PI; alpha += 0.01) { - S1Point p = new S1Point(alpha); + S1Point p = S1Point.of(alpha); if (alpha < 0.5 * Math.PI || alpha > 1.5 * Math.PI) { Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p)); Assert.assertEquals(Location.INSIDE, split.getMinus().checkPoint(p)); @@ -89,7 +89,7 @@ public class ArcsSetTest { Arc arc = new Arc(Math.PI, Geometry.TWO_PI, 1.0e-10); ArcsSet.Split split = set.split(arc); for (double alpha = 0.01; alpha < Geometry.TWO_PI; alpha += 0.01) { - S1Point p = new S1Point(alpha); + S1Point p = S1Point.of(alpha); if (alpha > Math.PI) { Assert.assertEquals(Location.OUTSIDE, split.getPlus().checkPoint(p)); Assert.assertEquals(Location.INSIDE, split.getMinus().checkPoint(p)); @@ -99,11 +99,11 @@ public class ArcsSetTest { } } - S1Point zero = new S1Point(0.0); + S1Point zero = S1Point.of(0.0); Assert.assertEquals(Location.BOUNDARY, split.getPlus().checkPoint(zero)); Assert.assertEquals(Location.BOUNDARY, split.getMinus().checkPoint(zero)); - S1Point pi = new S1Point(Math.PI); + S1Point pi = S1Point.of(Math.PI); Assert.assertEquals(Location.BOUNDARY, split.getPlus().checkPoint(pi)); Assert.assertEquals(Location.BOUNDARY, split.getMinus().checkPoint(pi)); @@ -118,9 +118,9 @@ public class ArcsSetTest { public void testFullEqualEndPoints() { ArcsSet set = new ArcsSet(1.0, 1.0, 1.0e-10); Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(9.0))); for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) { - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(alpha))); } Assert.assertEquals(1, set.asList().size()); Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10); @@ -132,9 +132,9 @@ public class ArcsSetTest { public void testFullCircle() { ArcsSet set = new ArcsSet(1.0e-10); Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(9.0))); for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) { - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(alpha))); } Assert.assertEquals(1, set.asList().size()); Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10); @@ -163,8 +163,8 @@ public class ArcsSetTest { @Test public void testSpecialConstruction() { List<SubHyperplane<S1Point>> boundary = new ArrayList<>(); - boundary.add(new LimitAngle(new S1Point(0.0), false, 1.0e-10).wholeHyperplane()); - boundary.add(new LimitAngle(new S1Point(Geometry.TWO_PI - 1.0e-11), true, 1.0e-10).wholeHyperplane()); + boundary.add(new LimitAngle(S1Point.of(0.0), false, 1.0e-10).wholeHyperplane()); + boundary.add(new LimitAngle(S1Point.of(Geometry.TWO_PI - 1.0e-11), true, 1.0e-10).wholeHyperplane()); ArcsSet set = new ArcsSet(boundary, 1.0e-10); Assert.assertEquals(Geometry.TWO_PI, set.getSize(), 1.0e-10); Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20); @@ -190,20 +190,20 @@ public class ArcsSetTest { ArcsSet aMb = (ArcsSet) new RegionFactory<S1Point>().difference(a, b); for (int k = -2; k < 3; ++k) { - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(0.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(0.9 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(1.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(1.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(2.9 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(3.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(3.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(4.9 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(5.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(5.9 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(6.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(6.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(6.2 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(0.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(0.9 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(1.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(1.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(2.9 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(3.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(3.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(4.9 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(5.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(5.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(5.9 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(6.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(6.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(6.2 + k * Geometry.TWO_PI))); } List<Arc> aMbList = aMb.asList(); @@ -236,19 +236,19 @@ public class ArcsSetTest { ArcsSet aMb = (ArcsSet) new RegionFactory<S1Point>().intersection(a, b); for (int k = -2; k < 3; ++k) { - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(0.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(1.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(1.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(2.9 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(3.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(3.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(4.9 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.0 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(5.1 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.INSIDE, aMb.checkPoint(new S1Point(5.4 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(new S1Point(5.5 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(5.6 + k * Geometry.TWO_PI))); - Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(new S1Point(6.2 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(0.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(1.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(1.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(2.9 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(3.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(3.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(4.9 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(5.0 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(5.1 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.INSIDE, aMb.checkPoint(S1Point.of(5.4 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.BOUNDARY, aMb.checkPoint(S1Point.of(5.5 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(5.6 + k * Geometry.TWO_PI))); + Assert.assertEquals(Location.OUTSIDE, aMb.checkPoint(S1Point.of(6.2 + k * Geometry.TWO_PI))); } List<Arc> aMbList = aMb.asList(); @@ -270,15 +270,15 @@ public class ArcsSetTest { new ArcsSet(0.5, 2.0, 1.0e-10)), new ArcsSet(0.0, 5.5, 1.0e-10)); Assert.assertEquals(3.0, set.getSize(), 1.0e-10); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(0.0))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(4.0))); - Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(new S1Point(6.0))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(1.2))); - Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(5.25))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(0.5))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(3.0))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.0))); - Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.5))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(0.0))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(4.0))); + Assert.assertEquals(Region.Location.OUTSIDE, set.checkPoint(S1Point.of(6.0))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(1.2))); + Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(5.25))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(0.5))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(3.0))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.0))); + Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.5))); List<Arc> list = set.asList(); Assert.assertEquals(2, list.size()); @@ -337,8 +337,8 @@ public class ArcsSetTest { @Test public void testShiftedAngles() { for (int k = -2; k < 3; ++k) { - SubLimitAngle l1 = new LimitAngle(new S1Point(1.0 + k * Geometry.TWO_PI), false, 1.0e-10).wholeHyperplane(); - SubLimitAngle l2 = new LimitAngle(new S1Point(1.5 + k * Geometry.TWO_PI), true, 1.0e-10).wholeHyperplane(); + SubLimitAngle l1 = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, 1.0e-10).wholeHyperplane(); + SubLimitAngle l2 = new LimitAngle(S1Point.of(1.5 + k * Geometry.TWO_PI), true, 1.0e-10).wholeHyperplane(); ArcsSet set = new ArcsSet(new BSPTree<>(l1, new BSPTree<S1Point>(Boolean.FALSE), new BSPTree<>(l2, @@ -349,9 +349,9 @@ public class ArcsSetTest { 1.0e-10); for (double alpha = 1.0e-6; alpha < Geometry.TWO_PI; alpha += 0.001) { if (alpha < 1 || alpha > 1.5) { - Assert.assertEquals(Location.OUTSIDE, set.checkPoint(new S1Point(alpha))); + Assert.assertEquals(Location.OUTSIDE, set.checkPoint(S1Point.of(alpha))); } else { - Assert.assertEquals(Location.INSIDE, set.checkPoint(new S1Point(alpha))); + Assert.assertEquals(Location.INSIDE, set.checkPoint(S1Point.of(alpha))); } } } @@ -360,9 +360,9 @@ public class ArcsSetTest { @Test(expected=ArcsSet.InconsistentStateAt2PiWrapping.class) public void testInconsistentState() { - SubLimitAngle l1 = new LimitAngle(new S1Point(1.0), false, 1.0e-10).wholeHyperplane(); - SubLimitAngle l2 = new LimitAngle(new S1Point(2.0), true, 1.0e-10).wholeHyperplane(); - SubLimitAngle l3 = new LimitAngle(new S1Point(3.0), false, 1.0e-10).wholeHyperplane(); + SubLimitAngle l1 = new LimitAngle(S1Point.of(1.0), false, 1.0e-10).wholeHyperplane(); + SubLimitAngle l2 = new LimitAngle(S1Point.of(2.0), true, 1.0e-10).wholeHyperplane(); + SubLimitAngle l3 = new LimitAngle(S1Point.of(3.0), false, 1.0e-10).wholeHyperplane(); new ArcsSet(new BSPTree<>(l1, new BSPTree<S1Point>(Boolean.FALSE), new BSPTree<>(l2, diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java index 454979a..f9a9b3b 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java @@ -25,7 +25,7 @@ public class LimitAngleTest { @Test public void testReversedLimit() { for (int k = -2; k < 3; ++k) { - LimitAngle l = new LimitAngle(new S1Point(1.0 + k * Geometry.TWO_PI), false, 1.0e-10); + LimitAngle l = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, 1.0e-10); Assert.assertEquals(l.getLocation().getAlpha(), l.getReverse().getLocation().getAlpha(), 1.0e-10); Assert.assertEquals(l.getTolerance(), l.getReverse().getTolerance(), 1.0e-10); Assert.assertTrue(l.sameOrientationAs(l)); diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java index 8b0b989..eac954d 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/S1PointTest.java @@ -17,17 +17,20 @@ package org.apache.commons.geometry.spherical.oned; import org.apache.commons.geometry.core.Geometry; +import org.apache.commons.geometry.core.util.Coordinates; import org.junit.Assert; import org.junit.Test; public class S1PointTest { + private static final double EPS = 1e-10; + @Test public void testS1Point() { for (int k = -2; k < 3; ++k) { - S1Point p = new S1Point(1.0 + k * Geometry.TWO_PI); - Assert.assertEquals(Math.cos(1.0), p.getVector().getX(), 1.0e-10); - Assert.assertEquals(Math.sin(1.0), p.getVector().getY(), 1.0e-10); + S1Point p = S1Point.of(1.0 + k * Geometry.TWO_PI); + Assert.assertEquals(Math.cos(1.0), p.getVector().getX(), EPS); + Assert.assertEquals(Math.sin(1.0), p.getVector().getY(), EPS); Assert.assertFalse(p.isNaN()); } } @@ -35,14 +38,14 @@ public class S1PointTest { @Test public void testNaN() { Assert.assertTrue(S1Point.NaN.isNaN()); - Assert.assertTrue(S1Point.NaN.equals(new S1Point(Double.NaN))); - Assert.assertFalse(new S1Point(1.0).equals(S1Point.NaN)); + Assert.assertTrue(S1Point.NaN.equals(S1Point.of(Double.NaN))); + Assert.assertFalse(S1Point.of(1.0).equals(S1Point.NaN)); } @Test public void testEquals() { - S1Point a = new S1Point(1.0); - S1Point b = new S1Point(1.0); + S1Point a = S1Point.of(1.0); + S1Point b = S1Point.of(1.0); Assert.assertEquals(a.hashCode(), b.hashCode()); Assert.assertFalse(a == b); Assert.assertTrue(a.equals(b)); @@ -52,9 +55,44 @@ public class S1PointTest { @Test public void testDistance() { - S1Point a = new S1Point(1.0); - S1Point b = new S1Point(a.getAlpha() + 0.5 * Math.PI); + S1Point a = S1Point.of(1.0); + S1Point b = S1Point.of(a.getAlpha() + 0.5 * Math.PI); Assert.assertEquals(0.5 * Math.PI, a.distance(b), 1.0e-10); } + @Test + public void testToString() { + // act/assert + Assert.assertEquals("(0.0)", S1Point.of(0.0).toString()); + Assert.assertEquals("(1.0)", S1Point.of(1.0).toString()); + } + + @Test + public void testParse() { + // act/assert + checkPoint(S1Point.parse("(0)"), 0.0); + checkPoint(S1Point.parse("(1)"), 1.0); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + S1Point.parse("abc"); + } + + @Test + public void testGetFactory() { + // act + Coordinates.Factory1D<S1Point> factory = S1Point.getFactory(); + + // assert + checkPoint(factory.create(0), 0); + checkPoint(factory.create(1), 1); + checkPoint(factory.create(Geometry.TWO_PI), 0); + } + + private void checkPoint(S1Point p, double alpha) { + Assert.assertEquals(alpha, p.getAlpha(), EPS); + } + } diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java index a958dcf..7b9ad53 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java @@ -47,7 +47,7 @@ public class CircleTest { @Test public void testXY() { - Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10); + Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10); Assert.assertEquals(0.0, circle.getPointAt(0).distance(circle.getXAxis()), 1.0e-10); Assert.assertEquals(0.0, circle.getPointAt(0.5 * Math.PI).distance(circle.getYAxis()), 1.0e-10); Assert.assertEquals(0.5 * Math.PI, Vector3D.angle(circle.getXAxis(), circle.getYAxis()), 1.0e-10); @@ -60,7 +60,7 @@ public class CircleTest { @Test public void testReverse() { - Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10); + Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10); Circle reversed = circle.getReverse(); Assert.assertEquals(0.0, reversed.getPointAt(0).distance(reversed.getXAxis()), 1.0e-10); Assert.assertEquals(0.0, reversed.getPointAt(0.5 * Math.PI).distance(reversed.getYAxis()), 1.0e-10); @@ -82,7 +82,7 @@ public class CircleTest { @Test public void testPhase() { - Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10); + Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10); Vector3D p = Vector3D.of(1, 2, -4); Vector3D samePhase = circle.getPointAt(circle.getPhase(p)); Assert.assertEquals(0.0, @@ -98,20 +98,20 @@ public class CircleTest { @Test public void testSubSpace() { - Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10); - Assert.assertEquals(0.0, circle.toSubSpace(new S2Point(circle.getXAxis())).getAlpha(), 1.0e-10); - Assert.assertEquals(0.5 * Math.PI, circle.toSubSpace(new S2Point(circle.getYAxis())).getAlpha(), 1.0e-10); + Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10); + Assert.assertEquals(0.0, circle.toSubSpace(S2Point.of(circle.getXAxis())).getAlpha(), 1.0e-10); + Assert.assertEquals(0.5 * Math.PI, circle.toSubSpace(S2Point.of(circle.getYAxis())).getAlpha(), 1.0e-10); Vector3D p = Vector3D.of(1, 2, -4); - Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(new S2Point(p)).getAlpha(), 1.0e-10); + Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(S2Point.of(p)).getAlpha(), 1.0e-10); } @Test public void testSpace() { - Circle circle = new Circle(new S2Point(1.2, 2.5), new S2Point(-4.3, 0), 1.0e-10); + Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10); for (double alpha = 0; alpha < Geometry.TWO_PI; alpha += 0.1) { Vector3D p = Vector3D.linearCombination(Math.cos(alpha), circle.getXAxis(), Math.sin(alpha), circle.getYAxis()); - Vector3D q = circle.toSpace(new S1Point(alpha)).getVector(); + Vector3D q = circle.toSpace(S1Point.of(alpha)).getVector(); Assert.assertEquals(0.0, p.distance(q), 1.0e-10); Assert.assertEquals(0.5 * Math.PI, Vector3D.angle(circle.getPole(), q), 1.0e-10); } @@ -120,12 +120,12 @@ public class CircleTest { @Test public void testOffset() { Circle circle = new Circle(Vector3D.PLUS_Z, 1.0e-10); - Assert.assertEquals(0.0, circle.getOffset(new S2Point(Vector3D.PLUS_X)), 1.0e-10); - Assert.assertEquals(0.0, circle.getOffset(new S2Point(Vector3D.MINUS_X)), 1.0e-10); - Assert.assertEquals(0.0, circle.getOffset(new S2Point(Vector3D.PLUS_Y)), 1.0e-10); - Assert.assertEquals(0.0, circle.getOffset(new S2Point(Vector3D.MINUS_Y)), 1.0e-10); - Assert.assertEquals(-0.5 * Math.PI, circle.getOffset(new S2Point(Vector3D.PLUS_Z)), 1.0e-10); - Assert.assertEquals(0.5 * Math.PI, circle.getOffset(new S2Point(Vector3D.MINUS_Z)), 1.0e-10); + Assert.assertEquals(0.0, circle.getOffset(S2Point.of(Vector3D.PLUS_X)), 1.0e-10); + Assert.assertEquals(0.0, circle.getOffset(S2Point.of(Vector3D.MINUS_X)), 1.0e-10); + Assert.assertEquals(0.0, circle.getOffset(S2Point.of(Vector3D.PLUS_Y)), 1.0e-10); + Assert.assertEquals(0.0, circle.getOffset(S2Point.of(Vector3D.MINUS_Y)), 1.0e-10); + Assert.assertEquals(-0.5 * Math.PI, circle.getOffset(S2Point.of(Vector3D.PLUS_Z)), 1.0e-10); + Assert.assertEquals(0.5 * Math.PI, circle.getOffset(S2Point.of(Vector3D.MINUS_Z)), 1.0e-10); } @@ -164,7 +164,7 @@ public class CircleTest { RotationConvention.VECTOR_OPERATOR); Transform<S2Point, S1Point> t = Circle.getTransform(r); - S2Point p = new S2Point(Vector3D.of(sphRandom.nextVector())); + S2Point p = S2Point.of(Vector3D.of(sphRandom.nextVector())); S2Point tp = t.apply(p); Assert.assertEquals(0.0, r.applyTo(p.getVector()).distance(tp.getVector()), 1.0e-10); @@ -175,7 +175,7 @@ public class CircleTest { Assert.assertEquals(0.0, r.applyTo(c.getYAxis()).distance(tc.getYAxis()), 1.0e-10); Assert.assertEquals(c.getTolerance(), ((Circle) t.apply(c)).getTolerance(), 1.0e-10); - SubLimitAngle sub = new LimitAngle(new S1Point(Geometry.TWO_PI * random.nextDouble()), + SubLimitAngle sub = new LimitAngle(S1Point.of(Geometry.TWO_PI * random.nextDouble()), random.nextBoolean(), 1.0e-10).wholeHyperplane(); Vector3D psub = c.getPointAt(((LimitAngle) sub.getHyperplane()).getLocation().getAlpha()); SubLimitAngle tsub = (SubLimitAngle) t.apply(sub, c, tc); diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java index bbf5891..1661921 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/S2PointTest.java @@ -18,45 +18,48 @@ package org.apache.commons.geometry.spherical.twod; import org.apache.commons.geometry.core.Geometry; +import org.apache.commons.geometry.core.util.Coordinates; import org.junit.Assert; import org.junit.Test; public class S2PointTest { + private static final double EPS = 1e-10; + @Test public void testS2Point() { for (int k = -2; k < 3; ++k) { - S2Point p = new S2Point(1.0 + k * Geometry.TWO_PI, 1.4); - Assert.assertEquals(1.0 + k * Geometry.TWO_PI, p.getTheta(), 1.0e-10); - Assert.assertEquals(1.4, p.getPhi(), 1.0e-10); - Assert.assertEquals(Math.cos(1.0) * Math.sin(1.4), p.getVector().getX(), 1.0e-10); - Assert.assertEquals(Math.sin(1.0) * Math.sin(1.4), p.getVector().getY(), 1.0e-10); - Assert.assertEquals(Math.cos(1.4), p.getVector().getZ(), 1.0e-10); + S2Point p = S2Point.of(1.0 + k * Geometry.TWO_PI, 1.4); + Assert.assertEquals(1.0 + k * Geometry.TWO_PI, p.getTheta(), EPS); + Assert.assertEquals(1.4, p.getPhi(), EPS); + Assert.assertEquals(Math.cos(1.0) * Math.sin(1.4), p.getVector().getX(), EPS); + Assert.assertEquals(Math.sin(1.0) * Math.sin(1.4), p.getVector().getY(), EPS); + Assert.assertEquals(Math.cos(1.4), p.getVector().getZ(), EPS); Assert.assertFalse(p.isNaN()); } } @Test(expected=IllegalArgumentException.class) public void testNegativePolarAngle() { - new S2Point(1.0, -1.0); + S2Point.of(1.0, -1.0); } @Test(expected=IllegalArgumentException.class) public void testTooLargePolarAngle() { - new S2Point(1.0, 3.5); + S2Point.of(1.0, 3.5); } @Test public void testNaN() { Assert.assertTrue(S2Point.NaN.isNaN()); - Assert.assertTrue(S2Point.NaN.equals(new S2Point(Double.NaN, 1.0))); - Assert.assertFalse(new S2Point(1.0, 1.3).equals(S2Point.NaN)); + Assert.assertTrue(S2Point.NaN.equals(S2Point.of(Double.NaN, 1.0))); + Assert.assertFalse(S2Point.of(1.0, 1.3).equals(S2Point.NaN)); } @Test public void testEquals() { - S2Point a = new S2Point(1.0, 1.0); - S2Point b = new S2Point(1.0, 1.0); + S2Point a = S2Point.of(1.0, 1.0); + S2Point b = S2Point.of(1.0, 1.0); Assert.assertEquals(a.hashCode(), b.hashCode()); Assert.assertFalse(a == b); Assert.assertTrue(a.equals(b)); @@ -66,12 +69,46 @@ public class S2PointTest { @Test public void testDistance() { - S2Point a = new S2Point(1.0, 0.5 * Math.PI); - S2Point b = new S2Point(a.getTheta() + 0.5 * Math.PI, a.getPhi()); + S2Point a = S2Point.of(1.0, 0.5 * Math.PI); + S2Point b = S2Point.of(a.getTheta() + 0.5 * Math.PI, a.getPhi()); Assert.assertEquals(0.5 * Math.PI, a.distance(b), 1.0e-10); Assert.assertEquals(Math.PI, a.distance(a.negate()), 1.0e-10); Assert.assertEquals(0.5 * Math.PI, S2Point.MINUS_I.distance(S2Point.MINUS_K), 1.0e-10); - Assert.assertEquals(0.0, new S2Point(1.0, 0).distance(new S2Point(2.0, 0)), 1.0e-10); + Assert.assertEquals(0.0, S2Point.of(1.0, 0).distance(S2Point.of(2.0, 0)), 1.0e-10); + } + + @Test + public void testToString() { + // act/assert + Assert.assertEquals("(0.0, 0.0)", S2Point.of(0.0, 0.0).toString()); + Assert.assertEquals("(1.0, 2.0)", S2Point.of(1.0, 2.0).toString()); + } + + @Test + public void testParse() { + // act/assert + checkPoint(S2Point.parse("(0,0)"), 0.0, 0.0); + checkPoint(S2Point.parse("(1,2)"), 1.0, 2.0); } + @Test(expected = IllegalArgumentException.class) + public void testParse_failure() { + // act/assert + S2Point.parse("abc"); + } + + @Test + public void testGetFactory() { + // act + Coordinates.Factory2D<S2Point> factory = S2Point.getFactory(); + + // assert + checkPoint(factory.create(0, 0), 0, 0); + checkPoint(factory.create(1, 2), 1, 2); + } + + private void checkPoint(S2Point p, double theta, double phi) { + Assert.assertEquals(theta, p.getTheta(), EPS); + Assert.assertEquals(phi, p.getPhi(), EPS); + } } diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java index 0f52671..0f056e8 100644 --- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java +++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java @@ -43,7 +43,7 @@ public class SphericalPolygonsSetTest { 0x852fd2a0ed8d2f6dl)); for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); - Assert.assertEquals(Location.INSIDE, full.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, full.checkPoint(S2Point.of(v))); } Assert.assertEquals(4 * Math.PI, new SphericalPolygonsSet(0.01, new S2Point[0]).getSize(), 1.0e-10); Assert.assertEquals(0, new SphericalPolygonsSet(0.01, new S2Point[0]).getBoundarySize(), 1.0e-10); @@ -61,7 +61,7 @@ public class SphericalPolygonsSetTest { 0x76d9205d6167b6ddl)); for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); - Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(S2Point.of(v))); } Assert.assertEquals(0, empty.getSize(), 1.0e-10); Assert.assertEquals(0, empty.getBoundarySize(), 1.0e-10); @@ -81,11 +81,11 @@ public class SphericalPolygonsSetTest { for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); if (v.getZ() < -sinTol) { - Assert.assertEquals(Location.INSIDE, south.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, south.checkPoint(S2Point.of(v))); } else if (v.getZ() > sinTol) { - Assert.assertEquals(Location.OUTSIDE, south.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.OUTSIDE, south.checkPoint(S2Point.of(v))); } else { - Assert.assertEquals(Location.BOUNDARY, south.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.BOUNDARY, south.checkPoint(S2Point.of(v))); } } Assert.assertEquals(1, south.getBoundaryLoops().size()); @@ -117,11 +117,11 @@ public class SphericalPolygonsSetTest { for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) { - Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, octant.checkPoint(S2Point.of(v))); } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) { - Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(S2Point.of(v))); } else { - Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(S2Point.of(v))); } } @@ -156,7 +156,7 @@ public class SphericalPolygonsSetTest { Assert.assertEquals(3, count); Assert.assertEquals(0.0, - octant.getBarycenter().distance(new S2Point(Vector3D.of(1, 1, 1))), + octant.getBarycenter().distance(S2Point.of(Vector3D.of(1, 1, 1))), 1.0e-10); Assert.assertEquals(0.5 * Math.PI, octant.getSize(), 1.0e-10); @@ -166,7 +166,7 @@ public class SphericalPolygonsSetTest { EnclosingBall<S2Point> reversedCap = ((SphericalPolygonsSet) factory.getComplement(octant)).getEnclosingCap(); - Assert.assertEquals(0, reversedCap.getCenter().distance(new S2Point(Vector3D.of(-1, -1, -1))), 1.0e-10); + Assert.assertEquals(0, reversedCap.getCenter().distance(S2Point.of(Vector3D.of(-1, -1, -1))), 1.0e-10); Assert.assertEquals(Math.PI - Math.asin(1.0 / Math.sqrt(3)), reversedCap.getRadius(), 1.0e-10); } @@ -182,11 +182,11 @@ public class SphericalPolygonsSetTest { for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) { - Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, octant.checkPoint(S2Point.of(v))); } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) { - Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(S2Point.of(v))); } else { - Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(S2Point.of(v))); } } } @@ -208,11 +208,11 @@ public class SphericalPolygonsSetTest { for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); if (((v.getX() < -sinTol) || (v.getY() < -sinTol)) && (v.getZ() > sinTol)) { - Assert.assertEquals(Location.INSIDE, threeOctants.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, threeOctants.checkPoint(S2Point.of(v))); } else if (((v.getX() > sinTol) && (v.getY() > sinTol)) || (v.getZ() < -sinTol)) { - Assert.assertEquals(Location.OUTSIDE, threeOctants.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.OUTSIDE, threeOctants.checkPoint(S2Point.of(v))); } else { - Assert.assertEquals(Location.BOUNDARY, threeOctants.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.BOUNDARY, threeOctants.checkPoint(S2Point.of(v))); } } @@ -274,14 +274,14 @@ public class SphericalPolygonsSetTest { boundary.add(create(Vector3D.PLUS_Z, Vector3D.MINUS_Y, Vector3D.PLUS_X, tol, 0.0, 0.5 * Math.PI)); SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol); - Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1, 1, 1).normalize()))); - Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(Vector3D.of(-1, 1, 1).normalize()))); - Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(Vector3D.of(-1, -1, 1).normalize()))); - Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1, -1, 1).normalize()))); - Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1, 1, -1).normalize()))); - Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of(-1, 1, -1).normalize()))); - Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(Vector3D.of(-1, -1, -1).normalize()))); - Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(Vector3D.of( 1, -1, -1).normalize()))); + Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1, 1, 1).normalize()))); + Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(Vector3D.of(-1, 1, 1).normalize()))); + Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(Vector3D.of(-1, -1, 1).normalize()))); + Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1, -1, 1).normalize()))); + Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1, 1, -1).normalize()))); + Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of(-1, 1, -1).normalize()))); + Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(Vector3D.of(-1, -1, -1).normalize()))); + Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(Vector3D.of( 1, -1, -1).normalize()))); Assert.assertEquals(Geometry.TWO_PI, polygon.getSize(), 1.0e-10); Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), 1.0e-10); @@ -342,15 +342,15 @@ public class SphericalPolygonsSetTest { for (int i = 0; i < 1000; ++i) { Vector3D v = Vector3D.of(random.nextVector()); if ((v.getX() < -sinTol) && (v.getY() < -sinTol) && (v.getZ() < -sinTol)) { - Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(v))); } else if ((v.getX() < sinTol) && (v.getY() < sinTol) && (v.getZ() < sinTol)) { - Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(S2Point.of(v))); } else if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) { - Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.INSIDE, polygon.checkPoint(S2Point.of(v))); } else if ((v.getX() > -sinTol) && (v.getY() > -sinTol) && (v.getZ() > -sinTol)) { - Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(S2Point.of(v))); } else { - Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(v))); + Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.of(v))); } } @@ -366,17 +366,17 @@ public class SphericalPolygonsSetTest { public void testPartWithHole() { double tol = 0.01; double alpha = 0.7; - S2Point center = new S2Point(Vector3D.of(1, 1, 1)); + S2Point center = S2Point.of(Vector3D.of(1, 1, 1)); SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_Z, alpha, 6, tol); SphericalPolygonsSet hole = new SphericalPolygonsSet(tol, - new S2Point(Math.PI / 6, Math.PI / 3), - new S2Point(Math.PI / 3, Math.PI / 3), - new S2Point(Math.PI / 4, Math.PI / 6)); + S2Point.of(Math.PI / 6, Math.PI / 3), + S2Point.of(Math.PI / 3, Math.PI / 3), + S2Point.of(Math.PI / 4, Math.PI / 6)); SphericalPolygonsSet hexaWithHole = (SphericalPolygonsSet) new RegionFactory<S2Point>().difference(hexa, hole); for (double phi = center.getPhi() - alpha + 0.1; phi < center.getPhi() + alpha - 0.1; phi += 0.07) { - Location l = hexaWithHole.checkPoint(new S2Point(Math.PI / 4, phi)); + Location l = hexaWithHole.checkPoint(S2Point.of(Math.PI / 4, phi)); if (phi < Math.PI / 6 || phi > Math.PI / 3) { Assert.assertEquals(Location.INSIDE, l); } else { @@ -428,24 +428,24 @@ public class SphericalPolygonsSetTest { concentric.getSize(), 1.0e-10); // we expect lots of sign changes as we traverse all concentric rings - double phi = new S2Point(center).getPhi(); - Assert.assertEquals(+0.207, concentric.projectToBoundary(new S2Point(-0.60, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.048, concentric.projectToBoundary(new S2Point(-0.21, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point(-0.10, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 0.01, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.049, concentric.projectToBoundary(new S2Point( 0.16, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.038, concentric.projectToBoundary(new S2Point( 0.29, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.097, concentric.projectToBoundary(new S2Point( 0.48, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.64, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.072, concentric.projectToBoundary(new S2Point( 0.79, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.93, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.091, concentric.projectToBoundary(new S2Point( 1.08, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.037, concentric.projectToBoundary(new S2Point( 1.28, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.051, concentric.projectToBoundary(new S2Point( 1.40, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 1.55, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point( 1.67, phi)).getOffset(), 0.01); - Assert.assertEquals(-0.044, concentric.projectToBoundary(new S2Point( 1.79, phi)).getOffset(), 0.01); - Assert.assertEquals(+0.201, concentric.projectToBoundary(new S2Point( 2.16, phi)).getOffset(), 0.01); + double phi = S2Point.of(center).getPhi(); + Assert.assertEquals(+0.207, concentric.projectToBoundary(S2Point.of(-0.60, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.048, concentric.projectToBoundary(S2Point.of(-0.21, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.027, concentric.projectToBoundary(S2Point.of(-0.10, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.041, concentric.projectToBoundary(S2Point.of( 0.01, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.049, concentric.projectToBoundary(S2Point.of( 0.16, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.038, concentric.projectToBoundary(S2Point.of( 0.29, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.097, concentric.projectToBoundary(S2Point.of( 0.48, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.022, concentric.projectToBoundary(S2Point.of( 0.64, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.072, concentric.projectToBoundary(S2Point.of( 0.79, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.022, concentric.projectToBoundary(S2Point.of( 0.93, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.091, concentric.projectToBoundary(S2Point.of( 1.08, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.037, concentric.projectToBoundary(S2Point.of( 1.28, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.051, concentric.projectToBoundary(S2Point.of( 1.40, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.041, concentric.projectToBoundary(S2Point.of( 1.55, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.027, concentric.projectToBoundary(S2Point.of( 1.67, phi)).getOffset(), 0.01); + Assert.assertEquals(-0.044, concentric.projectToBoundary(S2Point.of( 1.79, phi)).getOffset(), 0.01); + Assert.assertEquals(+0.201, concentric.projectToBoundary(S2Point.of( 2.16, phi)).getOffset(), 0.01); } @@ -544,7 +544,7 @@ public class SphericalPolygonsSetTest { } private S2Point s2Point(double latitude, double longitude) { - return new S2Point(Math.toRadians(longitude), Math.toRadians(90.0 - latitude)); + return S2Point.of(Math.toRadians(longitude), Math.toRadians(90.0 - latitude)); } }
