/** * Multiplies this {@link Quaternion} by a {@link Vector3}. * Note that if you plan on using the returned {@link Vector3}, * you should clone it immediately as it is an internal scratch * member of this {@link Quaternion} and may be modified at any * time. This is the same as out = q*vector*`q, meaning the magnitude * will be maintained. * * @param vector {@link Vector3} to multiply by. * * @return {@link Vector3} The result of the multiplication. */ @NonNull public Vector3 multiply(@NonNull Vector3 vector) { mTmpVec3.setAll(x, y, z); mTmpVec1.crossAndSet(mTmpVec3, vector); mTmpVec2.crossAndSet(mTmpVec3, mTmpVec1); mTmpVec1.multiply(2.0 * w); mTmpVec2.multiply(2.0); mTmpVec1.add(mTmpVec2); mTmpVec1.add(vector); return mTmpVec1; }
Vector3 semiminorAxis = mScratch3.crossAndSet(mScratch1, mScratch2); semiminorAxis.multiply(b);
protected Quaternion quaternionFromVector(Vector3 vec) { vec.normalize(); final double angle = MathUtil.radiansToDegrees(Math.acos(Vector3.dot(mForwardVec, vec))); final Quaternion q = new Quaternion(); q.fromAngleAxis(mTmpQuatVector.crossAndSet(mForwardVec, vec), angle); return q; } }
mTmpVec3.crossAndSet(WorldParameters.RIGHT_AXIS, u); if (mTmpVec3.length() < 1e-6) { mTmpVec3.crossAndSet(WorldParameters.UP_AXIS, u); mTmpVec3.crossAndSet(u, v).normalize(); x = mTmpVec3.x; y = mTmpVec3.y;
/** * Calculates the position on the spiral for the specified polar angle. This takes an additional * parameter of a {@link Vector3} which will be set to the calculated position. * * @param result {@link Vector3} to set with the updated position. * @param theta {@code double} the polar angle to calculate for, in degrees. */ @Override public void calculatePoint(Vector3 result, double theta) { final double angle = mSpiralIn ? mThetaOffset + theta : theta - mThetaOffset; final double r = a * Math.exp(mDensity * angle); // Update the rotation mRotation.fromAngleAxis(mUp, Math.toDegrees(angle)); //.inverse(); // Rotate the start-end vector based on the angle mScratch.setAll(mRotation.multiply(mStart)).normalize(); // Set the correct length result.setAll(mScratch.multiply(r)); if (mCalculateTangents) { mCurrentTangent.crossAndSet(mUp, mScratch); } }
/** * Calculates the position on the spiral for the specified polar angle. This takes an additional * parameter of a {@link Vector3} which will be set to the calculated position. * * @param result {@link Vector3} to set with the updated position. * @param theta {@code double} the polar angle to calculate for, in degrees. */ @Override public void calculatePoint(Vector3 result, double theta) { double angle = mSpiralIn ? mThetaOffset - theta : theta + mThetaOffset; if (angle == 0.0) angle = 1e-9; //Prevent a divide by zero for negative densities. final double r = a * Math.pow(angle, mInvDensity); // Update the rotation mRotation.fromAngleAxis(mUp, Math.toDegrees(angle)); // Rotate the start-end vector based on the angle mScratch.setAll(mRotation.multiply(mStart)).normalize(); // Set the correct length result.setAll(mScratch.multiply(r)); if (mCalculateTangents) { mCurrentTangent.crossAndSet(mUp, mScratch); } }
/** * Sets this {@link Quaternion} to be oriented to a target {@link Vector3}. * It is safe to use the input vectors for other things as they are cloned internally. * * @param lookAt {@link Vector3} The point to look at. * @param upDirection {@link Vector3} to use as the up direction. * * @return A reference to this {@link Quaternion} to facilitate chaining. */ @NonNull public Quaternion lookAt(@NonNull Vector3 lookAt, @NonNull Vector3 upDirection) { mTmpVec1.setAll(lookAt); mTmpVec2.setAll(upDirection); // Vectors are parallel/anti-parallel if their dot product magnitude and length product are equal final double dotProduct = Vector3.dot(lookAt, upDirection); final double dotError = Math.abs(Math.abs(dotProduct) - (lookAt.length() * upDirection.length())); if (dotError <= PARALLEL_TOLERANCE) { // The look and up vectors are parallel mTmpVec2.normalize(); if (dotProduct < 0) { mTmpVec1.inverse(); } fromRotationBetween(WorldParameters.FORWARD_AXIS, mTmpVec1); return this; } Vector3.orthoNormalize(mTmpVec1, mTmpVec2); // Find the forward and up vectors mTmpVec3.crossAndSet(mTmpVec2, mTmpVec1); // Create the right vector fromAxes(mTmpVec3, mTmpVec2, mTmpVec1); return this; }
temp_normal.crossAndSet(scratch1, scratch0); temp_normal.normalize(); scratch0.subtractAndSet(vertex2, vertex0); scratch1.subtractAndSet(vertex2, vertex1); temp_normal.crossAndSet(scratch1, scratch0); temp_normal.normalize();
/** * Sets the world axis values after checking that they are all orthogonal to each other. The check performed * is to verify that the cross product between {@code right} and {@code up} is equivilant to {@code forward} * withing 1ppm error on each component. * * @param right {@link Vector3} The desired right vector. Must be normalized. * @param up {@link Vector3} The desired up vector. Must be normalized. * @param forward {@link Vector3} The desired forward vector. Must be normalized. */ public static void setWorldAxes(Vector3 right, Vector3 up, Vector3 forward) { TEMP_VECTOR.crossAndSet(right, up); if (!TEMP_VECTOR.equals(forward, 1e-6)) { throw new IllegalArgumentException("World axes must be orthogonal."); } RIGHT_AXIS.setAll(right); NEG_RIGHT_AXIS.setAll(RIGHT_AXIS).inverse(); UP_AXIS.setAll(up); NEG_UP_AXIS.setAll(UP_AXIS).inverse(); FORWARD_AXIS.setAll(forward); NEG_FORWARD_AXIS.setAll(FORWARD_AXIS).inverse(); } }
@Test public void testCrossAndSet() { final Vector3 t = new Vector3(); final Vector3 u = new Vector3(1d, 2d, 3d); final Vector3 v = new Vector3(4d, 5d, 6d); final Vector3 out = t.crossAndSet(u, v); assertNotNull(out); assertTrue(out == t); assertEquals(-3d, t.x, 0); assertEquals(6d, t.y, 0); assertEquals(-3d, t.z, 0); }
/** * Multiplies this {@link Quaternion} by a {@link Vector3}. * Note that if you plan on using the returned {@link Vector3}, * you should clone it immediately as it is an internal scratch * member of this {@link Quaternion} and may be modified at any * time. * * @param vector {@link Vector3} to multiply by. * @return {@link Vector3} The result of the multiplication. */ public Vector3 multiply(final Vector3 vector) { mTmpVec3.setAll(x, y, z); mTmpVec1.crossAndSet(mTmpVec3, vector); mTmpVec2.crossAndSet(mTmpVec3, mTmpVec1); mTmpVec1.multiply(2.0 * w); mTmpVec2.multiply(2.0); mTmpVec1.add(mTmpVec2); mTmpVec1.add(vector); return mTmpVec1; }
protected Quaternion quaternionFromVector(Vector3 vec) { vec.normalize(); final double angle = MathUtil.radiansToDegrees(Math.acos(Vector3.dot(mForwardVec, vec))); final Quaternion q = new Quaternion(); q.fromAngleAxis(mTmpQuatVector.crossAndSet(mForwardVec, vec), angle); return q; } }
mTmpVec3.crossAndSet(WorldParameters.RIGHT_AXIS, v1); if (mTmpVec3.length() < 1e-6) { mTmpVec3.crossAndSet(WorldParameters.UP_AXIS, v1);
/** * Calculates the position on the spiral for the specified polar angle. This takes an additional * parameter of a {@link Vector3} which will be set to the calculated position. * * @param result {@link Vector3} to set with the updated position. * @param theta {@code double} the polar angle to calculate for, in degrees. */ @Override public void calculatePoint(Vector3 result, double theta) { final double angle = mSpiralIn ? mThetaOffset + theta : theta - mThetaOffset; final double r = a * Math.exp(mDensity * angle); // Update the rotation mRotation.fromAngleAxis(mUp, Math.toDegrees(angle)); //.inverse(); // Rotate the start-end vector based on the angle mScratch.setAll(mRotation.multiply(mStart)).normalize(); // Set the correct length result.setAll(mScratch.multiply(r)); if (mCalculateTangents) { mCurrentTangent.crossAndSet(mUp, mScratch); } }
/** * Calculates the position on the spiral for the specified polar angle. This takes an additional * parameter of a {@link Vector3} which will be set to the calculated position. * * @param result {@link Vector3} to set with the updated position. * @param theta {@code double} the polar angle to calculate for, in degrees. */ @Override public void calculatePoint(Vector3 result, double theta) { double angle = mSpiralIn ? mThetaOffset - theta : theta + mThetaOffset; if (angle == 0.0) angle = 1e-9; //Prevent a divide by zero for negative densities. final double r = a * Math.pow(angle, mInvDensity); // Update the rotation mRotation.fromAngleAxis(mUp, Math.toDegrees(angle)); // Rotate the start-end vector based on the angle mScratch.setAll(mRotation.multiply(mStart)).normalize(); // Set the correct length result.setAll(mScratch.multiply(r)); if (mCalculateTangents) { mCurrentTangent.crossAndSet(mUp, mScratch); } }
temp_normal.crossAndSet(scratch1, scratch0); temp_normal.normalize(); scratch0.subtractAndSet(vertex2, vertex0); scratch1.subtractAndSet(vertex2, vertex1); temp_normal.crossAndSet(scratch1, scratch0); temp_normal.normalize();
/** * Sets this {@link Quaternion} to be oriented to a target {@link Vector3}. * It is safe to use the input vectors for other things as they are cloned internally. * * @param lookAt {@link Vector3} The point to look at. * @param upDirection {@link Vector3} to use as the up direction. * @return A reference to this {@link Quaternion} to facilitate chaining. */ public Quaternion lookAt(Vector3 lookAt, Vector3 upDirection) { mTmpVec1.setAll(lookAt); mTmpVec2.setAll(upDirection); // Vectors are parallel/anti-parallel if their dot product magnitude and length product are equal final double dotProduct = Vector3.dot(lookAt, upDirection); final double dotError = Math.abs(Math.abs(dotProduct) - (lookAt.length() * upDirection.length())); if (dotError <= 1e-6) { // The look and up vectors are parallel mTmpVec2.normalize(); if (dotProduct < 0) mTmpVec1.inverse(); fromRotationBetween(WorldParameters.FORWARD_AXIS, mTmpVec1); return this; } Vector3.orthoNormalize(mTmpVec1, mTmpVec2); // Find the forward and up vectors mTmpVec3.crossAndSet(mTmpVec1, mTmpVec2); // Create the right vector fromAxes(mTmpVec3, mTmpVec2, mTmpVec1); return this; }
/** * Sets the world axis values after checking that they are all orthogonal to each other. The check performed * is to verify that the cross product between {@code right} and {@code up} is equivilant to {@code forward} * withing 1ppm error on each component. * * @param right {@link Vector3} The desired right vector. Must be normalized. * @param up {@link Vector3} The desired up vector. Must be normalized. * @param forward {@link Vector3} The desired forward vector. Must be normalized. */ public static void setWorldAxes(Vector3 right, Vector3 up, Vector3 forward) { TEMP_VECTOR.crossAndSet(right, up); if (!TEMP_VECTOR.equals(forward, 1e-6)) { throw new IllegalArgumentException("World axes must be orthogonal."); } RIGHT_AXIS.setAll(right); NEG_RIGHT_AXIS.setAll(RIGHT_AXIS).inverse(); UP_AXIS.setAll(up); NEG_UP_AXIS.setAll(UP_AXIS).inverse(); FORWARD_AXIS.setAll(forward); NEG_FORWARD_AXIS.setAll(FORWARD_AXIS).inverse(); } }