1 package org.djutils.draw.line;
2
3 import java.util.Arrays;
4 import java.util.Iterator;
5 import java.util.Locale;
6
7 import org.djutils.draw.Direction3d;
8 import org.djutils.draw.Drawable3d;
9 import org.djutils.draw.bounds.Bounds3d;
10 import org.djutils.draw.point.DirectedPoint3d;
11 import org.djutils.draw.point.Point3d;
12 import org.djutils.exceptions.Throw;
13 import org.djutils.math.AngleUtil;
14
15
16
17
18
19
20
21
22
23
24
25 public class Ray3d extends DirectedPoint3d implements Drawable3d, Ray<Ray3d, DirectedPoint3d, Point3d>
26 {
27
28 private static final long serialVersionUID = 20210119L;
29
30
31
32
33
34
35
36
37
38
39 public Ray3d(final double x, final double y, final double z, final double dirY, final double dirZ)
40 {
41 super(x, y, z, dirY, dirZ);
42 }
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public Ray3d(final double x, final double y, final double z, final double[] directionVector)
58 {
59 super(x, y, z, directionVector);
60 }
61
62
63
64
65
66
67
68
69
70 public Ray3d(final double x, final double y, final double z, final Direction3d dir)
71 {
72 super(x, y, z, dir);
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public Ray3d(final double x, final double y, final double z, final double throughX, final double throughY,
89 final double throughZ)
90 {
91 super(x, y, z, throughX, throughY, throughZ);
92 }
93
94
95
96
97
98
99
100
101
102
103
104 public Ray3d(final double x, final double y, final double z, final Point3d throughPoint)
105 {
106 super(x, y, z, throughPoint);
107 }
108
109
110
111
112
113
114
115
116
117
118 public Ray3d(final double[] xyz, final double dirY, final double dirZ)
119 {
120 super(xyz, dirY, dirZ);
121 }
122
123
124
125
126
127
128
129
130
131
132 public Ray3d(final double[] xyz, final double[] directionVector)
133 {
134 super(xyz, directionVector);
135 }
136
137
138
139
140
141
142
143
144
145
146 public Ray3d(final double[] xyz, final Direction3d dir)
147 {
148 super(xyz, dir);
149 }
150
151
152
153
154
155
156
157
158
159 public Ray3d(final Point3d point, final double dirY, final double dirZ)
160 {
161 super(point, dirY, dirZ);
162 }
163
164
165
166
167
168
169
170 public Ray3d(final Point3d point, final Direction3d dir)
171 {
172 super(point, dir);
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186
187 public Ray3d(final Point3d point, final double throughX, final double throughY, final double throughZ)
188 {
189 super(point, throughX, throughY, throughZ);
190 }
191
192
193
194
195
196
197
198
199
200 public Ray3d(final Point3d point, final Point3d throughPoint) throws NullPointerException, IllegalArgumentException
201 {
202 super(point, throughPoint);
203 }
204
205
206
207
208
209
210 public Ray3d(final DirectedPoint3d directedPoint)
211 {
212 this(directedPoint, directedPoint.dirY, directedPoint.dirZ);
213 }
214
215 @Override
216 public final double getDirY()
217 {
218 return this.dirY;
219 }
220
221 @Override
222 public final double getDirZ()
223 {
224 return this.dirZ;
225 }
226
227 @Override
228 public DirectedPoint3d getEndPoint()
229 {
230 return this;
231 }
232
233 @Override
234 public int size()
235 {
236 return 2;
237 }
238
239 @Override
240 public Iterator<Point3d> iterator()
241 {
242 double sinDirZ = Math.sin(this.dirZ);
243 double cosDirZ = Math.cos(this.dirZ);
244 double sinDirY = Math.sin(this.dirY);
245 double cosDirY = Math.cos(this.dirY);
246 Point3d[] array = new Point3d[] {this,
247 new Point3d(cosDirZ * sinDirY == 0 ? this.x : cosDirZ * sinDirY * Double.POSITIVE_INFINITY,
248 cosDirZ * sinDirZ == 0 ? this.y : cosDirZ * sinDirZ * Double.POSITIVE_INFINITY,
249 cosDirY == 0 ? this.z : cosDirY * Double.POSITIVE_INFINITY)};
250 return Arrays.stream(array).iterator();
251 }
252
253 @Override
254 public Bounds3d getBounds()
255 {
256 double sinDirZ = Math.sin(this.dirZ);
257 double cosDirZ = Math.cos(this.dirZ);
258 double sinDirY = Math.sin(this.dirY);
259 double cosDirY = Math.cos(this.dirY);
260 return new Bounds3d(cosDirZ * sinDirY >= 0 ? this.x : Double.NEGATIVE_INFINITY,
261 cosDirZ * sinDirY <= 0 ? this.x : Double.POSITIVE_INFINITY,
262 sinDirZ * sinDirY >= 0 ? this.y : Double.NEGATIVE_INFINITY,
263 sinDirZ * sinDirY <= 0 ? this.y : Double.POSITIVE_INFINITY, cosDirY >= 0 ? this.z : Double.NEGATIVE_INFINITY,
264 cosDirY <= 0 ? this.z : Double.POSITIVE_INFINITY);
265 }
266
267 @Override
268 public Ray3d neg()
269 {
270 return new Ray3d(-this.x, -this.y, -this.z, AngleUtil.normalizeAroundZero(this.dirY + Math.PI),
271 AngleUtil.normalizeAroundZero(this.dirZ + Math.PI));
272 }
273
274 @Override
275 public Ray3d flip()
276 {
277 return new Ray3d(this.x, this.y, this.z, AngleUtil.normalizeAroundZero(Math.PI - this.dirY),
278 AngleUtil.normalizeAroundZero(this.dirZ + Math.PI));
279 }
280
281 @Override
282 public Ray3d getLocationExtended(final double position) throws ArithmeticException, IllegalArgumentException
283 {
284 Throw.whenNaN(position, "position");
285 Throw.when(Double.isInfinite(position), IllegalArgumentException.class, "position must be finite");
286 double sinDirY = Math.sin(this.dirY);
287 double dX = Math.cos(this.dirZ) * sinDirY;
288 double dY = Math.sin(this.dirZ) * sinDirY;
289 double dZ = Math.cos(this.dirY);
290 return new Ray3d(this.x + dX * position, this.y + dY * position, this.z + dZ * position, this.dirY, this.dirZ);
291 }
292
293 @Override
294 public Point3d closestPointOnRay(final Point3d point) throws NullPointerException
295 {
296 Throw.whenNull(point, "point");
297 double sinDirY = Math.sin(this.dirY);
298 return point.closestPointOnLine(this.x, this.y, this.z, this.x + Math.cos(this.dirZ) * sinDirY,
299 this.y + Math.sin(this.dirZ) * sinDirY, this.z + Math.cos(this.dirY), true, false);
300 }
301
302 @Override
303 public Point3d projectOrthogonal(final Point3d point) throws NullPointerException
304 {
305 Throw.whenNull(point, "point");
306 double sinDirY = Math.sin(this.dirY);
307 return point.closestPointOnLine(this.x, this.y, this.z, this.x + Math.cos(this.dirZ) * sinDirY,
308 this.y + Math.sin(this.dirZ) * sinDirY, this.z + Math.cos(this.dirY), null, false);
309 }
310
311 @Override
312 public Point3d projectOrthogonalExtended(final Point3d point)
313 {
314 Throw.whenNull(point, "point");
315 double sinDirY = Math.sin(this.dirY);
316 return point.closestPointOnLine(getX(), getY(), getZ(), getX() + Math.cos(this.dirZ) * sinDirY,
317 getY() + Math.sin(this.dirZ) * sinDirY, getZ() + Math.cos(this.dirY), false, false);
318 }
319
320 @Override
321 public double projectOrthogonalFractional(final Point3d point) throws NullPointerException
322 {
323 Throw.whenNull(point, "point");
324 double sinDirY = Math.sin(this.dirY);
325 return point.fractionalPositionOnLine(this.x, this.y, this.z, this.x + Math.cos(this.dirZ) * sinDirY,
326 this.y + Math.sin(this.dirZ) * sinDirY, this.z + Math.cos(this.dirY), null, false);
327 }
328
329 @Override
330 public double projectOrthogonalFractionalExtended(final Point3d point) throws NullPointerException
331 {
332 Throw.whenNull(point, "point");
333 double sinDirY = Math.sin(this.dirY);
334 return point.fractionalPositionOnLine(getX(), getY(), getZ(), getX() + Math.cos(this.dirZ) * sinDirY,
335 getY() + Math.sin(this.dirZ) * sinDirY, getZ() + Math.cos(this.dirY), false, false);
336 }
337
338 @Override
339 public String toString()
340 {
341 return toString("%f", false);
342 }
343
344 @Override
345 public String toString(final String doubleFormat, final boolean doNotIncludeClassName)
346 {
347 String format = String.format("%1$s[x=%2$s, y=%2$s, z=%2$s, dirY=%2$s, dirZ=%2$s]",
348 doNotIncludeClassName ? "" : "Ray3d ", doubleFormat);
349 return String.format(Locale.US, format, this.x, this.y, this.z, this.dirY, this.dirZ);
350 }
351
352 @Override
353 public int hashCode()
354 {
355 return super.hashCode();
356 }
357
358 @Override
359 @SuppressWarnings("checkstyle:needbraces")
360 public boolean equals(final Object obj)
361 {
362 if (this == obj)
363 return true;
364 if (!super.equals(obj))
365 return false;
366 if (getClass() != obj.getClass())
367 return false;
368 return true;
369 }
370
371 }