package org.geogebra.common.kernel.Matrix; import org.geogebra.common.kernel.Kernel; /** * @author ggb3D * * Class for algebra utilities */ public final class CoordMatrixUtil { /** * Return points p1 from line1 and p2 from line2 that are the nearest * possible. Return infinite points if the two lines are parallel. * * @param o1 * origin of line1 * @param v1 * direction of line1 * @param o2 * origin of line2 * @param v2 * direction of line2 * @return {p1,p2,{p1 coord on l1,p2 coord on l2}} */ static final public Coords[] nearestPointsFromTwoLines(Coords o1, Coords v1, Coords o2, Coords v2) { double[] project1 = new double[4], project2 = new double[4], lineCoords = new double[2]; nearestPointsFromTwoLines(o1, v1, o2, v2, project1, project2, lineCoords, new double[4]); return new Coords[] { new Coords(project1), new Coords(project2), new Coords(lineCoords) }; } /** * Set points from line1 and from line2 that are the nearest possible. * Return infinite points if the two lines are parallel. * * @param o1 * origin of line1 * @param v1 * direction of line1 * @param o2 * origin of line2 * @param v2 * direction of line2 * @param project1 * point on line 1 * @param project2 * point on line 2 * @param lineCoords * parameters of each point on each line * @param tmp * tmp values (length 4) * */ static final public void nearestPointsFromTwoLines(Coords o1, Coords v1, Coords o2, Coords v2, double[] project1, double[] project2, double[] lineCoords, double[] tmp) { // if v1 and v2 are parallel, return infinite points v1 and v2 Coords vn = v1.crossProduct(v2); if (vn.equalsForKernel(0, Kernel.STANDARD_PRECISION)) { // Application.debug("v1="+v1.toString()+"\nv2="+v2.toString()); v1.copy(project1); v2.copy(project2); lineCoords[0] = Double.NaN; lineCoords[1] = Double.NaN; return; } // plane containing o1, v1, vn, with v2 direction // projection of o2 on this plane o2.projectPlaneNoCheck(v1, vn, v2, o1, project2, tmp); lineCoords[1] = -tmp[2]; // points in lines coords // plane containing o2, v2, vn, with v1 direction // projection of o1 on this plane o1.projectPlaneNoCheck(v2, vn, v1, o2, project1, tmp); lineCoords[0] = -tmp[2]; // points in lines coords } /** * Return the point p intersection of the line and the plane. <br> * Return infinite point (direction of the line) if the line is parallel to * plane. * * @param line * the line * @param plane * the plane * @return two vectors {globalCoords,inPlaneCoords}: the point p * intersection of the line and the plane, and the original point in * (plane.vx, plane.vy, line direction, line origin) coords */ static final public Coords[] intersectLinePlane(CoordMatrix line, CoordMatrix plane) { Coords v = line.getColumn(1); // if v is orthogonal to vn, v is parallel to the plane and so the line // is // if (Kernel.isEqual(vn.dotproduct(v),0,Kernel.STANDARD_PRECISION)) // return null; // project the origin of the line on the plane (along v direction) Coords o = line.getColumn(2); Coords[] result = new Coords[] { new Coords(4), new Coords(4) }; o.projectPlaneThruV(plane, v, result[0], result[1]); return result; } /** * return the spherical coords of v * * @param v * 3D vector in cartesian coords * @return the spherical coords of v */ static final public void sphericalCoords(Coords v, Coords ret) { double x = v.get(1); double y = v.get(2); double z = v.get(3); // norms double n2 = x * x + y * y; double n1 = Math.sqrt(n2); double norm = Math.sqrt(n2 + z * z); // angles double a; if (n1 == 0) { a = 0; } else { a = Math.acos(x / n1); if (y < 0) { a *= -1; } } double b; if (norm == 0) { b = 0; } else { b = Math.acos(n1 / norm); if (z < 0) { b *= -1; } } ret.setX(norm); ret.setY(a); ret.setZ(b); } /** * * @param origin * @param direction * @param plane * @return (a,b,c) where ax+by+c=0 is an equation of the line in the plane */ static final public Coords lineEquationVector(Coords origin, Coords direction, CoordMatrix plane) { Coords o = new Coords(4); origin.projectPlaneInPlaneCoords(plane, o); Coords d = new Coords(4); direction.projectPlaneInPlaneCoords(plane, d); return lineEquationVector(o, d); } /** * * @param origin * @param direction * @return (a,b,c) where ax+by+c=0 is an equation of the line in xOy plane */ static final public Coords lineEquationVector(Coords origin, Coords direction) { // if lines is not in the plane, return null if (!Kernel.isZero(origin.getZ()) || !Kernel.isZero(direction.getZ())) { return null; } double x = -direction.getY(); double y = direction.getX(); double z = -x * origin.getX() - y * origin.getY(); return new Coords(x, y, z); } /** * * @param plane1 * @param plane2 * @return {origin, direction} of the line intersection of the two planes */ static final public Coords[] intersectPlanes(CoordMatrix plane1, CoordMatrix plane2) { // compute direction vector Coords vn1 = plane1.getVz(); Coords vn2 = plane2.getVz(); Coords v = vn1.crossProduct(vn2); Coords direction = new Coords(4); Coords origin = new Coords(4); // compute origin if (v.isZero()) { // planes are parallel or equal origin.set(plane1.getOrigin()); // planes are equal plane1.getOrigin().projectPlaneInPlaneCoords(plane2, direction); if (!Kernel.isZero(direction.getZ())) { // plane are not included: // return (0,0,0,0) as // origin origin.set(0); } } else { // projection of first plane origin on second plane // direction orthogonal to v and colinear to first plane plane1.getOrigin().projectPlaneThruV(plane2, vn1.crossProduct4(v), origin); } // return line direction.set(v); direction.setW(0); // v is Coords(3) return new Coords[] { origin, direction }; } }