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