1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.threed;
18
19 import java.util.Arrays;
20
21 import org.apache.commons.geometry.euclidean.threed.line.Lines3D;
22 import org.apache.commons.geometry.euclidean.threed.shape.Parallelepiped;
23 import org.apache.commons.numbers.core.Precision;
24 import org.junit.jupiter.api.Test;
25
26 class BoundarySourceLinecaster3DTest {
27
28 private static final double TEST_EPS = 1e-10;
29
30 private static final Precision.DoubleEquivalence TEST_PRECISION =
31 Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
32
33 private static final BoundarySource3D UNIT_CUBE = Parallelepiped.builder(TEST_PRECISION)
34 .setPosition(Vector3D.of(0.5, 0.5, 0.5))
35 .build();
36
37 @Test
38 void testLinecast_line_simple() {
39
40 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
41
42
43
44
45 LinecastChecker3D.with(linecaster)
46 .expectNothing()
47 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0, 4, 4), Vector3D.Unit.MINUS_X, TEST_PRECISION));
48
49
50 LinecastChecker3D.with(linecaster)
51 .expect(Vector3D.of(0, 0.5, 0.5), Vector3D.Unit.MINUS_X)
52 .and(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
53 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0.5, 0.5, 0.5), Vector3D.Unit.PLUS_X, TEST_PRECISION));
54
55 LinecastChecker3D.with(linecaster)
56 .expect(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
57 .and(Vector3D.of(0, 0.5, 0.5), Vector3D.Unit.MINUS_X)
58 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0.5, 0.5, 0.5), Vector3D.Unit.MINUS_X, TEST_PRECISION));
59 }
60
61 @Test
62 void testLinecast_line_alongFace() {
63
64 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
65
66
67 LinecastChecker3D.with(linecaster)
68 .expect(Vector3D.ZERO, Vector3D.Unit.MINUS_Y)
69 .and(Vector3D.ZERO, Vector3D.Unit.MINUS_Z)
70 .and(Vector3D.of(0, 1, 1), Vector3D.Unit.PLUS_Z)
71 .and(Vector3D.of(0, 1, 1), Vector3D.Unit.PLUS_Y)
72 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(0, 1, 1), TEST_PRECISION));
73 }
74
75 @Test
76 void testLinecast_line_corners() {
77
78 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
79
80
81
82
83 LinecastChecker3D.with(linecaster)
84 .expect(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_Z)
85 .and(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_Y)
86 .and(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_X)
87 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(1, 1, 1), Vector3D.of(1, -1, -1), TEST_PRECISION));
88
89
90 LinecastChecker3D.with(linecaster)
91 .expect(Vector3D.ZERO, Vector3D.Unit.MINUS_X)
92 .and(Vector3D.ZERO, Vector3D.Unit.MINUS_Y)
93 .and(Vector3D.ZERO, Vector3D.Unit.MINUS_Z)
94 .and(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_Z)
95 .and(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_Y)
96 .and(Vector3D.of(1, 1, 1), Vector3D.Unit.PLUS_X)
97 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION));
98 }
99
100 @Test
101 void testLinecast_line_removesDuplicatePoints() {
102
103 final BoundarySource3D src = BoundarySource3D.of(
104 Planes.convexPolygonFromVertices(Arrays.asList(Vector3D.ZERO, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y), TEST_PRECISION),
105 Planes.convexPolygonFromVertices(Arrays.asList(Vector3D.ZERO, Vector3D.Unit.PLUS_Y, Vector3D.Unit.MINUS_X), TEST_PRECISION)
106 );
107 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(src);
108
109
110 LinecastChecker3D.with(linecaster)
111 .expect(Vector3D.of(0, 0.5, 0), Vector3D.Unit.PLUS_Z)
112 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(-1, 0.5, 1), Vector3D.of(1, 0, -1), TEST_PRECISION));
113 }
114
115 @Test
116 void testLinecast_segment_simple() {
117
118 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
119
120
121
122
123 LinecastChecker3D.with(linecaster)
124 .expectNothing()
125 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0, 4, 4), Vector3D.Unit.MINUS_X, TEST_PRECISION)
126 .segment(-10, 10));
127
128
129 LinecastChecker3D.with(linecaster)
130 .expectNothing()
131 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0.5, 0.5, 0.5), Vector3D.Unit.PLUS_X, TEST_PRECISION)
132 .segment(2, 10));
133
134
135 LinecastChecker3D.with(linecaster)
136 .expect(Vector3D.of(0, 0.5, 0.5), Vector3D.Unit.MINUS_X)
137 .and(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
138 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0.5, 0.5, 0.5), Vector3D.Unit.PLUS_X, TEST_PRECISION)
139 .segment(-10, 10));
140
141 LinecastChecker3D.with(linecaster)
142 .expect(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
143 .and(Vector3D.of(0, 0.5, 0.5), Vector3D.Unit.MINUS_X)
144 .whenGiven(Lines3D.fromPointAndDirection(Vector3D.of(0.5, 0.5, 0.5), Vector3D.Unit.MINUS_X, TEST_PRECISION)
145 .segment(-10, 10));
146 }
147
148 @Test
149 void testLinecast_segment_boundaryExcluded() {
150
151 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
152
153
154 final Vector3D center = Vector3D.of(0.5, 0.5, 0.5);
155 LinecastChecker3D.with(linecaster)
156 .expect(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
157 .whenGiven(Lines3D.fromPointAndDirection(center, Vector3D.Unit.PLUS_X, TEST_PRECISION)
158 .rayFrom(center));
159
160 LinecastChecker3D.with(linecaster)
161 .expect(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
162 .whenGiven(Lines3D.fromPointAndDirection(center, Vector3D.Unit.MINUS_X, TEST_PRECISION)
163 .reverseRayTo(center));
164 }
165
166 @Test
167 void testLinecast_segment_startEndPointsOnBoundaries() {
168
169 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
170
171
172 LinecastChecker3D.with(linecaster)
173 .expect(Vector3D.of(1, 0.5, 0.5), Vector3D.Unit.PLUS_X)
174 .and(Vector3D.of(0, 0.5, 0.5), Vector3D.Unit.MINUS_X)
175 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(1, 0.5, 0.5), Vector3D.of(0, 0.5, 0.5), TEST_PRECISION));
176 }
177
178 @Test
179 void testLinecast_segment_alongFace() {
180
181 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
182
183
184
185
186 LinecastChecker3D.with(linecaster)
187 .expect(Vector3D.of(0, 1, 0), Vector3D.Unit.MINUS_X)
188 .and(Vector3D.of(1, 1, 0), Vector3D.Unit.PLUS_X)
189 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(-1, 1, 0), Vector3D.of(2, 1, 0), TEST_PRECISION));
190
191
192 LinecastChecker3D.with(linecaster)
193 .expect(Vector3D.of(1, 1, 0), Vector3D.Unit.PLUS_X)
194 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(0.25, 1, 0), Vector3D.of(2, 1, 0), TEST_PRECISION));
195
196
197 LinecastChecker3D.with(linecaster)
198 .expectNothing()
199 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(0.25, 1, 0), Vector3D.of(0.75, 1, 0), TEST_PRECISION));
200 }
201
202 @Test
203 void testLinecast_segment_corners() {
204
205 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(UNIT_CUBE);
206
207 final Vector3D corner = Vector3D.of(1, 1, 1);
208
209
210
211
212 LinecastChecker3D.with(linecaster)
213 .expect(corner, Vector3D.Unit.PLUS_Z)
214 .and(corner, Vector3D.Unit.PLUS_Y)
215 .and(corner, Vector3D.Unit.PLUS_X)
216 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(0.5, 0.5, 0.5), Vector3D.of(2, 2, 2), TEST_PRECISION));
217
218
219 LinecastChecker3D.with(linecaster)
220 .expect(corner, Vector3D.Unit.PLUS_Z)
221 .and(corner, Vector3D.Unit.PLUS_Y)
222 .and(corner, Vector3D.Unit.PLUS_X)
223 .whenGiven(Lines3D.segmentFromPoints(corner, Vector3D.of(2, 0, 2), TEST_PRECISION));
224
225
226 LinecastChecker3D.with(linecaster)
227 .expect(corner, Vector3D.Unit.PLUS_Z)
228 .and(corner, Vector3D.Unit.PLUS_Y)
229 .and(corner, Vector3D.Unit.PLUS_X)
230 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(0, 2, 2), corner, TEST_PRECISION));
231 }
232
233 @Test
234 void testLinecast_segment_removesDuplicatePoints() {
235
236 final BoundarySource3D src = BoundarySource3D.of(
237 Planes.convexPolygonFromVertices(Arrays.asList(Vector3D.ZERO, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y), TEST_PRECISION),
238 Planes.convexPolygonFromVertices(Arrays.asList(Vector3D.ZERO, Vector3D.Unit.PLUS_Y, Vector3D.Unit.MINUS_X), TEST_PRECISION)
239 );
240 final BoundarySourceLinecaster3D linecaster = new BoundarySourceLinecaster3D(src);
241
242
243 LinecastChecker3D.with(linecaster)
244 .expect(Vector3D.of(0, 0.5, 0), Vector3D.Unit.PLUS_Z)
245 .whenGiven(Lines3D.segmentFromPoints(Vector3D.of(-1, 0.5, 1), Vector3D.of(1, 0.5, -1), TEST_PRECISION));
246 }
247 }