1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.threed.mesh;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.NoSuchElementException;
25 import java.util.regex.Pattern;
26 import java.util.stream.Collectors;
27
28 import org.apache.commons.geometry.core.GeometryTestUtils;
29 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
30 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
31 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
32 import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
33 import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
34 import org.apache.commons.geometry.euclidean.threed.Bounds3D;
35 import org.apache.commons.geometry.euclidean.threed.Planes;
36 import org.apache.commons.geometry.euclidean.threed.RegionBSPTree3D;
37 import org.apache.commons.geometry.euclidean.threed.Triangle3D;
38 import org.apache.commons.geometry.euclidean.threed.Vector3D;
39 import org.apache.commons.geometry.euclidean.threed.shape.Parallelepiped;
40 import org.junit.Assert;
41 import org.junit.Test;
42
43 public class SimpleTriangleMeshTest {
44
45 private static final double TEST_EPS = 1e-10;
46
47 private static final DoublePrecisionContext TEST_PRECISION =
48 new EpsilonDoublePrecisionContext(TEST_EPS);
49
50 @Test
51 public void testFrom_verticesAndFaces() {
52
53 final Vector3D[] vertices = {
54 Vector3D.ZERO,
55 Vector3D.of(1, 1, 0),
56 Vector3D.of(1, 1, 1),
57 Vector3D.of(0, 0, 1)
58 };
59
60 final int[][] faceIndices = new int[][] {
61 {0, 1, 2},
62 {0, 2, 3}
63 };
64
65
66 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faceIndices, TEST_PRECISION);
67
68
69 Assert.assertEquals(4, mesh.getVertexCount());
70 Assert.assertEquals(Arrays.asList(vertices), mesh.getVertices());
71
72 Assert.assertEquals(2, mesh.getFaceCount());
73
74 final List<TriangleMesh.Face> faces = mesh.getFaces();
75 Assert.assertEquals(2, faces.size());
76
77 final TriangleMesh.Face f1 = faces.get(0);
78 Assert.assertEquals(0, f1.getIndex());
79 Assert.assertArrayEquals(new int[] {0, 1, 2}, f1.getVertexIndices());
80 Assert.assertSame(vertices[0], f1.getPoint1());
81 Assert.assertSame(vertices[1], f1.getPoint2());
82 Assert.assertSame(vertices[2], f1.getPoint3());
83 Assert.assertEquals(Arrays.asList(vertices[0], vertices[1], vertices[2]), f1.getVertices());
84 Assert.assertTrue(f1.definesPolygon());
85
86 final Triangle3D t1 = f1.getPolygon();
87 Assert.assertEquals(Arrays.asList(vertices[0], vertices[1], vertices[2]), t1.getVertices());
88
89 final TriangleMesh.Face f2 = faces.get(1);
90 Assert.assertEquals(1, f2.getIndex());
91 Assert.assertArrayEquals(new int[] {0, 2, 3}, f2.getVertexIndices());
92 Assert.assertSame(vertices[0], f2.getPoint1());
93 Assert.assertSame(vertices[2], f2.getPoint2());
94 Assert.assertSame(vertices[3], f2.getPoint3());
95 Assert.assertEquals(Arrays.asList(vertices[0], vertices[2], vertices[3]), f2.getVertices());
96 Assert.assertTrue(f2.definesPolygon());
97
98 final Triangle3D t2 = f2.getPolygon();
99 Assert.assertEquals(Arrays.asList(vertices[0], vertices[2], vertices[3]), t2.getVertices());
100
101 final Bounds3D bounds = mesh.getBounds();
102 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, bounds.getMin(), TEST_EPS);
103 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 1, 1), bounds.getMax(), TEST_EPS);
104
105 Assert.assertSame(TEST_PRECISION, mesh.getPrecision());
106 }
107
108 @Test
109 public void testFrom_verticesAndFaces_empty() {
110
111 final Vector3D[] vertices = {};
112
113 final int[][] faceIndices = new int[][] {};
114
115
116 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faceIndices, TEST_PRECISION);
117
118
119 Assert.assertEquals(0, mesh.getVertexCount());
120 Assert.assertEquals(0, mesh.getVertices().size());
121
122 Assert.assertEquals(0, mesh.getFaceCount());
123 Assert.assertEquals(0, mesh.getFaces().size());
124
125 Assert.assertNull(mesh.getBounds());
126
127 Assert.assertTrue(mesh.toTree().isEmpty());
128 }
129
130 @Test
131 public void testFrom_boundarySource() {
132
133 final BoundarySource3D src = Parallelepiped.axisAligned(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
134
135
136 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(src, TEST_PRECISION);
137
138
139 Assert.assertEquals(8, mesh.getVertexCount());
140
141 final Vector3D p1 = Vector3D.of(0, 0, 0);
142 final Vector3D p2 = Vector3D.of(0, 0, 1);
143 final Vector3D p3 = Vector3D.of(0, 1, 0);
144 final Vector3D p4 = Vector3D.of(0, 1, 1);
145
146 final Vector3D p5 = Vector3D.of(1, 0, 0);
147 final Vector3D p6 = Vector3D.of(1, 0, 1);
148 final Vector3D p7 = Vector3D.of(1, 1, 0);
149 final Vector3D p8 = Vector3D.of(1, 1, 1);
150
151 final List<Vector3D> vertices = mesh.getVertices();
152 Assert.assertEquals(8, vertices.size());
153
154 Assert.assertTrue(vertices.contains(p1));
155 Assert.assertTrue(vertices.contains(p2));
156 Assert.assertTrue(vertices.contains(p3));
157 Assert.assertTrue(vertices.contains(p4));
158 Assert.assertTrue(vertices.contains(p5));
159 Assert.assertTrue(vertices.contains(p6));
160 Assert.assertTrue(vertices.contains(p7));
161 Assert.assertTrue(vertices.contains(p8));
162
163 Assert.assertEquals(12, mesh.getFaceCount());
164
165 final RegionBSPTree3D tree = mesh.toTree();
166
167 Assert.assertEquals(1, tree.getSize(), TEST_EPS);
168 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0.5), tree.getCentroid(), TEST_EPS);
169
170 Assert.assertSame(TEST_PRECISION, mesh.getPrecision());
171 }
172
173 @Test
174 public void testFrom_boundarySource_empty() {
175
176 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(BoundarySource3D.from(Collections.emptyList()),
177 TEST_PRECISION);
178
179
180 Assert.assertEquals(0, mesh.getVertexCount());
181 Assert.assertEquals(0, mesh.getVertices().size());
182
183 Assert.assertEquals(0, mesh.getFaceCount());
184 Assert.assertEquals(0, mesh.getFaces().size());
185
186 Assert.assertNull(mesh.getBounds());
187
188 Assert.assertTrue(mesh.toTree().isEmpty());
189 }
190
191 @Test
192 public void testVertices_iterable() {
193
194 final List<Vector3D> vertices = Arrays.asList(
195 Vector3D.ZERO,
196 Vector3D.of(1, 0, 0),
197 Vector3D.of(0, 1, 0)
198 );
199
200 final List<int[]> faceIndices = Collections.singletonList(new int[]{0, 1, 2});
201
202 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faceIndices, TEST_PRECISION);
203
204
205 final List<Vector3D> result = new ArrayList<>();
206 mesh.vertices().forEach(result::add);
207
208
209 Assert.assertEquals(vertices, result);
210 }
211
212 @Test
213 public void testFaces_iterable() {
214
215 final List<Vector3D> vertices = Arrays.asList(
216 Vector3D.ZERO,
217 Vector3D.of(1, 0, 0),
218 Vector3D.of(0, 1, 0),
219 Vector3D.of(0, 0, 1)
220 );
221
222 final List<int[]> faceIndices = Arrays.asList(
223 new int[] {0, 1, 2},
224 new int[] {0, 2, 3}
225 );
226
227 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faceIndices, TEST_PRECISION);
228
229
230 final List<TriangleMesh.Face> result = new ArrayList<>();
231 mesh.faces().forEach(result::add);
232
233
234 Assert.assertEquals(2, result.size());
235
236 final TriangleMesh.Face f1 = result.get(0);
237 Assert.assertEquals(0, f1.getIndex());
238 Assert.assertArrayEquals(new int[] {0, 1, 2}, f1.getVertexIndices());
239 Assert.assertSame(vertices.get(0), f1.getPoint1());
240 Assert.assertSame(vertices.get(1), f1.getPoint2());
241 Assert.assertSame(vertices.get(2), f1.getPoint3());
242 Assert.assertEquals(Arrays.asList(vertices.get(0), vertices.get(1), vertices.get(2)), f1.getVertices());
243 Assert.assertTrue(f1.definesPolygon());
244
245 final TriangleMesh.Face f2 = result.get(1);
246 Assert.assertEquals(1, f2.getIndex());
247 Assert.assertArrayEquals(new int[] {0, 2, 3}, f2.getVertexIndices());
248 Assert.assertSame(vertices.get(0), f2.getPoint1());
249 Assert.assertSame(vertices.get(2), f2.getPoint2());
250 Assert.assertSame(vertices.get(3), f2.getPoint3());
251 Assert.assertEquals(Arrays.asList(vertices.get(0), vertices.get(2), vertices.get(3)), f2.getVertices());
252 Assert.assertTrue(f2.definesPolygon());
253 }
254
255 @Test
256 public void testFaces_iterator() {
257
258 final List<Vector3D> vertices = Arrays.asList(
259 Vector3D.ZERO,
260 Vector3D.of(1, 0, 0),
261 Vector3D.of(0, 1, 0)
262 );
263
264 final List<int[]> faceIndices = Arrays.asList(
265 new int[] {0, 1, 2}
266 );
267
268 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faceIndices, TEST_PRECISION);
269
270
271 final Iterator<TriangleMesh.Face> it = mesh.faces().iterator();
272
273 Assert.assertTrue(it.hasNext());
274 Assert.assertEquals(0, it.next().getIndex());
275 Assert.assertFalse(it.hasNext());
276
277 GeometryTestUtils.assertThrows(() -> it.next(), NoSuchElementException.class);
278 }
279
280 @Test
281 public void testTriangleStream() {
282
283 final List<Vector3D> vertices = Arrays.asList(
284 Vector3D.ZERO,
285 Vector3D.of(1, 0, 0),
286 Vector3D.of(0, 1, 0),
287 Vector3D.of(0, 0, 1)
288 );
289
290 final List<int[]> faceIndices = Arrays.asList(
291 new int[] {0, 1, 2},
292 new int[] {0, 2, 3}
293 );
294
295 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faceIndices, TEST_PRECISION);
296
297
298 final List<Triangle3D> tris = mesh.triangleStream().collect(Collectors.toList());
299
300
301 Assert.assertEquals(2, tris.size());
302
303 final Triangle3D t1 = tris.get(0);
304 Assert.assertSame(vertices.get(0), t1.getPoint1());
305 Assert.assertSame(vertices.get(1), t1.getPoint2());
306 Assert.assertSame(vertices.get(2), t1.getPoint3());
307
308 final Triangle3D t2 = tris.get(1);
309 Assert.assertSame(vertices.get(0), t2.getPoint1());
310 Assert.assertSame(vertices.get(2), t2.getPoint2());
311 Assert.assertSame(vertices.get(3), t2.getPoint3());
312 }
313
314 @Test
315 public void testToTriangleMesh() {
316
317 final DoublePrecisionContext precision1 = new EpsilonDoublePrecisionContext(1e-1);
318 final DoublePrecisionContext precision2 = new EpsilonDoublePrecisionContext(1e-2);
319 final DoublePrecisionContext precision3 = new EpsilonDoublePrecisionContext(1e-1);
320
321 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(Parallelepiped.unitCube(TEST_PRECISION), precision1);
322
323
324 Assert.assertSame(mesh, mesh.toTriangleMesh(precision1));
325
326 final SimpleTriangleMesh other = mesh.toTriangleMesh(precision2);
327 Assert.assertSame(precision2, other.getPrecision());
328 Assert.assertEquals(mesh.getVertices(), other.getVertices());
329 Assert.assertEquals(12, other.getFaceCount());
330 for (int i = 0; i < 12; ++i) {
331 Assert.assertArrayEquals(mesh.getFace(i).getVertexIndices(), other.getFace(i).getVertexIndices());
332 }
333
334 Assert.assertSame(mesh, mesh.toTriangleMesh(precision3));
335 }
336
337 @Test
338 public void testFace_doesNotDefineTriangle() {
339
340 final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
341 final Vector3D[] vertices = new Vector3D[] {
342 Vector3D.ZERO,
343 Vector3D.of(0.01, -0.01, 0.01),
344 Vector3D.of(0.01, 0.01, 0.01),
345 Vector3D.of(1, 0, 0),
346 Vector3D.of(2, 0.01, 0)
347 };
348 final int[][] faces = new int[][] {
349 {0, 1, 2},
350 {0, 3, 4}
351 };
352 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(vertices, faces, precision);
353
354
355 final Pattern msgPattern = Pattern.compile("^Points do not define a plane: .*");
356
357 Assert.assertFalse(mesh.getFace(0).definesPolygon());
358 GeometryTestUtils.assertThrows(() -> {
359 mesh.getFace(0).getPolygon();
360 }, IllegalArgumentException.class, msgPattern);
361
362 Assert.assertFalse(mesh.getFace(1).definesPolygon());
363 GeometryTestUtils.assertThrows(() -> {
364 mesh.getFace(1).getPolygon();
365 }, IllegalArgumentException.class, msgPattern);
366 }
367
368 @Test
369 public void testToTree_smallNumberOfFaces() {
370
371 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(Parallelepiped.unitCube(TEST_PRECISION), TEST_PRECISION);
372
373
374 final RegionBSPTree3D tree = mesh.toTree();
375
376
377 Assert.assertFalse(tree.isFull());
378 Assert.assertFalse(tree.isEmpty());
379 Assert.assertFalse(tree.isInfinite());
380 Assert.assertTrue(tree.isFinite());
381
382 Assert.assertEquals(1, tree.getSize(), 1);
383 Assert.assertEquals(6, tree.getBoundarySize(), 1);
384
385 Assert.assertEquals(6, tree.getRoot().height());
386 }
387
388 @Test
389 public void testTransform() {
390
391 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(Parallelepiped.unitCube(TEST_PRECISION), TEST_PRECISION);
392
393 final AffineTransformMatrix3D t = AffineTransformMatrix3D.createScale(1, 2, 3)
394 .translate(0.5, 1, 1.5);
395
396
397 final SimpleTriangleMesh result = mesh.transform(t);
398
399
400 Assert.assertNotSame(mesh, result);
401
402 Assert.assertEquals(8, result.getVertexCount());
403 Assert.assertEquals(12, result.getFaceCount());
404
405 final Bounds3D resultBounds = result.getBounds();
406 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, resultBounds.getMin(), TEST_EPS);
407 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 2, 3), resultBounds.getMax(), TEST_EPS);
408
409 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 1, 1.5), result.toTree().getCentroid(), TEST_EPS);
410 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, mesh.toTree().getCentroid(), TEST_EPS);
411 }
412
413 @Test
414 public void testTransform_empty() {
415
416 final SimpleTriangleMesh mesh = SimpleTriangleMesh.builder(TEST_PRECISION).build();
417
418 final AffineTransformMatrix3D t = AffineTransformMatrix3D.createScale(1, 2, 3);
419
420
421 final SimpleTriangleMesh result = mesh.transform(t);
422
423
424 Assert.assertEquals(0, result.getVertexCount());
425 Assert.assertEquals(0, result.getFaceCount());
426
427 Assert.assertNull(result.getBounds());
428 }
429
430 @Test
431 public void testToString() {
432
433 final Triangle3D tri = Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0),
434 TEST_PRECISION);
435 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(BoundarySource3D.from(tri), TEST_PRECISION);
436
437
438 final String str = mesh.toString();
439
440
441 GeometryTestUtils.assertContains("SimpleTriangleMesh[vertexCount= 3, faceCount= 1, bounds= Bounds3D[", str);
442 }
443
444 @Test
445 public void testFaceToString() {
446
447 final Triangle3D tri = Planes.triangleFromVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0),
448 TEST_PRECISION);
449 final SimpleTriangleMesh mesh = SimpleTriangleMesh.from(BoundarySource3D.from(tri), TEST_PRECISION);
450
451
452 final String str = mesh.getFace(0).toString();
453
454
455 GeometryTestUtils.assertContains("SimpleTriangleFace[index= 0, vertexIndices= [0, 1, 2], vertices= [(0", str);
456 }
457
458 @Test
459 public void testBuilder_mixedBuildMethods() {
460
461 final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
462 final SimpleTriangleMesh.Builder builder = SimpleTriangleMesh.builder(precision);
463
464
465 builder.addVertices(Arrays.asList(Vector3D.ZERO, Vector3D.of(1, 0, 0)));
466 builder.useVertex(Vector3D.of(0, 0, 1));
467 builder.addVertex(Vector3D.of(0, 1, 0));
468 builder.useVertex(Vector3D.of(1, 1, 1));
469
470 builder.addFace(0, 2, 1);
471 builder.addFaceUsingVertices(Vector3D.of(0.5, 0, 0), Vector3D.of(1.01, 0, 0), Vector3D.of(1, 1, 0.95));
472
473 final SimpleTriangleMesh mesh = builder.build();
474
475
476 Assert.assertEquals(6, mesh.getVertexCount());
477 Assert.assertEquals(2, mesh.getFaceCount());
478
479 final List<TriangleMesh.Face> faces = mesh.getFaces();
480 Assert.assertEquals(2, faces.size());
481
482 Assert.assertArrayEquals(new int[] {0, 2, 1}, faces.get(0).getVertexIndices());
483 Assert.assertArrayEquals(new int[] {5, 1, 4}, faces.get(1).getVertexIndices());
484 }
485
486 @Test
487 public void testBuilder_addVerticesAndFaces() {
488
489 final SimpleTriangleMesh mesh = SimpleTriangleMesh.builder(TEST_PRECISION)
490 .addVertices(new Vector3D[] {
491 Vector3D.ZERO,
492 Vector3D.of(1, 1, 0),
493 Vector3D.of(1, 1, 1),
494 Vector3D.of(0, 0, 1)
495 })
496 .addFaces(new int[][] {
497 {0, 1, 2},
498 {0, 2, 3}
499 })
500 .build();
501
502
503 Assert.assertEquals(4, mesh.getVertexCount());
504 Assert.assertEquals(2, mesh.getFaceCount());
505 }
506
507 @Test
508 public void testBuilder_invalidFaceIndices() {
509
510 final SimpleTriangleMesh.Builder builder = SimpleTriangleMesh.builder(TEST_PRECISION);
511 builder.useVertex(Vector3D.ZERO);
512 builder.useVertex(Vector3D.of(1, 0, 0));
513 builder.useVertex(Vector3D.of(0, 1, 0));
514
515 final String msgBase = "Invalid vertex index: ";
516
517
518 GeometryTestUtils.assertThrows(() -> {
519 builder.addFace(-1, 1, 2);
520 }, IllegalArgumentException.class, msgBase + "-1");
521
522 GeometryTestUtils.assertThrows(() -> {
523 builder.addFace(0, 3, 2);
524 }, IllegalArgumentException.class, msgBase + "3");
525
526 GeometryTestUtils.assertThrows(() -> {
527 builder.addFace(0, 1, 4);
528 }, IllegalArgumentException.class, msgBase + "4");
529
530 GeometryTestUtils.assertThrows(() -> {
531 builder.addFaces(new int[][] {{-1, 1, 2}});
532 }, IllegalArgumentException.class, msgBase + "-1");
533
534 GeometryTestUtils.assertThrows(() -> {
535 builder.addFaces(new int[][] {{0, 3, 2}});
536 }, IllegalArgumentException.class, msgBase + "3");
537
538 GeometryTestUtils.assertThrows(() -> {
539 builder.addFaces(new int[][] {{0, 1, 4}});
540 }, IllegalArgumentException.class, msgBase + "4");
541 }
542
543 @Test
544 public void testBuilder_invalidFaceIndexCount() {
545
546 final SimpleTriangleMesh.Builder builder = SimpleTriangleMesh.builder(TEST_PRECISION);
547 builder.useVertex(Vector3D.ZERO);
548 builder.useVertex(Vector3D.of(1, 0, 0));
549 builder.useVertex(Vector3D.of(0, 1, 0));
550 builder.useVertex(Vector3D.of(0, 0, 1));
551
552 final String msgBase = "Face must contain 3 vertex indices; found ";
553
554
555 GeometryTestUtils.assertThrows(() -> {
556 builder.addFaces(new int[][] {{}});
557 }, IllegalArgumentException.class, msgBase + "0");
558
559 GeometryTestUtils.assertThrows(() -> {
560 builder.addFaces(new int[][] {{0}});
561 }, IllegalArgumentException.class, msgBase + "1");
562
563 GeometryTestUtils.assertThrows(() -> {
564 builder.addFaces(new int[][] {{0, 1}});
565 }, IllegalArgumentException.class, msgBase + "2");
566
567 GeometryTestUtils.assertThrows(() -> {
568 builder.addFaces(new int[][] {{0, 1, 2, 3}});
569 }, IllegalArgumentException.class, msgBase + "4");
570 }
571
572 @Test
573 public void testBuilder_cannotModifyOnceBuilt() {
574
575 final SimpleTriangleMesh.Builder builder = SimpleTriangleMesh.builder(TEST_PRECISION)
576 .addVertices(new Vector3D[] {
577 Vector3D.ZERO,
578 Vector3D.of(1, 1, 0),
579 Vector3D.of(1, 1, 1),
580 })
581 .addFaces(new int[][] {
582 {0, 1, 2}
583 });
584 builder.build();
585
586 final String msg = "Builder instance cannot be modified: mesh construction is complete";
587
588
589 GeometryTestUtils.assertThrows(() -> {
590 builder.useVertex(Vector3D.ZERO);
591 }, IllegalStateException.class, msg);
592
593 GeometryTestUtils.assertThrows(() -> {
594 builder.addVertex(Vector3D.ZERO);
595 }, IllegalStateException.class, msg);
596
597 GeometryTestUtils.assertThrows(() -> {
598 builder.addVertices(Collections.singletonList(Vector3D.ZERO));
599 }, IllegalStateException.class, msg);
600
601 GeometryTestUtils.assertThrows(() -> {
602 builder.addVertices(new Vector3D[] {Vector3D.ZERO});
603 }, IllegalStateException.class, msg);
604
605 GeometryTestUtils.assertThrows(() -> {
606 builder.addFaceUsingVertices(Vector3D.ZERO, Vector3D.of(1, 0, 0), Vector3D.of(0, 1, 0));
607 }, IllegalStateException.class, msg);
608
609 GeometryTestUtils.assertThrows(() -> {
610 builder.addFace(0, 1, 2);
611 }, IllegalStateException.class, msg);
612
613 GeometryTestUtils.assertThrows(() -> {
614 builder.addFaces(Collections.singletonList(new int[]{0, 1, 2}));
615 }, IllegalStateException.class, msg);
616
617 GeometryTestUtils.assertThrows(() -> {
618 builder.addFaces(new int[][] {{0, 1, 2}});
619 }, IllegalStateException.class, msg);
620 }
621
622 @Test
623 public void testBuilder_addFaceAndVertices_vs_addFaceUsingVertices() {
624
625 final SimpleTriangleMesh.Builder builder = SimpleTriangleMesh.builder(TEST_PRECISION);
626 final Vector3D p1 = Vector3D.ZERO;
627 final Vector3D p2 = Vector3D.of(1, 0, 0);
628 final Vector3D p3 = Vector3D.of(0, 1, 0);
629
630
631 builder.addFaceUsingVertices(p1, p2, p3);
632 builder.addFaceAndVertices(p1, p2, p3);
633 builder.addFaceUsingVertices(p1, p2, p3);
634
635
636 Assert.assertEquals(6, builder.getVertexCount());
637 Assert.assertEquals(3, builder.getFaceCount());
638
639 final SimpleTriangleMesh mesh = builder.build();
640
641 Assert.assertEquals(6, mesh.getVertexCount());
642 Assert.assertEquals(3, mesh.getFaceCount());
643
644 final TriangleMesh.Face f1 = mesh.getFace(0);
645 Assert.assertArrayEquals(new int[] {0, 1, 2}, f1.getVertexIndices());
646
647 final TriangleMesh.Face f2 = mesh.getFace(1);
648 Assert.assertArrayEquals(new int[] {3, 4, 5}, f2.getVertexIndices());
649
650 final TriangleMesh.Face f3 = mesh.getFace(2);
651 Assert.assertArrayEquals(new int[] {0, 1, 2}, f3.getVertexIndices());
652 }
653 }