View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.commons.geometry.examples.io.threed.obj;
    18
    19  import java.io.ByteArrayInputStream;
    20  import java.io.ByteArrayOutputStream;
    21  import java.io.File;
    22  import java.io.IOException;
    23  import java.io.InputStream;
    24  import java.io.OutputStream;
    25  import java.io.UncheckedIOException;
    26  import java.net.URL;
    27  import java.nio.file.Files;
    28
    29  import org.apache.commons.geometry.core.GeometryTestUtils;
    30  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
    31  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
    32  import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
    33  import org.apache.commons.geometry.euclidean.threed.Planes;
    34  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    35  import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
    36  import org.junit.Assert;
    37  import org.junit.Rule;
    38  import org.junit.Test;
    39  import org.junit.rules.TemporaryFolder;
    40
    41  public class OBJModelIOHandlerTest {
    42
    43      private static final double TEST_EPS = 1e-10;
    44
    45      private static final DoublePrecisionContext TEST_PRECISION =
    46              new EpsilonDoublePrecisionContext(TEST_EPS);
    47
    48      private static final String CUBE_MINUS_SPHERE_MODEL = "/models/cube-minus-sphere.obj";
    49
    50      private static final int CUBE_MINUS_SPHERE_VERTICES = 1688;
    51
    52      private static final int CUBE_MINUS_SPHERE_FACES = 728;
    53
    54      @Rule
    55      public TemporaryFolder tempFolder = new TemporaryFolder();
    56
    57      private OBJModelIOHandler handler = new OBJModelIOHandler();
    58
    59      @Test
    60      public void testHandlesType() {
    61          // act/assert
    62          Assert.assertFalse(handler.handlesType(null));
    63          Assert.assertFalse(handler.handlesType(""));
    64          Assert.assertFalse(handler.handlesType(" "));
    65          Assert.assertFalse(handler.handlesType("abc"));
    66          Assert.assertFalse(handler.handlesType("stl"));
    67
    68          Assert.assertTrue(handler.handlesType("obj"));
    69          Assert.assertTrue(handler.handlesType("OBJ"));
    70          Assert.assertTrue(handler.handlesType("oBj"));
    71      }
    72
    73      @Test
    74      public void testRead_fromFile() throws Exception {
    75          // act
    76          BoundarySource3D src = handler.read("obj", cubeMinusSphereFile(), TEST_PRECISION);
    77
    78          // assert
    79          TriangleMesh mesh = (TriangleMesh) src;
    80          Assert.assertEquals(CUBE_MINUS_SPHERE_VERTICES, mesh.getVertexCount());
    81          Assert.assertEquals(CUBE_MINUS_SPHERE_FACES, mesh.getFaceCount());
    82      }
    83
    84      @Test
    85      public void testRead_fromFile_unsupportedType() throws Exception {
    86          // arrange
    87          File file = cubeMinusSphereFile();
    88
    89          // act/assert
    90          GeometryTestUtils.assertThrows(() -> {
    91              handler.read("stl", file, TEST_PRECISION);
    92          }, IllegalArgumentException.class, "File type is not supported by this handler: stl");
    93      }
    94
    95      @Test
    96      public void testRead_fromFile_ioException() throws Exception {
    97          // arrange
    98          File file = new File("doesnotexist.obj");
    99
    100         // act/assert
    101         GeometryTestUtils.assertThrows(() -> {
    102             handler.read("obj", file, TEST_PRECISION);
    103         }, UncheckedIOException.class);
    104     }
    105
    106     @Test
    107     public void testRead_fromStream() throws Exception {
    108         // act
    109         BoundarySource3D src;
    110         try (InputStream in = Files.newInputStream(cubeMinusSphereFile().toPath())) {
    111             src = handler.read("obj", cubeMinusSphereFile(), TEST_PRECISION);
    112         }
    113
    114         // assert
    115         TriangleMesh mesh = (TriangleMesh) src;
    116         Assert.assertEquals(CUBE_MINUS_SPHERE_VERTICES, mesh.getVertexCount());
    117         Assert.assertEquals(CUBE_MINUS_SPHERE_FACES, mesh.getFaceCount());
    118     }
    119
    120     @Test
    121     public void testRead_fromStream_unsupportedType() throws Exception {
    122         // arrange
    123         File file = cubeMinusSphereFile();
    124
    125         // act/assert
    126         try (InputStream in = Files.newInputStream(file.toPath())) {
    127             GeometryTestUtils.assertThrows(() -> {
    128                 handler.read("stl", in, TEST_PRECISION);
    129             }, IllegalArgumentException.class, "File type is not supported by this handler: stl");
    130         }
    131     }
    132
    133     @Test
    134     public void testRead_fromStream_ioException() throws Exception {
    135         // act/assert
    136         GeometryTestUtils.assertThrows(() -> {
    137             handler.read("obj", new FailingInputStream(), TEST_PRECISION);
    138         }, UncheckedIOException.class, "IOException: test");
    139     }
    140
    141     @Test
    142     public void testWrite_toFile() throws Exception {
    143         // arrange
    144         File out = tempFolder.newFile("out.obj");
    145
    146         BoundarySource3D src = BoundarySource3D.from(
    147                 Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0), TEST_PRECISION)
    148             );
    149
    150         // act
    151         handler.write(src, "OBJ", out);
    152
    153         // assert
    154         TriangleMesh mesh = (TriangleMesh) handler.read("obj", out, TEST_PRECISION);
    155         Assert.assertEquals(3, mesh.getVertexCount());
    156         Assert.assertEquals(1, mesh.getFaceCount());
    157     }
    158
    159     @Test
    160     public void testWrite_toFile_unsupportedFormat() throws Exception {
    161         // arrange
    162         File out = tempFolder.newFile("out.obj");
    163
    164         BoundarySource3D src = BoundarySource3D.from(
    165                 Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0), TEST_PRECISION)
    166             );
    167
    168         // act/assert
    169         GeometryTestUtils.assertThrows(() -> {
    170             handler.write(src, "stl", out);
    171         }, IllegalArgumentException.class, "File type is not supported by this handler: stl");
    172     }
    173
    174     @Test
    175     public void testWrite_toFile_ioException() throws Exception {
    176         // arrange
    177         File out = tempFolder.newFolder("notafile");
    178
    179         BoundarySource3D src = BoundarySource3D.from(
    180                 Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0), TEST_PRECISION)
    181             );
    182
    183         // act/assert
    184         GeometryTestUtils.assertThrows(() -> {
    185             handler.write(src, "OBJ", out);
    186         }, UncheckedIOException.class);
    187     }
    188
    189     @Test
    190     public void testWrite_toStream() throws Exception {
    191         // arrange
    192         ByteArrayOutputStream out = new ByteArrayOutputStream();
    193
    194         BoundarySource3D src = BoundarySource3D.from(
    195                 Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0), TEST_PRECISION)
    196             );
    197
    198         // act
    199         handler.write(src, "OBJ", out);
    200
    201         // assert
    202         TriangleMesh mesh = (TriangleMesh) handler.read("obj", new ByteArrayInputStream(out.toByteArray()),
    203                 TEST_PRECISION);
    204         Assert.assertEquals(3, mesh.getVertexCount());
    205         Assert.assertEquals(1, mesh.getFaceCount());
    206     }
    207
    208     @Test
    209     public void testWrite_toStream_unsupportedFormat() throws Exception {
    210         // arrange
    211         File file = tempFolder.newFile("out.obj");
    212
    213         BoundarySource3D src = BoundarySource3D.from(
    214                 Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0), TEST_PRECISION)
    215             );
    216
    217         // act/assert
    218         try (OutputStream out = Files.newOutputStream(file.toPath())) {
    219             GeometryTestUtils.assertThrows(() -> {
    220                 handler.write(src, "stl", out);
    221             }, IllegalArgumentException.class, "File type is not supported by this handler: stl");
    222         }
    223     }
    224
    225     @Test
    226     public void testWrite_toStream_ioException() throws Exception {
    227         // arrange
    228         BoundarySource3D src = BoundarySource3D.from(
    229                 Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0), TEST_PRECISION)
    230             );
    231
    232         // act/assert
    233         GeometryTestUtils.assertThrows(() -> {
    234             handler.write(src, "OBJ", new FailingOutputStream());
    235         }, UncheckedIOException.class, "IOException: test");
    236     }
    237
    238     private static File cubeMinusSphereFile() throws Exception {
    239         URL url = OBJModelIOHandlerTest.class.getResource(CUBE_MINUS_SPHERE_MODEL);
    240         return new File(url.toURI());
    241     }
    242
    243     private static final class FailingInputStream extends InputStream {
    244
    245         @Override
    246         public int read() throws IOException {
    247             throw new IOException("test");
    248         }
    249     }
    250
    251     private static final class FailingOutputStream extends OutputStream {
    252
    253         @Override
    254         public void write(int b) throws IOException {
    255             throw new IOException("test");
    256         }
    257     }
    258 }