public class RotationMatrix3d extends Matrix3dBase
This is used to rotate a 3 dimensional vector from one coordinate frame into another. If v0 and v1 denote the vector in the original frame 0 and target frame 1, respectively, then the rotation is computed according to
v1 = R v0where R is the rotation matrix. The columns of R represent the directions of the axes of frame 0 with respect to frame 1.
If R01 is a rotation from frame 0 to frame 1, and R12 is a rotation from frame 1 to frame 2, then the rotation from frame 0 to frame 2 is given by the product
R02 = R12 R01In this way, a rotation can be created by multiplying a series of subrotations.
If R01 is a rotation from frame 0 to frame 1, then the inverse rotation R10 is a rotation from frame 1 to frame 0, and is given by the transpose of R.
Matrix.Partition, Matrix.WriteFormat
Modifier and Type  Field and Description 

static int 
AXIS_ANGLE_STRING
Specifies a string representation of this rotation as a 4tuple consisting
of a rotation axis and the corresponding angle (in degrees).

static RotationMatrix3d 
IDENTITY
Global identity rotation.

static int 
MATRIX_STRING
Specifies a string representation of this rotation as a 3 x 3 matrix.

static RotationMatrix3d 
ROT_X_90
Global rotation defined by rotating 90 degrees counterclockwise about
the x axis.

INDEFINITE, POSITIVE_DEFINITE, SPD, SYMMETRIC
Constructor and Description 

RotationMatrix3d()
Creates a new rotation initialized to the identity.

RotationMatrix3d(AxisAngle axisAng)
Creates a new rotation specified by a rotation about an axis.

RotationMatrix3d(double[] m)
Creates a new rotation initialized to the specified entries.

RotationMatrix3d(double ux,
double uy,
double uz,
double ang)
Creates a new rotation specified by a rotation about an axis.

RotationMatrix3d(double m00,
double m01,
double m02,
double m10,
double m11,
double m12,
double m20,
double m21,
double m22)
Creates a new rotation initialized to the specified entries.

RotationMatrix3d(Quaternion quat)
Creates a new rotation specified by a quaternion.

RotationMatrix3d(RotationMatrix3d R)
Creates a new rotation which is a copy of an existing one.

RotationMatrix3d(Vector3d u,
double ang)
Creates a new rotation specified by a rotation about an axis.

Modifier and Type  Method and Description 

void 
checkOrthonormality() 
AxisAngle 
getAxisAngle()
Returns the axisangle parameters corresponding to this rotation.

void 
getAxisAngle(AxisAngle axisAng)
Returns the axisangle parameters corresponding to this rotation.

double 
getAxisAngle(Vector3d axis)
Gets the rotation axisangle representation for this rotation.

void 
getEuler(double[] angs)
Gets the Euler angles corresponding to this rotation.

void 
getRpy(double[] angs)
Gets the rollpitchyaw angles corresponding to this rotation.

void 
getXyz(double[] angs)
Gets the xyz rotation angles corresponding to this rotation.

boolean 
invert()
Inverts this rotation in place.

boolean 
invert(RotationMatrix3d R1)
Inverts rotation R1 and places the result in this rotation.

boolean 
isAxisAligned()
Returns true if this rotation transformtion is axisaligned  that is, if
all entries consist of either 1, 1, or 0.

boolean 
isAxisAligned(double tol)
Returns true if this rotation transformtion is axisaligned  that is, if
all entries consist of either 1, 1, or 0.

static void 
main(java.lang.String[] args) 
void 
mul(RotationMatrix3d R1)
Postmultiplies this rotation by another and places the result in this
rotation.

void 
mul(RotationMatrix3d R1,
RotationMatrix3d R2)
Multiplies rotation R1 by R2 and places the result in this rotation.

void 
mulAxisAngle(AxisAngle axisAng)
Postmultiplies this rotation by an implicit second rotation expressed as
an axisangle, and places the result in this rotation.

void 
mulAxisAngle(double ux,
double uy,
double uz,
double ang)
Postmultiplies this rotation by an implicit second rotation expressed as
an axisangle, and places the result in this rotation.

void 
mulAxisAngle(Vector3d u,
double ang)
Postmultiplies this rotation by an implicit second rotation expressed as
an axisangle, and places the result in this rotation.

void 
mulEuler(double phi,
double theta,
double psi)
Postmultiplies this rotation by an implicit second rotation described by
Euler angles, and places the result in this rotation.

void 
mulInverse(RotationMatrix3d R1)
Postmultiplies this rotation by the inverse of rotation R1 and places the
result in this rotation.

boolean 
mulInverse(Vector3d vr)
Multiplies the column vector vr by the inverse of this matrix and places
the result back in vr.

boolean 
mulInverse(Vector3d vr,
Vector3d v1)
Multiplies the column vector v1 by the inverse of this matrix and places
the result in vr.

void 
mulInverseBoth(RotationMatrix3d R1,
RotationMatrix3d R2)
Multiplies the inverse of rotation R1 by the inverse of rotation R2 and
places the result in this rotation.

void 
mulInverseLeft(RotationMatrix3d R1,
RotationMatrix3d R2)
Multiplies the inverse of rotation R1 by rotation R2 and places the result
in this rotation.

void 
mulInverseRight(RotationMatrix3d R1,
RotationMatrix3d R2)
Multiplies rotation R1 by the inverse of rotation R2 and places the result
in this rotation.

boolean 
mulInverseTranspose(Vector3d vr)
Multiplies vector vr by the inverse transpose of this matrix, in place.

boolean 
mulInverseTranspose(Vector3d vr,
Vector3d v1)
Multiplies the column vector v1 by the inverse transpose of this matrix
and places the result in vr.

void 
mulRotX(double ang)
Postmultiplies this rotation by an implicit second rotation consisting of
a rotation about the x axis, and places the result in this rotation.

void 
mulRotX180()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 180 degrees about the x axis, and places the result in
this rotation.

void 
mulRotX270()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 270 degrees about the x axis, and places the result in
this rotation.

void 
mulRotX90()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 90 degrees about the x axis, and places the result in
this rotation.

void 
mulRotY(double ang)
Postmultiplies this rotation by an implicit second rotation consisting of
a rotation about the y axis, and places the result in this rotation.

void 
mulRotY180()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 180 degrees about the x axis, and places the result in
this rotation.

void 
mulRotY270()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 270 degrees about the x axis, and places the result in
this rotation.

void 
mulRotY90()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 90 degrees about the x axis, and places the result in
this rotation.

void 
mulRotZ(double ang)
Postmultiplies this rotation by an implicit second rotation consisting of
a rotation about the z axis, and places the result in this rotation.

void 
mulRotZ180()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 180 degrees about the x axis, and places the result in
this rotation.

void 
mulRotZ270()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 270 degrees about the x axis, and places the result in
this rotation.

void 
mulRotZ90()
Postmultiplies this rotation by an implicit second rotation consisting
of a rotation of 90 degrees about the x axis, and places the result in
this rotation.

void 
mulRpy(double roll,
double pitch,
double yaw)
Postmultiplies this rotation by an implicit second rotation expressed by
rollpitchyaw angles, and places the result in this rotation.

void 
mulXyz(double rx,
double ry,
double rz)
Postmultiplies this rotation by an implicit second rotation expressed by
a sequence of intrinsic rotations about the xyz axes.

void 
negate()
Negates this rotation in place.

void 
normalize()
Normalizes this rotation, so as to ensure that its its columns are
orthonormal.

void 
rotateZDirection(Vector3d dirz)
Rotates this rotation so that the z axis points in a specified direction.

void 
scan(ReaderTokenizer rtok)
Reads the contents of this rotation from a ReaderTokenizer.

void 
set(double m00,
double m01,
double m02,
double m10,
double m11,
double m12,
double m20,
double m21,
double m22)
Sets this rotation explicitly from the supplied matrix entries.

void 
set(Quaternion q)
Sets this rotation to one represented by the quaternion q.

void 
setAxisAngle(AxisAngle axisAng)
Sets this rotation to one produced by rotating about an axis.

void 
setAxisAngle(double ux,
double uy,
double uz,
double ang)
Sets the rotation to one produced by rotating about an axis.

void 
setAxisAngle(Vector3d axis,
double ang)
Sets this rotation to one produced by rotating about an axis.

void 
setAxisAnglePrecise(AxisAngle axisAng)
Sets this rotation to one produced by rotating about an axis.

void 
setEuler(double[] angs)
Sets this rotation to one produced by Euler angles.

void 
setEuler(double phi,
double theta,
double psi)
Sets this rotation to one produced by Euler angles.

void 
setRandom()
Sets this rotation to one produced by rotating about a random axis by a
random angle.

void 
setRandom(java.util.Random generator)
Sets this rotation to one produced by rotating about a random axis by a
random angle, using a supplied random number generator.

void 
setRotX(double ang)
Sets this rotation to one produced by rotating about the x axis.

void 
setRotY(double ang)
Sets this rotation to one produced by rotating about the y axis.

void 
setRotZ(double ang)
Sets this rotation to one produced by rotating about the z axis.

void 
setRpy(double[] angs)
Sets this rotation to one produced by rollpitchyaw angles.

void 
setRpy(double roll,
double pitch,
double yaw)
Sets this rotation to one produced by rollpitchyaw angles.

void 
setXDirection(Vector3d dirx)
Sets this rotation to one in which the x axis points in a specified
direction.

void 
setXYDirections(Vector3d xdir,
Vector3d ydir)
Sets this rotation using two vectors to indicate the directions of the x
and y axes.

void 
setXyz(double[] angs)
Sets this rotation to one produced by a sequence of successive rotations
about the xyz axes.

void 
setXyz(double rx,
double ry,
double rz)
Sets this rotation to one produced by a sequence of intrinsic rotations
about the xyz axes.

void 
setYDirection(Vector3d diry)
Sets this rotation to one in which the y axis points in a specified
direction.

void 
setYZDirections(Vector3d ydir,
Vector3d zdir)
Sets this rotation using two vectors to indicate the directions of the y
and z axes.

void 
setZDirection(Vector3d dirz)
Sets this rotation to one in which the z axis points in a specified
direction.

void 
setZXDirections(Vector3d zdir,
Vector3d xdir)
Sets this rotation using two vectors to indicate the directions of the z
and x axes.

java.lang.String 
toString()
Returns a string representation of this transformation as a 3 x 3 matrix.

java.lang.String 
toString(NumberFormat numberFmt,
int outputCode)
Returns a specified string representation of this transformation, with
each number formatted according to the a supplied numeric format.

java.lang.String 
toString(java.lang.String numberFmtStr)
Returns a string representation of this transformation as a 3 x 3 matrix,
with each number formatted according to a supplied numeric format.

java.lang.String 
toString(java.lang.String numberFmtStr,
int outputCode)
Returns a specified string representation of this transformation, with
each number formatted according to the a supplied numeric format.

void 
transpose()
Transposes this rotation in place.

void 
transpose(RotationMatrix3d R1)
Transposes rotation R1 and places the result in this rotation.

clone, colSize, determinant, epsilonEquals, equals, factorQR, frobeniusNorm, get, get, getColumn, getColumn, getColumn, getRow, getRow, getRow, infinityNorm, inverseTransform, isIdentity, isSymmetric, mul, mul, mul, mul, mulAdd, mulAdd, mulTranspose, mulTranspose, mulTransposeAdd, mulTransposeLeftAdd, mulTransposeRightAdd, negateColumn, negateRow, oneNorm, orthogonalDeterminant, rowSize, scaleColumn, scaleRow, set, set, set, set, setColumn, setColumn, setIdentity, setRow, setRow, solve, solveTranspose, trace
add, checkConsistency, set, set, set, setCCSValues, setColumn, setCRSValues, setRow, setSubMatrix
containsNaN, epsilonEquals, equals, frobeniusNormSquared, get, getCCSIndices, getCCSIndices, getCCSIndices, getCCSValues, getCCSValues, getCCSValues, getColumn, getCRSIndices, getCRSIndices, getCRSIndices, getCRSValues, getCRSValues, getCRSValues, getDefaultFormat, getRow, getSize, getSubMatrix, hasNaN, idString, isFixedSize, isWritable, maxNorm, mul, mul, mulAdd, mulAdd, mulAdd, mulTranspose, mulTranspose, mulTranspose, mulTransposeAdd, mulTransposeAdd, mulTransposeAdd, numNonZeroVals, numNonZeroVals, scan, setCRSValues, setDefaultFormat, setSize, toString, write, write, write, write, write, write, write, writeToFile
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
epsilonEquals, equals, frobeniusNormSquared, getCCSIndices, getCCSIndices, getCCSIndices, getCCSValues, getCCSValues, getCCSValues, getColumn, getCRSIndices, getCRSIndices, getCRSIndices, getCRSValues, getCRSValues, getCRSValues, getRow, getSize, getSubMatrix, isFixedSize, maxNorm, mul, mul, mulAdd, mulAdd, mulAdd, mulTranspose, mulTranspose, mulTranspose, mulTransposeAdd, mulTransposeAdd, mulTransposeAdd, numNonZeroVals, numNonZeroVals, setSize, toString, write, write, write
public static final RotationMatrix3d IDENTITY
public static final RotationMatrix3d ROT_X_90
public static final int AXIS_ANGLE_STRING
public static final int MATRIX_STRING
public RotationMatrix3d(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22)
NOTE: the user is responsible for ensuring the that specified matrix is orthogonal.
public RotationMatrix3d(double[] m)
NOTE: the user is responsible for ensuring the that specified matrix is orthogonal.
public RotationMatrix3d()
public RotationMatrix3d(AxisAngle axisAng)
axisAng
 gives the rotation axis and corresponding anglepublic RotationMatrix3d(Quaternion quat)
quat
 quaternion specifying the rotation.public RotationMatrix3d(Vector3d u, double ang)
u
 gives the rotation axisang
 rotation angle (radians)public RotationMatrix3d(double ux, double uy, double uz, double ang)
ux
 axis x coordinateuy
 axis y coordinateuz
 axis z coordinateang
 angle of rotation about the axis (radians)public RotationMatrix3d(RotationMatrix3d R)
R
 rotation to copypublic void mul(RotationMatrix3d R1)
R1
 rotation to multiply bypublic void mul(RotationMatrix3d R1, RotationMatrix3d R2)
R1
 first rotationR2
 second rotationpublic void mulInverse(RotationMatrix3d R1)
R1
 righthand rotationpublic void mulInverseLeft(RotationMatrix3d R1, RotationMatrix3d R2)
R1
 lefthand rotationR2
 righthand rotationpublic void mulInverseRight(RotationMatrix3d R1, RotationMatrix3d R2)
R1
 lefthand rotationR2
 righthand rotationpublic void mulInverseBoth(RotationMatrix3d R1, RotationMatrix3d R2)
R1
 lefthand rotationR2
 righthand rotationpublic boolean invert()
invert
in class Matrix3dBase
public boolean invert(RotationMatrix3d R1)
R1
 rotation to invertpublic void transpose()
transpose
in class Matrix3dBase
public void transpose(RotationMatrix3d R1)
R1
 rotation to transposepublic void negate()
negate
in class Matrix3dBase
public boolean mulInverse(Vector3d vr, Vector3d v1)
solve(vr,v1)
.mulInverse
in class Matrix3dBase
vr
 result vectorv1
 vector to multiply bypublic boolean mulInverse(Vector3d vr)
mulInverse
in class Matrix3dBase
vr
 vector to multiply by (in place)public boolean mulInverseTranspose(Vector3d vr, Vector3d v1)
mulInverseTranspose
in class Matrix3dBase
vr
 result vectorv1
 vector to multiply bypublic boolean mulInverseTranspose(Vector3d vr)
mulInverseTranspose
in class Matrix3dBase
vr
 vector to multiplypublic void normalize()
public void setXYDirections(Vector3d xdir, Vector3d ydir)
xdir
and ydir
must be nonzero and nonparallel or an
exception will be thrown.
xdir
and ydir
do not need to be perpendicular.
The x axis is formed by normalizing xdir. The z axis is then found by
normalizing the cross product of x and ydir. Finally, the y axis is
determined from the cross product of the z and x axes.
xdir
 direction for the x axisydir
 indicates direction for the y axis (not necessarily perpendicular to
xdir
)java.lang.IllegalArgumentException
 if xdir
or ydir
are zero, or if they are parallel.public void setYZDirections(Vector3d ydir, Vector3d zdir)
ydir
and zdir
must be nonzero and nonparallel or an
exception will be thrown.
ydir
and zdir
do not need to be perpendicular.
The y axis is formed by normalizing ydir. The x axis is then found by
normalizing the cross product of y and zdir. Finally, the z axis is
determined from the cross product of the x and y axes.
ydir
 direction for the y axiszdir
 indicates direction for the z axis (not necessarily perpendicular to
ydir
)java.lang.IllegalArgumentException
 if ydir
or zdir
are zero, or if they are parallel.public void setZXDirections(Vector3d zdir, Vector3d xdir)
zdir
and xdir
must be nonzero and nonparallel or an
exception will be thrown.
zdir
and xdir
do not need to be perpendicular.
The z axis is formed by normalizing zdir. The y axis is then found by
normalizing the cross product of z and xdir. Finally, the x axis is
determined from the cross product of the y and z axes.
zdir
 direction for the z axisxdir
 indicates direction for the x axis (not necessarily perpendicular to
xdir
)java.lang.IllegalArgumentException
 if zdir
or xdir
are zero, or if they are parallel.public void set(Quaternion q)
q
 quaternion representing the rotationpublic void set(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22)
normalize
to ensure that the resulting
matrix is orthogonal.m00
 element (0,0)m01
 element (0,1)m02
 element (0,2)m10
 element (1,0)m11
 element (1,1)m12
 element (1,2)m20
 element (2,0)m21
 element (2,1)m22
 element (2,2)public void setAxisAngle(AxisAngle axisAng)
axisAng
 gives the rotation axis and corresponding anglepublic void setAxisAnglePrecise(AxisAngle axisAng)
axisAng
 gives the rotation axis and corresponding anglepublic void setAxisAngle(Vector3d axis, double ang)
axis
 gives the rotation axisang
 rotation angle (radians)public void setAxisAngle(double ux, double uy, double uz, double ang)
ux
 axis x coordinateuy
 axis y coordinateuz
 axis z coordinateang
 angle of rotation about the axis (radians)public void setRotX(double ang)
ang
 angle of rotation (radians)public void mulRotX(double ang)
ang
 angle (radians) for the second rotationpublic void mulRotX90()
public void mulRotX180()
public void mulRotX270()
public void setRotY(double ang)
ang
 angle of rotation (radians)public void mulRotY(double ang)
ang
 angle (radians) for the second rotationpublic void mulRotY90()
public void mulRotY180()
public void mulRotY270()
public void setRotZ(double ang)
ang
 angle of rotation (radians)public void mulRotZ(double ang)
ang
 angle (radians) for the second rotationpublic void mulRotZ90()
public void mulRotZ180()
public void mulRotZ270()
public void mulAxisAngle(double ux, double uy, double uz, double ang)
ux
 rotation axis x componentuy
 rotation axis y componentuz
 rotation axis z componentang
 rotation angle (in radians)public void mulAxisAngle(Vector3d u, double ang)
u
 rotation axisang
 rotation angle (in radians)public void mulAxisAngle(AxisAngle axisAng)
axisAng
 axisangle representation of the rotationpublic AxisAngle getAxisAngle()
public void getAxisAngle(AxisAngle axisAng)
axisAng
 axisangle parameterspublic void setRpy(double roll, double pitch, double yaw)
roll
 first angle (radians)pitch
 second angle (radians)yaw
 third angle (radians)getRpy(double[])
public void setRpy(double[] angs)
angs
 contains the angles (roll, pitch, and yaw, in that order) in radians.setRpy(double,double,double)
public void mulRpy(double roll, double pitch, double yaw)
roll
 first angle (radians)pitch
 second angle (radians)yaw
 third angle (radians)public void getRpy(double[] angs)
angs
 returns the angles (roll, pitch, and yaw, in that order) in radians.setRpy(double,double,double)
public void setXyz(double rx, double ry, double rz)
rx
about the x axis, followed by a rotation ry
about the new y axis, and finally a rotation rz
about the new z
axis.rx
 first rotation about x (radians)ry
 second rotation about y (radians)rz
 third rotation about z (radians)getXyz(double[])
public void setXyz(double[] angs)
angs
 contains the angles (rx, ry, and rz, in that order) in radians.setXyz(double,double,double)
public void mulXyz(double rx, double ry, double rz)
rx
 first rotation about x (radians)ry
 second rotation about y (radians)rz
 third rotation about z (radians)setXyz(double,double,double)
public void getXyz(double[] angs)
setXyz(double,double,double)
.angs
 returns the xyz angles (rx, ry, and rz, in that order) in radians.public void setEuler(double phi, double theta, double psi)
phi
 first Euler angle (radians)theta
 second Euler angle (radians)psi
 third Euler angle (radians)getEuler(double[])
public void setEuler(double[] angs)
angs
 contains the Euler angles (phi, theta, and psi, in that order) in radians.setEuler(double,double,double)
public void mulEuler(double phi, double theta, double psi)
phi
 first Euler angle (radians)theta
 second Euler angle (radians)psi
 third Euler angle (radians)setEuler(double,double,double)
public void getEuler(double[] angs)
angs
 returns the Euler angles (phi, theta, and psi, in that order) in radians.setEuler(double,double,double)
public void setZDirection(Vector3d dirz)
dirz
is zero, the rotation is set
the identity.dirz
 direction for the new z axis. Does not need to be normalized.public void setXDirection(Vector3d dirx)
dirx
is zero, the rotation is set
the identity.dirx
 direction for the new x axis. Does not need to be normalized.public void setYDirection(Vector3d diry)
diry
is zero, the rotation is set
the identity.diry
 direction for the new y axis. Does not need to be normalized.public void rotateZDirection(Vector3d dirz)
dirz
 direction for the new z axispublic void setRandom()
public void setRandom(java.util.Random generator)
generator
 random number generatorpublic double getAxisAngle(Vector3d axis)
<=
angle <
Math.PI.axis
 returns the rotation axispublic boolean isAxisAligned(double tol)
tol
. The
implementation for this method assumes that the entries are properly
formed for a rotation matrix.tol
 tolerance to test whether entries are zero or one.public void checkOrthonormality()
public boolean isAxisAligned()
public java.lang.String toString()
toString
in class MatrixBase
MatrixBase.toString(String)
public java.lang.String toString(java.lang.String numberFmtStr)
toString
in interface Matrix
toString
in class MatrixBase
numberFmtStr
 numeric format string (see NumberFormat
)NumberFormat
public java.lang.String toString(java.lang.String numberFmtStr, int outputCode)
numberFmtStr
 numeric format string (see NumberFormat
)outputCode
 desired representation, which should be either
AXIS_ANGLE_STRING
or MATRIX_STRING
public java.lang.String toString(NumberFormat numberFmt, int outputCode)
numberFmt
 numeric formatoutputCode
 desired representation, which should be either
AXIS_ANGLE_STRING
or MATRIX_STRING
public void scan(ReaderTokenizer rtok) throws java.io.IOException
The first format is a set of 4 numbers describing the rotation in axisangle notation. The rotation axis is given first, followed by the rotation angle, in degrees. The axis does not need to be normalized. For example,
[ 0 1 0 90 ]defines a rotation of 90 degrees about the y axis.
The second format format is a set of 9 numbers describing the elements of the rotation matrix in rowmajor order. For example,
[ 0 1 0 1 0 0 0 0 1 ]defines a rotation of 90 degrees about the z axis.
The third format consists of a series of simple rotations, which are the multiplied together to form a final rotation. The following simple rotations may be specified:
rotX
ang
rotY
ang
rotZ
ang
[ rotX 45 rotZ 90 ]describes a rotation which is the product of a rotation of 45 degrees about the y axis and rotation of 90 degrees about the z axis.
scan
in interface Matrix
scan
in class MatrixBase
rtok
 ReaderTokenizer from which to read the rotation. Number parsing should be
enabled.java.io.IOException
 if an I/O error occured or if the rotation description is not consistent
with one of the above formats.public static void main(java.lang.String[] args)