View Javadoc
1   package com.github.celldynamics.quimp.geom;
2   
3   import java.awt.geom.Line2D;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import org.scijava.vecmath.Tuple2d;
8   import org.scijava.vecmath.Tuple2f;
9   import org.scijava.vecmath.Vector2d;
10  import org.scijava.vecmath.Vector2f;
11  
12  /**
13   * Defines 2D vector and performs operations on vectors and lines.
14   *
15   * <p>This definition of vector is often used in QuimP for expressing points as well
16   *
17   * @author Richard
18   */
19  public class ExtendedVector2d extends Vector2d {
20  
21    /**
22     * Constructs and initializes a Vector2d from the specified array.
23     * 
24     * @param v initial array
25     */
26    public ExtendedVector2d(double[] v) {
27      super(v);
28    }
29  
30    /**
31     * Constructs and initializes a Vector2d from the specified Tuple.
32     * 
33     * @param t1 initial Tuple
34     */
35    public ExtendedVector2d(Tuple2d t1) {
36      super(t1);
37    }
38  
39    /**
40     * Constructs and initializes a Vector2d from the specified Tuple.
41     * 
42     * @param t1 initial Tuple
43     */
44    public ExtendedVector2d(Tuple2f t1) {
45      super(t1);
46    }
47  
48    /**
49     * Constructs and initializes a Vector2d from the specified Vector.
50     * 
51     * @param v1 initial vestor
52     */
53    public ExtendedVector2d(Vector2d v1) {
54      super(v1);
55    }
56  
57    /**
58     * Constructs and initializes a Vector2d from the specified Vector.
59     * 
60     * @param v1 initial vestor
61     */
62    public ExtendedVector2d(Vector2f v1) {
63      super(v1);
64    }
65  
66    /**
67     * Constructs and initializes a Vector2d to (0,0).
68     */
69    public ExtendedVector2d() {
70      super();
71    }
72  
73    /**
74     * Simple constructor.
75     * 
76     * <p>Creates vector mounted at (0,0).
77     * 
78     * @param xx \c x coordinate of vector
79     * @param yy \c y coordinate of vector
80     */
81    public ExtendedVector2d(double xx, double yy) {
82      super(xx, yy);
83    }
84  
85    private static final long serialVersionUID = -7238793665995665600L;
86  
87    /**
88     * Make versor from vector.
89     */
90    public void makeUnit() {
91  
92      double length = length();
93      if (length != 0) {
94        x = x / length;
95        y = y / length;
96      }
97    }
98  
99    /**
100    * Set vector coordinates.
101    * 
102    * @param nx x coordinate
103    * @param ny y coordinate
104    */
105   public void setXY(double nx, double ny) {
106     y = ny;
107     x = nx;
108 
109   }
110 
111   /**
112    * Add vector to this.
113    * 
114    * @param v vector
115    */
116   public void addVec(ExtendedVector2d v) {
117     x += v.getX();
118     y += v.getY();
119   }
120 
121   /**
122    * Multiply this vector.
123    * 
124    * @param d multiplier
125    */
126   public void multiply(double d) {
127     x *= d;
128     y *= d;
129   }
130 
131   /**
132    * Power this vector.
133    * 
134    * @param p power
135    */
136   public void power(double p) {
137     x = Math.pow(x, p);
138     y = Math.pow(y, p);
139 
140   }
141 
142   /**
143    * Unit vector to target.
144    * 
145    * @param a a
146    * @param b b
147    * @return calc unit vector to target
148    */
149   public static ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d/../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d unitVector(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d a, ExtendedVector2d b) {
150     ExtendedVector2d vec = ExtendedVector2d.vecP2P(a, b);
151 
152     double length = vec.length();
153     if (length != 0) {
154       vec.setX(vec.getX() / length);
155       vec.setY(vec.getY() / length);
156     }
157     return vec;
158   }
159 
160   /**
161    * Generate linearly distributed doubles between a;b including a and b.
162    * 
163    * @param start start value
164    * @param end end value
165    * @param numPoints number of points
166    * @return list of values including a and b
167    */
168   public static List<Double> linspace(double start, double end, int numPoints) {
169     List<Double> result = new ArrayList<Double>();
170     double step = (end - start) / (numPoints - 1);
171     for (int i = 0; i <= numPoints - 2; i++) {
172       result.add(start + (i * step));
173     }
174     result.add(end);
175     return result;
176   }
177 
178   /**
179    * Create vector between points.
180    * 
181    * @param a start point
182    * @param b end point
183    * @return vector between points
184    */
185   public static ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d./../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d vecP2P(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d a, ExtendedVector2d b) {
186     // calc a vector between two points
187     ExtendedVector2dom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d vec = new ExtendedVector2d();
188 
189     vec.setX(b.getX() - a.getX());
190     vec.setY(b.getY() - a.getY());
191     return vec;
192   }
193 
194   /**
195    * Get length of the vector between points.
196    * 
197    * @param a initial point
198    * @param b end point
199    * @return length of the vector
200    */
201   public static double lengthP2P(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d a, ExtendedVector2d b) {
202     ExtendedVector2d v = vecP2P(a, b);
203     return v.length();
204   }
205 
206   /**
207    * Calculate the intersect between two edges A and B. Edge is defined as vector AB,
208    * where A and B stand for initial and terminal points given as vectors mounted at (0,0).
209    * 
210    * @param na1 initial point of A edge
211    * @param na2 terminal point of A edge
212    * @param nb1 initial point of B edge
213    * @param nb2 terminal point of B edge
214    * @return Intersect point
215    * @deprecated Actually not used in this version of QuimP
216    */
217   public static ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2dithub/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d lineIntersectionOLD(ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d na1, ExtendedVector2d na2,
218           ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d nb1, ExtendedVector2d nb2) {
219     double aa;
220     double bb;
221     double ab;
222     double ba;
223     double denom;
224     aa = na2.getY() - na1.getY();
225     ba = na1.getX() - na2.getX();
226 
227     ab = nb2.getY() - nb1.getY();
228     bb = nb1.getX() - nb2.getX();
229 
230     denom = aa * bb - ab * ba;
231 
232     if (denom == 0) { // lines are parallel
233       // System.out.println("parrellel lines");
234       return null;
235     }
236 
237     double ca;
238     double cb;
239 
240     ca = na2.getX() * na1.getY() - na1.getX() * na2.getY();
241     cb = nb2.getX() * nb1.getY() - nb1.getX() * nb2.getY();
242 
243     ExtendedVector2d cp = null;
244     double da2;
245     double da1;
246     double ea1;
247     double ea2;
248 
249     // intersection point
250     cp = new ExtendedVector2d((ba * cb - bb * ca) / denom, (ab * ca - aa * cb) / denom);
251 
252     // System.out.println("Pos Intersect at x:" + cp.getX() + ", y:" +
253     // cp.getY());
254 
255     // check in bounds of line1
256     da1 = cp.getX() - na1.getX(); // line1.getX1();
257     da2 = cp.getX() - na2.getX(); // line1.getX2();
258     ea1 = cp.getY() - na1.getY(); // line1.getY1();
259     ea2 = cp.getY() - na2.getY(); // line1.getY2();
260 
261     double db2;
262     double db1;
263     double eb1;
264     double eb2;
265     db1 = cp.getX() - nb1.getX(); // line2.getX1();
266     db2 = cp.getX() - nb2.getX(); // line2.getX2();
267     eb1 = cp.getY() - nb1.getY(); // line2.getY1();
268     eb2 = cp.getY() - nb2.getY(); // line2.getY2();
269 
270     if ((Math.abs(ba) >= (Math.abs(da1) + Math.abs(da2)))
271             && (Math.abs(aa) >= (Math.abs(ea1) + Math.abs(ea2)))) {
272 
273       if ((Math.abs(bb) >= (Math.abs(db1) + Math.abs(db2)))
274               && (Math.abs(ab) >= (Math.abs(eb1) + Math.abs(eb2)))) {
275 
276         // System.out.println("Intersect at x:" + cp.getX() + ", y:" +
277         // cp.getY());
278         return cp;
279       }
280     }
281     return null;
282   }
283 
284   /**
285    * lineIntersectionOLD2.
286    * 
287    * @param na1 initial point of A edge
288    * @param na2 terminal point of A edge
289    * @param nb1 initial point of B edge
290    * @param nb2 terminal point of B edge
291    * @return line intersection point
292    * @deprecated Actually not used in this version of QuimP
293    */
294   public static ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2dthub/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d lineIntersectionOLD2(ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d na1, ExtendedVector2d na2,
295           ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d nb1, ExtendedVector2d nb2) {
296     if (Line2D.linesIntersect(na1.getX(), na1.getY(), na2.getX(), na2.getY(), nb1.getX(),
297             nb1.getY(), nb2.getX(), nb2.getY())) {
298 
299       double aa;
300       double bb;
301       double ab;
302       double ba;
303       double denom;
304       aa = na2.getY() - na1.getY();
305       ba = na1.getX() - na2.getX();
306 
307       ab = nb2.getY() - nb1.getY();
308       bb = nb1.getX() - nb2.getX();
309 
310       denom = aa * bb - ab * ba;
311 
312       if (denom == 0) { // lines are parallel
313         System.out.println("parrellel lines");
314         return null;
315       }
316 
317       double ca;
318       double cb;
319 
320       ca = na2.getX() * na1.getY() - na1.getX() * na2.getY();
321       cb = nb2.getX() * nb1.getY() - nb1.getX() * nb2.getY();
322 
323       ExtendedVector2d cp = null;
324       // intersection point
325       cp = new ExtendedVector2d((ba * cb - bb * ca) / denom, (ab * ca - aa * cb) / denom);
326 
327       // cp.print("Intersect at: ");
328 
329       System.out.println("plot([" + na1.getX() + "," + na2.getX() + "],[" + na1.getY() + ","
330               + na2.getY() + "],'-ob');"); // matlab output
331       System.out.println("hold on; plot([" + nb1.getX() + "," + nb2.getX() + "],[" + nb1.getY()
332               + "," + nb2.getY() + "],'-or');");
333       System.out.println("plot(" + cp.x + "," + cp.y + ", 'og');");
334 
335       return cp;
336     } else {
337       return null;
338     }
339   }
340 
341   /**
342    * Compute the intersection between two line segments, or two lines of infinite length.
343    *
344    * @param x0 X coordinate first end point first line segment.
345    * @param y0 Y coordinate first end point first line segment.
346    * @param x1 X coordinate second end point first line segment.
347    * @param y1 Y coordinate second end point first line segment.
348    * @param x2 X coordinate first end point second line segment.
349    * @param y2 Y coordinate first end point second line segment.
350    * @param x3 X coordinate second end point second line segment.
351    * @param y3 Y coordinate second end point second line segment.
352    * @param intersection Preallocated by caller to double[2]
353    * @return -1 if lines are parallel (x,y unset), -2 if lines are parallel and overlapping (x, y
354    *         center) 0 if intersection outside segments (x,y set) +1 if segments intersect (x,y
355    *         set)
356    * @see <a href= "link">http://geosoft.no/software/geometry/Geometry.java.html</a>
357    */
358   public static int segmentIntersection(double x0, double y0, double x1, double y1, double x2,
359           double y2, double x3, double y3, double[] intersection) {
360 
361     final double limit = 1e-5;
362     final double infinity = 1e8;
363 
364     double x;
365     double y;
366 
367     //
368     // Convert the lines to the form y = ax + b
369     //
370 
371     // Slope of the two lines
372     double a0 = equals(x0, x1, limit) ? infinity : (y0 - y1) / (x0 - x1);
373     double a1 = equals(x2, x3, limit) ? infinity : (y2 - y3) / (x2 - x3);
374 
375     double b0 = y0 - a0 * x0; // y intersects intersects
376     double b1 = y2 - a1 * x2;
377 
378     // Check if lines are parallel (within tolloerance)
379     if (equals(a0, a1, limit)) {
380       if (!equals(b0, b1, limit)) {
381         return -1; // Parallel non-overlapping
382 
383       } else {
384         if (equals(x0, x1, limit)) {
385           if (Math.min(y0, y1) < Math.max(y2, y3) || Math.max(y0, y1) > Math.min(y2, y3)) {
386             double twoMiddle = y0 + y1 + y2 + y3 - min(y0, y1, y2, y3) - max(y0, y1, y2, y3);
387             y = (twoMiddle) / 2.0;
388             x = (y - b0) / a0;
389           } else {
390             return -1;
391           } // Parallel non-overlapping
392         } else {
393           if (Math.min(x0, x1) < Math.max(x2, x3) || Math.max(x0, x1) > Math.min(x2, x3)) {
394             double twoMiddle = x0 + x1 + x2 + x3 - min(x0, x1, x2, x3) - max(x0, x1, x2, x3);
395             x = (twoMiddle) / 2.0;
396             y = a0 * x + b0;
397           } else {
398             return -1;
399           }
400         }
401 
402         intersection[0] = x;
403         intersection[1] = y;
404         return -2;
405       }
406     }
407 
408     // Find correct intersection point
409     if (equals(a0, infinity, limit)) {
410       x = x0;
411       y = a1 * x + b1;
412     } else if (equals(a1, infinity, limit)) {
413       x = x2;
414       y = a0 * x + b0;
415     } else {
416       x = -(b0 - b1) / (a0 - a1);
417       y = a0 * x + b0;
418     }
419 
420     intersection[0] = x;
421     intersection[1] = y;
422 
423     // Then check if intersection is within line segments
424     double distanceFrom1;
425     if (equals(x0, x1, limit)) {
426       if (y0 < y1) {
427         distanceFrom1 = y < y0 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x0, y0))
428                 : y > y1 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x1, y1))
429                         : 0.0;
430       } else {
431         distanceFrom1 = y < y1 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x1, y1))
432                 : y > y0 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x0, y0))
433                         : 0.0;
434       }
435     } else {
436       if (x0 < x1) {
437         distanceFrom1 = x < x0 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x0, y0))
438                 : x > x1 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x1, y1))
439                         : 0.0;
440       } else {
441         distanceFrom1 = x < x1 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x1, y1))
442                 : x > x0 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x0, y0))
443                         : 0.0;
444       }
445     }
446 
447     double distanceFrom2;
448     if (equals(x2, x3, limit)) {
449 
450       if (y2 < y3) {
451         distanceFrom2 = y < y2 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x2, y2))
452                 : y > y3 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x3, y3))
453                         : 0.0;
454       } else {
455         distanceFrom2 = y < y3 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x3, y3))
456                 : y > y2 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x2, y2))
457                         : 0.0;
458       }
459     } else {
460       if (x2 < x3) {
461         distanceFrom2 = x < x2 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x2, y2))
462                 : x > x3 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x3, y3))
463                         : 0.0;
464       } else {
465         distanceFrom2 = x < x3 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x3, y3))
466                 : x > x2 ? lengthP2P(new ExtendedVector2dm/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d(x, y), new ExtendedVector2d(x2, y2))
467                         : 0.0;
468       }
469     }
470 
471     return equals(distanceFrom1, 0.0, limit) && equals(distanceFrom2, 0.0, limit) ? 1 : 0;
472   }
473 
474   /**
475    * Compute area of triangle (can be negative).
476    * 
477    * @param a a point
478    * @param b b point
479    * @param c c point
480    * @return area of triangle (can be negative)
481    */
482   public static double triangleArea(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d a, ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d b, ExtendedVector2d c) {
483     // calc area of a triangle (can be negative)
484     return (b.getX() - a.getX()) * (c.getY() - a.getY())
485             - (c.getX() - a.getX()) * (b.getY() - a.getY());
486   }
487 
488   /**
489    * Calculate the closest point on a segment to point P.
490    * 
491    * @param p point to test
492    * @param s0 first point of segment
493    * @param s1 last point of segment
494    * @return closest point on a segment to point P
495    */
496   public static ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2dcom/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d pointToSegment(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d p, ExtendedVector2d s0,
497           ExtendedVector2d s1) {
498     ExtendedVector2d v = ExtendedVector2d.vecP2P(s0, s1);
499     ExtendedVector2d w = ExtendedVector2d.vecP2P(s0, p);
500 
501     double c1 = dot(w, v);
502     if (c1 <= 0) {
503       return s0;
504     }
505 
506     double c2 = dot(v, v);
507     if (c2 <= c1) {
508       return s1;
509     }
510 
511     double b = c1 / c2;
512 
513     v.multiply(b);
514     v.addVec(s0);
515 
516     return v;
517   }
518 
519   /**
520    * Compute distance between closest point and segment.
521    * 
522    * @param p point to test
523    * @param s0 first point of segment
524    * @param s1 last point of segment
525    * @return distance between closest point and segment
526    */
527   public static double distPointToSegment(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d p, ExtendedVector2d s0,
528           ExtendedVector2d s1) {
529     ExtendedVector2d closest = ExtendedVector2d.pointToSegment(p, s0, s1);
530     return ExtendedVector2d.lengthP2P(p, closest);
531   }
532 
533   /**
534    * Compute scalar dot.
535    * 
536    * @param a left operand
537    * @param b right operand
538    * @return scalar dot
539    */
540   public static double dot(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d a, ExtendedVector2d b) {
541     double d = a.getX() * b.getX();
542     d += a.getY() * b.getY();
543     return d;
544   }
545 
546   /**
547    * Calculate non relative angle between 2 vectors.
548    * 
549    * @param aa vector
550    * @param bb vector
551    * @return angle between 2 vectors (non relative)
552    */
553   public static double angleNonRelative(ExtendedVector2d./../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d aa, ExtendedVector2d bb) {
554     ExtendedVector2d a;
555     ExtendedVector2d b;
556     a = new ExtendedVector2d(aa.getX(), aa.getY()); // make a copy
557     b = new ExtendedVector2d(bb.getX(), bb.getY());
558     a.makeUnit();
559     b.makeUnit();
560 
561     return Math.acos(dot(a, b));
562   }
563 
564   /**
565    * Calculate angle between 2 vectors.
566    * 
567    * @param aa vector
568    * @param bb vector
569    * @return angle between 2 vectors
570    */
571   public static double angle(ExtendedVector2d./../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d aa, ExtendedVector2d bb) {
572     ExtendedVector2d a;
573     ExtendedVector2d b;
574     a = new ExtendedVector2d(aa.getX(), aa.getY()); // make a copy
575     b = new ExtendedVector2d(bb.getX(), bb.getY());
576     a.makeUnit();
577     b.makeUnit();
578 
579     return Math.atan2(b.getY(), b.getX()) - Math.atan2(a.getY(), a.getX());
580   }
581 
582   /**
583    * Calculate distance of point to line given as two points.
584    * 
585    * @param p point to test
586    * @param a line point
587    * @param b line point
588    * @return distance of point to line given as two points
589    */
590   public static double distPoinToInfLine(ExtendedVector2d../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d p, ExtendedVector2d a,
591           ExtendedVector2d b) {
592     return (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);
593   }
594 
595   /**
596    * Check if two double precision numbers are "equal", i.e. close enough to a given limit.
597    *
598    * @param a First number to check
599    * @param b Second number to check
600    * @param limit The definition of "equal".
601    * @return True if the two numbers are "equal", false otherwise
602    * @see <a href= "link">http://geosoft.no/software/geometry/Geometry.java.htmll</a>
603    */
604   private static boolean equals(double a, double b, double limit) {
605     return Math.abs(a - b) < limit;
606   }
607 
608   /**
609    * Return smallest of four numbers.
610    *
611    * @param a First number to find smallest among.
612    * @param b Second number to find smallest among.
613    * @param c Third number to find smallest among.
614    * @param d Fourth number to find smallest among.
615    * @return Smallest of a, b, c and d.
616    * @see <a href= "link">http://geosoft.no/software/geometry/Geometry.java.htmll</a>
617    */
618   private static double min(double a, double b, double c, double d) {
619     return Math.min(Math.min(a, b), Math.min(c, d));
620   }
621 
622   /**
623    * Return largest of four numbers.
624    *
625    * @param a First number to find largest among.
626    * @param b Second number to find largest among.
627    * @param c Third number to find largest among.
628    * @param d Fourth number to find largest among.
629    * @return Largest of a, b, c and d.
630    * @see <a href= "link">http://geosoft.no/software/geometry/Geometry.java.htmll</a>
631    */
632   private static double max(double a, double b, double c, double d) {
633     return Math.max(Math.max(a, b), Math.max(c, d));
634   }
635 
636 }