package com.github.quickhull3d; /* * #%L * A Robust 3D Convex Hull Algorithm in Java * %% * Copyright (C) 2004 - 2014 John E. Lloyd * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * #L% */ import java.util.Random; /** * A three-element vector. This class is actually a reduced version of the * Vector3d class contained in the author's matlib package (which was partly * inspired by javax.vecmath). Only a mininal number of methods which are * relevant to convex hull generation are supplied here. * * @author John E. Lloyd, Fall 2004 */ public class Vector3d { /** * Precision of a double. */ static private final double DOUBLE_PREC = 2.2204460492503131e-16; /** * First element */ public double x; /** * Second element */ public double y; /** * Third element */ public double z; /** * Creates a 3-vector and initializes its elements to 0. */ public Vector3d() { } /** * Creates a 3-vector by copying an existing one. * * @param v * vector to be copied */ public Vector3d(Vector3d v) { set(v); } /** * Creates a 3-vector with the supplied element values. * * @param x * first element * @param y * second element * @param z * third element */ public Vector3d(double x, double y, double z) { set(x, y, z); } /** * Gets a single element of this vector. Elements 0, 1, and 2 correspond to * x, y, and z. * * @param i * element index * @return element value throws ArrayIndexOutOfBoundsException if i is not * in the range 0 to 2. */ public double get(int i) { switch (i) { case 0: { return x; } case 1: { return y; } case 2: { return z; } default: { throw new ArrayIndexOutOfBoundsException(i); } } } /** * Sets a single element of this vector. Elements 0, 1, and 2 correspond to * x, y, and z. * * @param i * element index * @param value * element value * @return element value throws ArrayIndexOutOfBoundsException if i is not * in the range 0 to 2. */ public void set(int i, double value) { switch (i) { case 0: { x = value; break; } case 1: { y = value; break; } case 2: { z = value; break; } default: { throw new ArrayIndexOutOfBoundsException(i); } } } /** * Sets the values of this vector to those of v1. * * @param v1 * vector whose values are copied */ public void set(Vector3d v1) { x = v1.x; y = v1.y; z = v1.z; } /** * Adds vector v1 to v2 and places the result in this vector. * * @param v1 * left-hand vector * @param v2 * right-hand vector */ public void add(Vector3d v1, Vector3d v2) { x = v1.x + v2.x; y = v1.y + v2.y; z = v1.z + v2.z; } /** * Adds this vector to v1 and places the result in this vector. * * @param v1 * right-hand vector */ public void add(Vector3d v1) { x += v1.x; y += v1.y; z += v1.z; } /** * Subtracts vector v1 from v2 and places the result in this vector. * * @param v1 * left-hand vector * @param v2 * right-hand vector */ public void sub(Vector3d v1, Vector3d v2) { x = v1.x - v2.x; y = v1.y - v2.y; z = v1.z - v2.z; } /** * Subtracts v1 from this vector and places the result in this vector. * * @param v1 * right-hand vector */ public void sub(Vector3d v1) { x -= v1.x; y -= v1.y; z -= v1.z; } /** * Scales the elements of this vector by <code>s</code>. * * @param s * scaling factor */ public void scale(double s) { x = s * x; y = s * y; z = s * z; } /** * Scales the elements of vector v1 by <code>s</code> and places the results * in this vector. * * @param s * scaling factor * @param v1 * vector to be scaled */ public void scale(double s, Vector3d v1) { x = s * v1.x; y = s * v1.y; z = s * v1.z; } /** * Returns the 2 norm of this vector. This is the square root of the sum of * the squares of the elements. * * @return vector 2 norm */ public double norm() { return Math.sqrt(x * x + y * y + z * z); } /** * Returns the square of the 2 norm of this vector. This is the sum of the * squares of the elements. * * @return square of the 2 norm */ public double normSquared() { return x * x + y * y + z * z; } /** * Returns the Euclidean distance between this vector and vector v. * * @return distance between this vector and v */ public double distance(Vector3d v) { double dx = x - v.x; double dy = y - v.y; double dz = z - v.z; return Math.sqrt(dx * dx + dy * dy + dz * dz); } /** * Returns the squared of the Euclidean distance between this vector and * vector v. * * @return squared distance between this vector and v */ public double distanceSquared(Vector3d v) { double dx = x - v.x; double dy = y - v.y; double dz = z - v.z; return dx * dx + dy * dy + dz * dz; } /** * Returns the dot product of this vector and v1. * * @param v1 * right-hand vector * @return dot product */ public double dot(Vector3d v1) { return x * v1.x + y * v1.y + z * v1.z; } /** * Normalizes this vector in place. */ public void normalize() { double lenSqr = x * x + y * y + z * z; double err = lenSqr - 1; if (err > (2 * DOUBLE_PREC) || err < -(2 * DOUBLE_PREC)) { double len = Math.sqrt(lenSqr); x /= len; y /= len; z /= len; } } /** * Sets the elements of this vector to zero. */ public void setZero() { x = 0; y = 0; z = 0; } /** * Sets the elements of this vector to the prescribed values. * * @param x * value for first element * @param y * value for second element * @param z * value for third element */ public void set(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } /** * Computes the cross product of v1 and v2 and places the result in this * vector. * * @param v1 * left-hand vector * @param v2 * right-hand vector */ public void cross(Vector3d v1, Vector3d v2) { double tmpx = v1.y * v2.z - v1.z * v2.y; double tmpy = v1.z * v2.x - v1.x * v2.z; double tmpz = v1.x * v2.y - v1.y * v2.x; x = tmpx; y = tmpy; z = tmpz; } /** * Sets the elements of this vector to uniformly distributed random values * in a specified range, using a supplied random number generator. * * @param lower * lower random value (inclusive) * @param upper * upper random value (exclusive) * @param generator * random number generator */ protected void setRandom(double lower, double upper, Random generator) { double range = upper - lower; x = generator.nextDouble() * range + lower; y = generator.nextDouble() * range + lower; z = generator.nextDouble() * range + lower; } /** * Returns a string representation of this vector, consisting of the x, y, * and z coordinates. * * @return string representation */ @Override public String toString() { return x + " " + y + " " + z; } }