package frame; import java.awt.Polygon; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; /** *LineIntersect is a class with static methods that enable the user *to find the intersection point of two lines on Java's coordinate system for *their GUIs. * *@author jBarry *@version (11.16.10) **/ public class CalculateArrowHead { public int[] intersectPoint; public double thetaInher; public double thetaHalf; public double theta2; public double theta3; public int size; public int quadrant; public CalculateArrowHead(Rectangle2D hitBox, Line2D inherLine, double theta, int size) { intersectPoint = hitBoxIntersectPoint(hitBox, inherLine); thetaInher = (getTheta_1(inherLine)*180)/Math.PI; thetaHalf = theta/2; this.size = size; } public Polygon makeArrow() { //The arrow head will be based, primarily, in // one quadrant. if(quadrant == 1)return arrowQuad1(); if(quadrant == 2)return arrowQuad2(); if(quadrant == 3)return arrowQuad3(); return arrowQuad4(); } /** * This method is called by makeArrow and it returns * a Polygon representing an arrowHead. Based in quadrant 4 * @return returns the Polygon representing the arrowHead * with the proper coordinates for the SlideBrowserPanel. */ private Polygon arrowQuad4() { Polygon arrow = new Polygon(); if(thetaInher - thetaHalf < 90) { theta2 = 90 - (thetaHalf - thetaInher); theta3 = 90 - (thetaHalf + thetaInher); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] + a1, intersectPoint[0] + a2}, new int[]{intersectPoint[1], intersectPoint[1] + b1, intersectPoint[1] - b2}, 3); } else if(thetaInher + thetaHalf > 90) { // A point on the quadrant-respective x or y-axis will be intersecting with // some point inside the arrow head. theta2 = thetaInher - thetaHalf; double thetaPart = 90 - thetaInher; double theta3 = 90 - (thetaHalf - thetaPart); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] + a1, intersectPoint[0] - a2}, new int[]{intersectPoint[1], intersectPoint[1] - b1, intersectPoint[1] - b2}, 3); } else { theta2 = 90 - (thetaHalf); theta3 = 90 - ((thetaHalf*2) + theta2); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] + a1, intersectPoint[0] + a2}, new int[]{intersectPoint[1], intersectPoint[1] - b1, intersectPoint[1] - b2}, 3); } return arrow; } /** * This method is called by makeArrow and it returns * a Polygon representing an arrowHead. Based in quadrant 3 * @return returns the Polygon representing the arrowHead * with the proper coordinates for the SlideBrowserPanel. */ private Polygon arrowQuad3() { Polygon arrow = new Polygon(); if(thetaInher - thetaHalf < 90) { theta2 = 90 - (thetaHalf - thetaInher); theta3 = 90 - (thetaHalf + thetaInher); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] - a1, intersectPoint[0] - a2}, new int[]{intersectPoint[1], intersectPoint[1] + b1, intersectPoint[1] - b2}, 3); } else if(thetaInher + thetaHalf > 90) { // A point on the quadrant-respective x or y-axis will be intersecting with // some point inside the arrow head. theta2 = thetaInher - thetaHalf; double thetaPart = 90 - thetaInher; double theta3 = 90 - (thetaHalf - thetaPart); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] - a1, intersectPoint[0] + a2}, new int[]{intersectPoint[1], intersectPoint[1] - b1, intersectPoint[1] - b2}, 3); } else {//In the middle of the quadrant. theta3 = 90 - ((thetaHalf) + thetaInher); theta2 = 90 - (theta3+(thetaHalf*2)); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] - a1, intersectPoint[0] - a2}, new int[]{intersectPoint[1], intersectPoint[1] - b1, intersectPoint[1] - b2}, 3); } return arrow; } /** * This method is called by makeArrow and it returns * a Polygon representing an arrowHead. Based in quadrant 2 * @return returns the Polygon representing the arrowHead * with the proper coordinates for the SlideBrowserPanel. */ private Polygon arrowQuad2() { Polygon arrow = new Polygon(); if(thetaInher - thetaHalf < 90) { theta2 = 90 - (thetaHalf - thetaInher); theta3 = 90 - (thetaHalf + thetaInher); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] - a1, intersectPoint[0] - a2}, new int[]{intersectPoint[1], intersectPoint[1] - b1, intersectPoint[1] + b2}, 3); } else if(thetaInher + thetaHalf > 90) { // A point on the quadrant-respective x or y-axis will be intersecting with // some point inside the arrow head. theta2 = thetaInher - thetaHalf; double thetaPart = 90 - thetaInher; double theta3 = 90 - (thetaHalf - thetaPart); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] - a1, intersectPoint[0] + a2}, new int[]{intersectPoint[1], intersectPoint[1] + b1, intersectPoint[1] + b2}, 3); } else { theta2 = 90 - (thetaHalf); theta3 = 90 - ((thetaHalf*2) + theta2); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] - a1, intersectPoint[0] - a2}, new int[]{intersectPoint[1], intersectPoint[1] + b1, intersectPoint[1] + b2}, 3); } return arrow; } /** * This method is called by makeArrow and it returns * a Polygon representing an arrowHead. Based in quadrant 1 * @return returns the Polygon representing the arrowHead * with the proper coordinates for the SlideBrowserPanel. */ private Polygon arrowQuad1() { Polygon arrow = new Polygon(); if(thetaInher - thetaHalf < 90) { theta2 = 90 - (thetaHalf - thetaInher); theta3 = 90 - (thetaHalf + thetaInher); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] + a1, intersectPoint[0] + a2}, new int[]{intersectPoint[1], intersectPoint[1] - b1, intersectPoint[1] + b2}, 3); } else if(thetaInher + thetaHalf > 90) { // A point on the quadrant-respective x or y-axis will be intersecting with // some point inside the arrow head. theta2 = thetaInher - thetaHalf; double thetaPart = 90 - thetaInher; double theta3 = 90 - (thetaHalf - thetaPart); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] + a1, intersectPoint[0] - a2}, new int[]{intersectPoint[1], intersectPoint[1] + b1, intersectPoint[1] + b2}, 3); } else { theta2 = 90 - (thetaHalf); theta3 = 90 - ((thetaHalf*2) + theta2); theta2 = (theta2*Math.PI)/180; theta3 = (theta3*Math.PI)/180; int a1 = (int) (size*Math.cos(theta2)); int b1 = (int) (size*Math.sin(theta2)); int a2 = (int) (size*Math.cos(theta3)); int b2 = (int) (size*Math.sin(theta3)); arrow = new Polygon(new int[]{intersectPoint[0], intersectPoint[0] + a1, intersectPoint[0] + a2}, new int[]{intersectPoint[1], intersectPoint[1] + b1, intersectPoint[1] + b2}, 3); } return arrow; } /** * Locates the side of the ChildNode's HitBox that the inheritance line intersects * and returns the intersection point of the line and the HitBox. * @param rect represents the ChildNode's HitBox. * @param inherLine the inheritance line that will intersect the HitBox. * @return returns the point where the childNode's HitBox and * its inheritance line intersects. Otherwise, returns an array of -1 values. */ private int[] hitBoxIntersectPoint(Rectangle2D rect, Line2D inherLine) { // System.out.println("HitBox line info\n x: " + rect.getX() + "y: " + rect.getY()); //Make a variable of a line that represents each side of the rectangle. //Case: top of HitBox. Line2D hitBoxSideLine = new Line2D.Double(rect.getX(), rect.getY(), rect.getX()+rect.getHeight(), rect.getY()); // System.out.println("HitBoxSideline info\n x1: " + hitBoxSideLine.getX1() + // " y1: " + hitBoxSideLine.getY1() + // " x2: " + hitBoxSideLine.getX2() + // " y2: " + hitBoxSideLine.getY2()); if(inherLine.intersectsLine(hitBoxSideLine)) { // System.out.println("Intersected top"); return getIntersectPoint(hitBoxSideLine, inherLine); } //Case: left side of HitBox. hitBoxSideLine = new Line2D.Double(rect.getX(), rect.getY(), rect.getX(), rect.getY()+rect.getHeight()); // System.out.println("HitBoxSideline info\n x1: " + hitBoxSideLine.getX1() + // " y1: " + hitBoxSideLine.getY1() + // " x2: " + hitBoxSideLine.getX2() + // " y2: " + hitBoxSideLine.getY2()); if(inherLine.intersectsLine(hitBoxSideLine)) { // System.out.println("Intersected left"); return getIntersectPoint(hitBoxSideLine, inherLine); } //Case: bottom of HitBox. hitBoxSideLine = new Line2D.Double(rect.getX(), rect.getY()+rect.getHeight(), rect.getX()+rect.getHeight(), rect.getY()+rect.getHeight()); // System.out.println("HitBoxSideline info\n x1: " + hitBoxSideLine.getX1() + // " y1: " + hitBoxSideLine.getY1() + // " x2: " + hitBoxSideLine.getX2() + // " y2: " + hitBoxSideLine.getY2()); if(inherLine.intersectsLine(hitBoxSideLine)) { // System.out.println("Intersected bottom"); return getIntersectPoint(hitBoxSideLine, inherLine); } //Case: right side of HitBox. hitBoxSideLine = new Line2D.Double(rect.getX()+rect.getHeight(), rect.getY(), rect.getX()+rect.getHeight(), rect.getY()+rect.getHeight()); // System.out.println("HitBoxSideline info\n x1: " + hitBoxSideLine.getX1() + // " y1: " + hitBoxSideLine.getY1() + // " x2: " + hitBoxSideLine.getX2() + // " y2: " + hitBoxSideLine.getY2()); if(inherLine.intersectsLine(hitBoxSideLine)) { // System.out.println("Intersected right"); return getIntersectPoint(hitBoxSideLine, inherLine); } return new int[]{-1,-1}; } /** * intersectPoint is a static method that takes two lines as an input and * returns their point of intersection. * @return Coordinates of the intersection in the form * of an array. * @param Intakes two Line2D objects that are representative of the * lines that the user wants to find the point of intersection for. */ private int[] getIntersectPoint(Line2D lineOne, Line2D lineTwo) { //point of intersection using (x,y) format. String[] eqnOne = getLineEqn(lineOne); String[] eqnTwo = getLineEqn(lineTwo); // Case: the HitBox line is Vertical, meaning that the // slope will be infinity. if(eqnOne[0] == "vertical") { return getIPHitBoxVertical(lineOne, eqnTwo); } // Case: the inheritance line is vertical, meaning that // its slope will be infinity. if(eqnTwo[0] == "vertical") { return getIpInherVertical(lineTwo, eqnOne); } //The following operations are similar to setting the equations //of two lines equal to each other and then solving for x. double slopeSubtract = Double.parseDouble(eqnOne[0]) - Double.parseDouble(eqnTwo[0]); double yIntSubtract = Double.parseDouble(eqnOne[1]) - Double.parseDouble(eqnTwo[1]); double negateYint = (-1)*yIntSubtract; int x = (int) (negateYint/slopeSubtract); //find the corresponding y-value by plugging x into any of the //equations of the original lines. Simple math. int y = (int) ((Double.parseDouble(eqnOne[0])*x) + Double.parseDouble(eqnOne[1])); return new int[]{x,y}; } /** * Calculates the intersection point of the HitBoxSideLine and the * Inheritance line if the InheritanceLine is vertical. * @param lineTwo the inheritanceLine object. * @param eqnOne the equation of the HitBoxSide line. * @return */ private int[] getIpInherVertical(Line2D lineTwo, String[] eqnOne) { int y = (int) ((Double.parseDouble(eqnOne[0])*lineTwo.getX1()) + Double.parseDouble(eqnOne[1])); return new int[]{(int) lineTwo.getX1(), y}; } /** * Calculates the intersection point between the * inheritanceLine and the HitBoxSideLine when the * HitBoxSideLine is vertical. * @param lineOne the HitBoxLine object. * @param eqnTwo the equation of the Inheritance line. * @return */ private int[] getIPHitBoxVertical(Line2D lineOne, String[] eqnTwo) { int y = (int) ((Double.parseDouble(eqnTwo[0])*lineOne.getX1()) + Double.parseDouble(eqnTwo[1])); return new int[]{(int) lineOne.getX1(), y}; } /** * This method takes in a Line2D object and outputs the equation of the line * in point-slope formula contained in an array of strings. * @param line * @return a string array that contains the point slope equation of * It is important to note that the first element of the array is the slope * and the second element of the array is the yIntercept. * the input param line. */ private String[] getLineEqn(Line2D line) { String[] slopeArray = slope(line); if(slopeArray[0] == "infinity") { return new String[]{"vertical"}; } double slope = Double.parseDouble(slopeArray[0]) / Double.parseDouble(slopeArray[1]); double yIntercept = line.getY1() - (slope*line.getX1()); String[] equation = new String[2]; equation[0] = Double.toString(slope); equation[1] = Double.toString(yIntercept); return equation; } /** * This method takes in a Line2D object and returns its slope. * @param line * @return returns the slope line. */ private String[] slope(Line2D line) { //Take the sum of each of the end points //in order to compare them to each other. // double sumCoordOne = line.getX1() + line.getY1(); // double sumCoordTwo = line.getX2() + line.getY2(); String[] slope = new String[2]; //We need to find the maximum end point of the line segment //with respect to Java's coordinate system. //Once it is found, we then calculate the slope of the //line segment based on the max end point. // if(sumCoordOne > sumCoordTwo) { String rise = Double.toString(line.getY1() - line.getY2()); String run = Double.toString(line.getX1() - line.getX2()); slope[0] = rise; slope[1] = run; if(run.compareTo("0.0") == 0) { return new String[]{"infinity", "infinity"}; } //TODO: System.out.println("rise: " + slope[0] + "\nrun: " + slope[1]); // } // else if(sumCoordOne < sumCoordTwo) { // slope[0] = (line.getY2() - line.getY1()); // slope[1] = (line.getX2() - line.getX1()); // System.out.println("rise: " + slope[0] + "\nrun: " + slope[1]); // } else { // slope = new double[]{-1,-1}; // } theQuadrant(slope); return slope; //If the line is horizontal, then the slope will be 0. } private void theQuadrant(String[] slope) { if(Double.parseDouble(slope[0]) >= 0) { if(Double.parseDouble(slope[1]) >= 0) { //any x+ is part of quad 1. //origin is part of quad 1. quadrant = 4; } else { // any x- is part of quad2. quadrant = 3; } } else if(Double.parseDouble(slope[0]) < 0) { if(Double.parseDouble(slope[1]) < 0) { quadrant = 2; } else { //y- and x+ are parts of quadrant 4. quadrant = 1; } } } /** * Calculate the value of the instance variable theta_1. * theta_1 represents the angle between the inheritance line and * the coordinate system with the origin on the intersection point * of the inherLine and the HitBox. * @return value of theta_1. */ private double getTheta_1(Line2D inherLine) { String[] slopeArray = slope(inherLine); double theta_1; try { theta_1 = Math.abs(Math.atan(Double.parseDouble(slopeArray[0])/Double.parseDouble(slopeArray[1]))); } catch (NumberFormatException e) { theta_1 = Double.MAX_VALUE; } return theta_1; } // public static void main(String[] args){ // CalculateArrowHead calc = new CalculateArrowHead(); // Line2D.Double lineOne = new Line2D.Double(12, 5, 20, 14); // Line2D.Double lineTwo = new Line2D.Double(12, 11, 19, 6); // int[] pt = calc.getIntersectPoint(lineOne, lineTwo); // System.out.println("x: " + pt[0] + "\ny: " + pt[1]); // } }