/*
* Copyright (C) 2014 Alfons Wirtz
* website www.freerouting.net
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License at <http://www.gnu.org/licenses/>
* for more details.
*
* Vector.java
*
* Created on 1. Februar 2003, 14:28
*/
package geometry.planar;
import java.math.BigInteger;
import datastructures.Signum;
/**
* Abstract class describing functionality of Vectors.
* Vectors are used for translating Points in the plane.
*
* @author Alfons Wirtz
*/
public abstract class Vector implements java.io.Serializable
{
/**
* returns true, if this vector is equal to the zero vector.
*/
public abstract boolean is_zero();
/**
* returns the Vector such that this plus this.negate() is zero
*/
public abstract Vector negate();
/**
* adds p_other to this vector
*/
public abstract Vector add( Vector p_other);
/**
* Let L be the line from the Zero Vector to p_other.
* The function returns
* Side.ON_THE_LEFT, if this Vector is on the left of L
* Side.ON_THE_RIGHT, if this Vector is on the right of L
* and Side.COLLINEAR, if this Vector is collinear with L.
*/
public abstract Side side_of(Vector p_other);
/**
* returns true, if the vector is horizontal or vertical
*/
public abstract boolean is_orthogonal();
/**
* returns true, if the vector is diagonal
*/
public abstract boolean is_diagonal();
/**
* Returns true, if the vector is orthogonal or diagonal
*/
public boolean is_multiple_of_45_degree()
{
return is_orthogonal() || is_diagonal();
}
/**
* The function returns
* Signum.POSITIVE, if the scalar product of this vector and p_other > 0,
* Signum.NEGATIVE, if the scalar product Vector is < 0,
* and Signum.ZERO, if the scalar product is equal 0.
*/
public abstract Signum projection(Vector p_other);
/**
* Returns an approximation of the scalar product of this vector
* with p_other by a double.
*/
public abstract double scalar_product(Vector p_other);
/**
* approximates the coordinates of this vector by float coordinates
*/
public abstract FloatPoint to_float();
/**
* Turns this vector by p_factor times 90 degree.
*/
public abstract Vector turn_90_degree(int p_factor);
/**
* Mirrors this vector at the x axis.
*/
public abstract Vector mirror_at_x_axis();
/**
* Mirrors this vector at the y axis.
*/
public abstract Vector mirror_at_y_axis();
/**
* Standard implementation of the zero vector .
*/
public static final IntVector ZERO = new IntVector(0, 0);
/**
* Creates a Vector (p_x, p_y) in the plane.
*/
public static Vector get_instance(int p_x, int p_y)
{
IntVector result = new IntVector(p_x, p_y);
if ( Math.abs(p_x) > Limits.CRIT_INT ||
Math.abs(p_x) > Limits.CRIT_INT )
{
return new RationalVector(result);
}
return result;
}
/**
* Creates a 2-dimensinal Vector from the 3 input values.
* If p_z != 0 it correspondents to the Vector in the plane
* with rational number coordinates (p_x / p_z, p_y / p_z).
*/
public static Vector get_instance(BigInteger p_x, BigInteger p_y,
BigInteger p_z)
{
if (p_z.signum() < 0)
{
// the dominator z of a RationalVector is expected to be positive
p_x = p_x.negate();
p_y = p_y.negate();
p_z = p_z.negate();
}
if ((p_x.mod(p_z)).signum() == 0 && (p_x.mod(p_z)).signum() == 0)
{
// p_x and p_y can be divided by p_z
p_x = p_x.divide(p_z);
p_y = p_y.divide(p_z);
p_z = BigInteger.ONE;
}
if (p_z.equals(BigInteger.ONE))
{
if ( (p_x.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 &&
(p_y.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 )
{
// the Point fits into an IntPoint
return new IntVector(p_x.intValue(), p_y.intValue());
}
}
return new RationalVector(p_x, p_y, p_z);
}
/**
* returns an approximation of the euclidian length of this vector
*/
public double length_approx()
{
return this.to_float().size();
}
/**
* Returns an approximation of the cosinus of the angle
* between this vector and p_other by a double.
*/
public double cos_angle(Vector p_other)
{
double result = this.scalar_product(p_other);
result /= this.to_float().size() * p_other.to_float().size();
return result;
}
/**
* Returns an approximation of the signed angle between this vector and p_other.
*/
public double angle_approx(Vector p_other)
{
double result = Math.acos(cos_angle(p_other));
if (this.side_of(p_other) == Side.ON_THE_LEFT)
{
result = - result;
}
return result;
}
/**
* Returns an approximation of the signed angle between this vector and the x axis.
*/
public double angle_approx()
{
Vector other = new IntVector(1, 0);
return other.angle_approx(this);
}
/**
* Returns an approximation vector of this vector with the same direction and
* length p_length.
*/
public abstract Vector change_length_approx(double p_lenght);
abstract Direction to_normalized_direction();
// auxiliary functions needed because the virtual function mechanism
// does not work in parameter position
abstract Vector add( IntVector p_other);
abstract Vector add( RationalVector p_other);
abstract Point add_to(IntPoint p_point);
abstract Point add_to(RationalPoint p_point);
abstract Side side_of(IntVector p_other);
abstract Side side_of(RationalVector p_other);
abstract Signum projection(IntVector p_other);
abstract Signum projection(RationalVector p_other);
abstract double scalar_product(IntVector p_other);
abstract double scalar_product(RationalVector p_other);
}