gt:             v = 1.0 - 2.0*random.nextFixedDouble();
context: /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
  package etomica.space3d;
  
  import etomica.api.IFunction;
  import etomica.api.IRandom;
  import etomica.api.IVector;
  import etomica.space.IVectorRandom;
  
  /**
   * Implementation of the Vector class for a 3-dimensional space.
   */
  public final class Vector3D implements IVectorRandom, java.io.Serializable {
  
      protected double x, y, z;
      private static final long serialVersionUID = 1L;
  
      public int getD() {
          return 3;
      }
  
      public Vector3D() {
          x = 0.0;
          y = 0.0;
          z = 0.0;
      }
  
      public Vector3D(double a1, double a2, double a3) {
          x = a1;
          y = a2;
          z = a3;
      }
  
      public Vector3D(double[] a) {
          if(a.length != 3){ 
              throw new IllegalArgumentException("Vector3D must be given a 3 element array.");
          }
          x = a[0];
          y = a[1];
          z = a[2];
      }
  
      public Vector3D(Vector3D u) {
          this.E(u);
      }
  
      public String toString() {
          return "(" + x + ", " + y + ", " + z + ")";
      }
  
      public double getX(int i) {
          return ((i == 0) ? x : (i == 1) ? y : z);
      }
  
      public void assignTo(double[] array) {
          array[0] = x;
          array[1] = y;
          array[2] = z;
      }
  
      public boolean equals(IVector v) {
          return (x == ((Vector3D) v).x) && (y == ((Vector3D) v).y)
                  && (z == ((Vector3D) v).z);
      }
  
      public boolean isZero() {
          return (x == 0.0) && (y == 0.0) && (z == 0);
      }
  
      public void E(IVector u) {
          x = ((Vector3D) u).x;
          y = ((Vector3D) u).y;
          z = ((Vector3D) u).z;
      }
  
      public void E(double a) {
          x = a;
          y = a;
          z = a;
      }
  
      public void E(double a, double b, double c) {
          x = a;
          y = b;
          z = c;
      }
  
      public void E(double[] u) {
          if(u.length != 3){ 
              throw new IllegalArgumentException("Vector3D must be given a 3 element array.");
          }
          x = u[0];
          y = u[1];
          z = u[2];
      }
      
      public void Ea1Tv1(double a1, IVector u) {
          x = a1 * ((Vector3D) u).x;
          y = a1 * ((Vector3D) u).y;
          z = a1 * ((Vector3D) u).z;
      }
  
      public void PEa1Tv1(double a1, IVector u) {
          x += a1 * ((Vector3D) u).x;
          y += a1 * ((Vector3D) u).y;
          z += a1 * ((Vector3D) u).z;
      }
  
      public void PE(IVector u) {
          x += ((Vector3D) u).x;
          y += ((Vector3D) u).y;
          z += ((Vector3D) u).z;
      }
  
      public void PE(double a) {
          x += a;
          y += a;
          z += a;
      }
  
      public void ME(IVector u) {
          x -= ((Vector3D) u).x;
          y -= ((Vector3D) u).y;
          z -= ((Vector3D) u).z;
      }
  
      public void TE(double a) {
          x *= a;
          y *= a;
          z *= a;
      }
  
      public void TE(IVector u) {
          x *= ((Vector3D) u).x;
          y *= ((Vector3D) u).y;
          z *= ((Vector3D) u).z;
      }
  
      public void DE(IVector u) {
          x /= ((Vector3D) u).x;
          y /= ((Vector3D) u).y;
          z /= ((Vector3D) u).z;
      }
  
      public void Ev1Pv2(IVector u1, IVector u2) {
          x = ((Vector3D) u1).x + ((Vector3D) u2).x;
          y = ((Vector3D) u1).y + ((Vector3D) u2).y;
          z = ((Vector3D) u1).z + ((Vector3D) u2).z;
      }
  
      public void Ev1Mv2(IVector u1, IVector u2) {
          x = ((Vector3D) u1).x - ((Vector3D) u2).x;
          y = ((Vector3D) u1).y - ((Vector3D) u2).y;
          z = ((Vector3D) u1).z - ((Vector3D) u2).z;
      }
      
      public void mod(IVector u) {
          mod((Vector3D) u);
      }
  
      public void mod(Vector3D u) {
          while (x > u.x)
              x -= u.x;
          while (x < 0.0)
              x += u.x;
          while (y > u.y)
              y -= u.y;
          while (y < 0.0)
              y += u.y;
          while (z > u.z)
              z -= u.z;
          while (z < 0.0)
              z += u.z;
      }
  
      public double squared() {
          return x * x + y * y + z * z;
      }
  
      public double Mv1Squared(IVector u) {
          double dx = x - ((Vector3D) u).x;
          double dy = y - ((Vector3D) u).y;
          double dz = z - ((Vector3D) u).z;
          return dx * dx + dy * dy + dz * dz;
      }
  
      public double dot(IVector u) {
          return x * ((Vector3D) u).x + y * ((Vector3D) u).y + z
                  * ((Vector3D) u).z;
      }
  
      /*
       * Sets this vector to an arbitrary vector in the plane normal to the given vector.
       * Does not normalize this vector on completion.  Assumes that the given vector is not identically zero.
       */
      public void setPerpendicularTo(IVector v) {
          Vector3D v3 = (Vector3D)v;
          if(v3.z != 0) {
              x = v3.z;
              y = v3.z;
              z = -(v3.x + v3.y);
          } else {
              x = -(v3.y + v3.z);
              y = v3.x;
              z = v3.x;
          }
      }
  
  
      public void setX(int a, double d) {
          if (a == 0)
              x = d;
          else if (a == 1)
              y = d;
          else
              z = d;
      }
  
      public void setRandomCube(IRandom random) {
          x = random.nextFixedDouble() - 0.5;
          y = random.nextFixedDouble() - 0.5;
          z = random.nextFixedDouble() - 0.5;
      }
  
      //generate point on surface of sphere according to method (4) here:
      //http://www.math.niu.edu/~rusin/known-math/96/sph.rand
      //and scale into the interior according to r^2
      public void setRandomInSphere(IRandom random) {
          double r = cubeRoot(random.nextFixedDouble());
          double u, v, s;
          do {
              u = 1.0 - 2.0*random.nextFixedDouble();
  