/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.spatial3d.geom;

A 3d vector in space, not necessarily going through the origin.
@lucene.experimental
/** * A 3d vector in space, not necessarily * going through the origin. * * @lucene.experimental */
public class Vector {
Values that are all considered to be essentially zero have a magnitude less than this.
/** * Values that are all considered to be essentially zero have a magnitude * less than this. */
public static final double MINIMUM_RESOLUTION = 1.0e-12;
Angular version of minimum resolution.
/** * Angular version of minimum resolution. */
public static final double MINIMUM_ANGULAR_RESOLUTION = Math.PI * MINIMUM_RESOLUTION;
For squared quantities, the bound is squared too.
/** * For squared quantities, the bound is squared too. */
public static final double MINIMUM_RESOLUTION_SQUARED = MINIMUM_RESOLUTION * MINIMUM_RESOLUTION;
For cubed quantities, cube the bound.
/** * For cubed quantities, cube the bound. */
public static final double MINIMUM_RESOLUTION_CUBED = MINIMUM_RESOLUTION_SQUARED * MINIMUM_RESOLUTION;
The x value
/** The x value */
public final double x;
The y value
/** The y value */
public final double y;
The z value
/** The z value */
public final double z;
Gram-Schmidt convergence envelope is a bit smaller than we really need because we don't want the math to fail afterwards in other places.
/** * Gram-Schmidt convergence envelope is a bit smaller than we really need because we don't want the math to fail afterwards in * other places. */
private static final double MINIMUM_GRAM_SCHMIDT_ENVELOPE = MINIMUM_RESOLUTION * 0.5;
Construct from (U.S.) x,y,z coordinates.
Params:
  • x – is the x value.
  • y – is the y value.
  • z – is the z value.
/** * Construct from (U.S.) x,y,z coordinates. *@param x is the x value. *@param y is the y value. *@param z is the z value. */
public Vector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; }
Construct a vector that is perpendicular to two other (non-zero) vectors. If the vectors are parallel, IllegalArgumentException will be thrown. Produces a normalized final vector.
Params:
  • A – is the first vector
  • BX – is the X value of the second
  • BY – is the Y value of the second
  • BZ – is the Z value of the second
/** * Construct a vector that is perpendicular to * two other (non-zero) vectors. If the vectors are parallel, * IllegalArgumentException will be thrown. * Produces a normalized final vector. * * @param A is the first vector * @param BX is the X value of the second * @param BY is the Y value of the second * @param BZ is the Z value of the second */
public Vector(final Vector A, final double BX, final double BY, final double BZ) { // We're really looking at two vectors and computing a perpendicular one from that. this(A.x, A.y, A.z, BX, BY, BZ); }
Construct a vector that is perpendicular to two other (non-zero) vectors. If the vectors are parallel, IllegalArgumentException will be thrown. Produces a normalized final vector.
Params:
  • AX – is the X value of the first
  • AY – is the Y value of the first
  • AZ – is the Z value of the first
  • BX – is the X value of the second
  • BY – is the Y value of the second
  • BZ – is the Z value of the second
/** * Construct a vector that is perpendicular to * two other (non-zero) vectors. If the vectors are parallel, * IllegalArgumentException will be thrown. * Produces a normalized final vector. * * @param AX is the X value of the first * @param AY is the Y value of the first * @param AZ is the Z value of the first * @param BX is the X value of the second * @param BY is the Y value of the second * @param BZ is the Z value of the second */
public Vector(final double AX, final double AY, final double AZ, final double BX, final double BY, final double BZ) { // We're really looking at two vectors and computing a perpendicular one from that. // We can think of this as having three points -- the origin, and two points that aren't the origin. // Normally, we can compute the perpendicular vector this way: // x = u2v3 - u3v2 // y = u3v1 - u1v3 // z = u1v2 - u2v1 // Sometimes that produces a plane that does not contain the original three points, however, due to // numerical precision issues. Then we continue making the answer more precise using the // Gram-Schmidt process: https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process // Compute the naive perpendicular final double thisX = AY * BZ - AZ * BY; final double thisY = AZ * BX - AX * BZ; final double thisZ = AX * BY - AY * BX; final double magnitude = magnitude(thisX, thisY, thisZ); if (magnitude == 0.0) { throw new IllegalArgumentException("Degenerate/parallel vector constructed"); } final double inverseMagnitude = 1.0/magnitude; double normalizeX = thisX * inverseMagnitude; double normalizeY = thisY * inverseMagnitude; double normalizeZ = thisZ * inverseMagnitude; // For a plane to work, the dot product between the normal vector // and the points needs to be less than the minimum resolution. // This is sometimes not true for points that are very close. Therefore // we need to adjust int i = 0; while (true) { final double currentDotProdA = AX * normalizeX + AY * normalizeY + AZ * normalizeZ; final double currentDotProdB = BX * normalizeX + BY * normalizeY + BZ * normalizeZ; if (Math.abs(currentDotProdA) < MINIMUM_GRAM_SCHMIDT_ENVELOPE && Math.abs(currentDotProdB) < MINIMUM_GRAM_SCHMIDT_ENVELOPE) { break; } // Converge on the one that has largest dot product final double currentVectorX; final double currentVectorY; final double currentVectorZ; final double currentDotProd; if (Math.abs(currentDotProdA) > Math.abs(currentDotProdB)) { currentVectorX = AX; currentVectorY = AY; currentVectorZ = AZ; currentDotProd = currentDotProdA; } else { currentVectorX = BX; currentVectorY = BY; currentVectorZ = BZ; currentDotProd = currentDotProdB; } // Adjust normalizeX = normalizeX - currentDotProd * currentVectorX; normalizeY = normalizeY - currentDotProd * currentVectorY; normalizeZ = normalizeZ - currentDotProd * currentVectorZ; // Normalize final double correctedMagnitude = magnitude(normalizeX, normalizeY, normalizeZ); final double inverseCorrectedMagnitude = 1.0 / correctedMagnitude; normalizeX = normalizeX * inverseCorrectedMagnitude; normalizeY = normalizeY * inverseCorrectedMagnitude; normalizeZ = normalizeZ * inverseCorrectedMagnitude; //This is probably not needed as the method seems to converge //quite quickly. But it is safer to have a way out. if (i++ > 10) { throw new IllegalArgumentException("Plane could not be constructed! Could not find a normal vector."); } } this.x = normalizeX; this.y = normalizeY; this.z = normalizeZ; }
Construct a vector that is perpendicular to two other (non-zero) vectors. If the vectors are parallel, IllegalArgumentException will be thrown. Produces a normalized final vector.
Params:
  • A – is the first vector
  • B – is the second
/** * Construct a vector that is perpendicular to * two other (non-zero) vectors. If the vectors are parallel, * IllegalArgumentException will be thrown. * Produces a normalized final vector. * * @param A is the first vector * @param B is the second */
public Vector(final Vector A, final Vector B) { this(A, B.x, B.y, B.z); }
Compute a magnitude of an x,y,z value.
/** Compute a magnitude of an x,y,z value. */
public static double magnitude(final double x, final double y, final double z) { return Math.sqrt(x*x + y*y + z*z); }
Compute a normalized unit vector based on the current vector.
Returns:the normalized vector, or null if the current vector has a magnitude of zero.
/** * Compute a normalized unit vector based on the current vector. * * @return the normalized vector, or null if the current vector has * a magnitude of zero. */
public Vector normalize() { double denom = magnitude(); if (denom < MINIMUM_RESOLUTION) // Degenerate, can't normalize return null; double normFactor = 1.0 / denom; return new Vector(x * normFactor, y * normFactor, z * normFactor); }
Evaluate the cross product of two vectors against a point. If the dot product of the resultant vector resolves to "zero", then return true.
Params:
  • A – is the first vector to use for the cross product.
  • B – is the second vector to use for the cross product.
  • point – is the point to evaluate.
Returns:true if we get a zero dot product.
/** * Evaluate the cross product of two vectors against a point. * If the dot product of the resultant vector resolves to "zero", then * return true. * @param A is the first vector to use for the cross product. * @param B is the second vector to use for the cross product. * @param point is the point to evaluate. * @return true if we get a zero dot product. */
public static boolean crossProductEvaluateIsZero(final Vector A, final Vector B, final Vector point) { // Include Gram-Schmidt in-line so we avoid creating objects unnecessarily // Compute the naive perpendicular final double thisX = A.y * B.z - A.z * B.y; final double thisY = A.z * B.x - A.x * B.z; final double thisZ = A.x * B.y - A.y * B.x; final double magnitude = magnitude(thisX, thisY, thisZ); if (magnitude == 0.0) { return true; } final double inverseMagnitude = 1.0/magnitude; double normalizeX = thisX * inverseMagnitude; double normalizeY = thisY * inverseMagnitude; double normalizeZ = thisZ * inverseMagnitude; // For a plane to work, the dot product between the normal vector // and the points needs to be less than the minimum resolution. // This is sometimes not true for points that are very close. Therefore // we need to adjust int i = 0; while (true) { final double currentDotProdA = A.x * normalizeX + A.y * normalizeY + A.z * normalizeZ; final double currentDotProdB = B.x * normalizeX + B.y * normalizeY + B.z * normalizeZ; if (Math.abs(currentDotProdA) < MINIMUM_GRAM_SCHMIDT_ENVELOPE && Math.abs(currentDotProdB) < MINIMUM_GRAM_SCHMIDT_ENVELOPE) { break; } // Converge on the one that has largest dot product final double currentVectorX; final double currentVectorY; final double currentVectorZ; final double currentDotProd; if (Math.abs(currentDotProdA) > Math.abs(currentDotProdB)) { currentVectorX = A.x; currentVectorY = A.y; currentVectorZ = A.z; currentDotProd = currentDotProdA; } else { currentVectorX = B.x; currentVectorY = B.y; currentVectorZ = B.z; currentDotProd = currentDotProdB; } // Adjust normalizeX = normalizeX - currentDotProd * currentVectorX; normalizeY = normalizeY - currentDotProd * currentVectorY; normalizeZ = normalizeZ - currentDotProd * currentVectorZ; // Normalize final double correctedMagnitude = magnitude(normalizeX, normalizeY, normalizeZ); final double inverseCorrectedMagnitude = 1.0 / correctedMagnitude; normalizeX = normalizeX * inverseCorrectedMagnitude; normalizeY = normalizeY * inverseCorrectedMagnitude; normalizeZ = normalizeZ * inverseCorrectedMagnitude; //This is probably not needed as the method seems to converge //quite quickly. But it is safer to have a way out. if (i++ > 10) { throw new IllegalArgumentException("Plane could not be constructed! Could not find a normal vector."); } } return Math.abs(normalizeX * point.x + normalizeY * point.y + normalizeZ * point.z) < MINIMUM_RESOLUTION; }
Do a dot product.
Params:
  • v – is the vector to multiply.
Returns:the result.
/** * Do a dot product. * * @param v is the vector to multiply. * @return the result. */
public double dotProduct(final Vector v) { return this.x * v.x + this.y * v.y + this.z * v.z; }
Do a dot product.
Params:
  • x – is the x value of the vector to multiply.
  • y – is the y value of the vector to multiply.
  • z – is the z value of the vector to multiply.
Returns:the result.
/** * Do a dot product. * * @param x is the x value of the vector to multiply. * @param y is the y value of the vector to multiply. * @param z is the z value of the vector to multiply. * @return the result. */
public double dotProduct(final double x, final double y, final double z) { return this.x * x + this.y * y + this.z * z; }
Determine if this vector, taken from the origin, describes a point within a set of planes.
Params:
  • bounds – is the first part of the set of planes.
  • moreBounds – is the second part of the set of planes.
Returns:true if the point is within the bounds.
/** * Determine if this vector, taken from the origin, * describes a point within a set of planes. * * @param bounds is the first part of the set of planes. * @param moreBounds is the second part of the set of planes. * @return true if the point is within the bounds. */
public boolean isWithin(final Membership[] bounds, final Membership... moreBounds) { // Return true if the point described is within all provided bounds //System.err.println(" checking if "+this+" is within bounds"); for (final Membership bound : bounds) { if (bound != null && !bound.isWithin(this)) { //System.err.println(" NOT within "+bound); return false; } } for (final Membership bound : moreBounds) { if (bound != null && !bound.isWithin(this)) { //System.err.println(" NOT within "+bound); return false; } } //System.err.println(" is within"); return true; }
Translate vector.
/** * Translate vector. */
public Vector translate(final double xOffset, final double yOffset, final double zOffset) { return new Vector(x - xOffset, y - yOffset, z - zOffset); }
Rotate vector counter-clockwise in x-y by an angle.
/** * Rotate vector counter-clockwise in x-y by an angle. */
public Vector rotateXY(final double angle) { return rotateXY(Math.sin(angle), Math.cos(angle)); }
Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos.
/** * Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos. */
public Vector rotateXY(final double sinAngle, final double cosAngle) { return new Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z); }
Rotate vector counter-clockwise in x-z by an angle.
/** * Rotate vector counter-clockwise in x-z by an angle. */
public Vector rotateXZ(final double angle) { return rotateXZ(Math.sin(angle), Math.cos(angle)); }
Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos.
/** * Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos. */
public Vector rotateXZ(final double sinAngle, final double cosAngle) { return new Vector(x * cosAngle - z * sinAngle, y, x * sinAngle + z * cosAngle); }
Rotate vector counter-clockwise in z-y by an angle.
/** * Rotate vector counter-clockwise in z-y by an angle. */
public Vector rotateZY(final double angle) { return rotateZY(Math.sin(angle), Math.cos(angle)); }
Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos.
/** * Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos. */
public Vector rotateZY(final double sinAngle, final double cosAngle) { return new Vector(x, z * sinAngle + y * cosAngle, z * cosAngle - y * sinAngle); }
Compute the square of a straight-line distance to a point described by the vector taken from the origin. Monotonically increasing for arc distances up to PI.
Params:
  • v – is the vector to compute a distance to.
Returns:the square of the linear distance.
/** * Compute the square of a straight-line distance to a point described by the * vector taken from the origin. * Monotonically increasing for arc distances up to PI. * * @param v is the vector to compute a distance to. * @return the square of the linear distance. */
public double linearDistanceSquared(final Vector v) { double deltaX = this.x - v.x; double deltaY = this.y - v.y; double deltaZ = this.z - v.z; return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; }
Compute the square of a straight-line distance to a point described by the vector taken from the origin. Monotonically increasing for arc distances up to PI.
Params:
  • x – is the x part of the vector to compute a distance to.
  • y – is the y part of the vector to compute a distance to.
  • z – is the z part of the vector to compute a distance to.
Returns:the square of the linear distance.
/** * Compute the square of a straight-line distance to a point described by the * vector taken from the origin. * Monotonically increasing for arc distances up to PI. * * @param x is the x part of the vector to compute a distance to. * @param y is the y part of the vector to compute a distance to. * @param z is the z part of the vector to compute a distance to. * @return the square of the linear distance. */
public double linearDistanceSquared(final double x, final double y, final double z) { double deltaX = this.x - x; double deltaY = this.y - y; double deltaZ = this.z - z; return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; }
Compute the straight-line distance to a point described by the vector taken from the origin. Monotonically increasing for arc distances up to PI.
Params:
  • v – is the vector to compute a distance to.
Returns:the linear distance.
/** * Compute the straight-line distance to a point described by the * vector taken from the origin. * Monotonically increasing for arc distances up to PI. * * @param v is the vector to compute a distance to. * @return the linear distance. */
public double linearDistance(final Vector v) { return Math.sqrt(linearDistanceSquared(v)); }
Compute the straight-line distance to a point described by the vector taken from the origin. Monotonically increasing for arc distances up to PI.
Params:
  • x – is the x part of the vector to compute a distance to.
  • y – is the y part of the vector to compute a distance to.
  • z – is the z part of the vector to compute a distance to.
Returns:the linear distance.
/** * Compute the straight-line distance to a point described by the * vector taken from the origin. * Monotonically increasing for arc distances up to PI. * * @param x is the x part of the vector to compute a distance to. * @param y is the y part of the vector to compute a distance to. * @param z is the z part of the vector to compute a distance to. * @return the linear distance. */
public double linearDistance(final double x, final double y, final double z) { return Math.sqrt(linearDistanceSquared(x, y, z)); }
Compute the square of the normal distance to a vector described by a vector taken from the origin. Monotonically increasing for arc distances up to PI/2.
Params:
  • v – is the vector to compute a distance to.
Returns:the square of the normal distance.
/** * Compute the square of the normal distance to a vector described by a * vector taken from the origin. * Monotonically increasing for arc distances up to PI/2. * * @param v is the vector to compute a distance to. * @return the square of the normal distance. */
public double normalDistanceSquared(final Vector v) { double t = dotProduct(v); double deltaX = this.x * t - v.x; double deltaY = this.y * t - v.y; double deltaZ = this.z * t - v.z; return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; }
Compute the square of the normal distance to a vector described by a vector taken from the origin. Monotonically increasing for arc distances up to PI/2.
Params:
  • x – is the x part of the vector to compute a distance to.
  • y – is the y part of the vector to compute a distance to.
  • z – is the z part of the vector to compute a distance to.
Returns:the square of the normal distance.
/** * Compute the square of the normal distance to a vector described by a * vector taken from the origin. * Monotonically increasing for arc distances up to PI/2. * * @param x is the x part of the vector to compute a distance to. * @param y is the y part of the vector to compute a distance to. * @param z is the z part of the vector to compute a distance to. * @return the square of the normal distance. */
public double normalDistanceSquared(final double x, final double y, final double z) { double t = dotProduct(x, y, z); double deltaX = this.x * t - x; double deltaY = this.y * t - y; double deltaZ = this.z * t - z; return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; }
Compute the normal (perpendicular) distance to a vector described by a vector taken from the origin. Monotonically increasing for arc distances up to PI/2.
Params:
  • v – is the vector to compute a distance to.
Returns:the normal distance.
/** * Compute the normal (perpendicular) distance to a vector described by a * vector taken from the origin. * Monotonically increasing for arc distances up to PI/2. * * @param v is the vector to compute a distance to. * @return the normal distance. */
public double normalDistance(final Vector v) { return Math.sqrt(normalDistanceSquared(v)); }
Compute the normal (perpendicular) distance to a vector described by a vector taken from the origin. Monotonically increasing for arc distances up to PI/2.
Params:
  • x – is the x part of the vector to compute a distance to.
  • y – is the y part of the vector to compute a distance to.
  • z – is the z part of the vector to compute a distance to.
Returns:the normal distance.
/** * Compute the normal (perpendicular) distance to a vector described by a * vector taken from the origin. * Monotonically increasing for arc distances up to PI/2. * * @param x is the x part of the vector to compute a distance to. * @param y is the y part of the vector to compute a distance to. * @param z is the z part of the vector to compute a distance to. * @return the normal distance. */
public double normalDistance(final double x, final double y, final double z) { return Math.sqrt(normalDistanceSquared(x, y, z)); }
Compute the magnitude of this vector.
Returns:the magnitude.
/** * Compute the magnitude of this vector. * * @return the magnitude. */
public double magnitude() { return magnitude(x,y,z); }
Compute whether two vectors are numerically identical.
Params:
  • otherX – is the other vector X.
  • otherY – is the other vector Y.
  • otherZ – is the other vector Z.
Returns:true if they are numerically identical.
/** * Compute whether two vectors are numerically identical. * @param otherX is the other vector X. * @param otherY is the other vector Y. * @param otherZ is the other vector Z. * @return true if they are numerically identical. */
public boolean isNumericallyIdentical(final double otherX, final double otherY, final double otherZ) { final double deltaX = x - otherX; final double deltaY = y - otherY; final double deltaZ = z - otherZ; return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ < MINIMUM_RESOLUTION_SQUARED; }
Compute whether two vectors are numerically identical.
Params:
  • other – is the other vector.
Returns:true if they are numerically identical.
/** * Compute whether two vectors are numerically identical. * @param other is the other vector. * @return true if they are numerically identical. */
public boolean isNumericallyIdentical(final Vector other) { final double deltaX = x - other.x; final double deltaY = y - other.y; final double deltaZ = z - other.z; return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ < MINIMUM_RESOLUTION_SQUARED; }
Compute whether two vectors are parallel.
Params:
  • otherX – is the other vector X.
  • otherY – is the other vector Y.
  • otherZ – is the other vector Z.
Returns:true if they are parallel.
/** * Compute whether two vectors are parallel. * @param otherX is the other vector X. * @param otherY is the other vector Y. * @param otherZ is the other vector Z. * @return true if they are parallel. */
public boolean isParallel(final double otherX, final double otherY, final double otherZ) { final double thisX = y * otherZ - z * otherY; final double thisY = z * otherX - x * otherZ; final double thisZ = x * otherY - y * otherX; return thisX * thisX + thisY * thisY + thisZ * thisZ < MINIMUM_RESOLUTION_SQUARED; }
Compute whether two vectors are numerically identical.
Params:
  • other – is the other vector.
Returns:true if they are parallel.
/** * Compute whether two vectors are numerically identical. * @param other is the other vector. * @return true if they are parallel. */
public boolean isParallel(final Vector other) { final double thisX = y * other.z - z * other.y; final double thisY = z * other.x - x * other.z; final double thisZ = x * other.y - y * other.x; return thisX * thisX + thisY * thisY + thisZ * thisZ < MINIMUM_RESOLUTION_SQUARED; }
Compute the desired magnitude of a unit vector projected to a given planet model.
Params:
  • planetModel – is the planet model.
  • x – is the unit vector x value.
  • y – is the unit vector y value.
  • z – is the unit vector z value.
Returns:a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid.
/** Compute the desired magnitude of a unit vector projected to a given * planet model. * @param planetModel is the planet model. * @param x is the unit vector x value. * @param y is the unit vector y value. * @param z is the unit vector z value. * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid. */
static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) { return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared); }
Compute the desired magnitude of a unit vector projected to a given planet model. The unit vector is specified only by a z value.
Params:
  • planetModel – is the planet model.
  • z – is the unit vector z value.
Returns:a magnitude value for that z value that projects the vector onto the specified ellipsoid.
/** Compute the desired magnitude of a unit vector projected to a given * planet model. The unit vector is specified only by a z value. * @param planetModel is the planet model. * @param z is the unit vector z value. * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid. */
static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) { return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared); } @Override public boolean equals(Object o) { if (!(o instanceof Vector)) return false; Vector other = (Vector) o; return (other.x == x && other.y == y && other.z == z); } @Override public int hashCode() { int result; long temp; temp = Double.doubleToLongBits(x); result = (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(y); result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(z); result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public String toString() { return "[X=" + x + ", Y=" + y + ", Z=" + z + "]"; } }