/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. 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. */ package org.geogebra.common.kernel.Matrix; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.util.debug.Log; /** * * A Ggb3DVector is composed of {x1,x2,...,xn} coordinates in double precision. * This class provides methods for basic linear algebra calculus. * * @author ggb3D * */ public class Coords { private double norm, sqNorm; private boolean calcNorm = true; private boolean calcSqNorm = true; /** origin 3D point */ public static final Coords O = new Coords(0, 0, 0, 1); /** zero vector */ public static final Coords ZERO = new Coords(0, 0, 0, 0); /** vx 3D vector */ public static final Coords VX = new Coords(1, 0, 0, 0); /** vy 3D vector */ public static final Coords VY = new Coords(0, 1, 0, 0); /** vz 3D vector */ public static final Coords VZ = new Coords(0, 0, 1, 0); /** vz 3D vector, down orientation */ public static final Coords VZm = new Coords(0, 0, -1, 0); /** undefined vector */ public static final Coords UNDEFINED = new Coords(Double.NaN, Double.NaN, Double.NaN, Double.NaN) { @Override public boolean isNotFinalUndefined() { return false; } @Override public boolean isFinalUndefined() { return true; } }; /** undefined vector */ public static final Coords UNDEFINED3VALUE0 = new Coords(0, 0, 0) { @Override public boolean isNotFinalUndefined() { return false; } @Override public boolean isFinalUndefined() { return true; } }; public static final Coords BLACK = new Coords(0, 0, 0, 1); public static final Coords DARK_GRAY = new Coords(68.0 / 255.0, 68.0 / 255.0, 68.0 / 255.0, 1); public double[] val; private int rows; /** * * @return (x,y,z,1) coords */ public static final Coords createInhomCoorsInD3() { Coords ret = new Coords(4); ret.setW(1); return ret; } // /////////////////////////////////////////////////: // Constructors /** * creates a vector of the dimension specified by rows. * * @param rows * number of rows */ public Coords(int rows) { this.rows = rows; // transpose = false; val = new double[rows]; /* * for (int i = 0; i < rows; i++) { val[i] = 0.0; } */ } /** * creates a vector with values vals * * @param vals * values {x1, x2, ...} */ public Coords(double[] vals) { this(vals.length); for (int i = 0; i < vals.length; i++) { val[i] = vals[i]; } } /** * creates a vector with same values as v * * @param v * vector */ public Coords(Coords v) { this(v.val); } /** * creates a 2D vector with the specified values * * @param u * @param v */ public Coords(double u, double v) { this(2); val[0] = u; val[1] = v; } /** * creates a 3D vector with the specified values * * @param x * @param y * @param z */ public Coords(double x, double y, double z) { this(3); val[0] = x; val[1] = y; val[2] = z; } /** * creates a 3D vector/point with the specified values * * @param x * @param y * @param z * @param w */ public Coords(double x, double y, double z, double w) { this(4); val[0] = x; val[1] = y; val[2] = z; val[3] = w; } // /////////////////////////////////////////////////: // setters and getters /** * sets v(i) to val0 * * @param i * number of the row * @param val0 * value */ public void set(int i, double val0) { val[i - 1] = val0; calcNorm = calcSqNorm = true; } /** * set four first values * * @param x * @param y * @param z * @param w */ public void set(double x, double y, double z, double w) { val[0] = x; val[1] = y; val[2] = z; val[3] = w; calcNorm = calcSqNorm = true; } /** * sets v to vals0 * * @param vals0 * values {x1, x2, ...} */ public void set(double[] vals0) { // Application.debug("-------------val.length = // "+val.length+"\n-------------vals0.length = "+vals0.length); for (int i = 0; i < vals0.length; i++) { val[i] = vals0[i]; } calcNorm = calcSqNorm = true; } /** * set 3 first values * * @param x * first value * @param y * second value * @param z * third value */ public void set(double x, double y, double z) { val[0] = x; val[1] = y; val[2] = z; } /** * set this values to v's * * @param v * coords * @param length * length first values only are updated */ public void setValues(Coords v, int length) { for (int i = 0; i < length; i++) { val[i] = v.val[i]; } } /** * set values from v * * @param v * coords */ public void set(Coords v) { set(v.val); } /** * set 3 first values from v * * @param v * coords */ public void set3(Coords v) { val[0] = v.val[0]; val[1] = v.val[1]; val[2] = v.val[2]; } /** * set 2 first values from v * * @param v * coords */ public void set2(Coords v) { val[0] = v.val[0]; val[1] = v.val[1]; } public void set(double val0) { for (int i = 0; i < rows; i++) { val[i] = val0; } norm = Math.sqrt(rows) * Math.abs(val0); calcNorm = calcSqNorm = true; } /** * returns v(i) * * @param i * number of the row * @return value */ public double get(int i) { return val[i - 1]; } public double getChecked(int i) { return i > val.length ? 0 : val[i - 1]; } /** * @param ret * copy of this * */ public void copy(double[] ret) { for (int i = 0; i < rows; i++) { ret[i] = val[i]; } } /** * returns v "x-coord" * * @return x-coord */ public double getX() { return val[0]; } /** * returns v "y-coord" * * @return y-coord */ public double getY() { return val[1]; } /** * returns v "z-coord" * * @return z-coord */ public double getZ() { if (val.length > 2) { return val[2]; } return 0; // z coord for 2D points } /** * returns v "w-coord" * * @return w-coord */ public double getW() { return val[3]; } /** * returns v last coord * * @return last coord */ public double getLast() { return val[rows - 1]; } /** * sets the "x-coord" * * @param val */ public void setX(double val) { this.val[0] = val; calcNorm = calcSqNorm = true; } /** * sets the "y-coord" * * @param val */ public void setY(double val) { this.val[1] = val; calcNorm = calcSqNorm = true; } /** * sets the "z-coord" * * @param val */ public void setZ(double val) { this.val[2] = val; calcNorm = calcSqNorm = true; } /** * sets the "w-coord" * * @param val */ public void setW(double val) { this.val[3] = val; calcNorm = calcSqNorm = true; } /** * returns number of rows of the vector * * @return number of rows */ public int getLength() { return rows; } /** * returns a copy of the vector * * @return a copy of the vector */ public Coords copyVector() { Coords result = new Coords(rows); for (int i = 0; i < rows; i++) { result.val[i] = val[i]; } return result; } /** * returns the start-end subvector * * @param start * number of starting row * @param end * number of end row * @return vector with rows between start and end * * deprecated create vector and use * {@link #setSubVector(Coords, int, int)} instead */ public Coords subVector(int start, int end) { int r = end - start + 1; Coords result = new Coords(r); for (int i = 0; i < r; i++) { result.val[i] = val[start + i - 1]; } return result; } /** * set this to start-end subvector of v * * @param v * vector * * @param start * number of starting row * @param end * number of end row * @return this */ public Coords setSubVector(Coords v, int start, int end) { int r = end - start + 1; for (int i = 0; i < r; i++) { val[i] = v.val[start + i - 1]; } return this; } /** * returns the subvector composed of this without the row number row * * @param row * number of the row to remove * @return vector composed of this without the row number row * * deprecated create vector and use * {@link #setSubVector(Coords, int)} instead */ public Coords subVector(int row) { int r = rows; Coords result = new Coords(r - 1); int shift = 0; for (int i = 0; i < r; i++) { if (i == row) { shift = 1; } else { result.val[i] = val[i + shift]; } } return result; } /** * set this to subvector composed of v without the row number row * * @param v * vector * * @param row * number of the row to remove * @return this */ public Coords setSubVector(Coords v, int row) { for (int i = 0; i < row; i++) { val[i] = v.val[i]; } for (int i = row; i < rows; i++) { val[i] = v.val[i + 1]; } return this; } // /////////////////////////////////////////////////: // basic operations /** * returns dot product this * v. * <p> * If this={x1,x2,...} and v={x'1,x'2,...}, the dot product is * x1*x'1+x2*x'2+... * * @param v * vector multiplied with * @return value of the dot product */ public double dotproduct(Coords v) { int len = Math.min(getLength(), v.getLength()); double res = 0; for (int i = 0; i < len; i++) { res += val[i] * v.val[i]; } return res; } /** * returns dot product this * v in dimension 3 * <p> * If this={x1,x2,x3} and v={x'1,x'2,x'3}, the dot product is * x1*x'1+x2*x'2+x3*x'3 * * @param v * vector multiplied with * @return value of the dot product */ public double dotproduct3(Coords v) { double res = 0; for (int i = 0; i < 3; i++) { res += val[i] * v.val[i]; } return res; } /** * Assume that (u,v) are orthogonal * * @param u * vector * @param v * vector * @return true if crossProduct(u,v)*w is almost zero */ final public boolean isDependentToOrtho(Coords u, Coords v) { double value = (u.getY() * v.getZ() - u.getZ() * v.getY()) * getX() + (u.getZ() * v.getX() - u.getX() * v.getZ()) * getY() + (u.getX() * v.getY() - u.getY() * v.getX()) * getZ(); return Kernel.isZero(value); } /** * returns cross product this * v. Attempt that the two vectors are of * dimension 3. * <p> * If this={x,y,z} and v={x',y',z'}, then cross * product={yz'-y'z,zx'-z'x,xy'-yx'} * * @param v * vector multiplied with * @return vector resulting of the cross product * * deprecated create vector and use * {@link #setCrossProduct(Coords, Coords)} instead */ final public Coords crossProduct(Coords v) { Coords ret = new Coords(3); ret.setCrossProduct(this, v); return ret; } /** * * @param v * @return 4-length vector equal to cross product this ^ v * * deprecated create vector and use * {@link #setCrossProduct(Coords, Coords)} instead */ final public Coords crossProduct4(Coords v) { Coords ret = new Coords(4); ret.setCrossProduct(this, v); return ret; } /** * set x,y,z values according to v1 ^ v2 cross product * * @param v1 * @param v2 */ final public void setCrossProduct(Coords v1, Coords v2) { val[0] = v1.val[1] * v2.val[2] - v1.val[2] * v2.val[1]; val[1] = v1.val[2] * v2.val[0] - v1.val[0] * v2.val[2]; val[2] = v1.val[0] * v2.val[1] - v1.val[1] * v2.val[0]; } final public double dotCrossProduct(Coords v1, Coords v2) { return val[0] * (v1.val[1] * v2.val[2] - v1.val[2] * v2.val[1]) + val[1] * (v1.val[2] * v2.val[0] - v1.val[0] * v2.val[2]) + val[2] * (v1.val[0] * v2.val[1] - v1.val[1] * v2.val[0]); } /** * Assuming this is a 3D vector * * @param v * vector * @return true if this and v are linear independent */ final public boolean isLinearIndependent(Coords v) { double value; value = val[1] * v.val[2] - val[2] * v.val[1]; if (!Kernel.isZero(value)) { return true; } value = val[2] * v.val[0] - val[0] * v.val[2]; if (!Kernel.isZero(value)) { return true; } value = val[0] * v.val[1] - val[1] * v.val[0]; if (!Kernel.isZero(value)) { return true; } return false; } final public boolean isLinearIndependentAllCoords(Coords v) { int index = 0; boolean notFound = true; double r1 = 0, r2 = 0; // first try to find non zero coords while (notFound && index < getLength()) { double c1 = val[index]; double c2 = v.val[index]; if (Kernel.isZero(c1)) { if (!Kernel.isZero(c2)) { return true; } // c1 and c2 are 0: continue } else { // c1 is not 0 if (Kernel.isZero(c2)) { return true; } // c2 is not 0 notFound = false; r1 = c1; r2 = c2; } index++; } // with non zero coords, verify other coords are dependents while (index < getLength()) { double value = r1 * v.val[index] - val[index] * r2; if (!Kernel.isZero(value)) { return true; } index++; } // all coords are lin dep return false; } /** * returns the scalar norm. * <p> * If this={x1,x2,...}, then norm=sqrt(x1*x1+x2*x2+...). Same result as * Math.sqrt(this.dotproduct(this)) * * @return the scalar norm */ public double norm() { if (calcNorm) { calcNorm(); calcNorm = false; } return norm; } /** * calc the norm * * @return the norm */ public double calcNorm() { calcSquareNorm(); norm = Math.sqrt(sqNorm); return norm; } /** * calc the square norm * * @return the square norm */ public double calcSquareNorm() { sqNorm = 0; for (int i = 0; i < val.length; i++) { sqNorm += val[i] * val[i]; } return sqNorm; } /** * The norm must be already calculated by calcNorm() * * @return the norm */ public double getNorm() { return norm; } /** * returns the square of the scalar norm. * <p> * If this={x1,x2,...}, then norm=x1*x1+x2*x2+... Same result as * this.dotproduct(this) * * @return the scalar norm */ public double squareNorm() { if (calcSqNorm) { calcSquareNorm(); calcSqNorm = false; } return sqNorm; } /** * returns this normalized WARNING : recalc the norm * * @return this normalized */ public Coords normalized() { return normalized(false); } /** * returns this normalized WARNING : recalc the norm * * @param checkOneDirection * check if one of the result coord is near to 1 (for Kernel) * @return this normalized * * deprecated create vector and use * {@link #setNormalized(Coords, boolean)} instead */ public Coords normalized(boolean checkOneDirection) { Coords ret = new Coords(getLength()); calcNorm(); double normInv = 1 / getNorm(); int len = getLength(); for (int i = 0; i < len; i++) { double v = val[i] * normInv; // check if v is near to be one direction vector if (checkOneDirection && Kernel.isEqual(Math.abs(v), 1)) { if (v < 0) { ret.val[i] = -1; } else { ret.val[i] = 1; } for (int j = 0; j < i; j++) { ret.val[j] = 0; } for (int j = i + 1; j < len; j++) { ret.val[j] = 0; } break; } ret.val[i] = v; } return ret; } /** * set this equal to normalized vector. Warning: recalc vector's norm * * @param vector * vector * * @return this */ public Coords setNormalized(Coords vector) { return setNormalized(vector, false); } /** * set this equal to normalized vector. Warning: recalc vector's norm * * @param vector * vector * * @param checkOneDirection * check if one of the result coord is near to 1 (for Kernel) * @return this */ public Coords setNormalized(Coords vector, boolean checkOneDirection) { vector.calcNorm(); double normInv = 1 / vector.getNorm(); for (int i = 0; i < rows; i++) { double v = vector.val[i] * normInv; // check if v is near to be one direction vector if (checkOneDirection && Kernel.isEqual(Math.abs(v), 1)) { if (v < 0) { val[i] = -1; } else { val[i] = 1; } for (int j = 0; j < i; j++) { val[j] = 0; } for (int j = i + 1; j < rows; j++) { val[j] = 0; } break; } val[i] = v; } return this; } /** * put this normalized in ret (WARNING : recalc the norm) * * @param ret * */ public void normalized(Coords ret) { calcNorm(); double normInv = 1 / getNorm(); for (int i = 0; i < ret.rows; i++) { double v = val[i] * normInv; ret.val[i] = v; } } /** * WARNING : recalc the norm set this to norm=1 * * @return this normalized */ public Coords normalize() { normalize(true); return this; } /** * * @param recalcNorm * says if the norm has to be recalculated * @return this normalized */ public Coords normalize(boolean recalcNorm) { if (recalcNorm) { calcNorm(); } double normInv = 1 / getNorm(); int len = getLength(); for (int i = 0; i < len; i++) { val[i] *= normInv; } norm = sqNorm = 1.0; return this; } /** * returns the distance between this and v * * @param v * second vector * @return (this-v).norm() */ public double distance(Coords v) { return this.sub(v).norm(); } /** * * Calc square distance to v - only on x, y, z coords * * @param v * coords * @return square distance */ public double squareDistance3(Coords v) { double x = getX() - v.getX(); double y = getY() - v.getY(); double z = getZ() - v.getZ(); return x * x + y * y + z * z; } /** * returns the shortest vector between this and a 3D-line represented by the * matrix {V O} * * @param O * origin of the line * @param V * direction of the line * @return shortest vector between this and the line */ private Coords vectorToLine(Coords O, Coords V) { Coords OM = this.sub(O); Coords N = V.normalized(); Coords OH = N.mul(OM.dotproduct(N)); // TODO optimize return OM.sub(OH); } /** * returns the distance between this and a 3D-line represented by the matrix * {V O} * * @param O * origin of the line * @param V * direction of the line * @return distance between this and the line */ public double distLine(Coords O, Coords V) { return vectorToLine(O, V).norm(); } /** * returns the square distance between this and a 3D-line represented by the * matrix {V O} (only computed on x, y, z) * * @param O * origin of the line * @param V * direction of the line * @return distance between this and the line */ public double squareDistLine3(Coords O, Coords V) { Coords v = vectorToLine(O, V); return v.getX() * v.getX() + v.getY() * v.getY() + v.getZ() * v.getZ(); } /** * * @param o * point of the plane * @param vn * normal direction to the plane * @return distance of this to the plane */ public double distPlane(Coords o, Coords vn) { return Math.abs(distPlaneOriented(o, vn)); } /** * * @param o * point of the plane * @param vn * normal direction to the plane * @return oriented distance of this to the plane */ public double distPlaneOriented(Coords o, Coords vn) { return this.sub(o).dotproduct(vn); } /** * returns this projected on the plane represented by the matrix (third * vector used for direction). If direction is parallel to the plane, return * infinite point (direction vector). * <p> * Attempt this to be of dimension 4, and the matrix to be of dimension 4*4. * * * set two vectors {globalCoords,inPlaneCoords}: the point projected, and * the original point in plane coords * * @param m * matrix {v1 v2 v3 o} where (o,v1,v2) is a coord sys fo the * plane, and v3 the direction used for projection * */ public void projectPlane(CoordMatrix m, Coords globalCoords, Coords inPlaneCoords) { projectPlane(m.getVx(), m.getVy(), m.getVz(), m.getOrigin(), globalCoords, inPlaneCoords); } public void projectPlane(Coords vx, Coords vy, Coords vz, Coords o, Coords globalCoords, Coords inPlaneCoords) { projectPlane(vx, vy, vz, o, globalCoords.val, inPlaneCoords.val); } public void projectPlane(Coords vx, Coords vy, Coords vz, Coords o, double[] globalCoords, double[] inPlaneCoords) { if (Kernel.isEqual((vx.crossProduct(vy)).dotproduct(vz), 0, Kernel.STANDARD_PRECISION)) { // direction of projection is parallel to the plane : point is // infinite inPlaneCoords[0] = 0; // x inPlaneCoords[1] = 0; // y inPlaneCoords[2] = -1; // z inPlaneCoords[3] = 0; // w globalCoords[0] = vz.getX(); // x globalCoords[1] = vz.getY(); // y globalCoords[2] = vz.getZ(); // z globalCoords[3] = vz.getW(); // w return; } // direction is not parallel to the plane projectPlaneNoCheck(vx, vy, vz, o, globalCoords, inPlaneCoords); } public void projectPlaneInPlaneCoords(CoordMatrix m, Coords inPlaneCoords) { projectPlaneInPlaneCoords(m.getVx(), m.getVy(), m.getVz(), m.getOrigin(), inPlaneCoords); } public void projectPlaneInPlaneCoords(Coords vx, Coords vy, Coords vz, Coords o, Coords inPlaneCoords) { if (vz.isDependentToOrtho(vx, vy)) { // direction of projection is parallel to the plane : point is // infinite // Application.printStacktrace("infinity"); inPlaneCoords.setX(0); inPlaneCoords.setY(0); inPlaneCoords.setZ(-1); inPlaneCoords.setW(0); return; } // direction is not parallel to the plane projectPlaneNoCheckInPlaneCoords(vx, vy, vz, o, inPlaneCoords.val); } public void projectPlane(CoordMatrix m, Coords globalCoords) { projectPlane(m.getVx(), m.getVy(), m.getVz(), m.getOrigin(), globalCoords); } public void projectPlane(Coords vx, Coords vy, Coords vz, Coords o, Coords globalCoords) { if (vz.isDependentToOrtho(vx, vy)) { // direction of projection is parallel to the plane : point is // infinite // Application.printStacktrace("infinity"); globalCoords.set(vz); return; } // direction is not parallel to the plane // we can use globalCoords twice as it will be set at this end projectPlaneNoCheck(vx, vy, vz, o, globalCoords.val, globalCoords.val); } /** * project on plane with known inverse matrix * * @param m * inverse matrix * @return 3D point in plane coords (z = distance(point, plane)) */ final public Coords projectPlaneWithInverseMatrix(CoordMatrix m) { return m.mul(this); } /** * returns this projected on the plane represented by the matrix (third * vector used for direction), no check if direction is parallel to the * plane. * <p> * Attempt this to be of dimension 4, and the matrix to be of dimension 4*4. * * @param vx * @param vy * @param vz * @param o * * matrix {vx vy vz o} where (o,vx,vy) is a coord sys for the * plane, and vz the direction used for projection */ public void projectPlaneNoCheck(Coords vx, Coords vy, Coords vz, Coords o, double[] globalCoords, double[] inPlaneCoords) { // project in plane coords projectPlaneNoCheckInPlaneCoords(vx, vy, vz, o, inPlaneCoords); // globalCoords=this-inPlaneCoords_z*plane_vz double coeff = -inPlaneCoords[2]; // inPlaneCoords may use globalCoords // for memory vz.mul(coeff, globalCoords); this.add(globalCoords, globalCoords); // note : globalCoords must be set at the end (when dummy inPlaneCoords) } public void projectPlaneNoCheckInPlaneCoords(Coords vx, Coords vy, Coords vz, Coords o, double[] inPlaneCoords) { // m*inPlaneCoords=this CoordMatrix.solve(inPlaneCoords, this, vx, vy, vz, o); } /** * returns this projected on the plane represented by the matrix, with * vector v used for direction. * <p> * Attempt this to be of dimension 4, the matrix to be of dimension 4*4, and * the vector to be of dimension 4. * * * set two vectors {globalCoords,inPlaneCoords}: the point projected, and * the original point in plane coords * * @param m * matrix {v1 v2 ?? o} where (o,v1,v2) is a coord sys fo the * plane, and v3 * @param v * the direction used for projection */ public void projectPlaneThruV(CoordMatrix m, Coords v, Coords globalCoords, Coords inPlaneCoords) { projectPlane(m.getVx(), m.getVy(), v, m.getOrigin(), globalCoords, inPlaneCoords); } public void projectPlaneThruV(CoordMatrix m, Coords v, Coords globalCoords) { projectPlane(m.getVx(), m.getVy(), v, m.getOrigin(), globalCoords); } public void projectPlaneThruVInPlaneCoords(CoordMatrix m, Coords v, Coords inPlaneCoords) { projectPlaneInPlaneCoords(m.getVx(), m.getVy(), v, m.getOrigin(), inPlaneCoords); } /** * returns this projected on the plane represented by the matrix, with * vector v used for direction. * <p> * If v is parallel to plane, then plane third vector is used instead * * * set two vectors {globalCoords,inPlaneCoords}: the point projected, and * the original point in plane coords * * @param m * matrix {v1 v2 v3 o} where (o,v1,v2) is a coord sys fo the * plane, and v3 * @param v * the direction used for projection (v3 is used instead if v is * parallel to the plane) */ public void projectPlaneThruVIfPossible(CoordMatrix m, Coords v, Coords globalCoords, Coords inPlaneCoords) { // check if v is parallel to plane Coords v3 = m.getColumn(3); if (Kernel.isEqual(v3.dotproduct(v), 0.0, Kernel.STANDARD_PRECISION)) { projectPlane(m, globalCoords, inPlaneCoords); return; } // if not, use v for direction projectPlane(m.getVx(), m.getVy(), v, m.getOrigin(), globalCoords, inPlaneCoords); } public void projectPlaneThruVIfPossible(CoordMatrix m, Coords v, Coords globalCoords) { // check if v is parallel to plane Coords v3 = m.getColumn(3); if (Kernel.isEqual(v3.dotproduct(v), 0.0, Kernel.STANDARD_PRECISION)) { projectPlane(m, globalCoords); return; } projectPlane(m.getVx(), m.getVy(), v, m.getOrigin(), globalCoords); } public void projectPlaneThruVIfPossible(Coords vx, Coords vy, Coords vz, Coords o, Coords v, Coords globalCoords) { // check if v is parallel to plane if (Kernel.isEqual(vz.dotproduct(v), 0.0, Kernel.STANDARD_PRECISION)) { projectPlane(vx, vy, vz, o, globalCoords); return; } projectPlane(vx, vy, v, o, globalCoords); } public void projectPlaneThruVIfPossibleInPlaneCoords(CoordMatrix m, Coords v, Coords inPlaneCoords) { // check if v is parallel to plane Coords v3 = m.getColumn(3); if (Kernel.isEqual(v3.dotproduct(v), 0.0, Kernel.STANDARD_PRECISION)) { projectPlaneInPlaneCoords(m, inPlaneCoords); return; } // if not, use v for direction projectPlaneInPlaneCoords(m.getVx(), m.getVy(), v, m.getOrigin(), inPlaneCoords); } /** * returns this projected on the plane represented by the matrix, with * vector v used for direction. * <p> * If v is parallel to plane, first project old position of the line * (this,v), then project the result using plane third vector * * @param m * matrix {v1 v2 v3 o} where (o,v1,v2) is a coord sys fo the * plane, and v3 * @param oldCoords * old position of this * @param v * the direction used for projection (v3 is used instead if v is * parallel to the plane) * @return two vectors {globalCoords,inPlaneCoords}: the point projected, * and the original point in plane coords */ public void projectPlaneThruVIfPossible(CoordMatrix m, Coords oldCoords, Coords v, Coords globalCoords, Coords inPlaneCoords) { // Application.debug(this+"\nold=\n"+oldCoords); // check if v is parallel to plane Coords v3 = m.getColumn(3); if (Kernel.isZero(v3.dotproduct(v))) { Coords firstProjection = Coords.createInhomCoorsInD3(); oldCoords.projectLine(this, v, firstProjection, null); firstProjection.projectPlane(m, globalCoords, inPlaneCoords); return; } // if not, use v for direction projectPlane(m.getVx(), m.getVy(), v, m.getOrigin(), globalCoords, inPlaneCoords); } /** * calculates projection of this on the 3D-line represented by the matrix {V * O}. * * @param O * origin of the line * @param V * direction of the line * @param H * point projected * @param parameters * {parameter on the line, normalized parameter} */ public void projectLine(Coords O, Coords V, Coords H, double[] parameters) { this.sub(O, H); // OM Coords N = V.normalized(); double parameter = H.dotproduct(N); // OM.N N.mul(parameter, H); // OH O.add(H, H); if (parameters == null) { return; } parameters[0] = parameter / V.norm(); parameters[1] = parameter; } /** * calculates projection of this on the 3D-line represented by the matrix {V * O}. * * @param O * origin of the line * @param P * point on the line * @param H * point projected * @param parameters * {parameter on the line, normalized parameter} */ public void projectLineSub(Coords O, Coords P, Coords H, double[] parameters) { this.sub(O, H); // OM Coords V = P.sub(O); double vn = V.norm(); Coords N = V.normalize(); double parameter = H.dotproduct(N); // OM.N N.mul(parameter, H); // OH O.add(H, H); if (parameters == null) { return; } parameters[0] = parameter / vn; parameters[1] = parameter; } /** * calculates projection of this on the 3D-line represented by the matrix {V * O}. * * @param O * origin of the line * @param V * direction of the line * @param H * point projected */ public void projectLine(Coords O, Coords V, Coords H) { this.sub(O, H); // OM Coords N = V.normalized(); double parameter = H.dotproduct(N); // OM.N N.mul(parameter, H); // OH O.add(H, H); } /** * calculates projection of this as far as possible to the 3D-line * represented by the matrix {V O} regarding V2 direction. * * @param O * origin of the line * @param V * direction of the line * @param V2 * direction of projection * @return point projected */ public void projectNearLine(Coords O, Coords V, Coords V2, Coords project) { Coords V3 = V.crossProduct(V2); if (Kernel.isEqual(V3.norm(), 0.0, Kernel.STANDARD_PRECISION)) { project.set(this); return; } projectPlane(V, V3, V2, O, project); } /** * Calc the parameter on (O,V) of the point of (O,V) that is the nearest to * line (this,V2). * * If V and V2 are parallel, return O. * * @param O * origin of the line where this is projected * @param V * direction of the line where this is projected * @param V2 * direction of projection * @param tmp * temp coords * @return parameter of the proj. point on the line */ public double projectedParameterOnLineWithDirection(Coords O, Coords V, Coords V2, Coords tmp) { Coords V3 = V.crossProduct4(V2); if (V3.isZero()) { return 0; } O.projectPlaneInPlaneCoords(V2, V3, V, this, tmp); return -tmp.getZ(); } /** * returns this-v * * @param v * vector subtracted * @return this-v * * deprecated create vector and use {@link #setSub(Coords, Coords)} * instead */ public Coords sub(Coords v) { int i; Coords result = new Coords(rows); for (i = 0; i < rows; i++) { result.val[i] = val[i] - v.val[i]; } return result; } /** * * @param v * vector * @param result * gets this - v */ public void sub(Coords v, Coords result) { for (int i = 0; i < result.rows; i++) { result.val[i] = val[i] - v.val[i]; } } /** * set this to v1 - v2 * * @param v1 * vector * @param v2 * vector * @return this */ public Coords setSub(Coords v1, Coords v2) { for (int i = 0; i < rows; i++) { val[i] = v1.val[i] - v2.val[i]; } return this; } /** * set this to v1 - v2 (only first 3 values) * * @param v1 * vector * @param v2 * vector * @return this */ public Coords setSub3(Coords v1, Coords v2) { for (int i = 0; i < 3; i++) { val[i] = v1.val[i] - v2.val[i]; } return this; } /** * returns n-1 length vector, all coordinates divided by the n-th. * <p> * If this={x1,x2,xn}, it returns {x1/xn,x2/xn,...,x(n-1)} * * @return {x1/xn,x2/xn,...,x(n-1)/xn} * * deprecated create vector and use {@link #setInhomCoords(Coords)} * instead */ public Coords getInhomCoords() { int r = rows; Coords result = new Coords(r - 1); double wdiv = 1 / val[r - 1]; for (int i = 0; i < r - 1; i++) { result.val[i] = val[i] * wdiv; } return result; } public double getInhom(int i) { int r = rows; double wdiv = 1 / val[r - 1]; return val[i] * wdiv; } /** * If v={x1,x2,xn}, this gets {x1/xn,x2/xn,...,x(n-1)} * * @param v * vector * * @return this */ public Coords setInhomCoords(Coords v) { double wdiv = 1 / v.val[rows - 1]; for (int i = 0; i < rows - 1; i++) { val[i] = v.val[i] * wdiv; } return this; } /** * returns n length vector, all coordinates divided by the n-th. * * @return {x1/xn,x2/xn,...,x(n-1)/xn,1} * * deprecated create vector and use * {@link #setInhomCoordsInSameDimension(Coords)} instead */ public Coords getInhomCoordsInSameDimension() { int r = rows; if (Kernel.isEqual(val[r - 1], 1)) { return this; } Coords result = new Coords(r); double wdiv = 1 / val[r - 1]; for (int i = 0; i < r - 1; i++) { result.val[i] = val[i] * wdiv; } result.val[r - 1] = 1; return result; } /** * * If v={x1,x2,xn}, this gets {x1/xn,x2/xn,...,x(n-1, 1)} * * @param v * vector * * @return this */ public Coords setInhomCoordsInSameDimension(Coords v) { setInhomCoords(v); val[rows - 1] = 1; return this; } /** * set values in inhom coords */ public void setInhomCoords() { if (Kernel.isEqual(val[rows - 1], 1)) { return; } double wdiv = 1 / val[rows - 1]; for (int i = 0; i < rows - 1; i++) { val[i] *= wdiv; } val[rows - 1] = 1; } /** * returns n length vector, all coordinates divided by the n-th. * <p> * If this={x1,x2,xn}, it returns {x1/xn,x2/xn,...,1} * * @return {x1/xn,x2/xn,...,1} * * deprecated create vector and use {@link #setCoordsLast1(Coords)} * instead */ public Coords getCoordsLast1() { int len = getLength(); Coords result = new Coords(len); double lastCoord = val[len - 1]; if (lastCoord != 0.0) { double lastCoordInv = 1 / lastCoord; for (int i = 0; i < len; i++) { result.val[i] = val[i] * lastCoordInv; } } else { result.set(this); } return result; } /** * * If v={x1,x2,xn}, this gets {x1/xn,x2/xn,...,1} * * @param v * vector * * @return this */ public Coords setCoordsLast1(Coords v) { double lastCoord = v.val[rows - 1]; if (lastCoord != 0.0) { double lastCoordInv = 1 / lastCoord; for (int i = 0; i < rows; i++) { val[i] = v.val[i] * lastCoordInv; } } else { set(v); } return this; } /** * * @return this with (n-1) coord removed deprecated create vector and use * {@link #setProjectInfDim(Coords)} instead */ public Coords projectInfDim() { int len = getLength(); Coords result = new Coords(len - 1); for (int i = 0; i < len - 1; i++) { result.val[i] = val[i]; } result.val[len - 2] = val[len - 1]; return result; } /** * set this equal to v with (n-1) coord removed * * @param v * vector * @return this */ public Coords setProjectInfDim(Coords v) { for (int i = 0; i < v.rows - 1; i++) { val[i] = v.val[i]; } val[rows - 2] = v.val[rows - 1]; return this; } /** * Return true if this==v for the precision given (ie each coordinates are * not different more than precision). * * @param v * vector compared with * @param precision * @return true if the vectors are equal */ public boolean equalsForKernel(Coords v, double precision) { int len = getLength(); for (int i = 0; i < len; i++) { if (!Kernel.isEqual(val[i], v.val[i], precision)) { return false; } } return true; } /** * Return true if this==v for the precision given (ie each coordinates are * not different more than precision). * * @param v * vector compared with * @return true if the vectors are equal */ public boolean equalsForKernel(Coords v) { int len = getLength(); for (int i = 0; i < len; i++) { if (!Kernel.isEqual(val[i], v.val[i])) { return false; } } return true; } /** * Return true if this==v for Kernel.STANDARD_PRECISION precision (ie each * coordinates are not different more than precision). * * @param v * vector compared with * @return true if the vectors are equal */ public boolean isEqual(Coords v) { return equalsForKernel(v, Kernel.STANDARD_PRECISION); } /** * check if all entries are zero * * @param precision * @return */ public boolean isZero() { int len = getLength(); for (int i = 0; i < len; i++) { if (!Kernel.isEqual(val[i], 0, Kernel.STANDARD_PRECISION)) { return false; } } return true; } /** * @param dim * number of coords that must be 0 * @return whether first dim coords are 0 */ public boolean isZero(int dim) { for (int i = 0; i < dim; i++) { if (!Kernel.isEqual(val[i], 0, Kernel.STANDARD_PRECISION)) { return false; } } return true; } /** * Return true if all coordinates are not different from val more than * precision. * * @param val * value compared with * @param precision * @return true if all coordinates are not different from val more than * precision. */ public boolean equalsForKernel(double val, double precision) { int len = getLength(); for (int i = 0; i < len; i++) { if (!Kernel.isEqual(this.val[i], val, precision)) { return false; } } return true; } /** * Assume that "this" is a non-zero vector in 3-space. This method returns * an array v of two vectors {v[0], v[1]} (rows=4) so that (this, v[0], * v[1]) is a right-handed orthonormal system. * * deprecated create vectors and use * {@link #completeOrthonormal(Coords, Coords)} instead */ public Coords[] completeOrthonormal() { Coords vn1 = new Coords(4); if (val[0] != 0) { vn1.val[0] = -val[1]; vn1.val[1] = val[0]; vn1.normalize(); } else { vn1.val[0] = 1.0; } Coords vn2 = this.crossProduct4(vn1); vn2.normalize(); return new Coords[] { vn1, vn2 }; } /** * Assume that "this" is a non-zero vector in 3-space. This method sets the * vectors vn1, vn2 (rows=4) so that (this, vn1, vn2) is a right-handed * orthonormal system. * * @param vn1 * vector (length 4) * @param vn2 * vector (length 4) */ public void completeOrthonormal(Coords vn1, Coords vn2) { if (val[0] != 0) { vn1.val[0] = -val[1]; vn1.val[1] = val[0]; vn1.val[2] = 0; vn1.val[3] = 0; vn1.normalize(); } else { vn1.val[0] = 1.0; vn1.val[1] = 0.0; vn1.val[2] = 0.0; vn1.val[3] = 0.0; } vn2.setCrossProduct(this, vn1); vn2.setW(0); vn2.normalize(); } /** * Assume that "this" is a non-zero vector in 3-space. This method sets the * vectors vn1, vn2 (rows=3) so that (this, vn1, vn2) is a right-handed * orthonormal system. * * @param vn1 * vector (length 3) * @param vn2 * vector (length 3) */ public void completeOrthonormal3(Coords vn1, Coords vn2) { if (val[0] != 0) { vn1.val[0] = -val[1]; vn1.val[1] = val[0]; vn1.val[2] = 0; vn1.normalize(); } else { vn1.val[0] = 1.0; vn1.val[1] = 0.0; vn1.val[2] = 0.0; } vn2.setCrossProduct(this, vn1); vn2.normalize(); } /** * Assume that "this" is a non-zero vector in 3-space. This method sets the * vector vn1 so that (this, vn1) is orthonormal * * @param vn1 * vector (length 4) */ public void completeOrthonormal(Coords vn1) { if (val[2] != 0) { vn1.val[2] = -val[1]; vn1.val[1] = val[2]; vn1.val[0] = 0; vn1.val[3] = 0; vn1.normalize(); } else { vn1.val[0] = 0.0; vn1.val[1] = 0.0; vn1.val[2] = 1.0; vn1.val[3] = 0.0; } } /** * Assume that "this" is a non-zero vector in 3-space. This method sets the * vector vn1 so that (this, vn1) is orthonormal. If this is in xOy plane, * then vn1 will. * * @param vn1 * vector (length 4) */ public void completeOrthonormalKeepInXOYPlaneIfPossible(Coords vn1) { vn1.val[3] = 0; completeOrthonormalKeepInXOYPlaneIfPossible3(vn1); } /** * Assume that "this" is a non-zero vector in 3-space. This method sets the * vector vn1 so that (this, vn1) is orthonormal. If this is in xOy plane, * then vn1 will. * * @param vn1 * vector (length 3) */ public void completeOrthonormalKeepInXOYPlaneIfPossible3(Coords vn1) { if (!Kernel.isZero(val[0]) || !Kernel.isZero(val[1])) { vn1.val[0] = -val[1]; vn1.val[1] = val[0]; vn1.val[2] = 0; vn1.normalize(); } else { vn1.val[0] = 1.0; vn1.val[1] = 0.0; vn1.val[2] = 0.0; } } // /////////////////////////////////////////////////// // BASIC OPERATIONS // /////////////////////////////////////////////////// /** * * @param v * @return * * deprecated create vector and use {@link #setAdd(Coords, Coords)} * or {@link #setAdd3(Coords, Coords)} instead */ public Coords add(Coords v) { Coords result = new Coords(rows); for (int i = 0; i < rows && i < v.rows; i++) { result.val[i] = val[i] + v.val[i]; } return result; } /** * put this + v into result * * @param v * vector * @param result * result */ public void add(Coords v, double[] result) { for (int i = 0; i < rows; i++) { result[i] = val[i] + v.val[i]; } } /** * put this + v into result * * @param v * vector * @param result * result */ public void add(double[] v, double[] result) { for (int i = 0; i < rows; i++) { result[i] = val[i] + v[i]; } } /** * * @param v * @return * * deprecated create vector and use {@link #setAdd(Coords, Coords)} * or {@link #setAdd3(Coords, Coords) instead */ public Coords addSmaller(Coords v) { Coords result = new Coords(rows); for (int i = 0; i < v.rows; i++) { result.val[i] = val[i] + v.val[i]; } return result; } /** * add values of v inside this * * @param v * vector * @return this */ public Coords addInside(Coords v) { for (int i = 0; i < v.val.length; i++) { val[i] += v.val[i]; } return this; } /** * add values of v inside this * * @param v * vector */ public Coords addInsideMul(Coords v, double coeff) { for (int i = 0; i < v.val.length; i++) { val[i] += coeff * v.val[i]; } return this; } /** * add v inside this * * @param v * value */ public void addInside(double v) { for (int i = 0; i < rows; i++) { val[i] += v; } } /** * * @param val0 * @return * * deprecated create vector and use {@link #setMul(Coords, double)} * instead */ public Coords mul(double val0) { Coords result = new Coords(rows); for (int i = 0; i < rows; i++) { result.val[i] = val[i] * val0; } return result; } /** * @return a copy of this coords object */ public Coords copy() { Coords result = new Coords(rows); for (int i = 0; i < rows; i++) { result.val[i] = val[i]; } return result; } /** * * @param val0 * factor * @param res * gets this * val0 */ public void mul(double val0, Coords res) { for (int i = 0; i < res.rows && i < rows; i++) { res.val[i] = val[i] * val0; } } /** * set this to v * val0 * * @param v * vector * @param val0 * value * @return this */ public Coords setMul(Coords v, double val0) { for (int i = 0; i < rows && i < v.rows; i++) { val[i] = v.val[i] * val0; } return this; } /** * set this to v * val0 (only 3 first values) * * @param v * vector * @param val0 * value * @return this */ public Coords setMul3(Coords v, double val0) { for (int i = 0; i < 3; i++) { val[i] = v.val[i] * val0; } return this; } /** * * @param val0 * factor * @param res * gets this * val0 */ public void mul(double val0, double[] res) { for (int i = 0; i < res.length && i < rows; i++) { res[i] = val[i] * val0; } } /** * * @param v * vector * @param res * gets this + v */ public void add(Coords v, Coords res) { for (int i = 0; i < res.rows; i++) { res.val[i] = v.val[i] + val[i]; } } /** * set this to v1 + v2 * * @param v1 * vector * @param v2 * vector * @return this */ public Coords setAdd(Coords v1, Coords v2) { for (int i = 0; i < rows; i++) { val[i] = v1.val[i] + v2.val[i]; } return this; } /** * set this to v1 + v2 (for 3 first coords) * * @param v1 * vector * @param v2 * vector * @return this */ public Coords setAdd3(Coords v1, Coords v2) { for (int i = 0; i < 3; i++) { val[i] = v1.val[i] + v2.val[i]; } return this; } /** * set this as barycenter for vectors in v * * @param v * vectors * @return this */ public Coords setBarycenter(Coords... v) { double f = 1.0 / v.length; for (int i = 0; i < rows; i++) { val[i] = 0; for (int j = 0; j < v.length; j++) { val[i] += v[j].val[i]; } val[i] *= f; } return this; } // /////////////////////////////////////////////////: /** for testing the package */ public static synchronized void main(String[] args) { Coords v1 = new Coords(2); v1.val[0] = 3.0; v1.val[1] = 4.0; Log.debug("v1.v1 = " + v1.dotproduct(v1)); } /** * if the ND hom coords is in x-y plane, return this coords * * @param coordsND * @return * * deprecated create 3 rows vector and use * {@link #setCoordsIn2DView(Coords)} instead */ public Coords getCoordsIn2DView() { int dim = rows - 1; switch (dim) { case 2: return new Coords(getX(), getY(), getZ()); case -1: case 0: return new Coords(0, 0, getX()); case 1: return new Coords(getX(), 0, getY()); default: for (int i = 3; i <= dim; i++) { if (Double.isNaN(get(i)) || !Kernel.isZero(get(i))) { return new Coords(Double.NaN, Double.NaN, Double.NaN); } } // get(3) to get(dim) are all zero return new Coords(get(1), get(2), get(dim + 1)); } } /** * if the ND hom coords is in x-y plane, set this to v coords * * @param v * vector * @return this * */ public Coords setCoordsIn2DView(Coords v) { int dim = v.rows - 1; switch (dim) { case 2: setX(v.getX()); setY(v.getY()); setZ(v.getZ()); break; case -1: case 0: setX(0); setY(0); setZ(v.getX()); break; case 1: setX(v.getX()); setY(0); setZ(v.getY()); break; default: for (int i = 3; i <= dim; i++) { if (Double.isNaN(v.get(i)) || !Kernel.isZero(v.get(i))) { setX(Double.NaN); setY(Double.NaN); setZ(Double.NaN); return this; } } // get(3) to get(dim) are all zero setX(v.get(1)); setY(v.get(2)); setZ(v.get(dim + 1)); } return this; } /** * this=(r,g,b,...) color representation * * @return gray scale intensity */ public double getGrayScale() { return 0.2989 * getX() + 0.5870 * getY() + 0.1140 * getZ(); } public void convertToGrayScale() { double gray = getGrayScale(); setX(gray); setY(gray); setZ(gray); } /** * assume this is equal to (x,y,z,w) * * @return true if define a defined point */ public boolean isPointDefined() { if (Kernel.isZero(getW())) { return false; } return isDefined(); } /** * returns false if one value equals NaN * * @return false if one value equals NaN */ public boolean isDefined() { if (val == null) { return false; } for (int i = 0; i < rows; i++) { if (Double.isNaN(val[i])) { return false; } } return true; } /** * set this to undefined */ public void setUndefined() { val[0] = Double.NaN; } /** * set all values to Double.POSITIVE_INFINITY */ public void setPositiveInfinity() { for (int i = 0; i < rows; i++) { val[i] = Double.POSITIVE_INFINITY; } } /** * set all values to Double.NEGATIVE_INFINITY */ public void setNegativeInfinity() { for (int i = 0; i < rows; i++) { val[i] = Double.NEGATIVE_INFINITY; } } /** * * set 3 floats array */ public void get3ForGL(float[] ret) { for (int i = 0; i < 3; i++) { ret[i] = (float) val[i]; } } /** * * set 4 floats array */ public void get4ForGL(float[] ret) { for (int i = 0; i < 4; i++) { ret[i] = (float) val[i]; } } /** * check for first non-zero value ; reverse all values if this one is * negative */ public void checkReverseForFirstValuePositive() { boolean zero = true; int i = 0; while (i < val.length && zero) { if (!Kernel.isZero(val[i])) { zero = false; } else { i++; } } if (!zero && val[i] < 0) { while (i < val.length) { val[i] *= -1; i++; } } } /** * returns double[] describing the matrix for openGL * * @return the matrix as a double[] */ public double[] get() { return val; } /** * get values and set it in ret * * @param ret * ret */ public void get(double[] ret) { for (int i = 0; i < ret.length; i++) { ret[i] = val[i]; } } /** @return false if at least one value is infinite */ public boolean isFinite() { for (int i = 0; i < rows; i++) { if (Double.isInfinite(val[i])) { return false; } } return true; } /** * multiply all values by v * * @param v * factor * @return this */ public Coords mulInside(double v) { for (int i = 0; i < val.length; i++) { val[i] *= v; } return this; } /** * mul 3 first values by v * * @param v * value * @return this */ public Coords mulInside3(double v) { for (int i = 0; i < 3; i++) { val[i] *= v; } return this; } /** * mul x, y, z by factors * * @param sx * x scale * @param sy * y scale * @param sz * z scale */ public void mulInside(double sx, double sy, double sz) { val[0] *= sx; val[1] *= sy; val[2] *= sz; } /** * mul coords by x, y, z factors * * @param coords * coords * @param sx * x scale * @param sy * y scale * @param sz * z scale */ public void setMul(Coords coords, double sx, double sy, double sz) { val[0] = coords.val[0] * sx; val[1] = coords.val[1] * sy; val[2] = coords.val[2] * sz; } @Override public String toString() { StringBuilder s = new StringBuilder(); for (int i = 0; i < val.length; i++) { s.append(val[i]); s.append('\n'); } return s.toString(); } /** * set this = m*v * * @param m * matrix * @param v * vector * @return this */ public Coords setMul(CoordMatrix m, Coords v) { for (int i = 1; i <= getLength(); i++) { double r = 0; for (int n = 1; n <= m.getColumns(); n++) { r += m.get(i, n) * v.get(n); } set(i, r); } return this; } /** * set this = m*v * * @param m * matrix * @param v * vector * @return this */ public Coords setMul(CoordMatrix m, double[] v) { for (int i = 1; i <= getLength(); i++) { double r = 0; for (int j = 0; j < v.length; j++) { r += m.get(i, j + 1) * v[j]; } set(i, r); } return this; } /** * set this = m*(x,y,z,1) * * @param m * matrix * @param x * point x coord * @param y * point y coord * @param z * point z coord * @return this */ public Coords setMulPoint(CoordMatrix m, double x, double y, double z) { for (int i = 1; i <= getLength(); i++) { set(i, m.get(i, 1) * x + m.get(i, 2) * y + m.get(i, 3) * z + m.get(i, 4)); } return this; } /** * @return true if not a final (constant) undefined Coords */ public boolean isNotFinalUndefined() { return true; } /** * @return true if a final (constant) undefined Coords */ public boolean isFinalUndefined() { return false; } public static void xyToCoordSystem(Coords coords, Coords vec) { if (!Kernel.isZero(vec.getZ())) { coords.setZ(-vec.getX() * coords.getX() / vec.getZ() - vec.getY() * coords.getY() / vec.getZ() - vec.getW() / vec.getZ()); } else { if (!Kernel.isZero(vec.getY())) { double oldY = coords.getY(); coords.setY(-vec.getX() * coords.getX() / vec.getY() - vec.getW() / vec.getY()); coords.setZ(oldY); } else { double oldX = coords.getX(); coords.setX(-vec.getW() / vec.getX()); coords.setZ(coords.getY()); coords.setY(oldX); } } } /** * set 2D barycenter from the two points * * @param param1 * @param param2 * @param leftPoint * @param rightPoint */ public void set(double param1, double param2, MyPoint leftPoint, MyPoint rightPoint) { val[0] = param2 * leftPoint.x + param1 * rightPoint.x; val[1] = param2 * leftPoint.y + param1 * rightPoint.y; val[2] = 1.0; } }