Advertisement
Deedlit

java geometry related usefull functions

Nov 6th, 2011
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 43.85 KB | None | 0 0
  1. /*
  2.  * (C) 2004 - Geotechnical Software Services
  3.  *
  4.  * This code is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU Lesser General Public
  6.  * License as published by the Free Software Foundation; either
  7.  * version 2.1 of the License, or (at your option) any later version.
  8.  *
  9.  * This code is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12.  * GNU Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with this program; if not, write to the Free
  16.  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  17.  * MA  02111-1307, USA.
  18.  */
  19. package java.sl2.ext.tools;
  20.  
  21.  
  22. /**
  23.  * Collection of geometry utility methods. All methods are static.
  24.  *
  25.  * @author <a href="mailto:info@geosoft.no">GeoSoft</a>
  26.  */
  27. public final class Geometry
  28. {
  29.  
  30.     /** Return true if c is between a and b. */
  31.     private static boolean isBetween(int a, int b, int c)
  32.     {
  33.         return b > a ? c >= a && c <= b : c >= b && c <= a;
  34.     }
  35.  
  36.  
  37.     /** Return true if c is between a and b. */
  38.     private static boolean isBetween(double a, double b, double c)
  39.     {
  40.         return b > a ? c >= a && c <= b : c >= b && c <= a;
  41.     }
  42.  
  43.  
  44.     /**
  45.      * Check if two double precision numbers are "equal", i.e. close enough
  46.      * to a given limit.
  47.      *
  48.      * @param a  First number to check
  49.      * @param b  Second number to check
  50.      * @param limit The definition of "equal".
  51.      *
  52.      * @return True if the twho numbers are "equal", false otherwise
  53.      */
  54.     private static boolean equals(double a, double b, double limit)
  55.     {
  56.         return Math.abs(a - b) < limit;
  57.     }
  58.  
  59.  
  60.     /**
  61.      * Check if two double precision numbers are "equal", i.e. close enough
  62.      * to a prespecified limit.
  63.      *
  64.      * @param a First number to check
  65.      * @param b Second number to check
  66.      *
  67.      * @return True if the twho numbers are "equal", false otherwise
  68.      */
  69.     private static boolean equals(double a, double b)
  70.     {
  71.         return equals(a, b, 1.0e-5);
  72.     }
  73.  
  74.  
  75.     /**
  76.      * Return smallest of four numbers.
  77.      *
  78.      * @param a First number to find smallest among.
  79.      * @param b Second number to find smallest among.
  80.      * @param c Third number to find smallest among.
  81.      * @param d Fourth number to find smallest among.
  82.      *
  83.      * @return Smallest of a, b, c and d.
  84.      */
  85.     private static double min(double a, double b, double c, double d)
  86.     {
  87.         return Math.min(Math.min(a, b), Math.min(c, d));
  88.     }
  89.  
  90.  
  91.     /**
  92.      * Return largest of four numbers.
  93.      *
  94.      * @param a First number to find largest among.
  95.      * @param b Second number to find largest among.
  96.      * @param c Third number to find largest among.
  97.      * @param d Fourth number to find largest among.
  98.      *
  99.      * @return Largest of a, b, c and d.
  100.      */
  101.     private static double max(double a, double b, double c, double d)
  102.     {
  103.         return Math.max(Math.max(a, b), Math.max(c, d));
  104.     }
  105.  
  106.  
  107.     /**
  108.      * Check if a specified point is inside a specified rectangle.
  109.      *
  110.      * @param x0, y0, x1, y1  Upper left and lower right corner of rectangle
  111.      *            (inclusive)
  112.      * @param x,y Point to check.
  113.      *
  114.      * @return True if the point is inside the rectangle,
  115.      *         false otherwise.
  116.      */
  117.     public static boolean isPointInsideRectangle(int x0, int y0, int x1, int y1, int x, int y)
  118.     {
  119.         return x >= x0 && x < x1 && y >= y0 && y < y1;
  120.     }
  121.  
  122.  
  123.     /**
  124.      * Check if a given point is inside a given (complex) polygon.
  125.      *
  126.      * @param x,      y            Polygon.
  127.      * @param pointX, pointY  Point to check.
  128.      *
  129.      * @return True if the given point is inside the polygon, false otherwise.
  130.      */
  131.     public static boolean isPointInsidePolygon(double[] x, double[] y, double pointX, double pointY)
  132.     {
  133.         boolean isInside = false;
  134.         int nPoints = x.length;
  135.  
  136.         int j = 0;
  137.         for (int i = 0; i < nPoints; i++)
  138.         {
  139.             j++;
  140.             if (j == nPoints)
  141.                 j = 0;
  142.  
  143.             if (y[i] < pointY && y[j] >= pointY || y[j] < pointY && y[i] >= pointY)
  144.             {
  145.                 if (x[i] + (pointY - y[i]) / (y[j] - y[i]) * (x[j] - x[i]) < pointX)
  146.                 {
  147.                     isInside = !isInside;
  148.                 }
  149.             }
  150.         }
  151.  
  152.         return isInside;
  153.     }
  154.  
  155.  
  156.     /**
  157.      * Check if a given point is inside a given polygon. Integer domain.
  158.      *
  159.      * @param x,      y            Polygon.
  160.      * @param pointX, pointY  Point to check.
  161.      *
  162.      * @return True if the given point is inside the polygon, false otherwise.
  163.      */
  164.     public static boolean isPointInsidePolygon(int[] x, int[] y, int pointX, int pointY)
  165.     {
  166.         boolean isInside = false;
  167.         int nPoints = x.length;
  168.  
  169.         int j = 0;
  170.         for (int i = 0; i < nPoints; i++)
  171.         {
  172.             j++;
  173.             if (j == nPoints)
  174.                 j = 0;
  175.  
  176.             if (y[i] < pointY && y[j] >= pointY || y[j] < pointY && y[i] >= pointY)
  177.             {
  178.                 if (x[i] + (double) (pointY - y[i]) / (double) (y[j] - y[i]) * (x[j] - x[i]) < pointX)
  179.                 {
  180.                     isInside = !isInside;
  181.                 }
  182.             }
  183.         }
  184.  
  185.         return isInside;
  186.     }
  187.  
  188.  
  189.     /**
  190.      * Find the point on the line p0,p1 [x,y,z] a given fraction from p0.
  191.      * Fraction of 0.0 whould give back p0, 1.0 give back p1, 0.5 returns
  192.      * midpoint of line p0,p1 and so on. F
  193.      * raction can be >1 and it can be negative to return any point on the
  194.      * line specified by p0,p1.
  195.      *
  196.      * @param p0             First coordinale of line [x,y,z].
  197.      * @param p0             Second coordinale of line [x,y,z].
  198.      * @param fractionFromP0 Point we are looking for coordinates of
  199.      * @param p           Coordinate of point we are looking for
  200.      */
  201.     public static double[] computePointOnLine(double[] p0, double[] p1, double fractionFromP0)
  202.     {
  203.         double[] p = new double[3];
  204.  
  205.         p[0] = p0[0] + fractionFromP0 * (p1[0] - p0[0]);
  206.         p[1] = p0[1] + fractionFromP0 * (p1[1] - p0[1]);
  207.         p[2] = p0[2] + fractionFromP0 * (p1[2] - p0[2]);
  208.  
  209.         return p;
  210.     }
  211.  
  212.  
  213.     /**
  214.      * Find the point on the line defined by x0,y0,x1,y1 a given fraction
  215.      * from x0,y0. 2D version of method above..
  216.      *
  217.      * @param x0,          y0         First point defining the line
  218.      * @param x1,          y1         Second point defining the line
  219.      * @param fractionFrom0 Distance from (x0,y0)
  220.      *
  221.      * @return x, y           Coordinate of point we are looking for
  222.      */
  223.     public static double[] computePointOnLine(double x0, double y0, double x1, double y1, double fractionFrom0)
  224.     {
  225.         double[] p0 = {x0, y0, 0.0};
  226.         double[] p1 = {x1, y1, 0.0};
  227.  
  228.         double[] p = Geometry.computePointOnLine(p0, p1, fractionFrom0);
  229.  
  230.         double[] r = {p[0], p[1]};
  231.         return r;
  232.     }
  233.  
  234.  
  235.     /**
  236.      * Extend a given line segment to a specified length.
  237.      *
  238.      * @param p0,     p1    Line segment to extend [x,y,z].
  239.      * @param toLength Length of new line segment.
  240.      * @param anchor   Specifies the fixed point during extension.
  241.      *                 If anchor is 0.0, p0 is fixed and p1 is adjusted.
  242.      *                 If anchor is 1.0, p1 is fixed and p0 is adjusted.
  243.      *                 If anchor is 0.5, the line is adjusted equally in each
  244.      *                 direction and so on.
  245.      */
  246.     public static void extendLine(double[] p0, double[] p1, double toLength, double anchor)
  247.     {
  248.         double[] p = Geometry.computePointOnLine(p0, p1, anchor);
  249.  
  250.         double length0 = toLength * anchor;
  251.         double length1 = toLength * (1.0 - anchor);
  252.  
  253.         Geometry.extendLine(p, p0, length0);
  254.         Geometry.extendLine(p, p1, length1);
  255.     }
  256.  
  257.  
  258.     /**
  259.      * Extend a given line segment to a given length and holding the first
  260.      * point of the line as fixed.
  261.      *
  262.      * @param p0,   p1  Line segment to extend. p0 is fixed during extension
  263.      * @param length Length of new line segment.
  264.      */
  265.     public static void extendLine(double[] p0, double[] p1, double toLength)
  266.     {
  267.         double oldLength = Geometry.length(p0, p1);
  268.         double lengthFraction = oldLength != 0.0 ? toLength / oldLength : 0.0;
  269.  
  270.         p1[0] = p0[0] + (p1[0] - p0[0]) * lengthFraction;
  271.         p1[1] = p0[1] + (p1[1] - p0[1]) * lengthFraction;
  272.         p1[2] = p0[2] + (p1[2] - p0[2]) * lengthFraction;
  273.     }
  274.  
  275.  
  276.     /**
  277.      * Return the length of a vector.
  278.      *
  279.      * @param v Vector to compute length of [x,y,z].
  280.      *
  281.      * @return Length of vector.
  282.      */
  283.     public static double length(double[] v)
  284.     {
  285.         return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  286.     }
  287.  
  288.  
  289.     /**
  290.      * Compute distance between two points.
  291.      *
  292.      * @param p0, p1  Points to compute distance between [x,y,z].
  293.      *
  294.      * @return Distance between points.
  295.      */
  296.     public static double length(double[] p0, double[] p1)
  297.     {
  298.         double[] v = Geometry.createVector(p0, p1);
  299.         return length(v);
  300.     }
  301.  
  302.  
  303.     /**
  304.      * Compute the length of the line from (x0,y0) to (x1,y1)
  305.      *
  306.      * @param x0, y0  First line end point.
  307.      * @param x1, y1  Second line end point.
  308.      *
  309.      * @return Length of line from (x0,y0) to (x1,y1).
  310.      */
  311.     public static double length(int x0, int y0, int x1, int y1)
  312.     {
  313.         return Geometry.length((double) x0, (double) y0, (double) x1, (double) y1);
  314.     }
  315.  
  316.  
  317.     /**
  318.      * Compute the length of the line from (x0,y0) to (x1,y1)
  319.      *
  320.      * @param x0, y0  First line end point.
  321.      * @param x1, y1  Second line end point.
  322.      *
  323.      * @return Length of line from (x0,y0) to (x1,y1).
  324.      */
  325.     public static double length(double x0, double y0, double x1, double y1)
  326.     {
  327.         double dx = x1 - x0;
  328.         double dy = y1 - y0;
  329.  
  330.         return Math.sqrt(dx * dx + dy * dy);
  331.     }
  332.  
  333.  
  334.     /**
  335.      * Compute the length of a polyline.
  336.      *
  337.      * @param x,       y     Arrays of x,y coordinates
  338.      * @param nPoints  Number of elements in the above.
  339.      * @param isClosed True if this is a closed polygon, false otherwise
  340.      *
  341.      * @return Length of polyline defined by x, y and nPoints.
  342.      */
  343.     public static double length(int[] x, int[] y, boolean isClosed)
  344.     {
  345.         double length = 0.0;
  346.  
  347.         int nPoints = x.length;
  348.         for (int i = 0; i < nPoints - 1; i++)
  349.             length += Geometry.length(x[i], y[i], x[i + 1], y[i + 1]);
  350.  
  351.         // Add last leg if this is a polygon
  352.         if (isClosed && nPoints > 1)
  353.             length += Geometry.length(x[nPoints - 1], y[nPoints - 1], x[0], y[0]);
  354.  
  355.         return length;
  356.     }
  357.  
  358.  
  359.     /**
  360.      * Return distance bwetween the line defined by (x0,y0) and (x1,y1)
  361.      * and the point (x,y).
  362.      * Ref: http://astronomy.swin.edu.au/pbourke/geometry/pointline/
  363.      * The 3D case should be similar.
  364.      *
  365.      * @param x0, y0  First point of line.
  366.      * @param x1, y1  Second point of line.
  367.      * @param x,  y,   Point to consider.
  368.      *
  369.      * @return Distance from x,y down to the (extended) line defined
  370.      *         by x0, y0, x1, y1.
  371.      */
  372.     public static double distance(int x0, int y0, int x1, int y1, int x, int y)
  373.     {
  374.         // If x0,y0,x1,y1 is same point, we return distance to that point
  375.         double length = Geometry.length(x0, y0, x1, y1);
  376.         if (length == 0.0)
  377.             return Geometry.length(x0, y0, x, y);
  378.  
  379.         // If u is [0,1] then (xp,yp) is on the line segment (x0,y0),(x1,y1).
  380.         double u = ((x - x0) * (x1 - x0) + (y - y0) * (y1 - y0)) / (length * length);
  381.  
  382.         // This is the intersection point of the normal.
  383.         // TODO: Might consider returning this as well.
  384.         double xp = x0 + u * (x1 - x0);
  385.         double yp = y0 + u * (y1 - y0);
  386.  
  387.         length = Geometry.length(xp, yp, x, y);
  388.         return length;
  389.     }
  390.  
  391.  
  392.     /**
  393.      * Find the angle between twree points. P0 is center point
  394.      *
  395.      * @param p0, p1, p2  Three points finding angle between [x,y,z].
  396.      *
  397.      * @return Angle (in radians) between given points.
  398.      */
  399.     public static double computeAngle(double[] p0, double[] p1, double[] p2)
  400.     {
  401.         double[] v0 = Geometry.createVector(p0, p1);
  402.         double[] v1 = Geometry.createVector(p0, p2);
  403.  
  404.         double dotProduct = Geometry.computeDotProduct(v0, v1);
  405.  
  406.         double length1 = Geometry.length(v0);
  407.         double length2 = Geometry.length(v1);
  408.  
  409.         double denominator = length1 * length2;
  410.  
  411.         double product = denominator != 0.0 ? dotProduct / denominator : 0.0;
  412.  
  413.         double angle = Math.acos(product);
  414.  
  415.         return angle;
  416.     }
  417.  
  418.  
  419.     /**
  420.      * Compute the dot product (a scalar) between two vectors.
  421.      *
  422.      * @param v0, v1  Vectors to compute dot product between [x,y,z].
  423.      *
  424.      * @return Dot product of given vectors.
  425.      */
  426.     public static double computeDotProduct(double[] v0, double[] v1)
  427.     {
  428.         return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2];
  429.     }
  430.  
  431.  
  432.     /**
  433.      * Compute the cross product (a vector) of two vectors.
  434.      *
  435.      * @param v0,         v1        Vectors to compute cross product between [x,y,z].
  436.      * @param crossProduct Cross product of specified vectors [x,y,z].
  437.      */
  438.     public static double[] computeCrossProduct(double[] v0, double[] v1)
  439.     {
  440.         double crossProduct[] = new double[3];
  441.  
  442.         crossProduct[0] = v0[1] * v1[2] - v0[2] * v1[1];
  443.         crossProduct[1] = v0[2] * v1[0] - v0[0] * v1[2];
  444.         crossProduct[2] = v0[0] * v1[1] - v0[1] * v1[0];
  445.  
  446.         return crossProduct;
  447.     }
  448.  
  449.  
  450.     /**
  451.      * Construct the vector specified by two points.
  452.      *
  453.      * @param p0, p1  Points the construct vector between [x,y,z].
  454.      *
  455.      * @return v       Vector from p0 to p1 [x,y,z].
  456.      */
  457.     public static double[] createVector(double[] p0, double[] p1)
  458.     {
  459.         double v[] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
  460.         return v;
  461.     }
  462.  
  463.  
  464.     /**
  465.      * Check if two points are on the same side of a given line.
  466.      * Algorithm from Sedgewick page 350.
  467.      *
  468.      * @param x0,  y0, x1, y1  The line.
  469.      * @param px0, py0        First point.
  470.      * @param px1, py1        Second point.
  471.      *
  472.      * @return <0 if points on opposite sides.
  473.      *         =0 if one of the points is exactly on the line
  474.      *         >0 if points on same side.
  475.      */
  476.     private static int sameSide(double x0, double y0, double x1, double y1, double px0, double py0, double px1, double py1)
  477.     {
  478.         int sameSide = 0;
  479.  
  480.         double dx = x1 - x0;
  481.         double dy = y1 - y0;
  482.         double dx1 = px0 - x0;
  483.         double dy1 = py0 - y0;
  484.         double dx2 = px1 - x1;
  485.         double dy2 = py1 - y1;
  486.  
  487.         // Cross product of the vector from the endpoint of the line to the point
  488.         double c1 = dx * dy1 - dy * dx1;
  489.         double c2 = dx * dy2 - dy * dx2;
  490.  
  491.         if (c1 != 0 && c2 != 0)
  492.             sameSide = c1 < 0 != c2 < 0 ? -1 : 1;
  493.         else if (dx == 0 && dx1 == 0 && dx2 == 0)
  494.             sameSide = !isBetween(y0, y1, py0) && !isBetween(y0, y1, py1) ? 1 : 0;
  495.         else if (dy == 0 && dy1 == 0 && dy2 == 0)
  496.             sameSide = !isBetween(x0, x1, px0) && !isBetween(x0, x1, px1) ? 1 : 0;
  497.  
  498.         return sameSide;
  499.     }
  500.  
  501.  
  502.     /**
  503.      * Check if two points are on the same side of a given line. Integer domain.
  504.      *
  505.      * @param x0,  y0, x1, y1  The line.
  506.      * @param px0, py0        First point.
  507.      * @param px1, py1        Second point.
  508.      *
  509.      * @return <0 if points on opposite sides.
  510.      *         =0 if one of the points is exactly on the line
  511.      *         >0 if points on same side.
  512.      */
  513.     private static int sameSide(int x0, int y0, int x1, int y1, int px0, int py0, int px1, int py1)
  514.     {
  515.         return sameSide((double) x0, (double) y0, (double) x1, (double) y1, (double) px0, (double) py0, (double) px1, (double) py1);
  516.     }
  517.  
  518.  
  519.     /**
  520.      * Check if two line segments intersects. Integer domain.
  521.      *
  522.      * @param x0, y0, x1, y1  End points of first line to check.
  523.      * @param x2, yy, x3, y3  End points of second line to check.
  524.      *
  525.      * @return True if the two lines intersects.
  526.      */
  527.     public static boolean isLineIntersectingLine(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
  528.     {
  529.         int s1 = Geometry.sameSide(x0, y0, x1, y1, x2, y2, x3, y3);
  530.         int s2 = Geometry.sameSide(x2, y2, x3, y3, x0, y0, x1, y1);
  531.  
  532.         return s1 <= 0 && s2 <= 0;
  533.     }
  534.  
  535.  
  536.     /**
  537.      * Check if a specified line intersects a specified rectangle.
  538.      * Integer domain.
  539.      *
  540.      * @param lx0, ly0        1st end point of line
  541.      * @param ly1, ly1        2nd end point of line
  542.      * @param x0,  y0, x1, y1  Upper left and lower right corner of rectangle
  543.      *             (inclusive).
  544.      *
  545.      * @return True if the line intersects the rectangle,
  546.      *         false otherwise.
  547.      */
  548.     public static boolean isLineIntersectingRectangle(int lx0, int ly0, int lx1, int ly1, int x0, int y0, int x1, int y1)
  549.     {
  550.         // Is one of the line endpoints inside the rectangle
  551.         if (Geometry.isPointInsideRectangle(x0, y0, x1, y1, lx0, ly0) || Geometry.isPointInsideRectangle(x0, y0, x1, y1, lx1, ly1))
  552.             return true;
  553.  
  554.         // If it intersects it goes through. Need to check three sides only.
  555.  
  556.         // Check against top rectangle line
  557.         if (Geometry.isLineIntersectingLine(lx0, ly0, lx1, ly1, x0, y0, x1, y0))
  558.             return true;
  559.  
  560.         // Check against left rectangle line
  561.         if (Geometry.isLineIntersectingLine(lx0, ly0, lx1, ly1, x0, y0, x0, y1))
  562.             return true;
  563.  
  564.         // Check against bottom rectangle line
  565.         if (Geometry.isLineIntersectingLine(lx0, ly0, lx1, ly1, x0, y1, x1, y1))
  566.             return true;
  567.  
  568.         return false;
  569.     }
  570.  
  571.  
  572.     /**
  573.      * Check if a specified polyline intersects a specified rectangle.
  574.      * Integer domain.
  575.      *
  576.      * @param x,  y            Polyline to check.
  577.      * @param x0, y0, x1, y1  Upper left and lower left corner of rectangle
  578.      *            (inclusive).
  579.      *
  580.      * @return True if the polyline intersects the rectangle,
  581.      *         false otherwise.
  582.      */
  583.     public static boolean isPolylineIntersectingRectangle(int[] x, int[] y, int x0, int y0, int x1, int y1)
  584.     {
  585.         if (x.length == 0)
  586.             return false;
  587.  
  588.         if (Geometry.isPointInsideRectangle(x[0], y[0], x0, y0, x1, y1))
  589.             return true;
  590.  
  591.         else if (x.length == 1)
  592.             return false;
  593.  
  594.         for (int i = 1; i < x.length; i++)
  595.         {
  596.             if (x[i - 1] != x[i] || y[i - 1] != y[i])
  597.                 if (Geometry.isLineIntersectingRectangle(x[i - 1], y[i - 1], x[i], y[i], x0, y0, x1, y1))
  598.                     return true;
  599.         }
  600.  
  601.         return false;
  602.     }
  603.  
  604.  
  605.     /**
  606.      * Check if a specified polygon intersects a specified rectangle.
  607.      * Integer domain.
  608.      *
  609.      * @param x  X coordinates of polyline.
  610.      * @param y  Y coordinates of polyline.
  611.      * @param x0 X of upper left corner of rectangle.
  612.      * @param y0 Y of upper left corner of rectangle.
  613.      * @param x1 X of lower right corner of rectangle.
  614.      * @param y1 Y of lower right corner of rectangle.
  615.      *
  616.      * @return True if the polyline intersects the rectangle, false otherwise.
  617.      */
  618.     public static boolean isPolygonIntersectingRectangle(int[] x, int[] y, int x0, int y0, int x1, int y1)
  619.     {
  620.         int n = x.length;
  621.  
  622.         if (n == 0)
  623.             return false;
  624.  
  625.         if (n == 1)
  626.             return Geometry.isPointInsideRectangle(x0, y0, x1, y1, x[0], y[0]);
  627.  
  628.         //
  629.         // If the polyline constituting the polygon intersects the rectangle
  630.         // the polygon does too.
  631.         //
  632.         if (Geometry.isPolylineIntersectingRectangle(x, y, x0, y0, x1, y1))
  633.             return true;
  634.  
  635.         // Check last leg as well
  636.         if (Geometry.isLineIntersectingRectangle(x[n - 2], y[n - 2], x[n - 1], y[n - 1], x0, y0, x1, y1))
  637.             return true;
  638.  
  639.         //
  640.         // The rectangle and polygon are now completely including each other
  641.         // or separate.
  642.         //
  643.         if (Geometry.isPointInsidePolygon(x, y, x0, y0) || Geometry.isPointInsideRectangle(x0, y0, x1, y1, x[0], y[0]))
  644.             return true;
  645.  
  646.         // Separate
  647.         return false;
  648.     }
  649.  
  650.  
  651.     /**
  652.      * Compute the area of the specfied polygon.
  653.      *
  654.      * @param x X coordinates of polygon.
  655.      * @param y Y coordinates of polygon.
  656.      *
  657.      * @return Area of specified polygon.
  658.      */
  659.     public static double computePolygonArea(double[] x, double[] y)
  660.     {
  661.         int n = x.length;
  662.  
  663.         double area = 0.0;
  664.         for (int i = 0; i < n - 1; i++)
  665.             area += (x[i] * y[i + 1]) - (x[i + 1] * y[i]);
  666.         area += (x[n - 1] * y[0]) - (x[0] * y[n - 1]);
  667.  
  668.         area *= 0.5;
  669.  
  670.         return area;
  671.     }
  672.  
  673.  
  674.     /**
  675.      * Compute the area of the specfied polygon.
  676.      *
  677.      * @param xy Geometry of polygon [x,y,...]
  678.      *
  679.      * @return Area of specified polygon.
  680.      */
  681.     public static double computePolygonArea(double[] xy)
  682.     {
  683.         int n = xy.length;
  684.  
  685.         double area = 0.0;
  686.         for (int i = 0; i < n - 2; i += 2)
  687.             area += (xy[i] * xy[i + 3]) - (xy[i + 2] * xy[i + 1]);
  688.         area += (xy[xy.length - 2] * xy[1]) - (xy[0] * xy[xy.length - 1]);
  689.  
  690.         area *= 0.5;
  691.  
  692.         return area;
  693.     }
  694.  
  695.  
  696.     /**
  697.      * Compute centorid (center of gravity) of specified polygon.
  698.      *
  699.      * @param x X coordinates of polygon.
  700.      * @param y Y coordinates of polygon.
  701.      *
  702.      * @return Centroid [x,y] of specified polygon.
  703.      */
  704.     public static double[] computePolygonCentroid(double[] x, double[] y)
  705.     {
  706.         double cx = 0.0;
  707.         double cy = 0.0;
  708.  
  709.         int n = x.length;
  710.         for (int i = 0; i < n - 1; i++)
  711.         {
  712.             double a = x[i] * y[i + 1] - x[i + 1] * y[i];
  713.             cx += (x[i] + x[i + 1]) * a;
  714.             cy += (y[i] + y[i + 1]) * a;
  715.         }
  716.         double a = x[n - 1] * y[0] - x[0] * y[n - 1];
  717.         cx += (x[n - 1] + x[0]) * a;
  718.         cy += (y[n - 1] + y[0]) * a;
  719.  
  720.         double area = Geometry.computePolygonArea(x, y);
  721.  
  722.         cx /= 6 * area;
  723.         cy /= 6 * area;
  724.  
  725.         return new double[]{cx, cy};
  726.     }
  727.  
  728.  
  729.     /**
  730.      * Find the 3D extent of a polyline.
  731.      *
  732.      * @param x    X coordinates of polyline.
  733.      * @param y    Y coordinates of polyline.
  734.      * @param z    Z coordinates of polyline.
  735.      *                May be null if this is a 2D case.
  736.      * @param xExtent Will upon return contain [xMin,xMax].
  737.      * @param yExtent Will upon return contain [xMin,xMax].
  738.      * @param zExtent Will upon return contain [xMin,xMax]. Unused (may be
  739.      *                set to null) if z is null.
  740.      */
  741.     public static void findPolygonExtent(double[] x, double[] y, double[] z, double[] xExtent, double[] yExtent, double[] zExtent)
  742.     {
  743.         double xMin = +Double.MAX_VALUE;
  744.         double xMax = -Double.MAX_VALUE;
  745.  
  746.         double yMin = +Double.MAX_VALUE;
  747.         double yMax = -Double.MAX_VALUE;
  748.  
  749.         double zMin = +Double.MAX_VALUE;
  750.         double zMax = -Double.MAX_VALUE;
  751.  
  752.         for (int i = 0; i < x.length; i++)
  753.         {
  754.             if (x[i] < xMin)
  755.                 xMin = x[i];
  756.             if (x[i] > xMax)
  757.                 xMax = x[i];
  758.  
  759.             if (y[i] < yMin)
  760.                 yMin = y[i];
  761.             if (y[i] > yMax)
  762.                 yMax = y[i];
  763.  
  764.             if (z != null)
  765.             {
  766.                 if (z[i] < zMin)
  767.                     zMin = z[i];
  768.                 if (z[i] > zMax)
  769.                     zMax = z[i];
  770.             }
  771.         }
  772.  
  773.         xExtent[0] = xMin;
  774.         xExtent[1] = xMax;
  775.  
  776.         yExtent[0] = yMin;
  777.         yExtent[1] = yMax;
  778.  
  779.         if (z != null)
  780.         {
  781.             zExtent[0] = zMin;
  782.             zExtent[1] = zMax;
  783.         }
  784.     }
  785.  
  786.  
  787.     /**
  788.      * Find the extent of a polygon.
  789.      *
  790.      * @param x    X coordinates of polygon.
  791.      * @param y    Y coordinates of polygon.
  792.      * @param xExtent Will upon return contain [xMin, xMax]
  793.      * @param yExtent Will upon return contain [yMin, yMax]
  794.      */
  795.     public static void findPolygonExtent(int[] x, int[] y, int[] xExtent,  // xMin, xMax
  796.                                          int[] yExtent)  // yMin, yMax
  797.     {
  798.         int xMin = +Integer.MAX_VALUE;
  799.         int xMax = -Integer.MAX_VALUE;
  800.  
  801.         int yMin = +Integer.MAX_VALUE;
  802.         int yMax = -Integer.MAX_VALUE;
  803.  
  804.         for (int i = 0; i < x.length; i++)
  805.         {
  806.             if (x[i] < xMin)
  807.                 xMin = x[i];
  808.             if (x[i] > xMax)
  809.                 xMax = x[i];
  810.  
  811.             if (y[i] < yMin)
  812.                 yMin = y[i];
  813.             if (y[i] > yMax)
  814.                 yMax = y[i];
  815.         }
  816.  
  817.         xExtent[0] = xMin;
  818.         xExtent[1] = xMax;
  819.  
  820.         yExtent[0] = yMin;
  821.         yExtent[1] = yMax;
  822.     }
  823.  
  824.  
  825.     /**
  826.      * Compute the intersection between two line segments, or two lines
  827.      * of infinite length.
  828.      *
  829.      * @param x0              X coordinate first end point first line segment.
  830.      * @param y0              Y coordinate first end point first line segment.
  831.      * @param x1              X coordinate second end point first line segment.
  832.      * @param y1              Y coordinate second end point first line segment.
  833.      * @param x2              X coordinate first end point second line segment.
  834.      * @param y2              Y coordinate first end point second line segment.
  835.      * @param x3              X coordinate second end point second line segment.
  836.      * @param y3              Y coordinate second end point second line segment.
  837.      * @param intersection[2] Preallocated by caller to double[2]
  838.      *
  839.      * @return -1 if lines are parallel (x,y unset),
  840.      *         -2 if lines are parallel and overlapping (x, y center)
  841.      *         0 if intesrection outside segments (x,y set)
  842.      *         +1 if segments intersect (x,y set)
  843.      */
  844.     public static int findLineSegmentIntersection(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double[] intersection)
  845.     {
  846.         // TODO: Make limit depend on input domain
  847.         final double LIMIT = 1e-5;
  848.         final double INFINITY = 1e10;
  849.  
  850.         double x, y;
  851.  
  852.         //
  853.         // Convert the lines to the form y = ax + b
  854.         //
  855.  
  856.         // Slope of the two lines
  857.         double a0 = Geometry.equals(x0, x1, LIMIT) ? INFINITY : (y0 - y1) / (x0 - x1);
  858.         double a1 = Geometry.equals(x2, x3, LIMIT) ? INFINITY : (y2 - y3) / (x2 - x3);
  859.  
  860.         double b0 = y0 - a0 * x0;
  861.         double b1 = y2 - a1 * x2;
  862.  
  863.         // Check if lines are parallel
  864.         if (Geometry.equals(a0, a1))
  865.         {
  866.             if (!Geometry.equals(b0, b1))
  867.                 return -1; // Parallell non-overlapping
  868.  
  869.             else
  870.             {
  871.                 if (Geometry.equals(x0, x1))
  872.                 {
  873.                     if (Math.min(y0, y1) < Math.max(y2, y3) || Math.max(y0, y1) > Math.min(y2, y3))
  874.                     {
  875.                         double twoMiddle = y0 + y1 + y2 + y3 - Geometry.min(y0, y1, y2, y3) - Geometry.max(y0, y1, y2, y3);
  876.                         y = (twoMiddle) / 2.0;
  877.                         x = (y - b0) / a0;
  878.                     } else
  879.                         return -1;  // Parallell non-overlapping
  880.                 } else
  881.                 {
  882.                     if (Math.min(x0, x1) < Math.max(x2, x3) || Math.max(x0, x1) > Math.min(x2, x3))
  883.                     {
  884.                         double twoMiddle = x0 + x1 + x2 + x3 - Geometry.min(x0, x1, x2, x3) - Geometry.max(x0, x1, x2, x3);
  885.                         x = (twoMiddle) / 2.0;
  886.                         y = a0 * x + b0;
  887.                     } else
  888.                         return -1;
  889.                 }
  890.  
  891.                 intersection[0] = x;
  892.                 intersection[1] = y;
  893.                 return -2;
  894.             }
  895.         }
  896.  
  897.         // Find correct intersection point
  898.         if (Geometry.equals(a0, INFINITY))
  899.         {
  900.             x = x0;
  901.             y = a1 * x + b1;
  902.         } else if (Geometry.equals(a1, INFINITY))
  903.         {
  904.             x = x2;
  905.             y = a0 * x + b0;
  906.         } else
  907.         {
  908.             x = -(b0 - b1) / (a0 - a1);
  909.             y = a0 * x + b0;
  910.         }
  911.  
  912.         intersection[0] = x;
  913.         intersection[1] = y;
  914.  
  915.         // Then check if intersection is within line segments
  916.         double distanceFrom1;
  917.         if (Geometry.equals(x0, x1))
  918.         {
  919.             if (y0 < y1)
  920.                 distanceFrom1 = y < y0 ? Geometry.length(x, y, x0, y0) : y > y1 ? Geometry.length(x, y, x1, y1) : 0.0;
  921.             else
  922.                 distanceFrom1 = y < y1 ? Geometry.length(x, y, x1, y1) : y > y0 ? Geometry.length(x, y, x0, y0) : 0.0;
  923.         } else
  924.         {
  925.             if (x0 < x1)
  926.                 distanceFrom1 = x < x0 ? Geometry.length(x, y, x0, y0) : x > x1 ? Geometry.length(x, y, x1, y1) : 0.0;
  927.             else
  928.                 distanceFrom1 = x < x1 ? Geometry.length(x, y, x1, y1) : x > x0 ? Geometry.length(x, y, x0, y0) : 0.0;
  929.         }
  930.  
  931.         double distanceFrom2;
  932.         if (Geometry.equals(x2, x3))
  933.         {
  934.             if (y2 < y3)
  935.                 distanceFrom2 = y < y2 ? Geometry.length(x, y, x2, y2) : y > y3 ? Geometry.length(x, y, x3, y3) : 0.0;
  936.             else
  937.                 distanceFrom2 = y < y3 ? Geometry.length(x, y, x3, y3) : y > y2 ? Geometry.length(x, y, x2, y2) : 0.0;
  938.         } else
  939.         {
  940.             if (x2 < x3)
  941.                 distanceFrom2 = x < x2 ? Geometry.length(x, y, x2, y2) : x > x3 ? Geometry.length(x, y, x3, y3) : 0.0;
  942.             else
  943.                 distanceFrom2 = x < x3 ? Geometry.length(x, y, x3, y3) : x > x2 ? Geometry.length(x, y, x2, y2) : 0.0;
  944.         }
  945.  
  946.         return Geometry.equals(distanceFrom1, 0.0) && Geometry.equals(distanceFrom2, 0.0) ? 1 : 0;
  947.     }
  948.  
  949.  
  950.     /**
  951.      * Find the intersections between a polygon and a straight line.
  952.      * <p/>
  953.      * NOTE: This method is only guaranteed to work if the polygon
  954.      * is first preprocessed so that "unneccesary" vertices are removed
  955.      * (i.e vertices on the straight line between its neighbours).
  956.      *
  957.      * @param x  X coordinates of polygon.
  958.      * @param y  Y coordinates of polygon.
  959.      * @param x0 X first end point of line.
  960.      * @param x0 Y first end point of line.
  961.      * @param x0 X second end point of line.
  962.      * @param x0 Y second end point of line.
  963.      *
  964.      * @return Intersections [x,y,x,y...].
  965.      */
  966.     public static double[] findLinePolygonIntersections(double[] x, double[] y, double x0, double y0, double x1, double y1)
  967.     {
  968.         double x2, y2, x3, y3;
  969.         double xi, yi;
  970.         int nPoints = x.length;
  971.  
  972.         int nIntersections = 0;
  973.         double[] intersections = new double[24];  // Result vector x,y,x,y,...
  974.         double[] intersection = new double[2];   // Any given intersection x,y
  975.  
  976.         for (int i = 0; i < nPoints; i++)
  977.         {
  978.             int next = i == nPoints - 1 ? 0 : i + 1;
  979.  
  980.             // The line segment of the polyline to check
  981.             x2 = x[i];
  982.             y2 = y[i];
  983.             x3 = x[next];
  984.             y3 = y[next];
  985.  
  986.             boolean isIntersecting = false;
  987.  
  988.             // Ignore segments of zero length
  989.             if (Geometry.equals(x2, x3) && Geometry.equals(y2, y3))
  990.                 continue;
  991.  
  992.             int type = Geometry.findLineSegmentIntersection(x0, y0, x1, y1, x2, y2, x3, y3, intersection);
  993.  
  994.             if (type == -2)
  995.             { // Overlapping
  996.                 int p1 = i == 0 ? nPoints - 1 : i - 1;
  997.                 int p2 = next == nPoints - 1 ? 0 : next + 1;
  998.  
  999.                 int side = Geometry.sameSide(x0, y0, x1, y1, x[p1], y[p1], x[p2], y[p2]);
  1000.  
  1001.                 if (side < 0)
  1002.                     isIntersecting = true;
  1003.             } else if (type == 1)
  1004.                 isIntersecting = true;
  1005.  
  1006.             // Add the intersection point
  1007.             if (isIntersecting)
  1008.             {
  1009.  
  1010.                 // Reallocate if necessary
  1011.                 if (nIntersections << 1 == intersections.length)
  1012.                 {
  1013.                     double[] newArray = new double[nIntersections << 2];
  1014.                     System.arraycopy(intersections, 0, newArray, 0, intersections.length);
  1015.                     intersections = newArray;
  1016.                 }
  1017.  
  1018.                 // Then add
  1019.                 intersections[nIntersections << 1 + 0] = intersection[0];
  1020.                 intersections[nIntersections << 1 + 1] = intersection[1];
  1021.  
  1022.                 nIntersections++;
  1023.             }
  1024.         }
  1025.  
  1026.         if (nIntersections == 0)
  1027.             return null;
  1028.  
  1029.         // Reallocate result so array match number of intersections
  1030.         double[] finalArray = new double[nIntersections << 2];
  1031.         System.arraycopy(intersections, 0, finalArray, 0, finalArray.length);
  1032.  
  1033.         return finalArray;
  1034.     }
  1035.  
  1036.  
  1037.     /**
  1038.      * Return the geometry of an ellipse based on its four top points.
  1039.      * Integer domain. The method use the generic createEllipse()
  1040.      * method for the main task, and then transforms this according
  1041.      * to any rotation or skew defined by the given top points.
  1042.      *
  1043.      * @param x X array of four top points of ellipse.
  1044.      * @param y Y array of four top points of ellipse.
  1045.      *
  1046.      * @return Geometry of ellipse [x,y,x,y...].
  1047.      */
  1048.     public static int[] createEllipse(int[] x, int[] y)
  1049.     {
  1050.         // Center of ellipse
  1051.         int x0 = (x[0] + x[2]) / 2;
  1052.         int y0 = (y[0] + y[2]) / 2;
  1053.  
  1054.         // Angle between axis define skew
  1055.         double[] p0 = {(double) x0, (double) y0, 0.0};
  1056.         double[] p1 = {(double) x[0], (double) y[0], 0.0};
  1057.         double[] p2 = {(double) x[1], (double) y[1], 0.0};
  1058.  
  1059.         double axisAngle = Geometry.computeAngle(p0, p1, p2);
  1060.  
  1061.         // dx / dy
  1062.         double dx = Geometry.length(x0, y0, x[1], y[1]);
  1063.         double dy = Geometry.length(x0, y0, x[0], y[0]) * Math.sin(axisAngle);
  1064.  
  1065.         // Create geometry for unrotated / unsheared ellipse
  1066.         int[] ellipse = createEllipse(x0, y0, (int) Math.round(dx), (int) Math.round(dy));
  1067.         int nPoints = ellipse.length / 2;
  1068.  
  1069.         // Shear if neccessary. If angle is close to 90 there is no shear.
  1070.         // If angle is close to 0 or 180 shear is infinite, and we set
  1071.         // it to zero as well.
  1072.         if (!Geometry.equals(axisAngle, Math.PI / 2.0, 0.1) && !Geometry.equals(axisAngle, Math.PI, 0.1) && !Geometry.equals(axisAngle, 0.0, 0.1))
  1073.         {
  1074.             double xShear = 1.0 / Math.tan(axisAngle);
  1075.             for (int i = 0; i < nPoints; i++)
  1076.                 ellipse[i * 2 + 0] += Math.round((ellipse[i * 2 + 1] - y0) * xShear);
  1077.         }
  1078.  
  1079.         // Rotate
  1080.         int ddx = x[1] - x0;
  1081.         int ddy = y0 - y[1];
  1082.  
  1083.         double angle;
  1084.         if (ddx == 0 && ddy == 0)
  1085.             angle = 0.0;
  1086.         else if (ddx == 0)
  1087.             angle = Math.PI / 2.0;
  1088.         else
  1089.             angle = Math.atan((double) ddy / (double) ddx);
  1090.  
  1091.         double cosAngle = Math.cos(angle);
  1092.         double sinAngle = Math.sin(angle);
  1093.  
  1094.         for (int i = 0; i < nPoints; i++)
  1095.         {
  1096.             int xr = (int) Math.round(x0 + (ellipse[i * 2 + 0] - x0) * cosAngle - (ellipse[i * 2 + 1] - y0) * sinAngle);
  1097.             int yr = (int) Math.round(y0 - (ellipse[i * 2 + 1] - y0) * cosAngle - (ellipse[i * 2 + 0] - x0) * sinAngle);
  1098.  
  1099.             ellipse[i * 2 + 0] = xr;
  1100.             ellipse[i * 2 + 1] = yr;
  1101.         }
  1102.  
  1103.         return ellipse;
  1104.     }
  1105.  
  1106.  
  1107.     /**
  1108.      * Create the geometry for an unrotated, unskewed ellipse.
  1109.      * Integer domain.
  1110.      *
  1111.      * @param x0 X center of ellipse.
  1112.      * @param y0 Y center of ellipse.
  1113.      * @param dx X ellipse radius.
  1114.      * @param dy Y ellipse radius.
  1115.      *
  1116.      * @return Ellipse geometry [x,y,x,y,...].
  1117.      */
  1118.     public static int[] createEllipse(int x0, int y0, int dx, int dy)
  1119.     {
  1120.         // Make sure deltas are positive
  1121.         dx = Math.abs(dx);
  1122.         dy = Math.abs(dy);
  1123.  
  1124.         // This is an approximate number of points we need to make a smooth
  1125.         // surface on a quater of the ellipse
  1126.         int nPoints = dx > dy ? dx : dy;
  1127.         nPoints /= 2;
  1128.         if (nPoints < 1)
  1129.             nPoints = 1;
  1130.  
  1131.         // Allocate arrays for holding the complete set of vertices around
  1132.         // the ellipse. Note that this is a complete ellipse: First and last
  1133.         // point coincide.
  1134.         int[] ellipse = new int[nPoints * 8 + 2];
  1135.  
  1136.         // Compute some intermediate results to save time in the inner loop
  1137.         int dxdy = dx * dy;
  1138.         int dx2 = dx * dx;
  1139.         int dy2 = dy * dy;
  1140.  
  1141.         // Handcode the entries in the four "corner" points of the ellipse,
  1142.         // i.e. at point 0, 90, 180, 270 and 360 degrees
  1143.         ellipse[nPoints * 0 + 0] = x0 + dx;
  1144.         ellipse[nPoints * 0 + 1] = y0;
  1145.  
  1146.         ellipse[nPoints * 8 + 0] = x0 + dx;
  1147.         ellipse[nPoints * 8 + 1] = y0;
  1148.  
  1149.         ellipse[nPoints * 2 + 0] = x0;
  1150.         ellipse[nPoints * 2 + 1] = y0 - dy;
  1151.  
  1152.         ellipse[nPoints * 4 + 0] = x0 - dx;
  1153.         ellipse[nPoints * 4 + 1] = y0;
  1154.  
  1155.         ellipse[nPoints * 6 + 0] = x0;
  1156.         ellipse[nPoints * 6 + 1] = y0 + dy;
  1157.  
  1158.         // Find the angle step
  1159.         double angleStep = nPoints > 0 ? Math.PI / 2.0 / nPoints : 0.0;
  1160.  
  1161.         // Loop over angles from 0 to 90. The rest of the ellipse can be derrived
  1162.         // from this first quadrant. For each angle set the four corresponding
  1163.         // ellipse points.
  1164.         double a = 0.0;
  1165.         for (int i = 1; i < nPoints; i++)
  1166.         {
  1167.             a += angleStep;
  1168.  
  1169.             double t = Math.tan(a);
  1170.  
  1171.             double x = (double) dxdy / Math.sqrt(t * t * dx2 + dy2);
  1172.             double y = x * t;
  1173.  
  1174.             int xi = (int) (x + 0.5);
  1175.             int yi = (int) (y + 0.5);
  1176.  
  1177.             ellipse[(nPoints * 0 + i) * 2 + 0] = x0 + xi;
  1178.             ellipse[(nPoints * 2 - i) * 2 + 0] = x0 - xi;
  1179.             ellipse[(nPoints * 2 + i) * 2 + 0] = x0 - xi;
  1180.             ellipse[(nPoints * 4 - i) * 2 + 0] = x0 + xi;
  1181.  
  1182.             ellipse[(nPoints * 0 + i) * 2 + 1] = y0 - yi;
  1183.             ellipse[(nPoints * 2 - i) * 2 + 1] = y0 - yi;
  1184.             ellipse[(nPoints * 2 + i) * 2 + 1] = y0 + yi;
  1185.             ellipse[(nPoints * 4 - i) * 2 + 1] = y0 + yi;
  1186.         }
  1187.  
  1188.         return ellipse;
  1189.     }
  1190.  
  1191.  
  1192.     /**
  1193.      * Create the geometry for an unrotated, unskewed ellipse.
  1194.      * Floating point domain.
  1195.      *
  1196.      * @param x0 X center of ellipse.
  1197.      * @param y0 Y center of ellipse.
  1198.      * @param dx X ellipse radius.
  1199.      * @param dy Y ellipse radius.
  1200.      *
  1201.      * @return Ellipse geometry [x,y,x,y,...].
  1202.      */
  1203.     public static double[] createEllipse(double x0, double y0, double dx, double dy)
  1204.     {
  1205.         // Make sure deltas are positive
  1206.         dx = Math.abs(dx);
  1207.         dy = Math.abs(dy);
  1208.  
  1209.         // As we don't know the resolution of the appliance of the ellipse
  1210.         // we create one vertex per 2nd degree. The nPoints variable holds
  1211.         // number of points in a quater of the ellipse.
  1212.         int nPoints = 45;
  1213.  
  1214.         // Allocate arrays for holding the complete set of vertices around
  1215.         // the ellipse. Note that this is a complete ellipse: First and last
  1216.         // point coincide.
  1217.         double[] ellipse = new double[nPoints * 8 + 2];
  1218.  
  1219.         // Compute some intermediate results to save time in the inner loop
  1220.         double dxdy = dx * dy;
  1221.         double dx2 = dx * dx;
  1222.         double dy2 = dy * dy;
  1223.  
  1224.         // Handcode the entries in the four "corner" points of the ellipse,
  1225.         // i.e. at point 0, 90, 180, 270 and 360 degrees
  1226.         ellipse[nPoints * 0 + 0] = x0 + dx;
  1227.         ellipse[nPoints * 0 + 1] = y0;
  1228.  
  1229.         ellipse[nPoints * 8 + 0] = x0 + dx;
  1230.         ellipse[nPoints * 8 + 1] = y0;
  1231.  
  1232.         ellipse[nPoints * 2 + 0] = x0;
  1233.         ellipse[nPoints * 2 + 1] = y0 - dy;
  1234.  
  1235.         ellipse[nPoints * 4 + 0] = x0 - dx;
  1236.         ellipse[nPoints * 4 + 1] = y0;
  1237.  
  1238.         ellipse[nPoints * 6 + 0] = x0;
  1239.         ellipse[nPoints * 6 + 1] = y0 + dy;
  1240.  
  1241.         // Find the angle step
  1242.         double angleStep = nPoints > 0 ? Math.PI / 2.0 / nPoints : 0.0;
  1243.  
  1244.         // Loop over angles from 0 to 90. The rest of the ellipse can be derrived
  1245.         // from this first quadrant. For each angle set the four corresponding
  1246.         // ellipse points.
  1247.         double a = 0.0;
  1248.         for (int i = 1; i < nPoints; i++)
  1249.         {
  1250.             a += angleStep;
  1251.  
  1252.             double t = Math.tan(a);
  1253.  
  1254.             double x = (double) dxdy / Math.sqrt(t * t * dx2 + dy2);
  1255.             double y = x * t + 0.5;
  1256.  
  1257.             ellipse[(nPoints * 0 + i) * 2 + 0] = x0 + x;
  1258.             ellipse[(nPoints * 2 - i) * 2 + 0] = x0 - x;
  1259.             ellipse[(nPoints * 2 + i) * 2 + 0] = x0 - x;
  1260.             ellipse[(nPoints * 4 - i) * 2 + 0] = x0 + x;
  1261.  
  1262.             ellipse[(nPoints * 0 + i) * 2 + 1] = y0 - y;
  1263.             ellipse[(nPoints * 2 - i) * 2 + 1] = y0 - y;
  1264.             ellipse[(nPoints * 2 + i) * 2 + 1] = y0 + y;
  1265.             ellipse[(nPoints * 4 - i) * 2 + 1] = y0 + y;
  1266.         }
  1267.  
  1268.         return ellipse;
  1269.     }
  1270.  
  1271.  
  1272.     /**
  1273.      * Create geometry for a circle. Integer domain.
  1274.      *
  1275.      * @param x0     X center of circle.
  1276.      * @param y0     Y center of circle.
  1277.      * @param radius Radius of circle.
  1278.      *
  1279.      * @return Geometry of circle [x,y,...]
  1280.      */
  1281.     public static int[] createCircle(int x0, int y0, int radius)
  1282.     {
  1283.         return createEllipse(x0, y0, radius, radius);
  1284.     }
  1285.  
  1286.  
  1287.     /**
  1288.      * Create geometry for a circle. Floating point domain.
  1289.      *
  1290.      * @param x0     X center of circle.
  1291.      * @param y0     Y center of circle.
  1292.      * @param radius Radius of circle.
  1293.      *
  1294.      * @return Geometry of circle [x,y,...]
  1295.      */
  1296.     public static double[] createCircle(double x0, double y0, double radius)
  1297.     {
  1298.         return createEllipse(x0, y0, radius, radius);
  1299.     }
  1300.  
  1301.  
  1302.     /**
  1303.      * Create the geometry of a sector of an ellipse.
  1304.      *
  1305.      * @param x0     X coordinate of center of ellipse.
  1306.      * @param y0     Y coordinate of center of ellipse.
  1307.      * @param dx     X radius of ellipse.
  1308.      * @param dy     Y radius of ellipse.
  1309.      * @param angle0 First angle of sector (in radians).
  1310.      * @param angle1 Second angle of sector (in radians).
  1311.      *
  1312.      * @return Geometry of secor [x,y,...]
  1313.      */
  1314.     public static int[] createSector(int x0, int y0, int dx, int dy, double angle0, double angle1)
  1315.     {
  1316.         // Determine a sensible number of points for arc
  1317.         double angleSpan = Math.abs(angle1 - angle0);
  1318.         double arcDistance = Math.max(dx, dy) * angleSpan;
  1319.         int nPoints = (int) Math.round(arcDistance / 15);
  1320.         double angleStep = angleSpan / (nPoints - 1);
  1321.  
  1322.         int[] xy = new int[nPoints * 2 + 4];
  1323.  
  1324.         int index = 0;
  1325.         for (int i = 0; i < nPoints; i++)
  1326.         {
  1327.             double angle = angle0 + angleStep * i;
  1328.             double x = dx * Math.cos(angle);
  1329.             double y = dy * Math.sin(angle);
  1330.  
  1331.             xy[index + 0] = x0 + (int) Math.round(x);
  1332.             xy[index + 1] = y0 - (int) Math.round(y);
  1333.  
  1334.             index += 2;
  1335.         }
  1336.  
  1337.         // Start and end geometry at center of ellipse to make it a closed polygon
  1338.         xy[nPoints * 2 + 0] = x0;
  1339.         xy[nPoints * 2 + 1] = y0;
  1340.         xy[nPoints * 2 + 2] = xy[0];
  1341.         xy[nPoints * 2 + 3] = xy[1];
  1342.  
  1343.         return xy;
  1344.     }
  1345.  
  1346.  
  1347.     /**
  1348.      * Create the geometry of a sector of a circle.
  1349.      *
  1350.      * @param x0     X coordinate of center of ellipse.
  1351.      * @param y0     Y coordinate of center of ellipse.
  1352.      * @param dx     X radius of ellipse.
  1353.      * @param dy     Y radius of ellipse.
  1354.      * @param angle0 First angle of sector (in radians).
  1355.      * @param angle1 Second angle of sector (in radians).
  1356.      *
  1357.      * @return Geometry of secor [x,y,...]
  1358.      */
  1359.     public static int[] createSector(int x0, int y0, int radius, double angle0, double angle1)
  1360.     {
  1361.         return createSector(x0, y0, radius, radius, angle0, angle1);
  1362.     }
  1363.  
  1364.  
  1365.     /**
  1366.      * Create the geometry of an arrow. The arrow is positioned at the
  1367.      * end (last point) of the specified polyline, as follows:
  1368.      * <p/>
  1369.      * 0,4--,
  1370.      * \  --,
  1371.      * \    --,
  1372.      * \      --,
  1373.      * \        --,
  1374.      * -------------------------3-----------1
  1375.      * /        --'
  1376.      * /      --'
  1377.      * /    --'
  1378.      * /  --'
  1379.      * 2--'
  1380.      *
  1381.      * @param x   X coordinates of polyline of where arrow is positioned
  1382.      *               in the end. Must contain at least two points.
  1383.      * @param y   Y coordinates of polyline of where arrow is positioned
  1384.      *               in the end.
  1385.      * @param length Length along the main axis from point 1 to the
  1386.      *               projection of point 0.
  1387.      * @param angle  Angle between the main axis and the line 1,0
  1388.      *               (and 1,2) in radians.
  1389.      * @param inset  Specification of point 3 [0.0-1.0], 1.0 will put
  1390.      *               point 3 at distance length from 1, 0.0 will put it
  1391.      *               at point 1.
  1392.      *
  1393.      * @return Array of the five coordinates [x,y,...].
  1394.      */
  1395.     public static int[] createArrow(int[] x, int[] y, double length, double angle, double inset)
  1396.     {
  1397.         int[] arrow = new int[10];
  1398.  
  1399.         int x0 = x[x.length - 1];
  1400.         int y0 = y[y.length - 1];
  1401.  
  1402.         arrow[2] = x0;
  1403.         arrow[3] = y0;
  1404.  
  1405.         // Find position of interior of the arrow along the polyline
  1406.         int[] pos1 = new int[2];
  1407.         Geometry.findPolygonPosition(x, y, length, pos1);
  1408.  
  1409.         // Angles
  1410.         double dx = x0 - pos1[0];
  1411.         double dy = y0 - pos1[1];
  1412.  
  1413.         // Polyline angle
  1414.         double v = dx == 0.0 ? Math.PI / 2.0 : Math.atan(Math.abs(dy / dx));
  1415.  
  1416.         v = dx > 0.0 && dy <= 0.0 ? Math.PI + v : dx > 0.0 && dy >= 0.0 ? Math.PI - v : dx <= 0.0 && dy < 0.0 ? -v : dx <= 0.0 && dy > 0.0 ? +v : 0.0;
  1417.  
  1418.         double v0 = v + angle;
  1419.         double v1 = v - angle;
  1420.  
  1421.         double edgeLength = length / Math.cos(angle);
  1422.  
  1423.         arrow[0] = x0 + (int) Math.round(edgeLength * Math.cos(v0));
  1424.         arrow[1] = y0 - (int) Math.round(edgeLength * Math.sin(v0));
  1425.  
  1426.         arrow[4] = x0 + (int) Math.round(edgeLength * Math.cos(v1));
  1427.         arrow[5] = y0 - (int) Math.round(edgeLength * Math.sin(v1));
  1428.  
  1429.         double c1 = inset * length;
  1430.  
  1431.         arrow[6] = x0 + (int) Math.round(c1 * Math.cos(v));
  1432.         arrow[7] = y0 - (int) Math.round(c1 * Math.sin(v));
  1433.  
  1434.         // Close polygon
  1435.         arrow[8] = arrow[0];
  1436.         arrow[9] = arrow[1];
  1437.  
  1438.         return arrow;
  1439.     }
  1440.  
  1441.  
  1442.     /**
  1443.      * Create geometry for an arrow along the specified line and with
  1444.      * tip at x1,y1. See general method above.
  1445.      *
  1446.      * @param x0     X first end point of line.
  1447.      * @param y0     Y first end point of line.
  1448.      * @param x1     X second end point of line.
  1449.      * @param y1     Y second end point of line.
  1450.      * @param length Length along the main axis from point 1 to the
  1451.      *               projection of point 0.
  1452.      * @param angle  Angle between the main axis and the line 1,0
  1453.      *               (and 1.2)
  1454.      * @param inset  Specification of point 3 [0.0-1.0], 1.0 will put
  1455.      *               point 3 at distance length from 1, 0.0 will put it
  1456.      *               at point 1.
  1457.      *
  1458.      * @return Array of the four coordinates [x,y,...].
  1459.      */
  1460.     public static int[] createArrow(int x0, int y0, int x1, int y1, double length, double angle, double inset)
  1461.     {
  1462.         int[] x = {x0, x1};
  1463.         int[] y = {y0, y1};
  1464.  
  1465.         return createArrow(x, y, length, angle, inset);
  1466.     }
  1467.  
  1468.  
  1469.     /**
  1470.      * Create geometry for a rectangle. Returns a closed polygon; first
  1471.      * and last points matches. Integer domain.
  1472.      *
  1473.      * @param x0     X corner of rectangle.
  1474.      * @param y0     Y corner of rectangle.
  1475.      * @param width  Width (may be negative to indicate leftwards direction)
  1476.      * @param height Height (may be negative to indicaten upwards direction)
  1477.      */
  1478.     public static int[] createRectangle(int x0, int y0, int width, int height)
  1479.     {
  1480.         return new int[]{
  1481.                 x0, y0, x0 + (width - 1), y0, x0 + (width - 1), y0 + (height - 1), x0, y0 + (height - 1), x0, y0
  1482.         };
  1483.     }
  1484.  
  1485.  
  1486.     /**
  1487.      * Create geometry for a rectangle. Returns a closed polygon; first
  1488.      * and last points matches. Floating point domain.
  1489.      *
  1490.      * @param x0     X corner of rectangle.
  1491.      * @param y0     Y corner of rectangle.
  1492.      * @param width  Width (may be negative to indicate leftwards direction)
  1493.      * @param height Height (may be negative to indicaten upwards direction)
  1494.      */
  1495.     public static double[] createRectangle(double x0, double y0, double width, double height)
  1496.     {
  1497.         return new double[]{
  1498.                 x0, y0, x0 + width, y0, x0 + width, y0 + height, x0, y0 + height, x0, y0
  1499.         };
  1500.     }
  1501.  
  1502.  
  1503.     /**
  1504.      * Create geometry of a star. Integer domain.
  1505.      *
  1506.      * @param x0          X center of star.
  1507.      * @param y0          Y center of star.
  1508.      * @param innerRadius Inner radis of arms.
  1509.      * @param outerRadius Outer radius of arms.
  1510.      * @param nArms    Number of arms.
  1511.      *
  1512.      * @return Geometry of star [x,y,x,y,...].
  1513.      */
  1514.     public static int[] createStar(int x0, int y0, int innerRadius, int outerRadius, int nArms)
  1515.     {
  1516.         int nPoints = nArms * 2 + 1;
  1517.  
  1518.         int[] xy = new int[nPoints * 2];
  1519.  
  1520.         double angleStep = 2.0 * Math.PI / nArms / 2.0;
  1521.  
  1522.         for (int i = 0; i < nArms * 2; i++)
  1523.         {
  1524.             double angle = i * angleStep;
  1525.             double radius = (i % 2) == 0 ? innerRadius : outerRadius;
  1526.  
  1527.             double x = x0 + radius * Math.cos(angle);
  1528.             double y = y0 + radius * Math.sin(angle);
  1529.  
  1530.             xy[i * 2 + 0] = (int) Math.round(x);
  1531.             xy[i * 2 + 1] = (int) Math.round(y);
  1532.         }
  1533.  
  1534.         // Close polygon
  1535.         xy[nPoints * 2 - 2] = xy[0];
  1536.         xy[nPoints * 2 - 1] = xy[1];
  1537.  
  1538.         return xy;
  1539.     }
  1540.  
  1541.  
  1542.     /**
  1543.      * Create geometry of a star. Floating point domain.
  1544.      *
  1545.      * @param x0          X center of star.
  1546.      * @param y0          Y center of star.
  1547.      * @param innerRadius Inner radis of arms.
  1548.      * @param outerRadius Outer radius of arms.
  1549.      * @param nArms    Number of arms.
  1550.      *
  1551.      * @return Geometry of star [x,y,x,y,...].
  1552.      */
  1553.     public static double[] createStar(double x0, double y0, double innerRadius, double outerRadius, int nArms)
  1554.     {
  1555.         int nPoints = nArms * 2 + 1;
  1556.  
  1557.         double[] xy = new double[nPoints * 2];
  1558.  
  1559.         double angleStep = 2.0 * Math.PI / nArms / 2.0;
  1560.  
  1561.         for (int i = 0; i < nArms * 2; i++)
  1562.         {
  1563.             double angle = i * angleStep;
  1564.             double radius = (i % 2) == 0 ? innerRadius : outerRadius;
  1565.  
  1566.             xy[i * 2 + 0] = x0 + radius * Math.cos(angle);
  1567.             xy[i * 2 + 1] = y0 + radius * Math.sin(angle);
  1568.         }
  1569.  
  1570.         // Close polygon
  1571.         xy[nPoints * 2 - 2] = xy[0];
  1572.         xy[nPoints * 2 - 1] = xy[1];
  1573.  
  1574.         return xy;
  1575.     }
  1576.  
  1577.  
  1578.     /**
  1579.      * Return the x,y position at distance "length" into the given polyline.
  1580.      *
  1581.      * @param x     X coordinates of polyline
  1582.      * @param y     Y coordinates of polyline
  1583.      * @param length   Requested position
  1584.      * @param position Preallocated to int[2]
  1585.      *
  1586.      * @return True if point is within polyline, false otherwise
  1587.      */
  1588.     public static boolean findPolygonPosition(int[] x, int[] y, double length, int[] position)
  1589.     {
  1590.         if (length < 0)
  1591.             return false;
  1592.  
  1593.         double accumulatedLength = 0.0;
  1594.         for (int i = 1; i < x.length; i++)
  1595.         {
  1596.             double legLength = Geometry.length(x[i - 1], y[i - 1], x[i], y[i]);
  1597.             if (legLength + accumulatedLength >= length)
  1598.             {
  1599.                 double part = length - accumulatedLength;
  1600.                 double fraction = part / legLength;
  1601.                 position[0] = (int) Math.round(x[i - 1] + fraction * (x[i] - x[i - 1]));
  1602.                 position[1] = (int) Math.round(y[i - 1] + fraction * (y[i] - y[i - 1]));
  1603.                 return true;
  1604.             }
  1605.  
  1606.             accumulatedLength += legLength;
  1607.         }
  1608.  
  1609.         // Length is longer than polyline
  1610.         return false;
  1611.     }
  1612. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement