1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.io.euclidean.threed;
18
19 import java.nio.file.Paths;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
25
26 import org.apache.commons.geometry.core.GeometryTestUtils;
27 import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
28 import org.apache.commons.geometry.euclidean.threed.PlaneConvexSubset;
29 import org.apache.commons.geometry.euclidean.threed.Planes;
30 import org.apache.commons.geometry.euclidean.threed.Triangle3D;
31 import org.apache.commons.geometry.euclidean.threed.Vector3D;
32 import org.apache.commons.geometry.euclidean.threed.mesh.SimpleTriangleMesh;
33 import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
34 import org.apache.commons.geometry.io.core.GeometryFormat;
35 import org.apache.commons.geometry.io.core.input.FileGeometryInput;
36 import org.apache.commons.geometry.io.core.input.GeometryInput;
37 import org.apache.commons.geometry.io.core.output.FileGeometryOutput;
38 import org.apache.commons.geometry.io.core.output.GeometryOutput;
39 import org.apache.commons.geometry.io.core.test.StubGeometryFormat;
40 import org.apache.commons.numbers.core.Precision;
41 import org.junit.jupiter.api.Assertions;
42 import org.junit.jupiter.api.Test;
43
44 class BoundaryIOManager3DTest {
45
46 private static final double TEST_EPS = 1e-10;
47
48 private static final Precision.DoubleEquivalence TEST_PRECISION = Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
49
50 private static final GeometryFormat TEST_FMT = new StubGeometryFormat("test");
51
52 private static final FacetDefinitionReader FACET_DEF_READER = new FacetDefinitionReader() {
53
54 @Override
55 public FacetDefinition readFacet() {
56 throw new UnsupportedOperationException();
57 }
58
59 @Override
60 public void close() {
61
62 }
63 };
64
65 private static final FacetDefinition FACET = new SimpleFacetDefinition(Arrays.asList(
66 Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 0), Vector3D.of(0, 1, 0)));
67
68 private static final Triangle3D TRI = Planes.triangleFromVertices(
69 Vector3D.ZERO, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y, TEST_PRECISION);
70
71 private static final TriangleMesh TRI_MESH = SimpleTriangleMesh.builder(TEST_PRECISION).build();
72
73 private final BoundaryIOManager3D manager = new BoundaryIOManager3D();
74
75 @Test
76 void testRegisterDefaultHandlers() {
77
78 manager.registerDefaultHandlers();
79
80
81
82 final GeometryFormat3D[] fmts = GeometryFormat3D.values();
83
84 Assertions.assertEquals(fmts.length, manager.getReadHandlers().size());
85 Assertions.assertEquals(fmts.length, manager.getWriteHandlers().size());
86
87 for (final GeometryFormat3D fmt : fmts) {
88 Assertions.assertNotNull(manager.getReadHandlerForFormat(fmt));
89 Assertions.assertNotNull(manager.getWriteHandlerForFormat(fmt));
90 }
91 }
92
93 @Test
94 void testFacetDefinitionReader_formatGiven() {
95
96 final StubReadHandler3D readHandler = new StubReadHandler3D();
97 manager.registerReadHandler(readHandler);
98
99 final GeometryInput in = new FileGeometryInput(Paths.get("myfile"));
100
101
102 final FacetDefinitionReader result = manager.facetDefinitionReader(in, TEST_FMT);
103
104
105 Assertions.assertSame(FACET_DEF_READER, result);
106 Assertions.assertSame(in, readHandler.inArg);
107 }
108
109 @Test
110 void testFacetDefinitionReader_nullFormat() {
111
112 final StubReadHandler3D readHandler = new StubReadHandler3D();
113 manager.registerReadHandler(readHandler);
114
115 final GeometryInput in = new FileGeometryInput(Paths.get("myfile.test"));
116
117
118 final FacetDefinitionReader result = manager.facetDefinitionReader(in, null);
119
120
121 Assertions.assertSame(FACET_DEF_READER, result);
122 Assertions.assertSame(in, readHandler.inArg);
123 }
124
125 @Test
126 void testFacetDefinitionReader_unknownHandler() {
127
128 checkUnknownReadHandler(manager::facetDefinitionReader);
129 }
130
131 @Test
132 void testFacets_formatGiven() {
133
134 final StubReadHandler3D readHandler = new StubReadHandler3D();
135 manager.registerReadHandler(readHandler);
136
137 final GeometryInput in = new FileGeometryInput(Paths.get("myfile"));
138
139
140 final Stream<FacetDefinition> result = manager.facets(in, TEST_FMT);
141
142
143 Assertions.assertEquals(Collections.singletonList(FACET), result.collect(Collectors.toList()));
144 Assertions.assertSame(in, readHandler.inArg);
145 }
146
147 @Test
148 void testFacets_nullFormat() {
149
150 final StubReadHandler3D readHandler = new StubReadHandler3D();
151 manager.registerReadHandler(readHandler);
152
153 final GeometryInput in = new FileGeometryInput(Paths.get("myfile.test"));
154
155
156 final Stream<FacetDefinition> result = manager.facets(in, null);
157
158
159 Assertions.assertEquals(Collections.singletonList(FACET), result.collect(Collectors.toList()));
160 Assertions.assertSame(in, readHandler.inArg);
161 }
162
163 @Test
164 void testFacets_unknownHandler() {
165
166 checkUnknownReadHandler(manager::facets);
167 }
168
169 @Test
170 void testTriangles_formatGiven() {
171
172 final StubReadHandler3D readHandler = new StubReadHandler3D();
173 manager.registerReadHandler(readHandler);
174
175 final GeometryInput in = new FileGeometryInput(Paths.get("myfile"));
176
177
178 final Stream<Triangle3D> result = manager.triangles(in, TEST_FMT, TEST_PRECISION);
179
180
181 Assertions.assertEquals(Collections.singletonList(TRI), result.collect(Collectors.toList()));
182 Assertions.assertSame(in, readHandler.inArg);
183 Assertions.assertSame(TEST_PRECISION, readHandler.precisionArg);
184 }
185
186 @Test
187 void testTriangles_nullFormat() {
188
189 final StubReadHandler3D readHandler = new StubReadHandler3D();
190 manager.registerReadHandler(readHandler);
191
192 final GeometryInput in = new FileGeometryInput(Paths.get("myfile.test"));
193
194
195 final Stream<Triangle3D> result = manager.triangles(in, null, TEST_PRECISION);
196
197
198 Assertions.assertEquals(Collections.singletonList(TRI), result.collect(Collectors.toList()));
199 Assertions.assertSame(in, readHandler.inArg);
200 Assertions.assertSame(TEST_PRECISION, readHandler.precisionArg);
201 }
202
203 @Test
204 void testTriangles_unknownHandler() {
205
206 checkUnknownReadHandler((in, fmt) -> manager.triangles(in, fmt, TEST_PRECISION));
207 }
208
209 @Test
210 void testReadTriangleMesh_formatGiven() {
211
212 final StubReadHandler3D readHandler = new StubReadHandler3D();
213 manager.registerReadHandler(readHandler);
214
215 final GeometryInput in = new FileGeometryInput(Paths.get("myfile"));
216
217
218 final TriangleMesh result = manager.readTriangleMesh(in, TEST_FMT, TEST_PRECISION);
219
220
221 Assertions.assertEquals(TRI_MESH, result);
222 Assertions.assertSame(in, readHandler.inArg);
223 Assertions.assertSame(TEST_PRECISION, readHandler.precisionArg);
224 }
225
226 @Test
227 void testReadTriangleMesh_nullFormat() {
228
229 final StubReadHandler3D readHandler = new StubReadHandler3D();
230 manager.registerReadHandler(readHandler);
231
232 final GeometryInput in = new FileGeometryInput(Paths.get("myfile.test"));
233
234
235 final TriangleMesh result = manager.readTriangleMesh(in, null, TEST_PRECISION);
236
237
238 Assertions.assertEquals(TRI_MESH, result);
239 Assertions.assertSame(in, readHandler.inArg);
240 Assertions.assertSame(TEST_PRECISION, readHandler.precisionArg);
241 }
242
243 @Test
244 void testReadTriangleMesh_unknownHandler() {
245
246 checkUnknownReadHandler((in, fmt) -> manager.readTriangleMesh(in, fmt, TEST_PRECISION));
247 }
248
249 @Test
250 void testWrite_stream_formatGiven() {
251
252 final StubWriteHandler3D writeHandler = new StubWriteHandler3D();
253 manager.registerWriteHandler(writeHandler);
254
255 final GeometryOutput out = new FileGeometryOutput(Paths.get("myfile"));
256
257
258 manager.write(Stream.of(TRI), out, TEST_FMT);
259
260
261 Assertions.assertEquals(Collections.singletonList(TRI), writeHandler.boundariesArg);
262 Assertions.assertSame(out, writeHandler.outArg);
263 }
264
265 @Test
266 void testWrite_stream_nullFormat() {
267
268 final StubWriteHandler3D writeHandler = new StubWriteHandler3D();
269 manager.registerWriteHandler(writeHandler);
270
271 final GeometryOutput out = new FileGeometryOutput(Paths.get("myfile.TEST"));
272
273
274 manager.write(Stream.of(TRI), out, null);
275
276
277 Assertions.assertEquals(Collections.singletonList(TRI), writeHandler.boundariesArg);
278 Assertions.assertSame(out, writeHandler.outArg);
279 }
280
281 @Test
282 void testWrite_stream_unknownHandler() {
283
284 checkUnknownWriteHandler((out, fmt) -> manager.write(Stream.of(TRI), out, fmt));
285 }
286
287 @Test
288 void testWriteFacets_stream_formatGiven() {
289
290 final StubWriteHandler3D writeHandler = new StubWriteHandler3D();
291 manager.registerWriteHandler(writeHandler);
292
293 final GeometryOutput out = new FileGeometryOutput(Paths.get("myfile"));
294
295
296 manager.writeFacets(Stream.of(FACET), out, TEST_FMT);
297
298
299 Assertions.assertEquals(Collections.singletonList(FACET), writeHandler.facetsArg);
300 Assertions.assertSame(out, writeHandler.outArg);
301 }
302
303 @Test
304 void testWriteFacets_stream_nullFormat() {
305
306 final StubWriteHandler3D writeHandler = new StubWriteHandler3D();
307 manager.registerWriteHandler(writeHandler);
308
309 final GeometryOutput out = new FileGeometryOutput(Paths.get("myfile.TEST"));
310
311
312 manager.writeFacets(Stream.of(FACET), out, null);
313
314
315 Assertions.assertEquals(Collections.singletonList(FACET), writeHandler.facetsArg);
316 Assertions.assertSame(out, writeHandler.outArg);
317 }
318
319 @Test
320 void testWriteFacets_stream_unknownHandler() {
321
322 checkUnknownWriteHandler((out, fmt) -> manager.writeFacets(Stream.of(FACET), out, fmt));
323 }
324
325 @Test
326 void testWriteFacets_collection_formatGiven() {
327
328 final StubWriteHandler3D writeHandler = new StubWriteHandler3D();
329 manager.registerWriteHandler(writeHandler);
330
331 final GeometryOutput out = new FileGeometryOutput(Paths.get("myfile"));
332
333
334 manager.writeFacets(Collections.singletonList(FACET), out, TEST_FMT);
335
336
337 Assertions.assertEquals(Collections.singletonList(FACET), writeHandler.facetsArg);
338 Assertions.assertSame(out, writeHandler.outArg);
339 }
340
341 @Test
342 void testWriteFacets_collection_nullFormat() {
343
344 final StubWriteHandler3D writeHandler = new StubWriteHandler3D();
345 manager.registerWriteHandler(writeHandler);
346
347 final GeometryOutput out = new FileGeometryOutput(Paths.get("myfile.TEST"));
348
349
350 manager.writeFacets(Collections.singletonList(FACET), out, null);
351
352
353 Assertions.assertEquals(Collections.singletonList(FACET), writeHandler.facetsArg);
354 Assertions.assertSame(out, writeHandler.outArg);
355 }
356
357 @Test
358 void testWriteFacets_collection_unknownHandler() {
359
360 checkUnknownWriteHandler((out, fmt) -> manager.writeFacets(Collections.singletonList(FACET), out, fmt));
361 }
362
363 private static void checkUnknownReadHandler(final ThrowingBiConsumer<GeometryInput, GeometryFormat> fn) {
364
365 final GeometryInput withFileExt = new FileGeometryInput(Paths.get("myfile.test"));
366 final GeometryInput noFileExt = new FileGeometryInput(Paths.get("myfile"));
367
368
369 GeometryTestUtils.assertThrowsWithMessage(
370 () -> fn.accept(withFileExt, TEST_FMT),
371 IllegalArgumentException.class, "Failed to find handler for format \"test\"");
372
373 GeometryTestUtils.assertThrowsWithMessage(
374 () -> fn.accept(withFileExt, null),
375 IllegalArgumentException.class, "Failed to find handler for file extension \"test\"");
376
377 GeometryTestUtils.assertThrowsWithMessage(
378 () -> fn.accept(noFileExt, null),
379 IllegalArgumentException.class, "Failed to find handler: no format specified and no file extension available");
380 }
381
382 private static void checkUnknownWriteHandler(final ThrowingBiConsumer<GeometryOutput, GeometryFormat> fn) {
383
384 final GeometryOutput withFileExt = new FileGeometryOutput(Paths.get("myfile.test"));
385 final GeometryOutput noFileExt = new FileGeometryOutput(Paths.get("myfile"));
386
387
388 GeometryTestUtils.assertThrowsWithMessage(
389 () -> fn.accept(withFileExt, TEST_FMT),
390 IllegalArgumentException.class, "Failed to find handler for format \"test\"");
391
392 GeometryTestUtils.assertThrowsWithMessage(
393 () -> fn.accept(withFileExt, null),
394 IllegalArgumentException.class, "Failed to find handler for file extension \"test\"");
395
396 GeometryTestUtils.assertThrowsWithMessage(
397 () -> fn.accept(noFileExt, null),
398 IllegalArgumentException.class, "Failed to find handler: no format specified and no file extension available");
399 }
400
401 @FunctionalInterface
402 private interface ThrowingBiConsumer<T, V> {
403 void accept(T t, V v) throws Exception;
404 }
405
406 private static final class StubReadHandler3D implements BoundaryReadHandler3D {
407
408 private GeometryInput inArg;
409
410 private Precision.DoubleEquivalence precisionArg;
411
412
413 @Override
414 public GeometryFormat getFormat() {
415 return TEST_FMT;
416 }
417
418
419 @Override
420 public BoundarySource3D read(final GeometryInput in, final Precision.DoubleEquivalence precision) {
421 throw new UnsupportedOperationException();
422 }
423
424
425 @Override
426 public Stream<PlaneConvexSubset> boundaries(final GeometryInput in,
427 final Precision.DoubleEquivalence precision) {
428 this.inArg = in;
429 this.precisionArg = precision;
430
431 return Stream.of(TRI);
432 }
433
434
435 @Override
436 public FacetDefinitionReader facetDefinitionReader(final GeometryInput in) {
437 this.inArg = in;
438
439 return FACET_DEF_READER;
440 }
441
442
443 @Override
444 public Stream<FacetDefinition> facets(final GeometryInput in) {
445 this.inArg = in;
446
447 return Stream.of(FACET);
448 }
449
450
451 @Override
452 public TriangleMesh readTriangleMesh(final GeometryInput in, final Precision.DoubleEquivalence precision) {
453 this.inArg = in;
454 this.precisionArg = precision;
455
456 return TRI_MESH;
457 }
458 }
459
460 private static final class StubWriteHandler3D implements BoundaryWriteHandler3D {
461
462 private Collection<? extends PlaneConvexSubset> boundariesArg;
463
464 private Collection<? extends FacetDefinition> facetsArg;
465
466 private GeometryOutput outArg;
467
468
469 @Override
470 public GeometryFormat getFormat() {
471 return TEST_FMT;
472 }
473
474
475 @Override
476 public void write(final Stream<? extends PlaneConvexSubset> boundaries, final GeometryOutput out) {
477 this.boundariesArg = boundaries.collect(Collectors.toList());
478 this.outArg = out;
479 }
480
481
482 @Override
483 public void write(final BoundarySource3D src, final GeometryOutput out) {
484 throw new UnsupportedOperationException();
485 }
486
487
488 @Override
489 public void writeFacets(final Stream<? extends FacetDefinition> facets, final GeometryOutput out) {
490 this.facetsArg = facets.collect(Collectors.toList());
491 this.outArg = out;
492 }
493
494
495 @Override
496 public void writeFacets(final Collection<? extends FacetDefinition> facets, final GeometryOutput out) {
497 this.facetsArg = facets;
498 this.outArg = out;
499 }
500 }
501 }