/*
* Mathset.java 2005-05-09
*
* Dirk Ansorge FernUniversitaet Hagen
*
*/
package twodsack.util;
import twodsack.setelement.datatype.basicdatatype.*;
import twodsack.util.number.*;
import java.lang.Math.*;
/**
* The Mathset class provides some mathematical methods that are need in a lot of methods of the 2D-SACK package.
* Most of the methods of this class take an instance of class {@link Point} as a vector in Euclidean space. Examples for
* this are methods like length: Point -> Rational or mulfac: Point -> Rational.
* Some of the methods exist twice, like length: Point -> Rational and length Point x Rational ->
* Rational. In the first case, a new Rational instance is constructed to store the result. In the seconde case,
* the Rational parameter is used to store the result. By doing this, new calls are avoided. This saves
* time and memory.
*/
public class Mathset {
/*
* constructors
*/
/**
* Don't use this constructor.
*/
private Mathset(){};
/*
* fields
*/
static final double DEVIATION_DOUBLE = RationalFactory.readDeviationDouble();
static final double DEVIATION_DOUBLE_NEG = RationalFactory.readDeviationDoubleNeg();
static boolean PRECISE;
static boolean preciseDefined;
//these values are used for linearly_dependent and pointPosition
static Rational DIFF_RAT1 = RationalFactory.constRational(0);
static Rational DIFF_RAT2 = RationalFactory.constRational(1);
/*
* methods
*/
/**
* Returns the length of the passed vector.
* Note, that during computation the conversion into a double value is necessary. The result may be not precise.
*
* @param v the given vector
* @return the length as Rational
*/
public static Rational length(Point v) {
Rational l = RationalFactory.constRational(Math.sqrt((v.x.times(v.x).plus(v.y.times(v.y))).getDouble()));
return l;
}//end method length
/**
* Returns the length of the passed vector.
* The result is stored in the parameter in. Note, that during computation the conversion into a double
* value is necessary. The result may be not precise.
*
* @param v the given vector
* @param in the result is stored in this parameter
* @return the length as Rational
*/
public static Rational length(Point v, Rational in) {
in.assign(Math.sqrt(v.x.times(v.x,in).plus(v.y.times(v.y,in),in).getDouble()));
return in;
}//end method length
/**
* Returns the length of the passed vector
*
* @param v the given vector
* @return the length as double
*/
public static double lengthD(Point v) {
double l = Math.sqrt(v.x.getDouble() * v.x.getDouble() + v.y.getDouble() * v.y.getDouble());
return l;
}//end method lengthD
/**
* Returns the sum of two vectors
*
* @param v1 the first vector
* @param v2 the second vector
* @return the sum of v1, v2 as Point
*/
public static Point sum(Point v1, Point v2) {
Point v = new Point((v1.x.plus(v2.x)),(v1.y.plus(v2.y)));
return v;
}//end method sum
/**
* Returns the difference of two vectors.
*
* @param v1 the first vector
* @param v2 the second vector
* @return v1-v2 as Point
*/
public static Point diff(Point v1, Point v2) {
Point v = new Point((v1.x.minus(v2.x)),(v1.y.minus(v2.y)));
return v;
}//end method diff
/**
* Returns the difference of two vectors.
* The result is stored in in. No new Point instance is constructed.
*
* @param v1 the first vector
* @param v2 the second vector
* @param in used to store the result
* @return v1-v2 as Point
*/
public static Point diff(Point v1, Point v2, Point in) {
in.x.assign(v1.x.minus(v2.x,DIFF_RAT1));
in.y.assign(v1.y.minus(v2.y,DIFF_RAT2));
return in;
}//end method diff
/**
* Returns the product of two vectors.
*
* @param v1 the first vector
* @param v2 the second vector
* @return v1*v2 as Rational
*/
public static Rational prod(Point v1, Point v2) {
Rational e = RationalFactory.constRational((v1.x.times(v2.x)).plus(v1.y.times(v2.y)));
return e;
}//end method prod
/**
* Returns the product of two vectors.
* The result is stored in in. No new Rational instance is constructed.
*
* @param v1 the first vector
* @param v2 the second vector
* @param in used to store the result
* @return v1*v2 as Rational
*/
public static Rational prod(Point v1, Point v2, Rational in) {
in.assign((v1.x.times(v2.x,in)).plus(v1.y.times(v2.y,in),in));
return in;
}//end method prod
/**
* Returns a new vector wich is the result of fac * p.
*
* @param p the vector
* @param fac the number
* @return a new Point instance which is equal to fac * p
*/
public static Point mulfac(Point p, Rational fac) {
return new Point(p.x.times(fac),p.y.times(fac));
}//end method mulfac
/**
* Returns a new vector which is the result of (p.x + fac, p.y + fac).
*
* @param p the vector
* @param fac the number
* @return a new Point instance which is equal to (p.x + fac, p.y + fac)
*/
public static Point addfac(Point p, double fac) {
Rational facR = RationalFactory.constRational(fac);
return new Point(p.x.plus(facR),p.y.plus(facR));
}//end method addfac
/**
* Returns a new vector which is the result of (p.x - fac, p.y - fac).
*
* @param p the vector
* @param fac the number
* @return a new Point instance which is equal to (p.x + fac, p.y + fac)
*/
public static Point subfac(Point p, double fac) {
Rational facR = RationalFactory.constRational(fac);
return new Point(p.x.minus(facR),p.y.minus(facR));
}//end method subfac
/**
* Returns true, if both segments are collinear.
*
* @param s1 the first segment
* @param s2 the second segment
* @return true, if s1, s2 are collinear
*/
public static boolean linearly_dependent(Segment s1, Segment s2) {
if (!preciseDefined) {
PRECISE = RationalFactory.readPrecise();
preciseDefined = true;
}//if
if (PRECISE) {
//PRECISE == true, use Deviation
Point sv1 = new Point(s1.getEndpoint().x.minus(s1.getStartpoint().x),
s1.getEndpoint().y.minus(s1.getStartpoint().y));
Point sv2 = new Point(s2.getEndpoint().x.minus(s2.getStartpoint().x),
s2.getEndpoint().y.minus(s2.getStartpoint().y));
boolean sv2X0 = sv2.x.equal(0);
boolean sv2Y0 = sv2.y.equal(0);
if (sv2X0 && sv2Y0) return true;
Rational t1 = RationalFactory.constRational(0);
Rational t2 = RationalFactory.constRational(0);
if (!sv2X0) t1 = sv1.x.dividedby(sv2.x);
if (!sv2Y0) t2 = sv1.y.dividedby(sv2.y);
boolean t1t2equal = false;
if (t1.minus(t2).equal(0)) t1t2equal = true;
else {
Rational zwires = (t1.minus(t2)).abs();
if (zwires.less(RationalFactory.readDeviation())) t1t2equal = true;
else t1t2equal = false;
}//else
if (t1t2equal && !(t1.equal(0) && t2.equal(0))) return true;
boolean compsv1x = (sv2.x.times(t1).minus(sv1.x)).abs().lessOrEqual(RationalFactory.readDeviation());
boolean compsv1y = (sv2.y.times(t2).minus(sv1.y)).abs().lessOrEqual(RationalFactory.readDeviation());
if (compsv1x && compsv1y) return true;
return false;
}//if
else {
//PRECISE == false, use double constants as deviation value
//DEVIATION_DOUBLE and DEVIATION_DOUBLE_NEG
double px = 0;
double py = 0;
double qx = s1.getEndpoint().x.getDouble() - s1.getStartpoint().x.getDouble();
double qy = s1.getEndpoint().y.getDouble() - s1.getStartpoint().y.getDouble();
double rx = 0;
double ry = 0;
double sx = s2.getEndpoint().x.getDouble() - s2.getStartpoint().x.getDouble();
double sy = s2.getEndpoint().y.getDouble() - s2.getStartpoint().y.getDouble();
double res1 = ((ry + py) / 2) * (rx - px);
double res2 = ((qy + ry) / 2) * (qx - rx);
double res3 = ((py + qy) / 2) * (px - qx);
double result1 = res1+res2+res3;
if (result1 > DEVIATION_DOUBLE ||
result1 < DEVIATION_DOUBLE_NEG) return false;
double res4 = ((sy + py) / 2) * (sx - px);
double res5 = ((qy + sy) / 2) * (qx - sx);
double res6 = ((py + qy) / 2) * (px - qx);
double result2 = res4+res5+res6;
if (result2 > DEVIATION_DOUBLE ||
result2 < DEVIATION_DOUBLE_NEG) return false;
return true;
}//else
}//end method linear_dependent
/**
* Returns the angle between two vectors.
* The scalar product is used to compute the angle.
*
* @param p1 the first vector
* @param p2 the second vector
* @return the angle as Rational
*/
public static Rational angle(Point p1, Point p2) {
Rational e = RationalFactory.constRational(prod(p1,p2).dividedby(length(p1).times(length(p2))));
e = RationalFactory.constRational(Math.acos(e.getDouble()));
e = RationalFactory.constRational(Math.toDegrees(e.getDouble()));
return e;
}//end method angle
/**
* Returns the angle between two vectors.
* The scalar product is used to compute the angle. The result is stored in in.
*
* @param p1 the first point
* @param p2 the second point
* @param in the result is stored in this parameter
* @return the angle as Rational
*/
public static Rational angle(Point p1, Point p2, Rational in) {
in.assign(prod(p1,p2).dividedby(length(p1).times(length(p2))));
double e = Math.acos(in.getDouble());
e = Math.toDegrees(e);
in.assign(e);
return in;
}//end method angle
/**
* Returns the angle between two vectors.
* The scalar product is used to compute the angle.
*
* @param p1 the first vector
* @param p2 the second vector
* @return the result as double
*/
public static double angleD(Point p1, Point p2) {
double e = (prod(p1,p2)).getDouble() / (lengthD(p1) * lengthD(p2));
e = Math.acos(e);
e = Math.toDegrees(e);
return e;
}//end method angleD
/**
* Normalizes the vector.
*
* @param p the 'in' vector
* @return the normalized p
*/
public static Point normalize(Point p){
p.x = p.x.dividedby(length(p));
p.y = p.y.dividedby(length(p));
return p;
}//end method normalize
/**
* Returns one of {0, -1, 1} depending on the position of p and the line through g1, g2.
* Returns 0, if p lies on the line through g1, g2.
* Returns 1, if p lies on the right side of the line through g1, g2.
* Returns -1 otherwise. * * @param g1 the first point of the line * @param g2 the second point of the line * @param p the point that is checked * @return one of {0, -1, 1} as byte */ public static byte pointPosition(Point g1, Point g2, Point p) { double s1x = g2.x.getDouble() - g1.x.getDouble(); double s1y = g2.y.getDouble() - g1.y.getDouble(); double s2x = p.x.getDouble() - g1.x.getDouble(); double s2y = p.y.getDouble() - g1.y.getDouble(); double t0 = s1x * s2y - s1y * s2x; if (t0 < DEVIATION_DOUBLE_NEG) return 1; else if (t0 > DEVIATION_DOUBLE) return -1; else return 0; }//end method pointPosition /** * Returns the projection of point p on the line through a, b. * * @param p the point that is projected * @param a the first point of the line * @param b the second point of the line * @return the projected point */ public static Point projectionPointLine(Point p, Point a, Point b) { Point AProj; Point AB; Point AP; AB = diff(b,a); AP = diff(p,a); AProj = mulfac(AB,prod(AB,AP).dividedby(prod(AB,AB))); Point retPoint = sum(AProj,a); return retPoint; }//end method projectionPointLine /** * Computes the center of three points representing a triangle. * * @param p1 first point * @param p2 second point * @param p3 third point * @return center */ public static Point center (Point p1, Point p2, Point p3) { return new Point (((p1.x.plus(p2.x.plus(p3.x))).dividedby(3)), ((p1.y.plus(p2.y.plus(p3.y))).dividedby(3))); }//end method center }//end class Mathset