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.io.euclidean.threed.obj;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.InputStream;
21  import java.nio.charset.Charset;
22  import java.nio.charset.StandardCharsets;
23  import java.util.Arrays;
24  import java.util.List;
25  
26  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
27  import org.apache.commons.geometry.euclidean.threed.Vector3D;
28  import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
29  import org.apache.commons.geometry.io.core.input.StreamGeometryInput;
30  import org.apache.commons.geometry.io.core.test.CloseCountInputStream;
31  import org.apache.commons.geometry.io.euclidean.EuclideanIOTestUtils;
32  import org.apache.commons.geometry.io.euclidean.threed.FacetDefinition;
33  import org.apache.commons.geometry.io.euclidean.threed.FacetDefinitionReader;
34  import org.apache.commons.geometry.io.euclidean.threed.GeometryFormat3D;
35  import org.apache.commons.numbers.core.Precision;
36  import org.junit.jupiter.api.Assertions;
37  import org.junit.jupiter.api.Test;
38  
39  class ObjBoundaryReadHandler3DTest {
40  
41      private static final double TEST_EPS = 1e-10;
42  
43      private static final Precision.DoubleEquivalence TEST_PRECISION =
44              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
45  
46      private final ObjBoundaryReadHandler3D handler = new ObjBoundaryReadHandler3D();
47  
48      @Test
49      void testProperties() {
50          // act/assert
51          Assertions.assertEquals(GeometryFormat3D.OBJ, handler.getFormat());
52          Assertions.assertEquals(StandardCharsets.UTF_8, handler.getDefaultCharset());
53      }
54  
55      @Test
56      void testFacetDefinitionReader() {
57          // arrange
58          final InputStream in = input(
59                  "v 0 0 0\n" +
60                  "v 1 1 0\n" +
61                  "v 0 1 0\n" +
62                  "f 1 2 3\n", StandardCharsets.UTF_8);
63  
64          // act
65          final FacetDefinitionReader reader = handler.facetDefinitionReader(new StreamGeometryInput(in));
66  
67          // assert
68          final List<FacetDefinition> facets = EuclideanIOTestUtils.readAll(reader);
69  
70          Assertions.assertEquals(1, facets.size());
71          EuclideanIOTestUtils.assertFacetVertices(facets.get(0),
72                  Arrays.asList(Vector3D.ZERO, Vector3D.of(1, 1, 0), Vector3D.of(0, 1, 0)), TEST_EPS);
73      }
74  
75      @Test
76      void testFacetDefinitionReader_usesInputCharset() {
77          // arrange
78          final InputStream in = input(
79                  "v 0 0 0\n" +
80                  "v 1 1 0\n" +
81                  "v 0 1 0\n" +
82                  "f 1 2 3\n", StandardCharsets.UTF_16);
83  
84          // act
85          final FacetDefinitionReader reader =
86                  handler.facetDefinitionReader(new StreamGeometryInput(in, null, StandardCharsets.UTF_16));
87  
88          // assert
89          final List<FacetDefinition> facets = EuclideanIOTestUtils.readAll(reader);
90  
91          Assertions.assertEquals(1, facets.size());
92          EuclideanIOTestUtils.assertFacetVertices(facets.get(0),
93                  Arrays.asList(Vector3D.ZERO, Vector3D.of(1, 1, 0), Vector3D.of(0, 1, 0)), TEST_EPS);
94      }
95  
96      @Test
97      void testFacetDefinitionReader_setDefaultCharset() {
98          // arrange
99          handler.setDefaultCharset(StandardCharsets.UTF_16);
100         final InputStream in = input(
101                 "v 0 0 0\n" +
102                 "v 1 1 0\n" +
103                 "v 0 1 0\n" +
104                 "f 1 2 3\n", StandardCharsets.UTF_16);
105 
106         // act
107         final FacetDefinitionReader reader = handler.facetDefinitionReader(new StreamGeometryInput(in));
108 
109         // assert
110         final List<FacetDefinition> facets = EuclideanIOTestUtils.readAll(reader);
111 
112         Assertions.assertEquals(1, facets.size());
113         EuclideanIOTestUtils.assertFacetVertices(facets.get(0),
114                 Arrays.asList(Vector3D.ZERO, Vector3D.of(1, 1, 0), Vector3D.of(0, 1, 0)), TEST_EPS);
115     }
116 
117     @Test
118     void testFacetDefinitionReader_close() {
119         // arrange
120         final CloseCountInputStream in = input("", StandardCharsets.UTF_8);
121 
122         // act/assert
123         try (FacetDefinitionReader reader = handler.facetDefinitionReader(new StreamGeometryInput(in))) {
124             Assertions.assertEquals(0, in.getCloseCount());
125         }
126 
127         Assertions.assertEquals(1, in.getCloseCount());
128     }
129 
130     @Test
131     void testReadTriangleMesh() {
132         // arrange
133         final CloseCountInputStream in = input(
134                 "v 0 0 0\n" +
135                 "v 1 1 0\n" +
136                 "v 0 1 0\n" +
137                 "f 1 2 3\n", StandardCharsets.UTF_8);
138 
139         // act
140         final TriangleMesh mesh = handler.readTriangleMesh(new StreamGeometryInput(in), TEST_PRECISION);
141 
142         // assert
143         Assertions.assertEquals(1, in.getCloseCount());
144 
145         Assertions.assertEquals(3, mesh.getVertexCount());
146         Assertions.assertEquals(1, mesh.getFaceCount());
147 
148         EuclideanTestUtils.assertVertexLoopSequence(
149                 Arrays.asList(Vector3D.ZERO, Vector3D.of(1, 1, 0), Vector3D.of(0, 1, 0)),
150                 mesh.getFace(0).getVertices(), TEST_PRECISION);
151     }
152 
153     @Test
154     void testReadTriangleMesh_nonDefaultCharset() {
155         // arrange
156         handler.setDefaultCharset(StandardCharsets.UTF_16);
157         final CloseCountInputStream in = input(
158                 "v 0 0 0\n" +
159                 "v 1 1 0\n" +
160                 "v 0 1 0\n" +
161                 "f 1 2 3\n", StandardCharsets.UTF_16);
162 
163         // act
164         final TriangleMesh mesh = handler.readTriangleMesh(new StreamGeometryInput(in), TEST_PRECISION);
165 
166         // assert
167         Assertions.assertEquals(1, in.getCloseCount());
168 
169         Assertions.assertEquals(3, mesh.getVertexCount());
170         Assertions.assertEquals(1, mesh.getFaceCount());
171 
172         EuclideanTestUtils.assertVertexLoopSequence(
173                 Arrays.asList(Vector3D.ZERO, Vector3D.of(1, 1, 0), Vector3D.of(0, 1, 0)),
174                 mesh.getFace(0).getVertices(), TEST_PRECISION);
175     }
176 
177     private static CloseCountInputStream input(final String str, final Charset charset) {
178         return new CloseCountInputStream(new ByteArrayInputStream(str.getBytes(charset)));
179     }
180 }