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