1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
76 BoundarySource3D src = handler.read("obj", cubeMinusSphereFile(), TEST_PRECISION);
77
78
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
87 File file = cubeMinusSphereFile();
88
89
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
98 File file = new File("doesnotexist.obj");
99
100
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
109 BoundarySource3D src;
110 try (InputStream in = Files.newInputStream(cubeMinusSphereFile().toPath())) {
111 src = handler.read("obj", cubeMinusSphereFile(), TEST_PRECISION);
112 }
113
114
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
123 File file = cubeMinusSphereFile();
124
125
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
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
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
151 handler.write(src, "OBJ", out);
152
153
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
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
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
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
184 GeometryTestUtils.assertThrows(() -> {
185 handler.write(src, "OBJ", out);
186 }, UncheckedIOException.class);
187 }
188
189 @Test
190 public void testWrite_toStream() throws Exception {
191
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
199 handler.write(src, "OBJ", out);
200
201
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
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
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
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
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 }