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