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".