/* * 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. * * RationalPoint.java * * Created on 1. Februar 2003, 13:12 */ package geometry.planar; import java.math.BigInteger; import datastructures.BigIntAux; /** * * Implementation of points in the projective plane represented by * 3 coordinates x, y, z, which are infinite precision integers. * Two projective points (x1, y1, z1) and (x2, y2 z2) are equal, * if they are located on the same line through the zero point, * that means, there exist a number r with x2 = r*x1, * y2 = r*y1 and z2 = r*z1. * The affine Point with rational coordinates represented by * the projective Point (x, y, z) is (x/z, y/z). * The projective plane with integer coordinates contains in * addition to the affine plane with rational coordinates the * so-called line at infinity, which consist of * all projective points (x, y, z) with z = 0. * * @author Alfons Wirtz */ public class RationalPoint extends Point implements java.io.Serializable { /** * approximates the coordinates of this point by float coordinates */ public FloatPoint to_float() { double xd = x.doubleValue(); double yd = y.doubleValue(); double zd = z.doubleValue(); if (zd == 0) { xd = Float.MAX_VALUE; yd = Float.MAX_VALUE; } else { xd /= zd; yd /= zd; } return new FloatPoint( xd, yd); } /** * returns true, if this RationalPoint 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); } public boolean is_infinite() { return z.signum() == 0; } public IntBox surrounding_box() { FloatPoint fp = to_float(); int llx = (int) Math.floor(fp.x); int lly = (int) Math.floor(fp.y); int urx = (int) Math.ceil(fp.x); int ury = (int) Math.ceil(fp.y); return new IntBox(llx, lly, urx, ury); } public IntOctagon surrounding_octagon() { FloatPoint fp = to_float(); int lx = (int) Math.floor(fp.x); int ly = (int) Math.floor(fp.y); int rx = (int) Math.ceil(fp.x); int uy = (int) Math.ceil(fp.y); double tmp = fp.x - fp.y; int ulx = (int) Math.floor(tmp); int lrx = (int) Math.ceil(tmp); tmp = fp.x + fp.y; int llx = (int) Math.floor(tmp); int urx = (int) Math.ceil(tmp); return new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); } public boolean is_contained_in(IntBox p_box) { BigInteger tmp = BigInteger.valueOf(p_box.ll.x).multiply(z); if (x.compareTo(tmp) < 0) { return false; } tmp = BigInteger.valueOf(p_box.ll.y).multiply(z); if (y.compareTo(tmp) < 0) { return false; } tmp = BigInteger.valueOf(p_box.ur.x).multiply(z); if (x.compareTo(tmp) > 0) { return false; } tmp = BigInteger.valueOf(p_box.ur.y).multiply(z); if (y.compareTo(tmp) > 0) { return false; } return true; } /** * returns the translation of this point by p_vector */ public Point translate_by(Vector p_vector) { if (p_vector.equals(Vector.ZERO)) { return this; } return p_vector.add_to(this) ; } Point translate_by(IntVector p_vector) { RationalVector vector = new RationalVector(p_vector); return translate_by(vector); } Point translate_by(RationalVector p_vector) { BigInteger v1[] = new BigInteger[3]; v1[0] = x; v1[1] = y; v1[2] = z; BigInteger v2[] = new BigInteger[3]; v2[0] = p_vector.x; v2[1] = p_vector.y; v2[2] = p_vector.z; BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); return new RationalPoint(result[0], result[1], result[2]); } /** * returns the difference vector of this point and p_other */ public Vector difference_by(Point p_other) { Vector tmp = p_other.difference_by(this); return tmp.negate(); } Vector difference_by(IntPoint p_other) { RationalPoint other = new RationalPoint(p_other); return difference_by(other); } Vector difference_by(RationalPoint 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.negate(); v2[1] = p_other.y.negate(); v2[2] = p_other.z; BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); return new RationalVector(result[0], result[1], result[2]); } /** * The function returns * Side.ON_THE_LEFT, if this Point is on the left * of the line from p_1 to p_2; * Side.ON_THE_RIGHT, if this Point is on the right * f the line from p_1 to p_2; * and Side.COLLINEAR, if this Point is collinear with p_1 and p_2. */ public Side side_of(Point p_1, Point p_2) { Vector v1 = difference_by(p_1); Vector v2 = p_2.difference_by(p_1); return v1.side_of(v2); } public Side side_of(Line p_line) { return side_of(p_line.a, p_line.b); } public Point perpendicular_projection(Line p_line) { // this function is at the moment only implemented for lines // consisting of IntPoints. // The general implementation is still missing. IntVector v = (IntVector)p_line.b.difference_by(p_line.a); BigInteger vxvx = BigInteger.valueOf((long)v.x * v.x); BigInteger vyvy = BigInteger.valueOf((long)v.y * v.y); BigInteger vxvy = BigInteger.valueOf((long) v.x * v.y); BigInteger denominator = vxvx.add(vyvy); BigInteger det = BigInteger.valueOf(((IntPoint)p_line.a).determinant((IntPoint)p_line.b)); BigInteger tmp1 = vxvx.multiply(x); BigInteger tmp2 = vxvy.multiply(y); tmp1 = tmp1.add(tmp2); tmp2 = det.multiply(BigInteger.valueOf(v.y)); tmp2 = tmp2.multiply(z); BigInteger proj_x = tmp1.add(tmp2); tmp1 = vxvy.multiply(x); tmp2 = vyvy.multiply(y); tmp1 = tmp1.add(tmp2); tmp2 = det.multiply(BigInteger.valueOf(v.x)); tmp2 = tmp2.multiply(z); BigInteger proj_y = tmp1.add(tmp2); int signum = denominator.signum(); if (signum != 0) { if (signum < 0) { denominator = denominator.negate(); proj_x = proj_x.negate(); proj_y = proj_y.negate(); } if ((proj_x.mod(denominator)).signum() == 0 && (proj_y.mod(denominator)).signum() == 0) { proj_x = proj_x.divide(denominator); proj_y = proj_y.divide(denominator); if (proj_x.abs().compareTo(Limits.CRIT_INT_BIG) <= 0 && proj_y.abs().compareTo(Limits.CRIT_INT_BIG) <= 0) { return new IntPoint(proj_x.intValue(), proj_y.intValue()); } denominator = BigInteger.ONE; } } return new RationalPoint(proj_x, proj_y, denominator); } public int compare_x(Point p_other) { return -p_other.compare_x(this); } public int compare_y(Point p_other) { return -p_other.compare_y(this); } int compare_x(RationalPoint p_other) { BigInteger tmp1 = this.x.multiply(p_other.z); BigInteger tmp2 = p_other.x.multiply(this.z); return tmp1.compareTo(tmp2); } int compare_y(RationalPoint p_other) { BigInteger tmp1 = this.y.multiply(p_other.z); BigInteger tmp2 = p_other.y.multiply(this.z); return tmp1.compareTo(tmp2); } int compare_x(IntPoint p_other) { BigInteger tmp1 = this.z.multiply(BigInteger.valueOf(p_other.x)); return this.x.compareTo(tmp1); } int compare_y(IntPoint p_other) { BigInteger tmp1 = this.z.multiply(BigInteger.valueOf(p_other.y)); return this.y.compareTo(tmp1); } /** * creates a RetionalPoint from 3 BigIntegers p_x, p_y and p_z. * They represent the 2-dimensinal point with the * rational number Tuple ( p_x / p_z , p_y / p_z). * Throws IllegalArgumentException if denominator p_z is <= 0 */ RationalPoint(BigInteger p_x, BigInteger p_y, BigInteger p_z) { x = p_x; y = p_y; z = p_z; if (p_z.signum() < 0) { throw new IllegalArgumentException ("RationalPoint: p_z is expected to be >= 0"); } } /** * creates a RetionalPoint from an IntPoint */ RationalPoint(IntPoint p_point) { x = BigInteger.valueOf(p_point.x); y = BigInteger.valueOf(p_point.y); z = BigInteger.ONE; } final BigInteger x; final BigInteger y; final BigInteger z; }