⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rotation.java

📁 Apache的common math数学软件包
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
    // we try other vectors    Vector3D u3 = Vector3D.crossProduct(u1, u2);    Vector3D v3 = Vector3D.crossProduct(v1, v2);    double u3x  = u3.getX();    double u3y  = u3.getY();    double u3z  = u3.getZ();    double v3x  = v3.getX();    double v3y  = v3.getY();    double v3z  = v3.getZ();    double dx3 = v3x - u3x;    double dy3 = v3y - u3y;    double dz3 = v3z - u3z;    k = new Vector3D(dy1 * dz3 - dz1 * dy3,                     dz1 * dx3 - dx1 * dz3,                     dx1 * dy3 - dy1 * dx3);    c = k.getX() * (u1y * u3z - u1z * u3y) +        k.getY() * (u1z * u3x - u1x * u3z) +        k.getZ() * (u1x * u3y - u1y * u3x);    if (c == 0) {      // the (q1, q2, q3) vector is aligned with u1:      // we try (u2, u3) and (v2, v3)      k = new Vector3D(dy2 * dz3 - dz2 * dy3,                       dz2 * dx3 - dx2 * dz3,                       dx2 * dy3 - dy2 * dx3);      c = k.getX() * (u2y * u3z - u2z * u3y) +          k.getY() * (u2z * u3x - u2x * u3z) +          k.getZ() * (u2x * u3y - u2y * u3x);      if (c == 0) {        // the (q1, q2, q3) vector is aligned with everything        // this is really the identity rotation        q0 = 1.0;        q1 = 0.0;        q2 = 0.0;        q3 = 0.0;        return;      }      // we will have to use u2 and v2 to compute the scalar part      uRef = u2;      vRef = v2;    }  }  // compute the vectorial part  c = Math.sqrt(c);  double inv = 1.0 / (c + c);  q1 = inv * k.getX();  q2 = inv * k.getY();  q3 = inv * k.getZ();  // compute the scalar part   k = new Vector3D(uRef.getY() * q3 - uRef.getZ() * q2,                    uRef.getZ() * q1 - uRef.getX() * q3,                    uRef.getX() * q2 - uRef.getY() * q1);   c = Vector3D.dotProduct(k, k);  q0 = Vector3D.dotProduct(vRef, k) / (c + c);  }  /** Build one of the rotations that transform one vector into another one.   * <p>Except for a possible scale factor, if the instance were   * applied to the vector u it will produce the vector v. There is an   * infinite number of such rotations, this constructor choose the   * one with the smallest associated angle (i.e. the one whose axis   * is orthogonal to the (u, v) plane). If u and v are colinear, an   * arbitrary rotation axis is chosen.</p>   * @param u origin vector   * @param v desired image of u by the rotation   * @exception IllegalArgumentException if the norm of one of the vectors is zero   */  public Rotation(Vector3D u, Vector3D v) {    double normProduct = u.getNorm() * v.getNorm();    if (normProduct == 0) {      throw new IllegalArgumentException("zero norm for rotation defining vector");    }    double dot = Vector3D.dotProduct(u, v);    if (dot < ((2.0e-15 - 1.0) * normProduct)) {      // special case u = -v: we select a PI angle rotation around      // an arbitrary vector orthogonal to u      Vector3D w = u.orthogonal();      q0 = 0.0;      q1 = -w.getX();      q2 = -w.getY();      q3 = -w.getZ();    } else {      // general case: (u, v) defines a plane, we select      // the shortest possible rotation: axis orthogonal to this plane      q0 = Math.sqrt(0.5 * (1.0 + dot / normProduct));      double coeff = 1.0 / (2.0 * q0 * normProduct);      q1 = coeff * (v.getY() * u.getZ() - v.getZ() * u.getY());      q2 = coeff * (v.getZ() * u.getX() - v.getX() * u.getZ());      q3 = coeff * (v.getX() * u.getY() - v.getY() * u.getX());    }  }  /** Build a rotation from three Cardan or Euler elementary rotations.   * <p>Cardan rotations are three successive rotations around the   * canonical axes X, Y and Z, each axis beeing used once. There are   * 6 such sets of rotations (XYZ, XZY, YXZ, YZX, ZXY and ZYX). Euler   * rotations are three successive rotations around the canonical   * axes X, Y and Z, the first and last rotations beeing around the   * same axis. There are 6 such sets of rotations (XYX, XZX, YXY,   * YZY, ZXZ and ZYZ), the most popular one being ZXZ.</p>   * <p>Beware that many people routinely use the term Euler angles even   * for what really are Cardan angles (this confusion is especially   * widespread in the aerospace business where Roll, Pitch and Yaw angles   * are often wrongly tagged as Euler angles).</p>   * @param order order of rotations to use   * @param alpha1 angle of the first elementary rotation   * @param alpha2 angle of the second elementary rotation   * @param alpha3 angle of the third elementary rotation   */  public Rotation(RotationOrder order,                  double alpha1, double alpha2, double alpha3) {    Rotation r1 = new Rotation(order.getA1(), alpha1);    Rotation r2 = new Rotation(order.getA2(), alpha2);    Rotation r3 = new Rotation(order.getA3(), alpha3);    Rotation composed = r1.applyTo(r2.applyTo(r3));    q0 = composed.q0;    q1 = composed.q1;    q2 = composed.q2;    q3 = composed.q3;  }  /** Revert a rotation.   * Build a rotation which reverse the effect of another   * rotation. This means that if r(u) = v, then r.revert(v) = u. The   * instance is not changed.   * @return a new rotation whose effect is the reverse of the effect   * of the instance   */  public Rotation revert() {    return new Rotation(-q0, q1, q2, q3, false);  }  /** Get the scalar coordinate of the quaternion.   * @return scalar coordinate of the quaternion   */  public double getQ0() {    return q0;  }  /** Get the first coordinate of the vectorial part of the quaternion.   * @return first coordinate of the vectorial part of the quaternion   */  public double getQ1() {    return q1;  }  /** Get the second coordinate of the vectorial part of the quaternion.   * @return second coordinate of the vectorial part of the quaternion   */  public double getQ2() {    return q2;  }  /** Get the third coordinate of the vectorial part of the quaternion.   * @return third coordinate of the vectorial part of the quaternion   */  public double getQ3() {    return q3;  }  /** Get the normalized axis of the rotation.   * @return normalized axis of the rotation   */  public Vector3D getAxis() {    double squaredSine = q1 * q1 + q2 * q2 + q3 * q3;    if (squaredSine == 0) {      return new Vector3D(1, 0, 0);    } else if (q0 < 0) {      double inverse = 1 / Math.sqrt(squaredSine);      return new Vector3D(q1 * inverse, q2 * inverse, q3 * inverse);    }    double inverse = -1 / Math.sqrt(squaredSine);    return new Vector3D(q1 * inverse, q2 * inverse, q3 * inverse);  }  /** Get the angle of the rotation.   * @return angle of the rotation (between 0 and &pi;)   */  public double getAngle() {    if ((q0 < -0.1) || (q0 > 0.1)) {      return 2 * Math.asin(Math.sqrt(q1 * q1 + q2 * q2 + q3 * q3));    } else if (q0 < 0) {      return 2 * Math.acos(-q0);    }    return 2 * Math.acos(q0);  }  /** Get the Cardan or Euler angles corresponding to the instance.   * <p>The equations show that each rotation can be defined by two   * different values of the Cardan or Euler angles set. For example   * if Cardan angles are used, the rotation defined by the angles   * a<sub>1</sub>, a<sub>2</sub> and a<sub>3</sub> is the same as   * the rotation defined by the angles &pi; + a<sub>1</sub>, &pi;   * - a<sub>2</sub> and &pi; + a<sub>3</sub>. This method implements   * the following arbitrary choices:</p>   * <ul>   *   <li>for Cardan angles, the chosen set is the one for which the   *   second angle is between -&pi;/2 and &pi;/2 (i.e its cosine is   *   positive),</li>   *   <li>for Euler angles, the chosen set is the one for which the   *   second angle is between 0 and &pi; (i.e its sine is positive).</li>   * </ul>   * <p>Cardan and Euler angle have a very disappointing drawback: all   * of them have singularities. This means that if the instance is   * too close to the singularities corresponding to the given   * rotation order, it will be impossible to retrieve the angles. For   * Cardan angles, this is often called gimbal lock. There is   * <em>nothing</em> to do to prevent this, it is an intrinsic problem   * with Cardan and Euler representation (but not a problem with the   * rotation itself, which is perfectly well defined). For Cardan   * angles, singularities occur when the second angle is close to   * -&pi;/2 or +&pi;/2, for Euler angle singularities occur when the   * second angle is close to 0 or &pi;, this implies that the identity   * rotation is always singular for Euler angles!</p>   * @param order rotation order to use   * @return an array of three angles, in the order specified by the set   * @exception CardanEulerSingularityException if the rotation is   * singular with respect to the angles set specified   */  public double[] getAngles(RotationOrder order)    throws CardanEulerSingularityException {    if (order == RotationOrder.XYZ) {      // r (Vector3D.plusK) coordinates are :      //  sin (theta), -cos (theta) sin (phi), cos (theta) cos (phi)      // (-r) (Vector3D.plusI) coordinates are :      // cos (psi) cos (theta), -sin (psi) cos (theta), sin (theta)      // and we can choose to have theta in the interval [-PI/2 ; +PI/2]      Vector3D v1 = applyTo(Vector3D.plusK);      Vector3D v2 = applyInverseTo(Vector3D.plusI);      if  ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {        throw new CardanEulerSingularityException(true);      }      return new double[] {        Math.atan2(-(v1.getY()), v1.getZ()),        Math.asin(v2.getZ()),        Math.atan2(-(v2.getY()), v2.getX())      };    } else if (order == RotationOrder.XZY) {      // r (Vector3D.plusJ) coordinates are :      // -sin (psi), cos (psi) cos (phi), cos (psi) sin (phi)      // (-r) (Vector3D.plusI) coordinates are :      // cos (theta) cos (psi), -sin (psi), sin (theta) cos (psi)      // and we can choose to have psi in the interval [-PI/2 ; +PI/2]      Vector3D v1 = applyTo(Vector3D.plusJ);      Vector3D v2 = applyInverseTo(Vector3D.plusI);      if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {        throw new CardanEulerSingularityException(true);      }      return new double[] {        Math.atan2(v1.getZ(), v1.getY()),       -Math.asin(v2.getY()),        Math.atan2(v2.getZ(), v2.getX())      };    } else if (order == RotationOrder.YXZ) {      // r (Vector3D.plusK) coordinates are :      //  cos (phi) sin (theta), -sin (phi), cos (phi) cos (theta)      // (-r) (Vector3D.plusJ) coordinates are :      // sin (psi) cos (phi), cos (psi) cos (phi), -sin (phi)      // and we can choose to have phi in the interval [-PI/2 ; +PI/2]      Vector3D v1 = applyTo(Vector3D.plusK);      Vector3D v2 = applyInverseTo(Vector3D.plusJ);      if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {        throw new CardanEulerSingularityException(true);      }      return new double[] {        Math.atan2(v1.getX(), v1.getZ()),       -Math.asin(v2.getZ()),        Math.atan2(v2.getX(), v2.getY())      };    } else if (order == RotationOrder.YZX) {      // r (Vector3D.plusI) coordinates are :      // cos (psi) cos (theta), sin (psi), -cos (psi) sin (theta)      // (-r) (Vector3D.plusJ) coordinates are :      // sin (psi), cos (phi) cos (psi), -sin (phi) cos (psi)      // and we can choose to have psi in the interval [-PI/2 ; +PI/2]      Vector3D v1 = applyTo(Vector3D.plusI);      Vector3D v2 = applyInverseTo(Vector3D.plusJ);      if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {        throw new CardanEulerSingularityException(true);      }      return new double[] {        Math.atan2(-(v1.getZ()), v1.getX()),        Math.asin(v2.getX()),        Math.atan2(-(v2.getZ()), v2.getY())      };    } else if (order == RotationOrder.ZXY) {      // r (Vector3D.plusJ) coordinates are :      // -cos (phi) sin (psi), cos (phi) cos (psi), sin (phi)      // (-r) (Vector3D.plusK) coordinates are :      // -sin (theta) cos (phi), sin (phi), cos (theta) cos (phi)      // and we can choose to have phi in the interval [-PI/2 ; +PI/2]      Vector3D v1 = applyTo(Vector3D.plusJ);      Vector3D v2 = applyInverseTo(Vector3D.plusK);      if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {        throw new CardanEulerSingularityException(true);      }      return new double[] {        Math.atan2(-(v1.getX()), v1.getY()),        Math.asin(v2.getY()),        Math.atan2(-(v2.getX()), v2.getZ())      };    } else if (order == RotationOrder.ZYX) {      // r (Vector3D.plusI) coordinates are :      //  cos (theta) cos (psi), cos (theta) sin (psi), -sin (theta)      // (-r) (Vector3D.plusK) coordinates are :      // -sin (theta), sin (phi) cos (theta), cos (phi) cos (theta)      // and we can choose to have theta in the interval [-PI/2 ; +PI/2]      Vector3D v1 = applyTo(Vector3D.plusI);      Vector3D v2 = applyInverseTo(Vector3D.plusK);      if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {        throw new CardanEulerSingularityException(true);      }      return new double[] {        Math.atan2(v1.getY(), v1.getX()),       -Math.asin(v2.getX()),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -