1 #Region "Microsoft.VisualBasic::c4709780fadcd0b85feef965947a8696, Microsoft.VisualBasic.Core\Language\Language\Java\Line2D.vb"
2
3     Author:
4     
5           asuka (amethyst.asuka@gcmodeller.org)
6           xie (genetics@smrucc.org)
7           xieguigang (xie.guigang@live.com)
8     
9     Copyright (c) 2018 GPL3 Licensed
10     
11     
12     GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     This program is free software: you can redistribute it and/or modify
16     it under the terms of the GNU General Public License as published by
17     the Free Software Foundation, either version 3 of the License, or
18     (at your option) any later version.
19     
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU General Public License for more details.
24     
25     You should have received a copy of the GNU General Public License
26     along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     /********************************************************************************/
31
32     Summaries:
33
34         Module Line2D
35     
36             Function: linesIntersect, ptLineDist, ptLineDistSq, ptSegDist, ptSegDistSq
37                       relativeCCW
38     
39     
40     /********************************************************************************/
41
42 #End Region
43
44 Imports Point2D = System.Drawing.PointF
45
46 ' * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
47 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
48 *
49 *
50 *
51 *
52 *
53 *
54 *
55 *
56 *
57 *
58 *
59 *
60 *
61 *
62 *
63 *
64 *
65 *
66 *
67 *
68
69
70 Namespace Language.Java
71
72
73     ''<summary>
74     ''This <code>Line2D</code> represents a line segment in {@code (x,y)}
75     ''coordinate space.  This [Class], like all of the Java 2D API, uses a
76     ''default coordinate system called <i>user space</i> in which the y-axis
77     ''values increase downward and x-axis values increase to the right.  For
78     ''more information on the user space coordinate system, see the
79     ''<a href="https://docs.oracle.com/javase/1.3/docs/guide/2d/spec/j2d-intro.fm2.html#61857">
80     ''Coordinate Systems</a> section of the Java 2D Programmer's Guide.
81     ''
82     ''This class is only the abstract superclass for all objects that
83     ''store a 2D line segment.
84     ''The actual storage representation of the coordinates is left to
85     ''the subclass.
86     ''
87     ''@author      Jim Graham
88     ''@since 1.2
89     ''</summary>
90     Public Module Line2D
91
92         ''<summary>
93         ''Returns an indicator of where the specified point
94         ''{@code (px,py)} lies with respect to the line segment from
95         ''{@code (x1,y1)} to {@code (x2,y2)}.
96         ''
97         ''The return value can be either 1, -1, or 0 and indicates
98         ''in which direction the specified line must pivot around its
99         ''first end point, {@code (x1,y1)}, in order to point at the
100         ''specified point {@code (px,py)}.
101         ''
102         ''A return value of 1 indicates that the line segment must
103         ''turn in the direction that takes the positive X axis towards
104         ''the negative Y axis.  In the default coordinate system used by
105         ''Java 2D, this direction is counterclockwise.
106         ''
107         ''A return value of -1 indicates that the line segment must
108         ''turn in the direction that takes the positive X axis towards
109         ''the positive Y axis.  In the default coordinate system, this
110         ''direction is clockwise.
111         ''
112         ''A return value of 0 indicates that the point lies
113         ''exactly on the line segment.  Note that an indicator value
114         ''of 0 is rare and not useful for determining collinearity
115         ''because of floating point rounding issues.
116         ''
117         ''If the point is colinear with the line segment, but
118         ''not between the end points, then the value will be -1 if the point
119         ''lies "beyond {@code (x1,y1)}" or 1 if the point lies
120         ''"beyond {@code (x2,y2)}".
121         ''</summary>
122         ''<param name="x1"> the X coordinate of the start point of the
123         ''          specified line segment </param>
124         ''<param name="y1"> the Y coordinate of the start point of the
125         ''          specified line segment </param>
126         ''<param name="x2"> the X coordinate of the end point of the
127         ''          specified line segment </param>
128         ''<param name="y2"> the Y coordinate of the end point of the
129         ''          specified line segment </param>
130         ''<param name="px"> the X coordinate of the specified point to be
131         ''          compared with the specified line segment </param>
132         ''<param name="py"> the Y coordinate of the specified point to be
133         ''          compared with the specified line segment </param>
134         ''<returns> an integer that indicates the position of the third specified
135         ''                 coordinates with respect to the line segment formed
136         ''                 by the first two specified coordinates.
137         ''@since 1.2 </returns>
138         Public Function relativeCCW(x1 As Double, y1 As Double, x2 As Double, y2 As Double, px As Double, py As DoubleAs Integer
139             x2 -= x1
140             y2 -= y1
141             px -= x1
142             py -= y1
143             Dim ccw As Double = px * y2 - py * x2
144             If ccw = 0.0 Then
145                 The point is colinear, classify based on which side of
146                 the segment the point falls on.  We can calculate a
147                 relative value using the projection of px,py onto the
148                 segment - a negative value indicates the point projects
149                 outside of the segment in the direction of the particular
150                 endpoint used as the origin for the projection.
151                 ccw = px * x2 + py * y2
152                 If ccw > 0.0 Then
153                     Reverse the projection to be relative to the original x2,y2
154                     x2 and y2 are simply negated.
155                     px and py need to have (x2 - x1) or (y2 - y1) subtracted
156                        from them (based on the original values)
157                     Since we really want to get a positive answer when the
158                        point is "beyond (x2,y2)", then we want to calculate
159                        the inverse anyway - thus we leave x2 & y2 negated.
160                     px -= x2
161                     py -= y2
162                     ccw = px * x2 + py * y2
163                     If ccw < 0.0 Then ccw = 0.0
164                 End If
165             End If
166             Return If(ccw < 0.0, -1, (If(ccw > 0.0, 1, 0)))
167         End Function
168
169         ''<summary>
170         ''Tests if the line segment from {@code (x1,y1)} to
171         ''{@code (x2,y2)} intersects the line segment from {@code (x3,y3)}
172         ''to {@code (x4,y4)}.
173         ''</summary>
174         ''<param name="x1"> the X coordinate of the start point of the first
175         ''          specified line segment </param>
176         ''<param name="y1"> the Y coordinate of the start point of the first
177         ''          specified line segment </param>
178         ''<param name="x2"> the X coordinate of the end point of the first
179         ''          specified line segment </param>
180         ''<param name="y2"> the Y coordinate of the end point of the first
181         ''          specified line segment </param>
182         ''<param name="x3"> the X coordinate of the start point of the second
183         ''          specified line segment </param>
184         ''<param name="y3"> the Y coordinate of the start point of the second
185         ''          specified line segment </param>
186         ''<param name="x4"> the X coordinate of the end point of the second
187         ''          specified line segment </param>
188         ''<param name="y4"> the Y coordinate of the end point of the second
189         ''          specified line segment </param>
190         ''<returns> <code>true</code> if the first specified line segment
191         ''                 and the second specified line segment intersect
192         ''                 each other; <code>false</code> otherwise.
193         ''@since 1.2 </returns>
194         Public Function linesIntersect(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x3 As Double, y3 As Double, x4 As Double, y4 As DoubleAs Boolean
195             Return ((relativeCCW(x1, y1, x2, y2, x3, y3) * relativeCCW(x1, y1, x2, y2, x4, y4) <= 0) AndAlso (relativeCCW(x3, y3, x4, y4, x1, y1) * relativeCCW(x3, y3, x4, y4, x2, y2) <= 0))
196         End Function
197
198         ''<summary>
199         ''Returns the square of the distance from a point to a line segment.
200         ''The distance measured is the distance between the specified
201         ''point and the closest point between the specified end points.
202         ''If the specified point intersects the line segment in between the
203         ''end points, this method returns 0.0.
204         ''</summary>
205         ''<param name="x1"> the X coordinate of the start point of the
206         ''          specified line segment </param>
207         ''<param name="y1"> the Y coordinate of the start point of the
208         ''          specified line segment </param>
209         ''<param name="x2"> the X coordinate of the end point of the
210         ''          specified line segment </param>
211         ''<param name="y2"> the Y coordinate of the end point of the
212         ''          specified line segment </param>
213         ''<param name="px"> the X coordinate of the specified point being
214         ''          measured against the specified line segment </param>
215         ''<param name="py"> the Y coordinate of the specified point being
216         ''          measured against the specified line segment </param>
217         ''<returns> a double value that is the square of the distance from the
218         ''                 specified point to the specified line segment. </returns>
219         Public Function ptSegDistSq(x1 As Double, y1 As Double, x2 As Double, y2 As Double, px As Double, py As DoubleAs Double
220             Adjust vectors relative to x1,y1
221             x2,y2 becomes relative vector from x1,y1 to end of segment
222             x2 -= x1
223             y2 -= y1
224             px,py becomes relative vector from x1,y1 to test point
225             px -= x1
226             py -= y1
227             Dim dotprod As Double = px * x2 + py * y2
228             Dim projlenSq As Double
229             If dotprod <= 0.0 Then
230                 px,py is on the side of x1,y1 away from x2,y2
231                 distance to segment is length of px,py vector
232                 "length of its (clipped) projection" is now 0.0
233                 projlenSq = 0.0
234             Else
235                 switch to backwards vectors relative to x2,y2
236                 x2,y2 are already the negative of x1,y1=>x2,y2
237                 to get px,py to be the negative of px,py=>x2,y2
238                 the dot product of two negated vectors is the same
239                 as the dot product of the two normal vectors
240                 px = x2 - px
241                 py = y2 - py
242                 dotprod = px * x2 + py * y2
243                 If dotprod <= 0.0 Then
244                     px,py is on the side of x2,y2 away from x1,y1
245                     distance to segment is length of (backwards) px,py vector
246                     "length of its (clipped) projection" is now 0.0
247                     projlenSq = 0.0
248                 Else
249                     px,py is between x1,y1 and x2,y2
250                     dotprod is the length of the px,py vector
251                     projected on the x2,y2=>x1,y1 vector times the
252                     length of the x2,y2=>x1,y1 vector
253                     projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2)
254                 End If
255             End If
256             Distance to line is now the length of the relative point
257             vector minus the length of its projection onto the line
258             (which is zero if the projection falls outside the range
259              of the line segment).
260             Dim lenSq As Double = px * px + py * py - projlenSq
261             If lenSq < 0 Then lenSq = 0
262             Return lenSq
263         End Function
264
265         ''<summary>
266         ''Returns the distance from a point to a line segment.
267         ''The distance measured is the distance between the specified
268         ''point and the closest point between the specified end points.
269         ''If the specified point intersects the line segment in between the
270         ''end points, this method returns 0.0.
271         ''</summary>
272         ''<param name="x1"> the X coordinate of the start point of the
273         ''          specified line segment </param>
274         ''<param name="y1"> the Y coordinate of the start point of the
275         ''          specified line segment </param>
276         ''<param name="x2"> the X coordinate of the end point of the
277         ''          specified line segment </param>
278         ''<param name="y2"> the Y coordinate of the end point of the
279         ''          specified line segment </param>
280         ''<param name="px"> the X coordinate of the specified point being
281         ''          measured against the specified line segment </param>
282         ''<param name="py"> the Y coordinate of the specified point being
283         ''          measured against the specified line segment </param>
284         ''<returns> a double value that is the distance from the specified point
285         ''                         to the specified line segment. </returns>
286         Public Function ptSegDist(x1 As Double, y1 As Double, x2 As Double, y2 As Double, px As Double, py As DoubleAs Double
287             Return System.Math.Sqrt(ptSegDistSq(x1, y1, x2, y2, px, py))
288         End Function
289
290         ''<summary>
291         ''Returns the square of the distance from a point to a line.
292         ''The distance measured is the distance between the specified
293         ''point and the closest point on the infinitely-extended line
294         ''defined by the specified coordinates.  If the specified point
295         ''intersects the line, this method returns 0.0.
296         ''</summary>
297         ''<param name="x1"> the X coordinate of the start point of the specified line </param>
298         ''<param name="y1"> the Y coordinate of the start point of the specified line </param>
299         ''<param name="x2"> the X coordinate of the end point of the specified line </param>
300         ''<param name="y2"> the Y coordinate of the end point of the specified line </param>
301         ''<param name="px"> the X coordinate of the specified point being
302         ''          measured against the specified line </param>
303         ''<param name="py"> the Y coordinate of the specified point being
304         ''          measured against the specified line </param>
305         ''<returns> a double value that is the square of the distance from the
306         ''                 specified point to the specified line. </returns>
307         Public Function ptLineDistSq(x1 As Double, y1 As Double, x2 As Double, y2 As Double, px As Double, py As DoubleAs Double
308             Adjust vectors relative to x1,y1
309             x2,y2 becomes relative vector from x1,y1 to end of segment
310             x2 -= x1
311             y2 -= y1
312             px,py becomes relative vector from x1,y1 to test point
313             px -= x1
314             py -= y1
315             Dim dotprod As Double = px * x2 + py * y2
316             dotprod is the length of the px,py vector
317             projected on the x1,y1=>x2,y2 vector times the
318             length of the x1,y1=>x2,y2 vector
319             Dim projlenSq As Double = dotprod * dotprod / (x2 * x2 + y2 * y2)
320             Distance to line is now the length of the relative point
321             vector minus the length of its projection onto the line
322             Dim lenSq As Double = px * px + py * py - projlenSq
323             If lenSq < 0 Then lenSq = 0
324             Return lenSq
325         End Function
326
327         ''<summary>
328         ''Returns the distance from a point to a line.
329         ''The distance measured is the distance between the specified
330         ''point and the closest point on the infinitely-extended line
331         ''defined by the specified coordinates.  If the specified point
332         ''intersects the line, this method returns 0.0.
333         ''</summary>
334         ''<param name="x1"> the X coordinate of the start point of the specified line </param>
335         ''<param name="y1"> the Y coordinate of the start point of the specified line </param>
336         ''<param name="x2"> the X coordinate of the end point of the specified line </param>
337         ''<param name="y2"> the Y coordinate of the end point of the specified line </param>
338         ''<param name="px"> the X coordinate of the specified point being
339         ''          measured against the specified line </param>
340         ''<param name="py"> the Y coordinate of the specified point being
341         ''          measured against the specified line </param>
342         ''<returns> a double value that is the distance from the specified
343         ''                  point to the specified line. </returns>
344         Public Function ptLineDist(x1 As Double, y1 As Double, x2 As Double, y2 As Double, px As Double, py As DoubleAs Double
345             Return System.Math.Sqrt(ptLineDistSq(x1, y1, x2, y2, px, py))
346         End Function
347     End Module
348 End Namespace