/* Chris Poon
 * Burnett Honors College Summer Institute
 *
 *Homework #2 - Route Solution
 *
 *This file contains 3 classes,
 *Point, Route, and HW2.
 *
 *Point and Route are those specified in the assignment, while HW2
 *is the actual object for executing the program.
 *
 *Point is the same as from assignment #1 except for two new public
 * methods getX() and getY() that returns the respective coordinate.
 *This was made since x,y are private fields of Point.
 *
 * */


import java.io.*;
import java.lang.Math;

class Point
{
        //the Point object representing a Cartesian point.
    
	int x,y;		//represents the actual coordinates of this Point object.

	public Point(){
		//Default constructor -sets Point to "origin"
		x=0; y=0;
	}
	public Point(int a, int b){
		//Constructor to set coordinates to parameters.
		x=a; y=b;
	}
	public double distanceTo(Point other){
		//Public method to return the distance as a double between _this_ 
		//point and parameter _other_

		return Math.sqrt( (x-other.x)*(x-other.x) + (y-other.y)*(y-other.y) );
	}
	public String directionTo(Point other){
		//Public method to return a string representing the direction from
		// _this_ Point and the parameter _other_

		String direction="";
		if (other.y>y) direction="N";			//if-else since only North XOR South
		else if (other.y<y) direction="S";

		if (other.x>x) direction+="E";			//if-else since only East XOR West
		else if (other.x<x) direction+="W";

		return direction;
	}
	public String toString(){
		//public method to return a String object representing _this_ Point.
		//  provided so there is an easy and appropriate way to output the object

		return ("(" + x + "," + y + ")");
	}
        public int getX(){
            //public method to return the x coordinate (int) of this object.
            return x;
        }
        public int getY(){
            //public method to return the y coordinate (int) of this object.
            return y;
        }
}

class Route{
    // The Route object: basically a line segment, composed of 2 points (below)
    Point one;          //the first point of the Route
    Point two;          //the second point of the Route
    
    public Route(){
        // The default constructor that will instanciate
        //  the points via their default constructor.
        one=new Point();
        two=new Point();
    }
    public Route(int x1, int y1, int x2, int y2){
        // The primary constructor that instanciates the points
        //  to the parameter coordinates.
        // Alternatively, it might be preferable to have a constructor
        //  that receives two Point objects.
        one=new Point(x1,y1);
        two=new Point(x2,y2);
    }
    public Point midpoint(){
        //The public method to return a new Point object that
        //  is the midpoint of _this_ Route.
        int x1,y1,x2,y2;
        
        x1=one.getX();      //These 4 statements retrieve the
        y1=one.getY();      // coordinates of the points
        x2=two.getX();      // since they cannot be accessed
        y2=two.getY();      // directly (ie., one.x is illegal).
        
        return (new Point( ((x1+x2)/2), ((y1+y2)/2) ));
    }
    public double interceptTo(Route target){
        //The public method to return a double containing the
        //  distance between the midpoint of _this_ Route and _target_
        Point midpt1=midpoint();            //Get the midpoints
        Point midpt2=target.midpoint();
                
        return (midpt1.distanceTo(midpt2)); //Return the distance.
    }
    public double angleBetween(Route target){
        //The public method that returns the angle between _this_
        //  Route and _target_ and specified in the assignment.
        //Note there were two methods of approach:
        // The first is a shift of the target line, meaning
        //  we find the offset of target.one to this.one
        //  We then apply this offset to target.two to create
        //  where target.two would be if target was shifted
        //  to share its first point with _this_.
        // Thus, we get a triangle to apply the Law of Cosines to.
        
        int shiftx=target.one.getX()-one.getX();    //the x offset/shift
        int shifty=target.one.getY()-one.getY();    //the y offset/shift
        int newx=target.two.getX()-shiftx;          //the resulting x
                                                    //coordinate of a shifted
                                                    //target.two.
        
        int newy=target.two.getY()-shifty;          //the resulting y
                                                    //coordinate of a shifted
                                                    //target.two.
        
        Point temp=new Point(newx,newy);            //the Point to represent
                                                    // where target.two ends up.
        
        double a,b,c,A;                             //the variables of the
                                                    //triang for Law of Cosines
        
                
        a=temp.distanceTo(two);                 //set the sides of the triangle
        b=one.distanceTo(two);
        c=target.one.distanceTo(target.two);
        
        A= -(a*a-b*b-c*c)/(2*b*c);              //solve for A via Law of Cosines
        A= Math.acos(A);
        
        //Below is the alternative method that involves vectors.
        //Basically, a vector is a ray that starts anywhere you want it to.
        // All that matters is the length and direction, which is described
        // via i,j; i being how far "right" it goes, and j how far "north"
        // it goes.  For example, a vector 3i+4j would represent a vector
        // that goes from the "origin" 3 units to the right, and 4 units up.
        //One of the most important aspects of vectors is that their
        // origin doesnt matter, so they can be shifted around to one's
        // content.
        //Relative to this assignment, vectors provide an easy method
        // to find the angle between two vectors.
        //It has been proven that to find the angle, A,  between two
        // vectors, a and b:
        // a@b=|a|*|b|*cos(A) where @ is the dot product and |a| is
        //  the magnitude (length) of a.
        // The dot product is defined as the sum of the multiplications
        //  of the respective components of a vector.  That is, say
        //  a=3i+4j and b=1i+6j, then a@b is (3*1)+(4*6)=72. 
        //So now that we have the formula, we can solve for the angle A:
        // A = arccos( (a@b)/(|a|*|b|)).
        
        /*
        double i1,i2,j1,j2;
        i1=two.getX()-one.getX();                //these lines break down
        i2=target.two.getX()-target.one.getX();  //the routes into their
        j1=two.getY()-one.getY();                //vector components.
        j2=target.two.getY()-target.one.getY();  //
        
        double len1=one.distanceTo(two);         //these are the magnitudes
        double len2=target.one.distanceTo(target.two); //of the vectors
        
        double A=i1*i2+j1*j2;                    //the dot product.
        A/=(len1*len2);                          //divide by magnitudes.
        A=Math.acos(A);                          //take the arccosine.
                                                 // ta-da.
            
         */
        
        return A;                   //returns a double, the angle A
    }
}

public class HW2{
    //The object to represent and execute our homework.
    // Again, our main only instanciates the HW object, whose
    //  constructor takes care of the everything.
    
    Route rt1;      //The route objects that will be inputted/analyzed.
    Route rt2;
    public HW2() throws IOException{
        //The constructor that calls a helper method to set the routes.
        //  It then outputs the desired calcuations directly.
        PrintWriter output=new PrintWriter(new FileWriter("out.txt"));
        
        setupRts();
        
        output.println(rt1.interceptTo(rt2));
        output.println(Math.toDegrees(rt1.angleBetween(rt2)));
        
        output.close();
    }
    void setupRts() throws IOException{
        //private helper method that reads the input from the file
        // and instanciates the Routes respectively.
        int x1,y1,x2,y2;
        BufferedReader input=new BufferedReader(new FileReader("in.txt"));
        
        for (int c=0;c<2;c++){
            //This for loop goes twice, once for each route.
            // At each iteration, it reads 4 integers
            // and instanciates the appropriate Route.
            x1=Integer.parseInt(input.readLine());
            y1=Integer.parseInt(input.readLine());
            x2=Integer.parseInt(input.readLine());
            y2=Integer.parseInt(input.readLine());
            
            //Note while that this works, it is somewhat sloppy
            // since I would have to change a whole mess
            // of things if I wanted to change the number of routes
            // inputted.  Remember, think re-usability!
            if (c==0)
                rt1=new Route(x1,y1,x2,y2);
            else
                rt2=new Route(x1,y1,x2,y2);
        }
        input.close();      //closes the input file
    }
    
    public static void main(String args[]) throws IOException{
        //Again, the main serves only to instantiate our HW2 object
        HW2 test=new HW2();
    }
}
