/** * */ package cz.cuni.mff.peckam.java.origamist.math; import static java.lang.Math.abs; import java.util.List; import javax.vecmath.AxisAngle4d; import javax.vecmath.Matrix3d; import javax.vecmath.Point2d; import javax.vecmath.Point3d; import javax.vecmath.Vector2d; import javax.vecmath.Vector3d; /** * A helper class for math operations. * * @author Martin Pecka */ public class MathHelper { public static final double EPSILON = 0.000001; /** * Checks if v2 is a scalar multiple of v1. If it is, returns the scalar s such that v1 = s*v2. * * @param v1 The vector to compare. * @param v2 The vector to compare. * @return The "quotient" ("v1/v2") or <code>null</code> if the vectors aren't parallel or if v2 is a zero vector * and v1 isn't. */ public static Double vectorQuotient3d(Vector3d v1, Vector3d v2) { Vector3d zero = new Vector3d(); boolean v1zero = v1.epsilonEquals(zero, EPSILON); boolean v2zero = v2.epsilonEquals(zero, EPSILON); if (v1zero || v2zero) { if (v1zero && v2zero) { return 1d; } else if (v1zero) { return 0d; } else { return null; } } Vector3d cross = new Vector3d(); cross.cross(v1, v2); if (!cross.epsilonEquals(zero, EPSILON)) return null; // the vectors aren't parallel if (abs(v2.x) > EPSILON) return v1.x / v2.x; if (abs(v2.y) > EPSILON) return v1.y / v2.y; if (abs(v2.z) > EPSILON) return v1.z / v2.z; assert false : "Vector v2 is not a zero vector, but none of its coordinates is diffrent from zero???"; return null; } /** * Checks if v2 is a scalar multiple of v1. If it is, returns the scalar s such that v1 = s*v2. * * @param v1 The vector to compare. * @param v2 The vector to compare. * @return The "quotient" ("v1/v2") or <code>null</code> if the vectors aren't parallel or if v2 is a zero vector * and v1 isn't. */ public static Double vectorQuotient2d(Vector2d v1, Vector2d v2) { Vector2d zero = new Vector2d(); boolean v1zero = v1.epsilonEquals(zero, EPSILON); boolean v2zero = v2.epsilonEquals(zero, EPSILON); if (v1zero || v2zero) { if (v1zero && v2zero) { return 1d; } else if (v1zero) { return 0d; } else { return null; } } Vector2d v2perp = new Vector2d(-v2.y, v2.x); // a vector perpendicular to v2 if (abs(v2perp.dot(v1)) < EPSILON) { // v1 is parallel to v2 if (abs(v2.x) > EPSILON) return v1.x / v2.x; if (abs(v2.y) > EPSILON) return v1.y / v2.y; assert false : "Vector v2 is not a zero vector, but none of its coordinates is nonzero???"; return null; } return null; } /** * Rotates the given point around the given line by the given angle. * * @param p The point to rotate. * @param axis The line to rotate around. * @param angle The angle to rotate. * @return The rotated point. */ public static Point3d rotate(Point3d p, Line3d axis, double angle) { Matrix3d mat = new Matrix3d(); // the rotation matrix mat.set(new AxisAngle4d(axis.v, angle)); // set the rotation component from axis and angle Point3d pt = new Point3d(p); pt.sub(axis.p); // translate the point and axis so that the axis goes through the zero point mat.transform(pt); // multiply the point with the rotation matrix pt.add(axis.p); // translate back return pt; } /** * Provided a list of points, removes those points that are epsilon-equal so that no two remaining points are * epsilon-equal. The changes are made directly to the provided list. * * @param list The list to scan for duplicates. * @return The input list after duplicate removal. */ public static List<Point3d> removeEpsilonEqualPoints(List<Point3d> list) { return removeEpsilonEqualPoints(list, EPSILON); } /** * Provided a list of points, removes those points that are epsilon-equal so that no two remaining points are * epsilon-equal. The changes are made directly to the provided list. * * @param list The list to scan for duplicates. * @param epsilon The epsilon to use in epsilonEquals(). * @return The input list after duplicate removal. */ public static List<Point3d> removeEpsilonEqualPoints(List<Point3d> list, double epsilon) { int i = 0; while (i < list.size() - 1) { int j = i + 1; Point3d iPoint = list.get(i); while (j < list.size()) { if (iPoint.epsilonEquals(list.get(j), epsilon)) { list.remove(j); } else { j++; } } i++; } return list; } /** * Provided a list of points, removes those points that are epsilon-equal so that no two remaining points are * epsilon-equal. The changes are made directly to the provided list. * * @param list The list to scan for duplicates. * @param epsilon The epsilon to use in epsilonEquals(). * @return The input list after duplicate removal. */ public static List<Point2d> removeEpsilonEqualPoints2d(List<Point2d> list, double epsilon) { int i = 0; while (i < list.size() - 1) { int j = i + 1; Point2d iPoint = list.get(i); while (j < list.size()) { if (iPoint.epsilonEquals(list.get(j), epsilon)) { list.remove(j); } else { j++; } } i++; } return list; } }