content: package edu.stanford.rsl.conrad.geometry.shapes.simple;
  
  import java.util.ArrayList;
  
  import edu.stanford.rsl.conrad.geometry.AbstractCurve;
  import edu.stanford.rsl.conrad.geometry.AbstractShape;
  import edu.stanford.rsl.conrad.geometry.transforms.Transform;
  import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
  import edu.stanford.rsl.conrad.numerics.SimpleOperators;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  import edu.stanford.rsl.conrad.numerics.Solvers;
  import edu.stanford.rsl.conrad.utils.CONRAD;
  
  public class StraightLine extends AbstractCurve {
  
  	private static final long serialVersionUID = 4615305861839196846L;
  	protected SimpleVector direction;
  	protected PointND point;
  	
  	/**
  	 * Creates a StraightLine from point with direction dir 
  	 * @param point the point
  	 * @param dir the direction
  	 */
  	public StraightLine(PointND point, SimpleVector dir){
  		this.direction = dir;
  		this.point = point;
  	}
  	
  	public StraightLine(StraightLine sl){
  		super(sl);
  		direction = (sl.direction != null) ? sl.direction.clone() : null;
  		point = (sl.point != null) ? sl.point.clone() : null;
  	}
  	
  	public void init(PointND point, SimpleVector dir){
  		this.direction = dir;
  		this.point = point;
  	}
  
  	/**
  	 * Creates a new Straight line passing from point to point2
  	 * @param point the base point
  	 * @param point2 the other point
  	 */
  	public StraightLine(PointND point, PointND point2){
  		this.direction = SimpleOperators.subtract(point2.getAbstractVector(), point.getAbstractVector());
  		this.point = point;
  	}
  	
  	public void init(PointND point, PointND point2){
  		this.direction = SimpleOperators.subtract(point2.getAbstractVector(), point.getAbstractVector());
  		this.point = point;
  	}
  
  	public void normalize(){
  		direction.normalizeL2();
  	}
  	
  	@Override
  	public PointND evaluate(double u) {
  		return new PointND(SimpleOperators.add(point.getAbstractVector(), direction.multipliedBy(u)));
  	}
  
  	@Override
  	public int getDimension() {
  		return point.getDimension();
  	}
  
  	protected SimpleVector computeIntersectionCoefficients(StraightLine l2){
  		SimpleVector b = SimpleOperators.subtract(l2.point.getAbstractVector(), point.getAbstractVector());
  		SimpleMatrix A = new SimpleMatrix(3, 2);
  		A.setColValue(0, direction);
  		A.setColValue(1, l2.direction);
  		return Solvers.solveLinearLeastSquares(A, b);
  	}
  	
  	@Override
  	public ArrayList<PointND> intersect(AbstractCurve other) {
  		if (other instanceof StraightLine) {
  			StraightLine l2 = (StraightLine) other;
  			ArrayList<PointND> list = new ArrayList<PointND>();
  			PointND i = intersect(l2);
  			if (i != null)
  				list.add(i);
  			
  			return list;
  
  		} else {
  			throw new RuntimeException("This curve is not supported yet");
  		}
  	}
  	
  	public PointND intersect(StraightLine line){
  		return intersect(line, CONRAD.SMALL_VALUE*1000);
  	}
  	
  	public PointND intersect(StraightLine line, double threshold){
  		SimpleVector lambda = computeIntersectionCoefficients(line);
  		PointND p1 = evaluate(lambda.getElement(0));
  		PointND p2 = line.evaluate(-lambda.getElement(1));
  		if (p1 != null) {
  			if (p1.euclideanDistance(p2) < threshold){
  				return p1;
  			} 	
  		}
  		return null;
  	}
  
  	/**
  	 * @return the direction
  	 */
  	public SimpleVector getDirection() {
  		return direction;
  	}
  
  	/**
  	 * @param direction the direction to set
  	 */
  	public void setDirection(SimpleVector direction) {
  		this.direction = direction;
  	}
  
  	/**
  	 * @return the point
  	 */
  	public PointND getPoint() {
  		return new PointND(point);
  	}
  
  	/**
  	 * @param point the point to set
  	 */
  	public void setPoint(PointND point) {
  		this.point = point;
  	}
  
  	@Override
  	public boolean isBounded() {
  		return false;
  	}
  
  	/**
  	 * Computes the closest distance between the line and the point p.
  	 * @param p the point p
  	 * @return the distance
  	 */
  	public double computeDistanceTo(PointND p) {
  		SimpleVector vector = SimpleOperators.subtract(point.getAbstractVector(), p.getAbstractVector());
  		double projectionValue = SimpleOperators.multiplyInnerProd(vector, direction);
  		return p.euclideanDistance(evaluate(projectionValue));
  	}
  
  	@Override
  	public void applyTransform(Transform t) {
  		point = t.transform(point);
  		direction = t.transform(direction);
  	}
  
  	@Override
  	public PointND[] getRasterPoints(int number) {
  		return null;
  	}
  	
  	@Override
  	public String toString(){
  		return point + " + n * " + direction;
  	}
  
  	@Override
  	public AbstractShape clone() {
  		return new StraightLine(this);
  	}
  
  
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier, Rotimi X Ojo 
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */