Package org.gvt.util

Source Code of org.gvt.util.ChsGeometry

package org.gvt.util;

import java.awt.geom.Line2D;
import java.util.*;

import org.eclipse.draw2d.geometry.*;
import org.gvt.util.ChsRectangle;

/**
* This class maintains a list of static geometry related utility methods.
*
* @author Ugur Dogrusoz
* @author Esat Belviranli
*
* Copyright: i-Vis Research Group, Bilkent University, 2007 - present
*/
abstract public class ChsGeometry
{
// -----------------------------------------------------------------------------
// Section: Class Methods
// -----------------------------------------------------------------------------
  /**
   * This method calculates the intersection (clipping) point the input
   * rectangle with the line defined by the input point and input rectangle center.
   */
  public static PrecisionPoint getIntersection(ChsRectangle rect,  double p2x, double p2y)
  {
    double p1x = rect.getCenterX();
    double p1y = rect.getCenterY();

    double topLeftX = rect.x;
    double topLeftY = rect.y;
    double topRightX = rect.getRight();
    double bottomLeftX = rect.x;
    double bottomLeftY = rect.getBottom();
    double bottomRightX = rect.getRight();

    //input point is inside of node
    if(p2x >= topLeftX && p2x <= topRightX &&
       p2y >= topLeftY && p2y <= bottomLeftY)
    {
      return null;
    }
   
    // line is vertical
    if (p1x == p2x)
    {
      if(p1y > p2y)
      {
        return new PrecisionPoint(p1x, topLeftY);
      }
      else if(p1y < p2y)
      {
        return new PrecisionPoint(p1x, bottomLeftY);
      }
      else
      {
        //not line, return null;
      }
    }
    // line is horizontal
    else if (p1y == p2y)
    {
      if(p1x > p2x)
      {
        return new PrecisionPoint(topLeftX, p1y);
      }
      else if(p1x < p2x)
      {
        return new PrecisionPoint(topRightX, p1y);
      }
      else
      {
        //not valid line, return null;
      }
    }
    else
    {
      //slope of node's diagonal
      double slope = rect.height / rect.width;
      //slope of line between center of rectangle and input point
      double slopePrime = (p2y - p1y) / (p2x - p1x);
      int cardinalDirection;
      double tempPointX;
      double tempPointY;
     
      //determine whether clipping pint is corner of node
      if(slope == slopePrime)
      {
        if(p1x > p2x)
        {
          return new PrecisionPoint(bottomLeftX, bottomLeftY);
        }
        else
        {
          return new PrecisionPoint(topRightX, topLeftY);
        }
      }
      else if((-slope) == slopePrime)
      {
        if(p1x > p2x)
        {
          return new PrecisionPoint(topLeftX, topLeftY);
        }
        else
        {
          return new PrecisionPoint(bottomRightX, bottomLeftY);
        }
      }
     
      //determine cardinal Direction
      if(p1x > p2x)
      {
        if(p1y > p2y)
        {
          cardinalDirection = getCardinalDirection(slope, slopePrime, 4);
        }
        else
        {
          cardinalDirection = getCardinalDirection(-slope, slopePrime, 3)
        }
      }
      else
      {
        if(p1y > p2y)
        {
          cardinalDirection = getCardinalDirection(-slope, slopePrime, 1)
        }
        else
        {
          cardinalDirection = getCardinalDirection(slope, slopePrime, 2);
        }
      }
     
      //find clipping point
      switch(cardinalDirection)
      {
        case 1:
          tempPointY = topLeftY;
          tempPointX = intersectsAtY(p1x, p2x, p1y, p2y, tempPointY);

          if (tempPointX != Double.NaN &&
            tempPointX <= bottomRightX &&
            tempPointX >= bottomLeftX)
          {
            return new PrecisionPoint(tempPointX, tempPointY);
          }
        case 2:
          tempPointX = bottomRightX;
          tempPointY = intersectsAtX(p1x, p2x,
            p1y, p2y, tempPointX);

          if (tempPointY != Double.NaN &&
            topLeftY < tempPointY &&
            tempPointY < bottomLeftY)
          {
            return new PrecisionPoint(tempPointX, tempPointY);
          }
        case 3:
          tempPointY = bottomLeftY;
          tempPointX = intersectsAtY(p1x, p2x, p1y, p2y, tempPointY);

          if (tempPointX != Double.NaN &&
            tempPointX <= bottomRightX &&
            tempPointX >= bottomLeftX)
          {
            return new PrecisionPoint(tempPointX, tempPointY);
          }
        case 4:
          tempPointX = bottomLeftX;
          tempPointY = intersectsAtX(p1x, p2x,
            p1y, p2y, tempPointX);

          if (tempPointY != Double.NaN &&
            topLeftY < tempPointY &&
            tempPointY < bottomLeftY)
          {
            return new PrecisionPoint(tempPointX, tempPointY);
          }
      }
    }
    return null;
  }
 
  /**
   * This method returns in which cardinal direction does input point stays
   * 1: North
   * 2: East
   * 3: South
   * 4: West
   */
  private static int getCardinalDirection(double slope, double slopePrime, int line)
  {
    if(slope > slopePrime)
    {
      return line;
    }
    else
    {
      return 1 + line % 4;
    }
  }
 
  /**
   * This method calculates the intersection (clipping) point the input
   * rectangle with the line defined by the input point pair.
   */
  public static PrecisionPoint getIntersection(ChsRectangle rect,
    double p1x, double p1y,
    double p2x, double p2y)
  {
    double ip1x = 0;
    double ip1y = 0;
    double ip2x = 0;
    double ip2y = 0;

    // Since we are not using objects for performance constraints,
    // we should have booleans indicating whether we found some
    // intersection point.
    boolean ip1Null = true;
    boolean ip2Null = true;

    double topLeftX = rect.x;
    double topLeftY = rect.y;
    double topRightX = rect.getRight();
    double bottomLeftX = rect.x;
    double bottomLeftY = rect.getBottom();
    double bottomRightX = rect.getRight();

    // Calculate top line
    if (p1x == p2x)
    {
      if (p1y == p2y)
      {
        // not a valid line, return null
      }
      else if (p1x >= bottomLeftX &&
         p1x <= bottomRightX)
      {
        // line vertical
        if (topLeftY != bottomLeftY)
        {
          ip1x = p1x;
          ip1y = bottomLeftY;
          ip2x = p1x;
          ip2y = topLeftY;

          ip1Null = ip2Null = false;
        }
        else
        {
          // Rectangle is in fact a line
          ip1x = p1x;
          ip1y = topLeftY;
          ip1Null = false;
        }
      }
    }
    else if (p1y == p2y)
    {
      // line horizantal
      if (p1y >= bottomLeftY &&
        p1y <= topLeftY)
      {
        if (topLeftX != topRightX)
        {
          ip1x = topRightX;
          ip1y = p1y;
          ip2x = p1x;
          ip2y = topLeftY;
          ip1Null = ip2Null = false;
        }
        else
        {
          // Rectangle is in fact a line
          ip1x = topLeftX;
          ip1y = p1y;
          ip1Null = false;
        }
      }
    }
    else
    {
      double tempPointX;
      double tempPointY;

      // General case, the line is not vertical or horizantal

      // Test hitting the top of the ractangle
      tempPointY = topLeftY;
      tempPointX = intersectsAtY(p1x, p2x,
        p1y, p2y, tempPointY);

      if (tempPointX != Double.NaN &&
        tempPointX <= bottomRightX &&
        tempPointX >= bottomLeftX)
      {
        ip1x = tempPointX;
        ip1y = topLeftY;
        ip1Null = false;
      }

      // Test hitting the bottom of the ractangle
      tempPointY = bottomLeftY;
      tempPointX = intersectsAtY(p1x, p2x,
        p1y, p2y, tempPointY);

      if (tempPointX != Double.NaN &&
        tempPointX <= bottomRightX &&
        tempPointX >= bottomLeftX)
      {
        if (ip1Null)
        {
          ip1x = tempPointX;
          ip1y = bottomLeftY;
          ip1Null = false;
        }
        else
        {
          ip2x = tempPointX;
          ip2y = bottomLeftY;
          ip2Null = false;
        }
      }

      // When hitting left or right, we exclude the corner points,
      // such that we don't get them twice.

      // Test hitting left of rectangle
      tempPointX = bottomLeftX;
      tempPointY = intersectsAtX(p1x, p2x,
        p1y, p2y, tempPointX);

      if (tempPointY != Double.NaN &&
        topLeftY < tempPointY &&
        tempPointY < bottomLeftY)
      {
        if (ip1Null)
        {
          ip1x = bottomLeftX;
          ip1y = tempPointY;
          ip1Null = false;
        }
        else
        {
          ip2x = bottomLeftX;
          ip2y = tempPointY;
          ip2Null = false;
        }
      }

      // Test hitting right of rectangle
      tempPointX = bottomRightX;
      tempPointY = intersectsAtX(p1x, p2x,
        p1y, p2y, tempPointX);

      if (tempPointY != Double.NaN &&
        topLeftY < tempPointY &&
        tempPointY < bottomLeftY)
      {
        if (ip1Null)
        {
          ip1x = bottomRightX;
          ip1y = tempPointY;
          ip1Null = false;
        }
        else
        {
          ip2x = bottomRightX;
          ip2y = tempPointY;
          ip2Null = false;
        }
      }
    }

    PrecisionPoint ip1 = null;
    PrecisionPoint ip2 = null;

    if (!ip1Null)
    {
      ip1 = new PrecisionPoint(ip1x,ip1y);
    }
    if (!ip2Null)
    {
      ip2 = new PrecisionPoint(ip2x,ip2y);
    }

    return findTheClosestPoint(p2x, p2y, ip1, ip2);
  }

  /**
   * This method returns the closest point, among the first and seconds point,
   * to the reference point
   */
  private static PrecisionPoint findTheClosestPoint(double refPointX,
    double refPointY,
    PrecisionPoint first,
    PrecisionPoint second)
  {
    PrecisionPoint temp = null;

    if (second == null && first != null)
    {
      temp = first;
    }
    else if (second != null && first == null)
    {
      temp = second;
    }
    else if (second != null && first != null)
    {
      double term1 = refPointX - first.preciseX;
      double term2 = refPointY - first.preciseY;

      double distanceFirst = term1 * term1 + term2 * term2;

      term1 = refPointX - second.preciseX;
      term2 = refPointY - second.preciseY;

      double distanceSecond = term1 * term1 + term2 * term2;

      if (distanceFirst >= distanceSecond)
      {
        temp = second;
      }
      else
      {
        temp = first;
      }
    }

    return temp;
  }

  /**
   * This method finds the y coordinate of a line at a specified x coordinate
   * returns a valid point if the line exists at x point and the line is not
   * vertical.
   */
  private static double intersectsAtX(double x1, double x2,
    double y1, double y2, double x)
  {
    double y = Double.NaN;

    if (x1 != x2 )
    {
      if (x == x1)
      {
        y = y1;
      }
      else if (x == x2)
      {
        y = y2;
      }
      else
      {
        double tempY = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);

        // Check whether found y is lying on the rectangle edge.
        if (((tempY <= y1 && tempY >= y2)||
          (tempY >= y1 && tempY <= y2)))
        {
          y = tempY;
        }
      }
    }

    return y;
  }

  /**
   * This method finds the x coordinate of a line at a specified y coordinate
   * returns a valid point if the line exists at y point and the line is not
   * horizantal.
   */
  private static double intersectsAtY(double x1, double x2,
    double y1, double y2, double y)
  {
    double x = Double.NaN;

    if (y1 != y2 )
    {
      if (y == y1)
      {
        x = x1;
      }
      else if (y == y2)
      {
        x = x2;
      }
      else
      {
        double tempX = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);

        // Check whether found x is lying on the rectangle edge.
        if (((tempX <= x1 && tempX >= x2)||
          (tempX >= x1 && tempX <= x2)))
        {
          x = tempX;
        }

      }
    }

    return x;
  }

  /**
   * This method calculates the intersection of the two lines defined by
   * point pairs (s1,s2) and (f1,f2).
   */
  public static Point getIntersection(Point s1, Point s2, Point f1, Point f2)
  {
    int x1 = s1.x;
    int y1 = s1.y;
    int x2 = s2.x;
    int y2 = s2.y;
    int x3 = f1.x;
    int y3 = f1.y;
    int x4 = f2.x;
    int y4 = f2.y;

    int x, y; // intersection point

    int a1, a2, b1, b2, c1, c2; // coefficients of line eqns.

    int denom;

    a1 = y2 - y1;
    b1 = x1 - x2;
    c1 = x2 * y1 - x1 * y2;  // { a1*x + b1*y + c1 = 0 is line 1 }

    a2 = y4 - y3;
    b2 = x3 - x4;
    c2 = x4 * y3 - x3 * y4;  // { a2*x + b2*y + c2 = 0 is line 2 }

    denom = a1 * b2 - a2 * b1;

    if (denom == 0)
    {
      return null;
    }

    x = (b1 * c2 - b2 * c1) / denom;
    y = (a2 * c1 - a1 * c2) / denom;

    return new Point(x, y);
  }

  /**
   * This method finds and returns the angle of the vector from the + x-axis
   * in clockwise direction (compatible w/ Java coordinate system!).
   */
  public static double angleOfVector(double Cx, double Cy,
    double Nx, double Ny)
  {
    double C_angle;

    if (Cx != Nx)
    {
      C_angle = Math.atan((Ny - Cy) / (Nx - Cx));

      if (Nx < Cx)
      {
        C_angle += Math.PI;
      }
      else if (Ny < Cy)
      {
        C_angle += TWO_PI;
      }
    }
    else if (Ny < Cy)
    {
      C_angle = ONE_AND_HALF_PI; // 270 degrees
    }
    else
    {
      C_angle = HALF_PI; // 90 degrees
    }

//    assert 0.0 <= C_angle && C_angle < TWO_PI;

    return C_angle;
  }

  /**
   * This method converts the given angle in radians to degrees.
   */
  public static double radian2degree(double rad)
  {
    return 180.0 * rad / Math.PI;
  }

  /**
   * This method checks whether the given two line segments (one with point
   * p1 and p2, the other with point p3 and p4) intersect at a point other
   * than these points.
   */
  public static boolean doIntersect(PrecisionPoint p1, PrecisionPoint p2,
    PrecisionPoint p3, PrecisionPoint p4)
  {
    boolean result = Line2D.linesIntersect(p1.preciseX, p1.preciseY,
      p2.preciseX, p2.preciseY, p3.preciseX, p3.preciseY,
      p4.preciseX, p4.preciseY);

    return result;
  }

  /*
   * Main method for testing purposes.
   */
  public static void main(String [] args)
  {
    ChsRectangle rect = new ChsRectangle();
    PrecisionPoint p1;
    PrecisionPoint p2;
    Random rand = new Random();
    double x;
    double y;
    double width;
    double height;
    double p1x;
    double p1y;
    double p2x;
    double p2y;

    int counter = 0;
    int i,j=0;
   
    for(i=0; i<10; i++)
    {
      System.out.println("------------------------------------");
      System.out.println("Test " + i + ":");
     
      x = 1000 * rand.nextDouble();
      y = 1000 * rand.nextDouble();
      width = 1000 * rand.nextDouble();
      height = 1000 * rand.nextDouble();
      System.out.println("X: " + x + "  Y: " + y + "  Width: " + width + "  Height: " + height);
      rect.setX(x);
      rect.setY(y);
      rect.setWidth(width);
      rect.setHeight(height);
     
      p1x = rect.getCenterX();
      p1y = rect.getCenterY();
     
      p2x = 1000 * rand.nextDouble();
      p2y = 1000 * rand.nextDouble();
     
      System.out.println("Input Point:  X - " + p2x + " Y - " + p2y);
     
      p2 = ChsGeometry.getIntersection(rect, p2x, p2y);
      p1 = ChsGeometry.getIntersection(rect, p1x, p1y, p2x, p2y);
           
      if(p1 == null && p2 == null)
      {
        i--;
        System.out.println("No clipping point");
        continue;
      }
      else if(p2 == null)
      {
        i--;j++;
        System.out.println("p2 is NULL");
        continue;
      }
      else if(p1 == null)
      {
        i--;j++;
        System.out.println("p1 is NULL");
        continue;
      }
     
      System.out.println("New: X - " + p2.preciseX + "  Y - " + p2.preciseY);
      System.out.println("Old: X - " + p1.preciseX + "  Y - " + p1.preciseY);
     
      if((Math.abs(p1.preciseX - p2.preciseX) < 0.000000001) && (Math.abs(p1.preciseY - p2.preciseY) < 0.00000001))
        counter++;
     
    }
   
    System.out.println(counter + " tests out of " + i + " tests are correct!");
    System.out.println(j + " tests out of " + (i+j) + " tests are skipped!");
   
   
  }

// -----------------------------------------------------------------------------
// Section: Class Constants
// -----------------------------------------------------------------------------
  /**
   * Some useful pre-calculated constants
   */
  public static final double HALF_PI = 0.5 * Math.PI;
  public static final double ONE_AND_HALF_PI = 1.5 * Math.PI;
  public static final double TWO_PI = 2.0 * Math.PI;
  public static final double THREE_PI = 3.0 * Math.PI;
}
TOP

Related Classes of org.gvt.util.ChsGeometry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.