Repository: commons-math Updated Branches: refs/heads/MATH_3_X 412eed93d -> 962a367a5
Added a way to build polyhedrons sets from a vertices and facets. Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/962a367a Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/962a367a Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/962a367a Branch: refs/heads/MATH_3_X Commit: 962a367a54f258f344976bf7b93bce155d52e04f Parents: 412eed9 Author: Luc Maisonobe <l...@apache.org> Authored: Sun Apr 12 16:57:31 2015 +0200 Committer: Luc Maisonobe <l...@apache.org> Committed: Sun Apr 12 16:59:49 2015 +0200 ---------------------------------------------------------------------- pom.xml | 8 +- src/changes/changes.xml | 4 + .../math3/exception/util/LocalizedFormats.java | 4 + .../math3/geometry/euclidean/threed/Plane.java | 8 +- .../euclidean/threed/PolyhedronsSet.java | 201 ++++++++++++- .../util/LocalizedFormats_fr.properties | 4 + .../exception/util/LocalizedFormatsTest.java | 2 +- .../geometry/euclidean/threed/PLYParser.java | 290 +++++++++++++++++++ .../euclidean/threed/PolyhedronsSetTest.java | 91 +++++- .../threed/pentomino-N-bad-orientation.ply | 40 +++ .../euclidean/threed/pentomino-N-hole.ply | 39 +++ .../threed/pentomino-N-out-of-plane.ply | 40 +++ .../euclidean/threed/pentomino-N-too-close.ply | 86 ++++++ .../geometry/euclidean/threed/pentomino-N.ply | 39 +++ 14 files changed, 835 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index fbc5508..07a3a14 100644 --- a/pom.xml +++ b/pom.xml @@ -600,9 +600,15 @@ <exclude>src/test/resources/org/apache/commons/math3/stat/data/NumAcc4.txt</exclude> <exclude>src/test/resources/org/apache/commons/math3/stat/data/Michelso.txt</exclude> <exclude>src/test/resources/org/apache/commons/math3/stat/data/Mavro.txt</exclude> + <exclude>src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/issue-1211.bsp</exclude> + <exclude>src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-bad-orientation.ply</exclude> + <exclude>src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-hole.ply</exclude> + <exclude>src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-out-of-plane.ply</exclude> + <exclude>src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-too-close.ply</exclude> + <exclude>src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-.ply</exclude> <!-- direction numbers for Sobol generation from Frances Y. Kuo and Stephen Joe, - available under a BSD-style license (see NOTICE.txt and LICENSE.txt) --> + available under a BSD-style license (see LICENSE.txt) --> <exclude>src/main/resources/assets/org/apache/commons/math3/random/new-joe-kuo-6.1000</exclude> <!-- text file explaining reference to a public domain image --> http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 561be34..e1ca5ec 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -51,6 +51,10 @@ If the output is not quite correct, check for invisible trailing spaces! </properties> <body> <release version="3.5" date="TBD" description="TBD"> + <action dev="luc" type="add"> + Added a way to build polyhedrons sets from a list of vertices and + facets specified using vertices indices. + </action> <action dev="psteitz" type="update" issue="MATH-1213"> Added Laguerre complex solve methods taking maxEval parameters. </action> http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/main/java/org/apache/commons/math3/exception/util/LocalizedFormats.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/exception/util/LocalizedFormats.java b/src/main/java/org/apache/commons/math3/exception/util/LocalizedFormats.java index 0f3848f..8fe4dc9 100644 --- a/src/main/java/org/apache/commons/math3/exception/util/LocalizedFormats.java +++ b/src/main/java/org/apache/commons/math3/exception/util/LocalizedFormats.java @@ -70,6 +70,7 @@ public enum LocalizedFormats implements Localizable { CANNOT_TRANSFORM_TO_DOUBLE("Conversion Exception in Transformation: {0}"), CARDAN_ANGLES_SINGULARITY("Cardan angles singularity"), CLASS_DOESNT_IMPLEMENT_COMPARABLE("class ({0}) does not implement Comparable"), + CLOSE_VERTICES("too close vertices near point ({0}, {1}, {2})"), CLOSEST_ORTHOGONAL_MATRIX_HAS_NEGATIVE_DETERMINANT("the closest orthogonal matrix has a negative determinant {0}"), COLUMN_INDEX_OUT_OF_RANGE("column index {0} out of allowed range [{1}, {2}]"), COLUMN_INDEX("column index ({0})"), /* keep */ @@ -91,6 +92,7 @@ public enum LocalizedFormats implements Localizable { DISCRETE_CUMULATIVE_PROBABILITY_RETURNED_NAN("Discrete cumulative probability function returned NaN for argument {0}"), DISTRIBUTION_NOT_LOADED("distribution not loaded"), DUPLICATED_ABSCISSA_DIVISION_BY_ZERO("duplicated abscissa {0} causes division by zero"), + EDGE_CONNECTED_TO_ONE_FACET("edge joining points ({0}, {1}, {2}) and ({3}, {4}, {5}) is connected to one facet only"), ELITISM_RATE("elitism rate ({0})"), EMPTY_CLUSTER_IN_K_MEANS("empty cluster in k-means"), EMPTY_INTERPOLATION_SAMPLE("sample for interpolation is empty"), @@ -103,6 +105,7 @@ public enum LocalizedFormats implements Localizable { EULER_ANGLES_SINGULARITY("Euler angles singularity"), EVALUATION("evaluation"), /* keep */ EXPANSION_FACTOR_SMALLER_THAN_ONE("expansion factor smaller than one ({0})"), + FACET_ORIENTATION_MISMATCH("facets orientation mismatch around edge joining points ({0}, {1}, {2}) and ({3}, {4}, {5})"), FACTORIAL_NEGATIVE_PARAMETER("must have n >= 0 for n!, got n = {0}"), FAILED_BRACKETING("number of iterations={4}, maximum iterations={5}, initial={6}, lower bound={7}, upper bound={8}, final a value={0}, final b value={1}, f(a)={2}, f(b)={3}"), FAILED_FRACTION_CONVERSION("Unable to convert {0} to fraction after {1} iterations"), @@ -285,6 +288,7 @@ public enum LocalizedFormats implements Localizable { OUT_OF_BOUND_SIGNIFICANCE_LEVEL("out of bounds significance level {0}, must be between {1} and {2}"), SIGNIFICANCE_LEVEL("significance level ({0})"), /* keep */ OUT_OF_ORDER_ABSCISSA_ARRAY("the abscissae array must be sorted in a strictly increasing order, but the {0}-th element is {1} whereas {2}-th is {3}"), + OUT_OF_PLANE("point ({0}, {1}, {2}) is out of plane"), OUT_OF_RANGE_ROOT_OF_UNITY_INDEX("out of range root of unity index {0} (must be in [{1};{2}])"), OUT_OF_RANGE("out of range"), /* keep */ OUT_OF_RANGE_SIMPLE("{0} out of [{1}, {2}] range"), /* keep */ http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java index a63e806..158818d 100644 --- a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java +++ b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java @@ -345,8 +345,8 @@ public class Plane implements Hyperplane<Euclidean3D>, Embedding<Euclidean3D, Eu */ public boolean isSimilarTo(final Plane plane) { final double angle = Vector3D.angle(w, plane.w); - return ((angle < 1.0e-10) && (FastMath.abs(originOffset - plane.originOffset) < 1.0e-10)) || - ((angle > (FastMath.PI - 1.0e-10)) && (FastMath.abs(originOffset + plane.originOffset) < 1.0e-10)); + return ((angle < 1.0e-10) && (FastMath.abs(originOffset - plane.originOffset) < tolerance)) || + ((angle > (FastMath.PI - 1.0e-10)) && (FastMath.abs(originOffset + plane.originOffset) < tolerance)); } /** Rotate the plane around the specified point. @@ -409,7 +409,7 @@ public class Plane implements Hyperplane<Euclidean3D>, Embedding<Euclidean3D, Eu */ public Line intersection(final Plane other) { final Vector3D direction = Vector3D.crossProduct(w, other.w); - if (direction.getNorm() < 1.0e-10) { + if (direction.getNorm() < tolerance) { return null; } final Vector3D point = intersection(this, other, new Plane(direction, tolerance)); @@ -478,7 +478,7 @@ public class Plane implements Hyperplane<Euclidean3D>, Embedding<Euclidean3D, Eu * @return true if p belongs to the plane */ public boolean contains(final Vector3D p) { - return FastMath.abs(getOffset(p)) < 1.0e-10; + return FastMath.abs(getOffset(p)) < tolerance; } /** Get the offset (oriented distance) of a parallel plane. http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java index 69d88b5..b06113b 100644 --- a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java +++ b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java @@ -17,11 +17,18 @@ package org.apache.commons.math3.geometry.euclidean.threed; import java.awt.geom.AffineTransform; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.List; +import org.apache.commons.math3.exception.MathIllegalArgumentException; +import org.apache.commons.math3.exception.NumberIsTooSmallException; +import org.apache.commons.math3.exception.util.LocalizedFormats; import org.apache.commons.math3.geometry.Point; import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D; import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; +import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet; import org.apache.commons.math3.geometry.euclidean.twod.SubLine; import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; import org.apache.commons.math3.geometry.partitioning.AbstractRegion; @@ -76,7 +83,7 @@ public class PolyhedronsSet extends AbstractRegion<Euclidean3D, Euclidean2D> { super(tree, tolerance); } - /** Build a polyhedrons set from a Boundary REPresentation (B-rep). + /** Build a polyhedrons set from a Boundary REPresentation (B-rep) specified by sub-hyperplanes. * <p>The boundary is provided as a collection of {@link * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the * interior part of the region on its minus side and the exterior on @@ -102,6 +109,29 @@ public class PolyhedronsSet extends AbstractRegion<Euclidean3D, Euclidean2D> { super(boundary, tolerance); } + /** Build a polyhedrons set from a Boundary REPresentation (B-rep) specified by connected vertices. + * <p> + * The boundary is provided as a list of vertices and a list of facets. + * Each facet is specified as an integer array containing the arrays vertices + * indices in the vertices list. Each facet normal is oriented by right hand + * rule to the facet vertices list. + * </p> + * <p> + * Some basic sanity checks are performed but not everything is thoroughly + * assessed, so it remains under caller responsibility to ensure the vertices + * and facets are consistent and properly define a polyhedrons set. + * </p> + * @param vertices list of polyhedrons set vertices + * @param facets list of facets, as vertices indices in the vertices list + * @param tolerance tolerance below which points are considered identical + * @exception MathIllegalArgumentException if some basic sanity checks fail + * @since 3.5 + */ + public PolyhedronsSet(final List<Vector3D> vertices, final List<int[]> facets, + final double tolerance) { + super(buildBoundary(vertices, facets, tolerance), tolerance); + } + /** Build a parallellepipedic box. * @param xMin low bound along the x direction * @param xMax high bound along the x direction @@ -215,6 +245,175 @@ public class PolyhedronsSet extends AbstractRegion<Euclidean3D, Euclidean2D> { return boundary.getTree(false); } + /** Build boundary from vertices and facets. + * @param vertices list of polyhedrons set vertices + * @param facets list of facets, as vertices indices in the vertices list + * @param tolerance tolerance below which points are considered identical + * @return boundary as a list of sub-hyperplanes + * @exception MathIllegalArgumentException if some basic sanity checks fail + * @since 3.5 + */ + private static List<SubHyperplane<Euclidean3D>> buildBoundary(final List<Vector3D> vertices, + final List<int[]> facets, + final double tolerance) { + + // check vertices distances + for (int i = 0; i < vertices.size() - 1; ++i) { + final Vector3D vi = vertices.get(i); + for (int j = i + 1; j < vertices.size(); ++j) { + if (Vector3D.distance(vi, vertices.get(j)) <= tolerance) { + throw new MathIllegalArgumentException(LocalizedFormats.CLOSE_VERTICES, + vi.getX(), vi.getY(), vi.getZ()); + } + } + } + + // find how vertices are referenced by facets + final int[][] references = findReferences(vertices, facets); + + // find how vertices are linked together by edges along the facets they belong to + final int[][] successors = successors(vertices, facets, references); + + // check edges orientations + for (int vA = 0; vA < vertices.size(); ++vA) { + for (final int vB : successors[vA]) { + + if (vB >= 0) { + // when facets are properly oriented, if vB is the successor of vA on facet f1, + // then there must be an adjacent facet f2 where vA is the successor of vB + boolean found = false; + for (final int v : successors[vB]) { + found = found || (v == vA); + } + if (!found) { + final Vector3D start = vertices.get(vA); + final Vector3D end = vertices.get(vB); + throw new MathIllegalArgumentException(LocalizedFormats.EDGE_CONNECTED_TO_ONE_FACET, + start.getX(), start.getY(), start.getZ(), + end.getX(), end.getY(), end.getZ()); + } + } + } + } + + final List<SubHyperplane<Euclidean3D>> boundary = new ArrayList<SubHyperplane<Euclidean3D>>(); + + for (final int[] facet : facets) { + + // define facet plane from the first 3 points + Plane plane = new Plane(vertices.get(facet[0]), vertices.get(facet[1]), vertices.get(facet[2]), + tolerance); + + // check all points are in the plane + final Vector2D[] two2Points = new Vector2D[facet.length]; + for (int i = 0 ; i < facet.length; ++i) { + final Vector3D v = vertices.get(facet[i]); + if (!plane.contains(v)) { + throw new MathIllegalArgumentException(LocalizedFormats.OUT_OF_PLANE, + v.getX(), v.getY(), v.getZ()); + } + two2Points[i] = plane.toSubSpace(v); + } + + // create the polygonal facet + boundary.add(new SubPlane(plane, new PolygonsSet(tolerance, two2Points))); + + } + + return boundary; + + } + + /** Find the facets that reference each edges. + * @param vertices list of polyhedrons set vertices + * @param facets list of facets, as vertices indices in the vertices list + * @return references array such that r[v][k] = f for some k if facet f contains vertex v + * @exception MathIllegalArgumentException if some facets have fewer than 3 vertices + * @since 3.5 + */ + private static int[][] findReferences(final List<Vector3D> vertices, final List<int[]> facets) { + + // find the maximum number of facets a vertex belongs to + final int[] nbFacets = new int[vertices.size()]; + int maxFacets = 0; + for (final int[] facet : facets) { + if (facet.length < 3) { + throw new NumberIsTooSmallException(LocalizedFormats.WRONG_NUMBER_OF_POINTS, + 3, facet.length, true); + } + for (final int index : facet) { + maxFacets = FastMath.max(maxFacets, ++nbFacets[index]); + } + } + + // set up the references array + final int[][] references = new int[vertices.size()][maxFacets]; + for (int[] r : references) { + Arrays.fill(r, -1); + } + for (int f = 0; f < facets.size(); ++f) { + for (final int v : facets.get(f)) { + // vertex v is referenced by facet f + int k = 0; + while (k < maxFacets && references[v][k] >= 0) { + ++k; + } + references[v][k] = f; + } + } + + return references; + + } + + /** Find the successors of all vertices among all facets they belong to. + * @param vertices list of polyhedrons set vertices + * @param facets list of facets, as vertices indices in the vertices list + * @param references facets references array + * @return indices of vertices that follow vertex v in some facet (the array + * may contain extra entries at the end, set to negative indices) + * @exception MathIllegalArgumentException if the same vertex appears more than + * once in the successors list (which means one facet orientation is wrong) + * @since 3.5 + */ + private static int[][] successors(final List<Vector3D> vertices, final List<int[]> facets, + final int[][] references) { + + // create an array large enough + final int[][] successors = new int[vertices.size()][references[0].length]; + for (final int[] s : successors) { + Arrays.fill(s, -1); + } + + for (int v = 0; v < vertices.size(); ++v) { + for (int k = 0; k < successors[v].length && references[v][k] >= 0; ++k) { + + // look for vertex v + final int[] facet = facets.get(references[v][k]); + int i = 0; + while (i < facet.length && facet[i] != v) { + ++i; + } + + // we have found vertex v, we deduce its successor on current facet + successors[v][k] = facet[(i + 1) % facet.length]; + for (int l = 0; l < k; ++l) { + if (successors[v][l] == successors[v][k]) { + final Vector3D start = vertices.get(v); + final Vector3D end = vertices.get(successors[v][k]); + throw new MathIllegalArgumentException(LocalizedFormats.FACET_ORIENTATION_MISMATCH, + start.getX(), start.getY(), start.getZ(), + end.getX(), end.getY(), end.getZ()); + } + } + + } + } + + return successors; + + } + /** {@inheritDoc} */ @Override public PolyhedronsSet buildNew(final BSPTree<Euclidean3D> tree) { http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/main/resources/assets/org/apache/commons/math3/exception/util/LocalizedFormats_fr.properties ---------------------------------------------------------------------- diff --git a/src/main/resources/assets/org/apache/commons/math3/exception/util/LocalizedFormats_fr.properties b/src/main/resources/assets/org/apache/commons/math3/exception/util/LocalizedFormats_fr.properties index c1a7c26..610ffb8 100644 --- a/src/main/resources/assets/org/apache/commons/math3/exception/util/LocalizedFormats_fr.properties +++ b/src/main/resources/assets/org/apache/commons/math3/exception/util/LocalizedFormats_fr.properties @@ -43,6 +43,7 @@ CANNOT_SUBSTITUTE_ELEMENT_FROM_EMPTY_ARRAY = impossible de substituer un \u00e9l CANNOT_TRANSFORM_TO_DOUBLE = Exception de conversion dans une transformation : {0} CARDAN_ANGLES_SINGULARITY = singularit\u00e9 d''angles de Cardan CLASS_DOESNT_IMPLEMENT_COMPARABLE = la classe ({0}) n''implante pas l''interface Comparable +CLOSE_VERTICES = sommets trop proches \u00e0 proximit\u00e9 du point ({0}, {1}, {2}) CLOSEST_ORTHOGONAL_MATRIX_HAS_NEGATIVE_DETERMINANT = la matrice orthogonale la plus proche a un d\u00e9terminant n\u00e9gatif {0} COLUMN_INDEX_OUT_OF_RANGE = l''index de colonne {0} est hors du domaine autoris\u00e9 [{1}, {2}] COLUMN_INDEX = index de colonne ({0}) @@ -64,6 +65,7 @@ DIMENSIONS_MISMATCH = dimensions incoh\u00e9rentes DISCRETE_CUMULATIVE_PROBABILITY_RETURNED_NAN = Discr\u00e8tes fonction de probabilit\u00e9 cumulative retourn\u00e9 NaN \u00e0 l''argument de {0} DISTRIBUTION_NOT_LOADED = aucune distribution n''a \u00e9t\u00e9 charg\u00e9e DUPLICATED_ABSCISSA_DIVISION_BY_ZERO = la duplication de l''abscisse {0} engendre une division par z\u00e9ro +EDGE_CONNECTED_TO_ONE_FACET = l''ar\u00eate joignant les points ({0}, {1}, {2}) et ({3}, {4}, {5}) n''est connect\u00e9e qu''\u00e0 une seule facette ELITISM_RATE = proportion d''\u00e9litisme ({0}) EMPTY_CLUSTER_IN_K_MEANS = groupe vide dans l''algorithme des k-moyennes EMPTY_INTERPOLATION_SAMPLE = \u00e9chantillon d''interpolation vide @@ -76,6 +78,7 @@ EQUAL_VERTICES_IN_SIMPLEX = sommets {0} et {1} \u00e9gaux dans la configuration EULER_ANGLES_SINGULARITY = singularit\u00e9 d''angles d''Euler EVALUATION = \u00e9valuation EXPANSION_FACTOR_SMALLER_THAN_ONE = facteur d''extension inf\u00e9rieur \u00e0 un ({0}) +FACET_ORIENTATION_MISMATCH = orientations incoh\u00e9rentes des facettes de part et d''autre de l''ar\u00eate joignant les points ({0}, {1}, {2}) et ({3}, {4}, {5}) FACTORIAL_NEGATIVE_PARAMETER = n doit \u00eatre positif pour le calcul de n!, or n = {0} FAILED_BRACKETING = nombre d''it\u00e9rations = {4}, it\u00e9rations maximum = {5}, valeur initiale = {6}, borne inf\u00e9rieure = {7}, borne sup\u00e9rieure = {8}, valeur a finale = {0}, valeur b finale = {1}, f(a) = {2}, f(b) = {3} FAILED_FRACTION_CONVERSION = Impossible de convertir {0} en fraction apr\u00e8s {1} it\u00e9rations @@ -257,6 +260,7 @@ OUT_OF_BOUNDS_QUANTILE_VALUE = valeur de quantile {0} hors bornes, doit \u00eatr OUT_OF_BOUND_SIGNIFICANCE_LEVEL = niveau de signification {0} hors domaine, doit \u00eatre entre {1} et {2} SIGNIFICANCE_LEVEL = niveau de signification ({0}) OUT_OF_ORDER_ABSCISSA_ARRAY = les abscisses doivent \u00eatre en ordre strictement croissant, mais l''\u00e9l\u00e9ment {0} vaut {1} alors que l''\u00e9l\u00e9ment {2} vaut {3} +OUT_OF_PLANE = le point ({0}, {1}, {2}) est hors du plan OUT_OF_RANGE_ROOT_OF_UNITY_INDEX = l''indice de racine de l''unit\u00e9 {0} est hors du domaine autoris\u00e9 [{1};{2}] OUT_OF_RANGE_SIMPLE = {0} hors du domaine [{1}, {2}] OUT_OF_RANGE_LEFT = {0} hors du domaine ({1}, {2}] http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/java/org/apache/commons/math3/exception/util/LocalizedFormatsTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/math3/exception/util/LocalizedFormatsTest.java b/src/test/java/org/apache/commons/math3/exception/util/LocalizedFormatsTest.java index 1a51f64..791829f 100644 --- a/src/test/java/org/apache/commons/math3/exception/util/LocalizedFormatsTest.java +++ b/src/test/java/org/apache/commons/math3/exception/util/LocalizedFormatsTest.java @@ -29,7 +29,7 @@ public class LocalizedFormatsTest { @Test public void testMessageNumber() { - Assert.assertEquals(322, LocalizedFormats.values().length); + Assert.assertEquals(326, LocalizedFormats.values().length); } @Test http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PLYParser.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PLYParser.java b/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PLYParser.java new file mode 100644 index 0000000..3303541 --- /dev/null +++ b/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PLYParser.java @@ -0,0 +1,290 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.geometry.euclidean.threed; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.commons.math3.util.Precision; + +/** This class is a small and incomplete parser for PLY files. + * <p> + * This parser is only intended for test purposes, it does not + * parse the full header, it does not handle all properties, + * it has rudimentary error handling. + * </p> + * @since 3.5 + */ +public class PLYParser { + + /** Parsed vertices. */ + private Vector3D[] vertices; + + /** Parsed faces. */ + private int[][] faces; + + /** Reader for PLY data. */ + private BufferedReader br; + + /** Last parsed line. */ + private String line; + + /** Simple constructor. + * @param stream stream to parse (closing it remains caller responsibility) + * @exception IOException if stream cannot be read + * @exception ParseException if stream content cannot be parsed + */ + public PLYParser(final InputStream stream) + throws IOException, ParseException { + + try { + br = new BufferedReader(new InputStreamReader(stream, "UTF-8")); + + // parse the header + List<Field> fields = parseNextLine(); + if (fields.size() != 1 || fields.get(0).getToken() != Token.PLY) { + complain(); + } + + boolean parsing = true; + int nbVertices = -1; + int nbFaces = -1; + int xIndex = -1; + int yIndex = -1; + int zIndex = -1; + int vPropertiesNumber = -1; + boolean inVertexElt = false; + boolean inFaceElt = false; + while (parsing) { + fields = parseNextLine(); + if (fields.size() < 1) { + complain(); + } + switch (fields.get(0).getToken()) { + case FORMAT: + if (fields.size() != 3 || + fields.get(1).getToken() != Token.ASCII || + fields.get(2).getToken() != Token.UNKNOWN || + !Precision.equals(Double.parseDouble(fields.get(2).getValue()), 1.0, 0.001)) { + complain(); + } + inVertexElt = false; + inFaceElt = false; + break; + case COMMENT: + // we just ignore this line + break; + case ELEMENT: + if (fields.size() != 3 || + (fields.get(1).getToken() != Token.VERTEX && fields.get(1).getToken() != Token.FACE) || + fields.get(2).getToken() != Token.UNKNOWN) { + complain(); + } + if (fields.get(1).getToken() == Token.VERTEX) { + nbVertices = Integer.parseInt(fields.get(2).getValue()); + inVertexElt = true; + inFaceElt = false; + } else { + nbFaces = Integer.parseInt(fields.get(2).getValue()); + inVertexElt = false; + inFaceElt = true; + } + break; + case PROPERTY: + if (inVertexElt) { + ++vPropertiesNumber; + if (fields.size() != 3 || + (fields.get(1).getToken() != Token.CHAR && + fields.get(1).getToken() != Token.UCHAR && + fields.get(1).getToken() != Token.SHORT && + fields.get(1).getToken() != Token.USHORT && + fields.get(1).getToken() != Token.INT && + fields.get(1).getToken() != Token.UINT && + fields.get(1).getToken() != Token.FLOAT && + fields.get(1).getToken() != Token.DOUBLE)) { + complain(); + } + if (fields.get(2).getToken() == Token.X) { + xIndex = vPropertiesNumber; + }else if (fields.get(2).getToken() == Token.Y) { + yIndex = vPropertiesNumber; + }else if (fields.get(2).getToken() == Token.Z) { + zIndex = vPropertiesNumber; + } + } else if (inFaceElt) { + if (fields.size() != 5 || + fields.get(1).getToken() != Token.LIST && + (fields.get(2).getToken() != Token.CHAR && + fields.get(2).getToken() != Token.UCHAR && + fields.get(2).getToken() != Token.SHORT && + fields.get(2).getToken() != Token.USHORT && + fields.get(2).getToken() != Token.INT && + fields.get(2).getToken() != Token.UINT) || + (fields.get(3).getToken() != Token.CHAR && + fields.get(3).getToken() != Token.UCHAR && + fields.get(3).getToken() != Token.SHORT && + fields.get(3).getToken() != Token.USHORT && + fields.get(3).getToken() != Token.INT && + fields.get(3).getToken() != Token.UINT) || + fields.get(4).getToken() != Token.VERTEX_INDICES) { + complain(); + } + } else { + complain(); + } + break; + case END_HEADER: + inVertexElt = false; + inFaceElt = false; + parsing = false; + break; + default: + throw new ParseException("unable to parse line: " + line, 0); + } + } + ++vPropertiesNumber; + + // parse vertices + vertices = new Vector3D[nbVertices]; + for (int i = 0; i < nbVertices; ++i) { + fields = parseNextLine(); + if (fields.size() != vPropertiesNumber || + fields.get(xIndex).getToken() != Token.UNKNOWN || + fields.get(yIndex).getToken() != Token.UNKNOWN || + fields.get(zIndex).getToken() != Token.UNKNOWN) { + complain(); + } + vertices[i] = new Vector3D(Double.parseDouble(fields.get(xIndex).getValue()), + Double.parseDouble(fields.get(yIndex).getValue()), + Double.parseDouble(fields.get(zIndex).getValue())); + } + + // parse faces + faces = new int[nbFaces][]; + for (int i = 0; i < nbFaces; ++i) { + fields = parseNextLine(); + if (fields.isEmpty() || + fields.size() != (Integer.parseInt(fields.get(0).getValue()) + 1)) { + complain(); + } + faces[i] = new int[fields.size() - 1]; + for (int j = 0; j < faces[i].length; ++j) { + faces[i][j] = Integer.parseInt(fields.get(j + 1).getValue()); + } + } + + } catch (NumberFormatException nfe) { + complain(); + } + } + + /** Complain about a bad line. + * @exception ParseException always thrown + */ + private void complain() throws ParseException { + throw new ParseException("unable to parse line: " + line, 0); + } + + /** Parse next line. + * @return parsed fields + * @exception IOException if stream cannot be read + * @exception ParseException if the line does not contain the expected number of fields + */ + private List<Field> parseNextLine() + throws IOException, ParseException { + final List<Field> fields = new ArrayList<Field>(); + line = br.readLine(); + if (line == null) { + throw new EOFException(); + } + final StringTokenizer tokenizer = new StringTokenizer(line); + while (tokenizer.hasMoreTokens()) { + fields.add(new Field(tokenizer.nextToken())); + } + return fields; + } + + /** Get the parsed vertices. + * @return parsed vertices + */ + public List<Vector3D> getVertices() { + return Arrays.asList(vertices); + } + + /** Get the parsed faces. + * @return parsed faces + */ + public List<int[]> getFaces() { + return Arrays.asList(faces); + } + + /** Tokens from PLY files. */ + private static enum Token { + PLY, FORMAT, ASCII, BINARY_BIG_ENDIAN, BINARY_LITTLE_ENDIAN, + COMMENT, ELEMENT, VERTEX, FACE, PROPERTY, LIST, OBJ_INFO, + CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE, + X, Y, Z, VERTEX_INDICES, END_HEADER, UNKNOWN; + } + + /** Parsed line fields. */ + private static class Field { + + /** Token. */ + private final Token token; + + /** Value. */ + private final String value; + + /** Simple constructor. + * @param value field value + */ + public Field(final String value) { + Token parsedToken = null; + try { + parsedToken = Token.valueOf(value.toUpperCase()); + } catch (IllegalArgumentException iae) { + parsedToken = Token.UNKNOWN; + } + this.token = parsedToken; + this.value = value; + } + + /** Get the recognized token. + * @return recognized token + */ + public Token getToken() { + return token; + } + + /** Get the field value. + * @return field value + */ + public String getValue() { + return value; + } + + } + +} http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSetTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSetTest.java b/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSetTest.java index 00e14c2..b4be154 100644 --- a/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSetTest.java +++ b/src/test/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSetTest.java @@ -20,13 +20,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.lang.reflect.Field; import java.text.ParseException; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; +import java.util.Arrays; +import java.util.List; import org.apache.commons.math3.exception.MathArithmeticException; import org.apache.commons.math3.exception.MathIllegalArgumentException; +import org.apache.commons.math3.exception.util.ExceptionContext; +import org.apache.commons.math3.exception.util.Localizable; +import org.apache.commons.math3.exception.util.LocalizedFormats; import org.apache.commons.math3.geometry.Vector; import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet; @@ -348,18 +352,7 @@ public class PolyhedronsSetTest { faces[9]=new int[]{1,4,0}; // front (-y) faces[10]=new int[]{3,6,2}; // back (+y) faces[11]=new int[]{6,3,7}; // back (+y) - // - Set<SubHyperplane<Euclidean3D>> pset=new HashSet<SubHyperplane<Euclidean3D>>(); - for (int f=0; f<faces.length; f++) { - int[] vidx=faces[f]; - Plane p=new Plane(verts[vidx[0]],verts[vidx[1]],verts[vidx[2]],tol); - Vector2D p0=p.toSubSpace(verts[vidx[0]]); - Vector2D p1=p.toSubSpace(verts[vidx[1]]); - Vector2D p2=p.toSubSpace(verts[vidx[2]]); - PolygonsSet lset=new PolygonsSet(tol,p0,p1,p2); - pset.add(new SubPlane(p,lset)); - } - PolyhedronsSet polyset=new PolyhedronsSet(pset,tol); + PolyhedronsSet polyset = new PolyhedronsSet(Arrays.asList(verts), Arrays.asList(faces), tol); Assert.assertEquals(8.0, polyset.getSize(), 1.0e-10); Assert.assertEquals(24.0, polyset.getBoundarySize(), 1.0e-10); String dump = RegionDumper.dump(polyset); @@ -370,6 +363,76 @@ public class PolyhedronsSetTest { } @Test + public void testConnectedFacets() throws IOException, ParseException { + InputStream stream = getClass().getResourceAsStream("pentomino-N.ply"); + PLYParser parser = new PLYParser(stream); + stream.close(); + PolyhedronsSet polyhedron = new PolyhedronsSet(parser.getVertices(), parser.getFaces(), 1.0e-10); + Assert.assertEquals( 5.0, polyhedron.getSize(), 1.0e-10); + Assert.assertEquals(22.0, polyhedron.getBoundarySize(), 1.0e-10); + } + + @Test + public void testTooClose() throws IOException, ParseException { + checkError("pentomino-N-too-close.ply", LocalizedFormats.CLOSE_VERTICES); + } + + @Test + public void testHole() throws IOException, ParseException { + checkError("pentomino-N-hole.ply", LocalizedFormats.EDGE_CONNECTED_TO_ONE_FACET); + } + + @Test + public void testNonPlanar() throws IOException, ParseException { + checkError("pentomino-N-out-of-plane.ply", LocalizedFormats.OUT_OF_PLANE); + } + + @Test + public void testOrientation() throws IOException, ParseException { + checkError("pentomino-N-bad-orientation.ply", LocalizedFormats.FACET_ORIENTATION_MISMATCH); + } + + @Test + public void testFacet2Vertices() throws IOException, ParseException { + checkError(Arrays.asList(Vector3D.ZERO, Vector3D.PLUS_I, Vector3D.PLUS_J, Vector3D.PLUS_K), + Arrays.asList(new int[] { 0, 1, 2 }, new int[] {2, 3}), + LocalizedFormats.WRONG_NUMBER_OF_POINTS); + } + + private void checkError(final String resourceName, final LocalizedFormats expected) { + try { + InputStream stream = getClass().getResourceAsStream(resourceName); + PLYParser parser = new PLYParser(stream); + stream.close(); + checkError(parser.getVertices(), parser.getFaces(), expected); + } catch (IOException ioe) { + Assert.fail(ioe.getLocalizedMessage()); + } catch (ParseException pe) { + Assert.fail(pe.getLocalizedMessage()); + } + } + + private void checkError(final List<Vector3D> vertices, final List<int[]> facets, + final LocalizedFormats expected) { + try { + new PolyhedronsSet(vertices, facets, 1.0e-10); + Assert.fail("an exception should have been thrown"); + } catch (MathIllegalArgumentException miae) { + try { + Field msgPatterns = ExceptionContext.class.getDeclaredField("msgPatterns"); + msgPatterns.setAccessible(true); + @SuppressWarnings("unchecked") + List<Localizable> list = (List<Localizable>) msgPatterns.get(miae.getContext()); + Assert.assertEquals(expected, list.get(0)); + } catch (NoSuchFieldException nsfe) { + Assert.fail(nsfe.getLocalizedMessage()); + } catch (IllegalAccessException iae) { + Assert.fail(iae.getLocalizedMessage()); + } + } + } + + @Test public void testIssue1211() throws IOException, ParseException { PolyhedronsSet polyset = RegionParser.parsePolyhedronsSet(loadTestData("issue-1211.bsp")); http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-bad-orientation.ply ---------------------------------------------------------------------- diff --git a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-bad-orientation.ply b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-bad-orientation.ply new file mode 100644 index 0000000..4109576 --- /dev/null +++ b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-bad-orientation.ply @@ -0,0 +1,40 @@ +ply +format ascii 1.0 +comment this file represents the 'N' pentomino +comment it has been created manually +comment the shape has a reversed orientation for facet 3 +element vertex 16 +property double x +property double y +property double z +element face 12 +property list uchar uint vertex_indices +end_header +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +2.0 1.0 0.0 +2.0 4.0 0.0 +1.0 4.0 0.0 +1.0 2.0 0.0 +0.0 2.0 0.0 +0.0 0.0 1.0 +1.0 0.0 1.0 +1.0 1.0 1.0 +2.0 1.0 1.0 +2.0 4.0 1.0 +1.0 4.0 1.0 +1.0 2.0 1.0 +0.0 2.0 1.0 +5 8 9 10 14 15 +5 10 11 12 13 14 +5 7 6 2 1 0 +5 2 3 4 5 6 +4 0 1 9 8 +4 1 2 10 9 +4 2 3 11 10 +4 3 4 12 11 +4 4 5 13 12 +4 5 6 14 13 +4 6 7 15 14 +4 7 0 8 15 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-hole.ply ---------------------------------------------------------------------- diff --git a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-hole.ply b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-hole.ply new file mode 100644 index 0000000..e40a025 --- /dev/null +++ b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-hole.ply @@ -0,0 +1,39 @@ +ply +format ascii 1.0 +comment this file represents the 'N' pentomino +comment it has been created manually +comment the shape has a missing face between vertices 0, 1, 9, 8 +element vertex 16 +property double x +property double y +property double z +element face 11 +property list uchar uint vertex_indices +end_header +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +2.0 1.0 0.0 +2.0 4.0 0.0 +1.0 4.0 0.0 +1.0 2.0 0.0 +0.0 2.0 0.0 +0.0 0.0 1.0 +1.0 0.0 1.0 +1.0 1.0 1.0 +2.0 1.0 1.0 +2.0 4.0 1.0 +1.0 4.0 1.0 +1.0 2.0 1.0 +0.0 2.0 1.0 +5 8 9 10 14 15 +5 10 11 12 13 14 +5 7 6 2 1 0 +5 6 5 4 3 2 +4 1 2 10 9 +4 2 3 11 10 +4 3 4 12 11 +4 4 5 13 12 +4 5 6 14 13 +4 6 7 15 14 +4 7 0 8 15 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-out-of-plane.ply ---------------------------------------------------------------------- diff --git a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-out-of-plane.ply b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-out-of-plane.ply new file mode 100644 index 0000000..c345eda --- /dev/null +++ b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-out-of-plane.ply @@ -0,0 +1,40 @@ +ply +format ascii 1.0 +comment this file represents the 'N' pentomino +comment it has been created manually +comment the shape is distorted with edge 7 moved, so associated facets are not planar +element vertex 16 +property double x +property double y +property double z +element face 12 +property list uchar uint vertex_indices +end_header +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +2.0 1.0 0.0 +2.0 4.0 0.0 +1.0 4.0 0.0 +1.0 2.0 0.0 +0.0 2.0 0.5 +0.0 0.0 1.0 +1.0 0.0 1.0 +1.0 1.0 1.0 +2.0 1.0 1.0 +2.0 4.0 1.0 +1.0 4.0 1.0 +1.0 2.0 1.0 +0.0 2.0 1.0 +5 8 9 10 14 15 +5 10 11 12 13 14 +5 7 6 2 1 0 +5 6 5 4 3 2 +4 0 1 9 8 +4 1 2 10 9 +4 2 3 11 10 +4 3 4 12 11 +4 4 5 13 12 +4 5 6 14 13 +4 6 7 15 14 +4 7 0 8 15 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-too-close.ply ---------------------------------------------------------------------- diff --git a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-too-close.ply b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-too-close.ply new file mode 100644 index 0000000..1701540 --- /dev/null +++ b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N-too-close.ply @@ -0,0 +1,86 @@ +ply +format ascii 1.0 +comment this file should trigger an error as it contains several vertices at the same location +comment the file was originally created using blender http://www.blender.org +element vertex 52 +property float x +property float y +property float z +property float nx +property float ny +property float nz +element face 20 +property list uchar uint vertex_indices +end_header +0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 +0.000000 1.000000 0.000000 1.000000 0.000000 0.000000 +0.000000 1.000000 1.000000 1.000000 0.000000 0.000000 +0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 +0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 +-2.000000 1.000000 0.000000 0.000000 1.000000 0.000000 +-2.000000 1.000000 1.000000 0.000000 1.000000 0.000000 +0.000000 1.000000 1.000000 0.000000 1.000000 0.000000 +-2.000000 1.000000 1.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 +0.000000 1.000000 1.000000 0.000000 0.000000 0.000000 +-2.000000 2.000000 1.000000 0.000000 0.000000 -1.000000 +1.000000 2.000000 1.000000 0.000000 0.000000 -1.000000 +1.000000 1.000000 1.000000 0.000000 0.000000 -1.000000 +-2.000000 1.000000 1.000000 -0.000000 -0.000000 -1.000000 +-2.000000 2.000000 0.000000 0.000000 -1.000000 -0.000000 +1.000000 2.000000 0.000000 0.000000 -1.000000 -0.000000 +1.000000 2.000000 1.000000 0.000000 -1.000000 -0.000000 +-2.000000 2.000000 1.000000 0.000000 -1.000000 -0.000000 +0.000000 0.000000 0.000000 -0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 -0.000000 0.000000 1.000000 +0.000000 1.000000 0.000000 -0.000000 0.000000 1.000000 +2.000000 0.000000 0.000000 -0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 -0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 -1.000000 0.000000 -0.000000 +2.000000 0.000000 0.000000 -1.000000 0.000000 -0.000000 +2.000000 0.000000 1.000000 -1.000000 0.000000 -0.000000 +2.000000 1.000000 1.000000 -1.000000 0.000000 -0.000000 +2.000000 0.000000 0.000000 0.000000 1.000000 0.000000 +0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 +0.000000 0.000000 1.000000 0.000000 1.000000 0.000000 +2.000000 0.000000 1.000000 0.000000 1.000000 0.000000 +-2.000000 1.000000 0.000000 1.000000 0.000000 0.000000 +-2.000000 2.000000 0.000000 1.000000 0.000000 0.000000 +-2.000000 2.000000 1.000000 1.000000 0.000000 0.000000 +-2.000000 1.000000 1.000000 1.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 0.000000 -1.000000 -0.000000 +2.000000 1.000000 0.000000 0.000000 -1.000000 -0.000000 +2.000000 1.000000 1.000000 0.000000 -1.000000 -0.000000 +1.000000 1.000000 1.000000 0.000000 -1.000000 -0.000000 +1.000000 2.000000 0.000000 -1.000000 0.000000 -0.000000 +1.000000 1.000000 0.000000 -1.000000 0.000000 -0.000000 +1.000000 1.000000 1.000000 -1.000000 0.000000 -0.000000 +1.000000 2.000000 1.000000 -1.000000 0.000000 -0.000000 +-2.000000 1.000000 0.000000 -0.000000 0.000000 1.000000 +1.000000 2.000000 0.000000 -0.000000 0.000000 1.000000 +-2.000000 2.000000 0.000000 -0.000000 0.000000 1.000000 +0.000000 0.000000 1.000000 -0.000000 0.000000 -1.000000 +2.000000 1.000000 1.000000 -0.000000 0.000000 -1.000000 +2.000000 0.000000 1.000000 -0.000000 0.000000 -1.000000 +2.000000 1.000000 1.000000 0.000000 0.000000 0.000000 +0.000000 1.000000 1.000000 -0.000000 -0.000000 -1.000000 +4 0 1 2 3 +4 4 5 6 7 +3 8 9 10 +3 11 12 13 +3 14 11 13 +4 15 16 17 18 +3 19 20 21 +3 22 23 20 +3 19 22 20 +4 24 25 26 27 +4 28 29 30 31 +4 32 33 34 35 +4 36 37 38 39 +4 40 41 42 43 +3 44 45 46 +3 21 20 45 +3 44 21 45 +3 47 48 49 +3 10 9 50 +3 47 51 48 http://git-wip-us.apache.org/repos/asf/commons-math/blob/962a367a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N.ply ---------------------------------------------------------------------- diff --git a/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N.ply b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N.ply new file mode 100644 index 0000000..4efbf20 --- /dev/null +++ b/src/test/resources/org/apache/commons/math3/geometry/euclidean/threed/pentomino-N.ply @@ -0,0 +1,39 @@ +ply +format ascii 1.0 +comment this file represents the 'N' pentomino +comment it has been created manually +element vertex 16 +property double x +property double y +property double z +element face 12 +property list uchar uint vertex_indices +end_header +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +2.0 1.0 0.0 +2.0 4.0 0.0 +1.0 4.0 0.0 +1.0 2.0 0.0 +0.0 2.0 0.0 +0.0 0.0 1.0 +1.0 0.0 1.0 +1.0 1.0 1.0 +2.0 1.0 1.0 +2.0 4.0 1.0 +1.0 4.0 1.0 +1.0 2.0 1.0 +0.0 2.0 1.0 +5 8 9 10 14 15 +5 10 11 12 13 14 +5 7 6 2 1 0 +5 6 5 4 3 2 +4 0 1 9 8 +4 1 2 10 9 +4 2 3 11 10 +4 3 4 12 11 +4 4 5 13 12 +4 5 6 14 13 +4 6 7 15 14 +4 7 0 8 15 \ No newline at end of file