There is an error in the code I posted earlier.  The method qVectorRotator
returns an incorrect result when the two argument vectors are antiparallel
(or nearly so).  Here's a fix; the original code, with the error indicated
is shown further down below.


  private static final double TOLERANCE      = 5E-4f;
  private static final Quat4f Q_IDENTITY     = new Quat4f(0f, 0f, 0f, 1f);

  public static Transform3D vectorRotator(Vector3f ua, Vector3f ub) {
    Transform3D t = new Transform3D();
    t.set(qVectorRotator(ua, ub));
    return t;
  }

  public static Quat4f qVectorRotator(Vector3f ua, Vector3f ub) {
    double ang = Math.acos(ua.dot(ub));
    if(Math.abs(ang) < TOLERANCE) { return Q_IDENTITY; }
    Vector3f v = new Vector3f();
    float s;
    if(Math.abs(Math.PI - ang) < TOLERANCE) {
      v = getPerp(ua);
      s = 0f;
    }
    else {
      v.cross(ua, ub);
      v.scale((float) Math.sin(ang/2d)/v.length());
      s = (float) Math.cos(ang/2.);
    }
    return new Quat4f(v.x, v.y, v.z, s);
  }

  public static Vector3f getPerp(Vector3f v) {
    float x, y, z;
    x = Math.abs(v.x); y = Math.abs(v.y); z = Math.abs(v.z);
    Vector3f a;
    // a points in the positive coordinate that is closest to
    // orthogonal to v.
    if(x <= y && x <= z) a = new Vector3f(1f, 0f, 0f);
    if(y <= z && y <= x) a = new Vector3f(0f, 1f, 0f);
    if(z <= x && z <= y) a = new Vector3f(0f, 0f, 1f);
    Vector3f p = new Vector3f();
    p.cross(v, a);
    p.normalize();
    return p;
  }

Cheers,

KJ





On Sat, 7 Jul 2001 06:52:59 -0400, Kynn Jones <[EMAIL PROTECTED]> wrote:

>   Date:    Fri, 6 Jul 2001 22:40:26 -0700
>   From:    Bob Dengle <[EMAIL PROTECTED]>
>   Subject: Rotating One Vector Into Another
>
>   Hi
>
>   I have two vector3ds. I want to rotate one so that it falls along the same
>   line as the other. Does anyone have any suggestions on how to do this? I
>   know how to compute the angle between the two vectors, but how do I go from
>   there to a rotation matrix? Thanks in advance.
>
>   B.D.
>
>Here's how I do it.
>
>  // TOLERANCE is used to decide when the difference between two
>  // angles is sufficiently close to zero that we may regard them as
>  // equal.
// THIS VALUE FOR TOLERANCE IS TOO SMALL:
>  private static final double TOLERANCE      = 0.00001;
>
>  private static final Quat4f Q_IDENTITY     = new Quat4f(0f, 0f, 0f, 1f);
>  private static final Quat4f Q_NEG_IDENTITY = new Quat4f(0f, 0f, 0f, -1f);
>
>  public static Transform3D vectorRotator(Vector3f ua, Vector3f ub) {
>    Transform3D t = new Transform3D();
>    Quat4f q = qVectorRotator(ua, ub);
>
>
>    if(!q.equals(Q_NEG_IDENTITY)) {
>      t.set(q);
>    }
>    else {
>      // for some reason, t.set(q) gives incorrect results when
>      // q equals Q_NEG_IDENTITY.
>      t.setScale(-1f);
>    }
>    return t;
>  }
>
>  public static Quat4f qVectorRotator(Vector3f ua, Vector3f ub) {
>    double angle = Math.acos(ua.dot(ub));
>    if(Math.abs(angle) < TOLERANCE) {
>      // if the angle subtended by ua and ub is sufficiently small
>      // we regard them as equal.
>      return Q_IDENTITY;
>    }
>    if(Math.abs(Math.PI - angle) < TOLERANCE) {
>      // this is the case when ua and ub are collinear but point in
>      // opposite directions.

// THIS IS WRONG:
>      return Q_NEG_IDENTITY;
>    }
>
>    Vector3f v = new Vector3f();
>    // here we build the quaternion for the general case.
>    v.cross(ua, ub);
>    v.scale((float) Math.sin(angle/2d)/v.length());
>    return new Quat4f(v.x, v.y, v.z, (float) Math.cos(angle/2.));
>  }

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to