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.  (I don't claim it's the best solution, and I
welcome constructive criticism and alternatives.)

In some utilities class, I define a static method called vectorRotator
that takes two unit (i.e. length 1) vectors ua and ub, and returns the
Transform3D that rotates ua into ub.  vectorRotator in turn uses the
static method qVectorRotator to produce the unit quaternion that
rotates ua into ub, and generates the desired Transform3D from this
quaternion:

  // TOLERANCE is used to decide when the difference between two
  // angles is sufficiently close to zero that we may regard them as
  // equal.
  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.
      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.));
  }

Cheers,

KJ

===========================================================================
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