/* * 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. * * RationalVector.java * * Created on 1. Februar 2003, 09:16 */ package geometry.planar; import java.math.BigInteger; import datastructures.BigIntAux; import datastructures.Signum; /** * * Analog RationalPoint, but implementing the functionality * of a Vector instead of the functionality of a Point. * * @author Alfons Wirtz */ public class RationalVector extends Vector implements java.io.Serializable { /** * creates a RetionalVector from 3 BigIntegers p_x, p_y and p_z. * They represent the 2-dimensional Vector with the * rational number Tuple ( p_x / p_z , p_y / p_z). */ public RationalVector(BigInteger p_x, BigInteger p_y, BigInteger p_z) { if (p_z.signum() >= 0) { x = p_x; y = p_y; z = p_z; } else { x = p_x.negate(); y = p_y.negate(); z = p_z.negate(); } } /** * creates a RetionalVector from an IntVector */ RationalVector(IntVector p_vector) { x = BigInteger.valueOf(p_vector.x); y = BigInteger.valueOf(p_vector.y); z = BigInteger.ONE; } /** * returns true, if the x and y coordinates of this vector are 0 */ public final boolean is_zero() { return x.signum() == 0 && y.signum() == 0; } /** * returns true, if this RationalVector is equal to p_ob */ public final boolean equals( Object p_ob ) { if ( this == p_ob ) { return true; } if ( p_ob == null ) { return false; } if ( getClass() != p_ob.getClass() ) { return false ; } RationalPoint other = (RationalPoint)p_ob; BigInteger det = BigIntAux.determinant(x, other.x, z, other.z); if (det.signum() != 0) { return false; } det = BigIntAux.determinant(y, other.y, z, other.z); return (det.signum() == 0); } /** * returns the Vector such that this plus this.minus() is zero */ public Vector negate() { return new RationalVector(x.negate(), y.negate(), z); } /** * adds p_other to this vector */ public final Vector add( Vector p_other) { return p_other.add(this); } /** * 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 Side side_of(Vector p_other) { Side tmp = p_other.side_of(this); return tmp.negate(); } public boolean is_orthogonal() { return (x.signum() == 0 || y.signum() == 0); } public boolean is_diagonal() { return x.abs().equals(y.abs()); } /** * The function returns * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, * Signum.NEGATIVE, if the scalar product is < 0, * and Signum.ZERO, if the scalar product is equal 0. */ public Signum projection(Vector p_other) { return p_other.projection(this); } /** * calculates the scalar product of this vector and p_other */ public double scalar_product(Vector p_other) { return p_other.scalar_product(this); } /** * approximates the coordinates of this vector by float coordinates */ public FloatPoint to_float() { double xd = x.doubleValue(); double yd = y.doubleValue(); double zd = z.doubleValue(); return new FloatPoint( xd / zd, yd / zd); } public Vector change_length_approx(double p_lenght) { System.out.println("RationalVector: change_length_approx not yet implemented"); return this; } public Vector turn_90_degree(int p_factor) { int n = p_factor; while (n < 0) { n += 4; } while (n >= 4) { n -= 4; } BigInteger new_x ; BigInteger new_y ; switch (n) { case 0: // 0 degree new_x = x; new_y = y; break; case 1: // 90 degree new_x = y.negate(); new_y = x ; break; case 2: // 180 degree new_x = x.negate() ; new_y = y.negate() ; break; case 3: // 270 degree new_x = y ; new_y = x.negate() ; break; default: return this; } return new RationalVector(new_x, new_y, this.z); } public Vector mirror_at_y_axis() { return new RationalVector(this.x.negate(), this.y, this.z); } public Vector mirror_at_x_axis() { return new RationalVector(this.x, this.y.negate(), this.z); } Direction to_normalized_direction() { BigInteger dx = x; BigInteger dy = y; BigInteger gcd = dx.gcd(y); dx = dx.divide(gcd); dy = dy.divide(gcd); if ( (dx.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && (dy.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) { return new IntDirection(dx.intValue(), dy.intValue()); } return new BigIntDirection(dx, dy); } double scalar_product(IntVector p_other) { Vector other = new RationalVector(p_other); return other.scalar_product(this); } double scalar_product(RationalVector p_other) { FloatPoint v1 = to_float(); FloatPoint v2 = p_other.to_float(); return v1.x * v2.x + v1.y * v2.y; } Signum projection(IntVector p_other) { Vector other = new RationalVector(p_other); return other.projection(this); } Signum projection(RationalVector p_other) { BigInteger tmp1 = x.multiply(p_other.x); BigInteger tmp2 = y.multiply(p_other.y); BigInteger tmp3 = tmp1.add(tmp2); int result = tmp3.signum(); return Signum.of(result); } final Vector add(IntVector p_other) { RationalVector other = new RationalVector(p_other); return add(other); } final Vector add(RationalVector p_other) { BigInteger v1[] = new BigInteger[3]; v1[0] = x; v1[1] = y; v1[2] = z; BigInteger v2[] = new BigInteger[3]; v2[0] = p_other.x; v2[1] = p_other.y; v2[2] = p_other.z; BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); return new RationalVector(result[0], result[1], result[2]); } Point add_to(IntPoint p_point) { BigInteger new_x = z.multiply(BigInteger.valueOf(p_point.x)); new_x = new_x.add(x); BigInteger new_y = z.multiply(BigInteger.valueOf(p_point.y)); new_y = new_y.add(y); return new RationalPoint(new_x, new_y, z); } Point add_to(RationalPoint p_point) { BigInteger v1[] = new BigInteger[3]; v1[0] = x; v1[1] = y; v1[2] = z; BigInteger v2[] = new BigInteger[3]; v2[0] = p_point.x; v2[1] = p_point.y; v2[2] = p_point.z; BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); return new RationalPoint(result[0], result[1], result[2]); } Side side_of(IntVector p_other) { RationalVector other = new RationalVector(p_other); return side_of(other); } Side side_of(RationalVector p_other) { BigInteger tmp_1 = y.multiply(p_other.x); BigInteger tmp_2 = x.multiply(p_other.y); BigInteger determinant = tmp_1.subtract(tmp_2); int signum = determinant.signum(); return Side.of(signum); } public final BigInteger x; public final BigInteger y; public final BigInteger z; }