/* * 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. * * IntPoint.java * * Created on 1. Februar 2003, 10:31 */ package geometry.planar; import java.math.BigInteger; /** * Implementation of the abstract class Point * as a tuple of integers. * * * @author Alfons Wirtz */ public class IntPoint extends Point implements java.io.Serializable { /** * create an IntPoint from two integer coordinates */ public IntPoint(int p_x, int p_y) { if (Math.abs(p_x) > Limits.CRIT_INT || Math.abs(p_y) > Limits.CRIT_INT) { System.out.println("Warning in IntPoint: p_x or p_y to big"); } x = p_x; y = p_y; } /** * Returns true, if this IntPoint 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 ; } IntPoint other = (IntPoint)p_ob ; return ( x == other.x && y == other.y ) ; } public boolean is_infinite() { return false; } public IntBox surrounding_box() { return new IntBox(this, this); } public IntOctagon surrounding_octagon() { int tmp_1 = x - y; int tmp_2 = x + y; return new IntOctagon(x, y, x, y, tmp_1, tmp_1, tmp_2, tmp_2); } public boolean is_contained_in(IntBox p_box) { return x >= p_box.ll.x && y >= p_box.ll.y && x <= p_box.ur.x && y <= p_box.ur.y; } /** * returns the translation of this point by p_vector */ public final 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 ) { return ( new IntPoint( x + p_vector.x, y + p_vector.y ) ) ; } Point translate_by( RationalVector p_vector ) { return p_vector.add_to(this); } /** * 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(RationalPoint p_other) { Vector tmp = p_other.difference_by(this); return tmp.negate(); } IntVector difference_by(IntPoint p_other) { return new IntVector(x - p_other.x, y - p_other.y); } public Side side_of(Line p_line) { Vector v1 = difference_by(p_line.a); Vector v2 = p_line.b.difference_by(p_line.a); return v1.side_of(v2); } /** * converts this point to a FloatPoint. */ public FloatPoint to_float() { return new FloatPoint(x, y); } /** * returns the determinant of the vectors (x, y) and (p_other.x, p_other.y) */ public final long determinant(IntPoint p_other) { return (long)x * p_other.y - (long)y * p_other.x; } 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 point_x = BigInteger.valueOf(x); BigInteger point_y = BigInteger.valueOf(y); BigInteger tmp1 = vxvx.multiply(point_x); BigInteger tmp2 = vxvy.multiply(point_y); tmp1 = tmp1.add(tmp2); tmp2 = det.multiply(BigInteger.valueOf(v.y)); BigInteger proj_x = tmp1.add(tmp2); tmp1 = vxvy.multiply(point_x); tmp2 = vyvy.multiply(point_y); tmp1 = tmp1.add(tmp2); tmp2 = det.multiply(BigInteger.valueOf(v.x)); BigInteger proj_y = tmp1.subtract(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); return new IntPoint(proj_x.intValue(), proj_y.intValue()); } } return new RationalPoint(proj_x, proj_y, denominator); } /** * Returns the signed area of the parallelogramm spanned by the vectors * p_2 - p_1 and this - p_1 */ public double signed_area( IntPoint p_1, IntPoint p_2 ) { IntVector d21 = (IntVector) p_2.difference_by(p_1) ; IntVector d01 = (IntVector) this.difference_by(p_1) ; return d21.determinant(d01) ; } /** * calculates the square of the distance between this point and p_to_point */ public double distance_square(IntPoint p_to_point) { double dx = p_to_point.x - this.x; double dy = p_to_point.y - this.y; return dx * dx + dy * dy; } /** * calculates the distance between this point and p_to_point */ public double distance(IntPoint p_to_point) { return Math.sqrt(distance_square(p_to_point)); } /** * Calculates the nearest point to this point on the horizontal or * vertical line through p_other (Snaps this point to on ortogonal line * through p_other). */ public IntPoint orthogonal_projection(IntPoint p_other) { IntPoint result; int horizontal_distance = Math.abs(this.x -p_other.x); int vertical_distance = Math.abs(this.y -p_other.y); if (horizontal_distance <= vertical_distance) { // projection onto the vertical line through p_other result = new IntPoint(p_other.x, this.y); } else { // projection onto the horizontal line through p_other result = new IntPoint(this.x, p_other.y); } return result; } /** * Calculates the nearest point to this point on an orthogonal or * diagonal line through p_other (Snaps this point to on 45 degree line * through p_other). */ public IntPoint fortyfive_degree_projection(IntPoint p_other) { int dx = this.x -p_other.x; int dy = this.y -p_other.y; double[] dist_arr = new double[4]; dist_arr[0] = Math.abs(dx); dist_arr[1] = Math.abs(dy); double diagonal_1 = ((double)dy - (double)dx) / 2; double diagonal_2 = ((double)dy + (double)dx) / 2; dist_arr[2] = Math.abs(diagonal_1); dist_arr[3] = Math.abs(diagonal_2); double min_dist = dist_arr[0]; for (int i = 1; i < 4; ++i) { if (dist_arr[i] < min_dist) { min_dist = dist_arr[i]; } } IntPoint result; if (min_dist == dist_arr[0]) { // projection onto the vertical line through p_other result = new IntPoint(p_other.x, this.y); } else if (min_dist == dist_arr[1]) { // projection onto the horizontal line through p_other result = new IntPoint(this.x, p_other.y); } else if (min_dist == dist_arr[2]) { // projection onto the right diagonal line through p_other int diagonal_value = (int)diagonal_2; result = new IntPoint(p_other.x + diagonal_value, p_other.y + diagonal_value); } else { // projection onto the left diagonal line through p_other int diagonal_value = (int)diagonal_1; result = new IntPoint(p_other.x - diagonal_value, p_other.y + diagonal_value); } return result; } /** * Calculates a corner point p so that the lines through this point and p and from * p to p_to_point are multiples of 45 degree, and that the angle at p will be * 45 degree. If p_left_turn, p_to_point will be on the left of the line * from this point to p, else on the right. * Returns null, if the line from this point to p_to_point is already a multiple * of 45 degree. */ public IntPoint fortyfive_degree_corner( IntPoint p_to_point, boolean p_left_turn) { int dx = p_to_point.x - this.x; int dy = p_to_point.y - this.y; IntPoint result; // handle the 8 sections between the 45 degree lines if (dy > 0 && dy < dx) { if (p_left_turn) { result = new IntPoint(p_to_point.x - dy, this.y); } else { result = new IntPoint(this.x + dy, p_to_point.y); } } else if (dx > 0 && dy > dx) { if (p_left_turn) { result = new IntPoint(p_to_point.x, this.y + dx); } else { result = new IntPoint(this.x, p_to_point.y - dx); } } else if (dx < 0 && dy > -dx) { if (p_left_turn) { result = new IntPoint(this.x, p_to_point.y + dx); } else { result = new IntPoint(p_to_point.x, this.y - dx); } } else if (dy > 0 && dy < -dx) { if (p_left_turn) { result = new IntPoint(this.x - dy, p_to_point.y); } else { result = new IntPoint(p_to_point.x + dy, this.y); } } else if (dy < 0 && dy > dx) { if (p_left_turn) { result = new IntPoint(p_to_point.x - dy, this.y); } else { result = new IntPoint(this.x + dy, p_to_point.y); } } else if (dx < 0 && dy < dx) { if (p_left_turn) { result = new IntPoint(p_to_point.x, this.y + dx); } else { result = new IntPoint(this.x, p_to_point.y - dx); } } else if (dx > 0 && dy < -dx) { if (p_left_turn) { result = new IntPoint(this.x, p_to_point.y + dx); } else { result = new IntPoint(p_to_point.x, this.y - dx); } } else if (dy < 0 && dy > -dx) { if (p_left_turn) { result = new IntPoint(this.x - dy, p_to_point.y); } else { result = new IntPoint(p_to_point.x + dy, this.y); } } else { // the line from this point to p_to_point is already a multiple of 45 degree result = null; } return result; } /** * Calculates a corner point p so that the lines through this point and p and from * p to p_to_point are hprizontal or vertical, and that the angle at p will be * 90 degree. If p_left_turn, p_to_point will be on the left of the line * from this point to p, else on the right. * Returns null, if the line from this point to p_to_point is already orthogonal. */ public IntPoint ninety_degree_corner( IntPoint p_to_point, boolean p_left_turn) { int dx = p_to_point.x - this.x; int dy = p_to_point.y - this.y; IntPoint result; // handle the 4 quadrants if (dx > 0 && dy > 0 || dx < 0 && dy < 0) { if (p_left_turn) { result = new IntPoint(p_to_point.x, this.y); } else { result = new IntPoint(this.x, p_to_point.y); } } else if (dx < 0 && dy > 0 || dx > 0 && dy < 0) { if (p_left_turn) { result = new IntPoint(this.x, p_to_point.y); } else { result = new IntPoint(p_to_point.x, this.y); } } else { //the line from this point to p_to_point is already orthogonal result = null; } return result; } 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(IntPoint p_other) { int result; if (this.x > p_other.x) { result = 1; } else if (this.x == p_other.x) { result = 0; } else { result = -1; } return result; } int compare_y(IntPoint p_other) { int result; if (this.y > p_other.y) { result = 1; } else if (this.y == p_other.y) { result = 0; } else { result = -1; } return result; } int compare_x(RationalPoint p_other) { return -p_other.compare_x(this); } int compare_y(RationalPoint p_other) { return -p_other.compare_y(this); } /** * the x coordinate of this point */ public final int x; /** * the y coordinate of this point */ public final int y; }