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