Class RotationTools
java.lang.Object
com.github.yellowstonegames.grid.RotationTools
This has tools for generating and applying matrix rotations, potentially in higher dimensions than the typical 2 or
3. You can use
My head hurts. Thanks to spenc on the libGDX Discord for carefully guiding me through this code, among several other people who helped a lot.
randomRotation2D(long) to very quickly generate a single 2D rotation matrix, and to get a 3D
matrix, you can either build on that 2D matrix using randomRotation3D(long, float[]) or use
randomRotation3D(long) to make a completely new one. The same follows for making a 4D rotation using a 3D
one, and so on. You can apply a rotation to a vector with rotate(float[], float[], float[]), and there's
also a method to multiply square matrices in matrixMultiply(float[], float[], float[], int).
My head hurts. Thanks to spenc on the libGDX Discord for carefully guiding me through this code, among several other people who helped a lot.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classA wrapper around similar logic toRotationTools, but with no allocation after construction. -
Method Summary
Modifier and TypeMethodDescriptionstatic double[]fillRandomDoubleRotation(long seed, int dimension, double[] out) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static double[]fillRandomDoubleRotation(Random random, int dimension, double[] out) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static double[]fillRandomDoubleRotation2D(long seed, double[] out) Fillsoutwith a 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]).static double[]fillRandomDoubleRotation2D(Random random, double[] out) Fillsoutwith a 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]).static float[]fillRandomRotation(long seed, int dimension, float[] out) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static float[]fillRandomRotation(Random random, int dimension, float[] out) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static float[]fillRandomRotation2D(long seed, float[] out) Fillsoutwith a 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]).static float[]fillRandomRotation2D(Random random, float[] out) Fillsoutwith a 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]).static double[]matrixMultiply(double[] lf, double[] rt, double[] out, int side) Multiplies two square matrices with side lengthside, and stores the result inout.static float[]matrixMultiply(float[] lf, float[] rt, float[] out, int side) Multiplies two square matrices with side lengthside, and stores the result inout.static double[]randomDoubleRotation(long seed, int dimension) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static double[]randomDoubleRotation(Random random, int dimension) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static double[]randomDoubleRotation2D(long seed) Creates a new 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation2D(Random random) Creates a new 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation3D(long seed) Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation3D(long seed, double[] rotation2D) Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation3D(Random random) Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation3D(Random random, double[] rotation2D) Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation4D(long seed) Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation4D(long seed, double[] rotation3D) Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation4D(Random random) Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation4D(Random random, double[] rotation3D) Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation5D(long seed) Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation5D(long seed, double[] rotation4D) Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation5D(Random random) Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation5D(Random random, double[] rotation4D) Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation6D(long seed) Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation6D(long seed, double[] rotation5D) Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation6D(Random random) Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation6D(Random random, double[] rotation5D) Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation7D(long seed) Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation7D(long seed, double[] rotation6D) Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation7D(Random random) Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]).static double[]randomDoubleRotation7D(Random random, double[] rotation6D) Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]).static longrandomize(long state) A more-specific variation onHasher.randomize1(long), this expects its inputs to change by a very large amount between every call, such as0x9E3779B97F4A7C15L.static float[]randomRotation(long seed, int dimension) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static float[]randomRotation(Random random, int dimension) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed.static float[]randomRotation2D(long seed) Creates a new 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation2D(Random random) Creates a new 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation3D(long seed) Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation3D(long seed, float[] rotation2D) Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation3D(Random random) Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation3D(Random random, float[] rotation2D) Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation4D(long seed) Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation4D(long seed, float[] rotation3D) Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation4D(Random random) Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation4D(Random random, float[] rotation3D) Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation5D(long seed) Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation5D(long seed, float[] rotation4D) Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation5D(Random random) Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation5D(Random random, float[] rotation4D) Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation6D(long seed) Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation6D(long seed, float[] rotation5D) Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation6D(Random random) Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation6D(Random random, float[] rotation5D) Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation7D(long seed) Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation7D(long seed, float[] rotation6D) Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation7D(Random random) Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]).static float[]randomRotation7D(Random random, float[] rotation6D) Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]).static double[]rotate(double[] input, double[] rotation, double[] output) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), and an output vector to write to (as a 1D double array), and does the math to rotateinputusingrotation, and add the results intooutput.static double[]rotate(double[] input, double[] rotation, double[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), an output vector to write to (as a 1D double array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut.static double[]rotate(double[] input, int offsetIn, int sizeIn, double[] rotation, double[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), an output vector to write to (as a 1D double array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut.static double[]rotate(double[] input, int offsetIn, int sizeIn, double[] rotation, int offsetRotation, int sizeRotation, double[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), an output vector to write to (as a 1D double array), and offsets/sizes for those arrays to use only part of each one, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut.static float[]rotate(float[] input, float[] rotation, float[] output) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), and an output vector to write to (as a 1D float array), and does the math to rotateinputusingrotation, and add the results intooutput.static float[]rotate(float[] input, float[] rotation, float[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), an output vector to write to (as a 1D float array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut.static float[]rotate(float[] input, int offsetIn, int sizeIn, float[] rotation, float[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), an output vector to write to (as a 1D float array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut.static float[]rotate(float[] input, int offsetIn, int sizeIn, float[] rotation, int offsetRotation, int sizeRotation, float[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), an output vector to write to (as a 1D float array), and offsets/sizes for those arrays to use only part of each one, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut.static double[]rotateStep(long seed, double[] small, int targetSize) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall.static double[]rotateStep(long seed, double[] small, int targetSize, double[] gauss, double[] house, double[] large, double[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall.static float[]rotateStep(long seed, float[] small, int targetSize) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall.static float[]rotateStep(long seed, float[] small, int targetSize, float[] gauss, float[] house, float[] large, float[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall.static double[]rotateStep(Random random, double[] small, int targetSize) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number generator, and uses the seed and some matrix operations to generate a random rotation based onsmall.static double[]rotateStep(Random random, double[] small, int targetSize, double[] gauss, double[] house, double[] large, double[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall.static float[]rotateStep(Random random, float[] small, int targetSize) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number generator, and uses the seed and some matrix operations to generate a random rotation based onsmall.static float[]rotateStep(Random random, float[] small, int targetSize, float[] gauss, float[] house, float[] large, float[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall.static double[]slerp(double[] start, double[] end, double alpha, double[] output) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place).static float[]slerp(float[] start, float[] end, float alpha, float[] output) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place).static double[]slerp(int n, double[] start, int startOffset, double[] end, int endOffset, double alpha, double[] output, int outputOffset) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place).static float[]slerp(int n, float[] start, int startOffset, float[] end, int endOffset, float alpha, float[] output, int outputOffset) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place).
-
Method Details
-
rotate
public static float[] rotate(float[] input, float[] rotation, float[] output) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), and an output vector to write to (as a 1D float array), and does the math to rotateinputusingrotation, and add the results intooutput. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectsrotation.length / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, rotation has lengthn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector of lengthnrotation- a rotation matrix of lengthn*mor greateroutput- the output vector of lengthm- Returns:
- output, potentially after modification
-
rotate
public static float[] rotate(float[] input, float[] rotation, float[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), an output vector to write to (as a 1D float array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectsrotation.length / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, rotation has lengthn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector of lengthnrotation- a rotation matrix of lengthn*moutput- the output vector of lengthmor greater; onlyrotation.length / input.lengthitems will be written tooffsetOut- the index inoutputto start writing the rotated output- Returns:
- output, potentially after modification
-
rotate
public static float[] rotate(float[] input, int offsetIn, int sizeIn, float[] rotation, float[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), an output vector to write to (as a 1D float array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectsrotation.length / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, rotation has lengthn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector that has length at least equal tooffsetIn + sizeInoffsetIn- the index ininputto start readingsizeIn- how many elements to read frominputrotation- a rotation matrix of lengthsizeIn * m, wheremis the length of an output vectoroutput- the output vector of lengthmor greater; onlyrotation.length / sizeInitems will be written tooffsetOut- the index inoutputto start writing the rotated output- Returns:
- output, potentially after modification
-
rotate
public static float[] rotate(float[] input, int offsetIn, int sizeIn, float[] rotation, int offsetRotation, int sizeRotation, float[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D float array), an input vector to rotate (as a 1D float array), an output vector to write to (as a 1D float array), and offsets/sizes for those arrays to use only part of each one, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectssizeRotation / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, sizeRotation isn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector that has length at least equal tooffsetIn + sizeInoffsetIn- the index ininputto start readingsizeIn- how many items to read frominputrotation- a rotation matrix of lengthsizeIn * m, wheremis the length of an output vectoroffsetRotation- the first index inrotationto start reading a rotation matrix fromsizeRotation- how many items to read fromrotationto use as a rotation matrixoutput- the output vector of lengthmor greater; onlysizeRotation / sizeInitems will be written tooffsetOut- the index inoutputto start writing the rotated output- Returns:
- output, potentially after modification
-
slerp
public static float[] slerp(float[] start, float[] end, float alpha, float[] output) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place). This does not allocate. This has undefined behavior if start and end are polar opposites; that is, points where for any coordinateain start, that coordinate in end is-aor any positive linear scale of the point where that is true. This degenerates to a linear interpolation if either start or end is the origin, and simply returns the start if both are the origin. Otherwise, this can smoothly move points that aren't already on the unit sphere towards the distance of the other point from the origin.
Based on the non-approximation code from an article by Volodymyr Agafonkin. Note that this is the "geometric slerp" rather than the version using quaternions in 3D (or rotors in other dimensions). It has been augmented slightly to handle start and end vectors that don't have unit length.- Parameters:
start- an n-dimensional point, wherestart.lengthis nend- another n-dimensional point, whereend.lengthis also the same nalpha- between 0 and 1, inclusive; how much to travel from start towards endoutput- the first n items in this will receive the interpolated position, modifying it in-place- Returns:
- output, after modifications.
-
slerp
public static float[] slerp(int n, float[] start, int startOffset, float[] end, int endOffset, float alpha, float[] output, int outputOffset) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place). This does not allocate. This has undefined behavior if start and end are polar opposites; that is, points where for any coordinateain start, that coordinate in end is-aor any positive linear scale of the point where that is true. This degenerates to a linear interpolation if either start or end is the origin, and simply returns the start if both are the origin. Otherwise, this can smoothly move points that aren't already on the unit sphere towards the distance of the other point from the origin.
Based on the non-approximation code from an article by Volodymyr Agafonkin. Note that this is the "geometric slerp" rather than the version using quaternions in 3D (or rotors in other dimensions). It has been augmented slightly to handle start and end vectors that don't have unit length.- Parameters:
n- the dimension of the points in start, end, and output; must be 2 or morestart- an n-dimensional point to rotate fromstartOffset- what array index to start reading from instartend- another n-dimensional point to rotate toendOffset- what array index to start reading from instartalpha- between 0 and 1, inclusive; how much to travel from start towards endoutput- will be modified in-place so n items, starting at outputOffset, have the resultoutputOffset- what array index to start writing to inoutput- Returns:
- output, after modifications.
-
matrixMultiply
public static float[] matrixMultiply(float[] lf, float[] rt, float[] out, int side) Multiplies two square matrices with side lengthside, and stores the result inout. The inputslfandrtare 1D float arrays treated as row-major matrices.- Parameters:
lf- the left input matrix, as row-majorrt- the right input matrix, as row-majorout- will be modified; this is where the output is summed into, and it is not cleared beforehandside- side length of each input matrix and the output matrix- Returns:
- out, potentially after modification
-
randomize
public static long randomize(long state) A more-specific variation onHasher.randomize1(long), this expects its inputs to change by a very large amount between every call, such as0x9E3779B97F4A7C15L. This is not as high-quality on its own as any of Hasher's randomize methods, but this class assumes the other random factors in things likeDistributor.normal(long)will make up for any lacking quality here.- Parameters:
state- change this withrandomize((state += 0x9E3779B97F4A7C15L))- Returns:
- a long that has been deterministically randomized from state
-
rotateStep
public static float[] rotateStep(long seed, float[] small, int targetSize) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall. This allocates a newtargetSize * targetSize-element float array on every call and returns it. It also allocates some more temporary float arrays to work with.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
seed- random number generator seedsmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1targetSize- the side length of the square matrix to be returned- Returns:
- a 1D float array that can be treated as a rotation matrix for inputs of size
targetSize
-
rotateStep
public static float[] rotateStep(long seed, float[] small, int targetSize, float[] gauss, float[] house, float[] large, float[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall. To avoid allocating arrays on each call to this, this method also takes four float arrays that this will clear and modify, to be used as temporary workspace. As long as the last four arguments have enough length, their contents don't matter. Whilegaussmust have length of at leasttargetSize, the last three must have length of at leasttargetSize * targetSize.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
seed- random number generator seed; may be a long or an intsmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1, and will not be modifiedtargetSize- the side length of the square matrix to be returnedgauss- a temporary float array that will be cleared; must have length of at leasttargetSizehouse- a temporary float array that will be cleared; must have length of at leasttargetSize * targetSizelarge- a temporary float array that will be cleared; must have length of at leasttargetSize * targetSizeout- the float array that will be cleared and returned; must have length of at leasttargetSize * targetSize- Returns:
out, which can be treated as a rotation matrix for inputs of sizetargetSize
-
randomRotation2D
public static float[] randomRotation2D(long seed) Creates a new 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]). Uses the given seed to get an angle usingTrigTools.SIN_TABLE.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 4-element float array, meant as effectively a 2D rotation matrix
-
fillRandomRotation2D
public static float[] fillRandomRotation2D(long seed, float[] out) Fillsoutwith a 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]). Scrambles the given seed withrandomize(long), then gets an angle usingTrigTools.SIN_TABLEandTrigTools.COS_TABLE.- Parameters:
seed- any long; will be scrambledout- a float array that must have at least 4 elements; will be cleared and returned- Returns:
out, meant as effectively a 2D rotation matrix
-
randomRotation3D
public static float[] randomRotation3D(long seed) Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLEand Gaussian floats usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 9-element float array, meant as effectively a 3D rotation matrix
-
randomRotation3D
public static float[] randomRotation3D(long seed, float[] rotation2D) Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get Gaussian floats usingDistributor.normal(long), and uses an existing 2D rotation matrix to avoid redoing any generation work already done for 2D. There will probably be some correlation between the appearance of the 2D rotation this will build upon and the 3D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 16-element float array, meant as effectively a 4D rotation matrix
-
randomRotation4D
public static float[] randomRotation4D(long seed) Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLEand Gaussian floats usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 16-element float array, meant as effectively a 4D rotation matrix
-
randomRotation4D
public static float[] randomRotation4D(long seed, float[] rotation3D) Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get Gaussian floats usingDistributor.normal(long), and uses an existing 3D rotation matrix to avoid redoing any generation work already done for 3D. There will probably be some correlation between the appearance of the 3D rotation this will build upon and the 4D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 16-element float array, meant as effectively a 4D rotation matrix
-
randomRotation5D
public static float[] randomRotation5D(long seed) Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLEand Gaussian floats usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 25-element float array, meant as effectively a 5D rotation matrix
-
randomRotation5D
public static float[] randomRotation5D(long seed, float[] rotation4D) Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get Gaussian floats usingDistributor.normal(long), and uses an existing 4D rotation matrix to avoid redoing any generation work already done for 4D. There will probably be some correlation between the appearance of the 4D rotation this will build upon and the 5D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 25-element float array, meant as effectively a 5D rotation matrix
-
randomRotation6D
public static float[] randomRotation6D(long seed) Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLEand Gaussian floats usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 36-element float array, meant as effectively a 6D rotation matrix
-
randomRotation6D
public static float[] randomRotation6D(long seed, float[] rotation5D) Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get Gaussian floats usingDistributor.normal(long), and uses an existing 5D rotation matrix to avoid redoing any generation work already done for 5D. There will probably be some correlation between the appearance of the 5D rotation this will build upon and the 6D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 36-element float array, meant as effectively a 6D rotation matrix
-
randomRotation7D
public static float[] randomRotation7D(long seed) Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLEand Gaussian floats usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 49-element float array, meant as effectively a 7D rotation matrix
-
randomRotation7D
public static float[] randomRotation7D(long seed, float[] rotation6D) Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get Gaussian floats usingDistributor.normal(long), and uses an existing 6D rotation matrix to avoid redoing any generation work already done for 6D. There will probably be some correlation between the appearance of the 5D rotation this will build upon and the 7D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambledrotation6D- an existing 6D rotation matrix stored in a 1D float array; often produced byrandomRotation6D(long)- Returns:
- a newly-allocated 49-element float array, meant as effectively a 7D rotation matrix
-
randomRotation
public static float[] randomRotation(long seed, int dimension) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomRotation4D(long), this doesn't allocate per dimension. For dimension 2, this only allocates the array it returns.
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(float[], float[], float[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
seed- any long; will be scrambleddimension- will be clamped to at minimum 2, but there is technically no maximum- Returns:
- a newly-allocated
dimension * dimension-element float array, meant as effectively adimension-D rotation matrix
-
fillRandomRotation
public static float[] fillRandomRotation(long seed, int dimension, float[] out) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomRotation4D(long), this doesn't allocate per dimension. For dimension 2, this doesn't allocate at all ifouthas at least length 4 (so it can store the resulting matrix).
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(float[], float[], float[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
seed- any long; will be scrambleddimension- will be clamped to at minimum 2, but there is technically no maximumout- a float array that should have at leastdimension * dimensionelements; will be modified- Returns:
out, after modifications, unless it was too small or null (then this returns a new array)
-
rotateStep
This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number generator, and uses the seed and some matrix operations to generate a random rotation based onsmall. This allocates a newtargetSize * targetSize-element float array on every call and returns it. It also allocates some more temporary float arrays to work with.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
random- random number generator; anyRandomfrom the JDK or from the juniper library workssmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1targetSize- the side length of the square matrix to be returned- Returns:
- a 1D float array that can be treated as a rotation matrix for inputs of size
targetSize
-
rotateStep
public static float[] rotateStep(Random random, float[] small, int targetSize, float[] gauss, float[] house, float[] large, float[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall. To avoid allocating arrays on each call to this, this method also takes four float arrays that this will clear and modify, to be used as temporary workspace. As long as the last four arguments have enough length, their contents don't matter. Whilegaussmust have length of at leasttargetSize, the last three must have length of at leasttargetSize * targetSize.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
random- random number generator; anyRandomfrom the JDK or from the juniper library workssmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1, and will not be modifiedtargetSize- the side length of the square matrix to be returnedgauss- a temporary float array that will be cleared; must have length of at leasttargetSizehouse- a temporary float array that will be cleared; must have length of at leasttargetSize * targetSizelarge- a temporary float array that will be cleared; must have length of at leasttargetSize * targetSizeout- the float array that will be cleared and returned; must have length of at leasttargetSize * targetSize- Returns:
out, which can be treated as a rotation matrix for inputs of sizetargetSize
-
randomRotation2D
Creates a new 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE.- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 4-element float array, meant as effectively a 2D rotation matrix
-
fillRandomRotation2D
Fillsoutwith a 1D float array that can be used as a 2D rotation matrix byrotate(float[], float[], float[]). Scrambles the given seed withrandomize(long), then gets an angle usingTrigTools.SIN_TABLE_DandTrigTools.COS_TABLE_D.- Parameters:
random- anyRandomfrom the JDK or from the juniper libraryout- a float array that must have at least 4 elements; will be cleared and returned- Returns:
out, meant as effectively a 2D rotation matrix
-
randomRotation3D
Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 9-element float array, meant as effectively a 3D rotation matrix
-
randomRotation3D
Creates a new 1D float array that can be used as a 3D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 16-element float array, meant as effectively a 4D rotation matrix
-
randomRotation4D
Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 16-element float array, meant as effectively a 4D rotation matrix
-
randomRotation4D
Creates a new 1D float array that can be used as a 4D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 16-element float array, meant as effectively a 4D rotation matrix
-
randomRotation5D
Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 25-element float array, meant as effectively a 5D rotation matrix
-
randomRotation5D
Creates a new 1D float array that can be used as a 5D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 25-element float array, meant as effectively a 5D rotation matrix
-
randomRotation6D
Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 36-element float array, meant as effectively a 6D rotation matrix
-
randomRotation6D
Creates a new 1D float array that can be used as a 6D rotation matrix byrotate(float[], float[], float[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 36-element float array, meant as effectively a 6D rotation matrix
-
randomRotation7D
Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLEand Gaussian floats usingDistributor.normal(long).- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 49-element float array, meant as effectively a 7D rotation matrix
-
randomRotation7D
Creates a new 1D float array that can be used as a 7D rotation matrix byrotate(float[], float[], float[]). Uses the given Random random to get Gaussian floats usingDistributor.normal(long), and uses an existing 6D rotation matrix to avoid redoing any generation work already done for 6D. There will probably be some correlation between the appearance of the 5D rotation this will build upon and the 7D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
random- anyRandomfrom the JDK or from the juniper libraryrotation6D- an existing 6D rotation matrix stored in a 1D float array; often produced byrandomRotation6D(long)- Returns:
- a newly-allocated 49-element float array, meant as effectively a 7D rotation matrix
-
randomRotation
Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomRotation4D(long), this doesn't allocate per dimension. For dimension 2, this only allocates the array it returns.
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(float[], float[], float[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
random- anyRandom, such as from the JDK or from the juniper librarydimension- will be clamped to at minimum 2, but there is technically no maximum- Returns:
- a newly-allocated
dimension * dimension-element float array, meant as effectively adimension-D rotation matrix
-
fillRandomRotation
Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomRotation4D(long), this doesn't allocate per dimension. For dimension 2, this doesn't allocate at all ifouthas at least length 4 (so it can store the resulting matrix).
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(float[], float[], float[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
random- anyRandomfrom the JDK or from the juniper librarydimension- will be clamped to at minimum 2, but there is technically no maximumout- a float array that should have at leastdimension * dimensionelements; will be modified- Returns:
out, after modifications, unless it was too small or null (then this returns a new array)
-
rotate
public static double[] rotate(double[] input, double[] rotation, double[] output) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), and an output vector to write to (as a 1D double array), and does the math to rotateinputusingrotation, and add the results intooutput. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectsrotation.length / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, rotation has lengthn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector of lengthnrotation- a rotation matrix of lengthn*mor greateroutput- the output vector of lengthm
-
rotate
public static double[] rotate(double[] input, double[] rotation, double[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), an output vector to write to (as a 1D double array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectsrotation.length / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, rotation has lengthn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector of lengthnrotation- a rotation matrix of lengthn*moutput- the output vector of lengthmor greater; onlyrotation.length / input.lengthitems will be written tooffsetOut- the index inoutputto start writing the rotated output
-
rotate
public static double[] rotate(double[] input, int offsetIn, int sizeIn, double[] rotation, double[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), an output vector to write to (as a 1D double array), and an offset into the output vector to start writing there, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectsrotation.length / input.lengthitems in output. If input has lengthnand output should receivemchanges, rotation has lengthn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector that has length at least equal tooffsetIn + sizeInoffsetIn- the index ininputto start readingsizeIn- how many elements to read frominputrotation- a rotation matrix of lengthsizeIn * m, wheremis the length of an output vectoroutput- the output vector of lengthmor greater; onlyrotation.length / sizeInitems will be written tooffsetOut- the index inoutputto start writing the rotated output
-
rotate
public static double[] rotate(double[] input, int offsetIn, int sizeIn, double[] rotation, int offsetRotation, int sizeRotation, double[] output, int offsetOut) A "raw" rotation method that takes a rotation matrix (as a row-major 1D double array), an input vector to rotate (as a 1D double array), an output vector to write to (as a 1D double array), and offsets/sizes for those arrays to use only part of each one, and does the math to rotateinputusingrotation, and add the results intooutputstarting atoffsetOut. This does not erase output before writing to it, so it can be called more than once to sum multiple rotations if so desired. The length of output can be arbitrarily large, so this is complete when it has completely processed rotation. That means this affectssizeRotation / input.lengthitems in output. Typically, if input has lengthnand output should receivemchanges, sizeRotation isn*m. This does no validation onrotation, hence why it is "raw" (also because it takes its inputs as unadorned 1D arrays).- Parameters:
input- an input vector that has length at least equal tooffsetIn + sizeInoffsetIn- the index ininputto start readingsizeIn- how many items to read frominputrotation- a rotation matrix of lengthsizeIn * m, wheremis the length of an output vectoroffsetRotation- the first index inrotationto start reading a rotation matrix fromsizeRotation- how many items to read fromrotationto use as a rotation matrixoutput- the output vector of lengthmor greater; onlysizeRotation / sizeInitems will be written tooffsetOut- the index inoutputto start writing the rotated output- Returns:
- output, potentially after modification
-
slerp
public static double[] slerp(double[] start, double[] end, double alpha, double[] output) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place). This does not allocate. This has undefined behavior if start and end are polar opposites; that is, points where for any coordinateain start, that coordinate in end is-aor any positive linear scale of the point where that is true. This degenerates to a linear interpolation if either start or end is the origin, and simply returns the start if both are the origin. Otherwise, this can smoothly move points that aren't already on the unit sphere towards the distance of the other point from the origin.
Unlike thefloatversion of this method, this callsMath.acos(double)andMath.sin(double)for higher precision. This is expected to be somewhat slower than using the approximations fromTrigTools.
Based on the non-approximation code from an article by Volodymyr Agafonkin. Note that this is the "geometric slerp" rather than the version using quaternions in 3D (or rotors in other dimensions). It has been augmented slightly to handle start and end vectors that don't have unit length.- Parameters:
start- an n-dimensional point, wherestart.lengthis nend- another n-dimensional point, whereend.lengthis also the same nalpha- between 0 and 1, inclusive; how much to travel from start towards endoutput- the first n items in this will receive the interpolated position, modifying it in-place- Returns:
- output, after modifications.
-
slerp
public static double[] slerp(int n, double[] start, int startOffset, double[] end, int endOffset, double alpha, double[] output, int outputOffset) A geometric "slerp" (spherical linear interpolation) from the input n-dimensional pointstartto the point in the same dimensionend, moving a fraction of the distance equal toalpha, and placing the result inoutput(modifying it in-place). This does not allocate. This has undefined behavior if start and end are polar opposites; that is, points where for any coordinateain start, that coordinate in end is-aor any positive linear scale of the point where that is true. This degenerates to a linear interpolation if either start or end is the origin, and simply returns the start if both are the origin. Otherwise, this can smoothly move points that aren't already on the unit sphere towards the distance of the other point from the origin.
Unlike thefloatversion of this method, this callsMath.acos(double)andMath.sin(double)for higher precision. This is expected to be somewhat slower than using the approximations fromTrigTools.
Based on the non-approximation code from an article by Volodymyr Agafonkin. Note that this is the "geometric slerp" rather than the version using quaternions in 3D (or rotors in other dimensions). It has been augmented slightly to handle start and end vectors that don't have unit length.- Parameters:
n- the dimension of the points in start, end, and output; must be 2 or morestart- an n-dimensional point to rotate fromstartOffset- what array index to start reading from instartend- another n-dimensional point to rotate toendOffset- what array index to start reading from instartalpha- between 0 and 1, inclusive; how much to travel from start towards endoutput- will be modified in-place so n items, starting at outputOffset, have the resultoutputOffset- what array index to start writing to inoutput- Returns:
- output, after modifications.
-
matrixMultiply
public static double[] matrixMultiply(double[] lf, double[] rt, double[] out, int side) Multiplies two square matrices with side lengthside, and stores the result inout. The inputslfandrtare 1D double arrays treated as row-major matrices.- Parameters:
lf- the left input matrix, as row-majorrt- the right input matrix, as row-majorout- will be modified; this is where the output is summed into, and it is not cleared beforehandside- side length of each input matrix and the output matrix
-
rotateStep
public static double[] rotateStep(long seed, double[] small, int targetSize) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall. This allocates a newtargetSize * targetSize-element double array on every call and returns it. It also allocates some more temporary double arrays to work with.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
seed- random number generator seedsmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1targetSize- the side length of the square matrix to be returned- Returns:
- a 1D double array that can be treated as a rotation matrix for inputs of size
targetSize
-
rotateStep
public static double[] rotateStep(long seed, double[] small, int targetSize, double[] gauss, double[] house, double[] large, double[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall. To avoid allocating arrays on each call to this, this method also takes four double arrays that this will clear and modify, to be used as temporary workspace. As long as the last four arguments have enough length, their contents don't matter. Whilegaussmust have length of at leasttargetSize, the last three must have length of at leasttargetSize * targetSize.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
seed- random number generator seed; may be a long or an intsmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1, and will not be modifiedtargetSize- the side length of the square matrix to be returnedgauss- a temporary double array that will be cleared; must have length of at leasttargetSizehouse- a temporary double array that will be cleared; must have length of at leasttargetSize * targetSizelarge- a temporary double array that will be cleared; must have length of at leasttargetSize * targetSizeout- the double array that will be cleared and returned; must have length of at leasttargetSize * targetSize- Returns:
out, which can be treated as a rotation matrix for inputs of sizetargetSize
-
randomDoubleRotation2D
public static double[] randomDoubleRotation2D(long seed) Creates a new 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]). Uses the given seed to get an angle usingTrigTools.SIN_TABLE_D.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 4-element double array, meant as effectively a 2D rotation matrix
-
fillRandomDoubleRotation2D
public static double[] fillRandomDoubleRotation2D(long seed, double[] out) Fillsoutwith a 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]). Scrambles the given seed withrandomize(long), then gets an angle usingTrigTools.SIN_TABLE_DandTrigTools.COS_TABLE_D.- Parameters:
seed- any long; will be scrambledout- a double array that must have at least 4 elements; will be cleared and returned- Returns:
out, meant as effectively a 2D rotation matrix
-
randomDoubleRotation3D
public static double[] randomDoubleRotation3D(long seed) Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLE_Dand Gaussian doubles usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 9-element double array, meant as effectively a 3D rotation matrix
-
randomDoubleRotation3D
public static double[] randomDoubleRotation3D(long seed, double[] rotation2D) Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get Gaussian doubles usingDistributor.normal(long), and uses an existing 2D rotation matrix to avoid redoing any generation work already done for 2D. There will probably be some correlation between the appearance of the 2D rotation this will build upon and the 3D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 16-element double array, meant as effectively a 4D rotation matrix
-
randomDoubleRotation4D
public static double[] randomDoubleRotation4D(long seed) Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLE_Dand Gaussian doubles usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 16-element double array, meant as effectively a 4D rotation matrix
-
randomDoubleRotation4D
public static double[] randomDoubleRotation4D(long seed, double[] rotation3D) Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get Gaussian doubles usingDistributor.normal(long), and uses an existing 3D rotation matrix to avoid redoing any generation work already done for 3D. There will probably be some correlation between the appearance of the 3D rotation this will build upon and the 4D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 16-element double array, meant as effectively a 4D rotation matrix
-
randomDoubleRotation5D
public static double[] randomDoubleRotation5D(long seed) Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLE_Dand Gaussian doubles usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 25-element double array, meant as effectively a 5D rotation matrix
-
randomDoubleRotation5D
public static double[] randomDoubleRotation5D(long seed, double[] rotation4D) Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get Gaussian doubles usingDistributor.normal(long), and uses an existing 4D rotation matrix to avoid redoing any generation work already done for 4D. There will probably be some correlation between the appearance of the 4D rotation this will build upon and the 5D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 25-element double array, meant as effectively a 5D rotation matrix
-
randomDoubleRotation6D
public static double[] randomDoubleRotation6D(long seed) Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLE_Dand Gaussian doubles usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 36-element double array, meant as effectively a 6D rotation matrix
-
randomDoubleRotation6D
public static double[] randomDoubleRotation6D(long seed, double[] rotation5D) Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get Gaussian doubles usingDistributor.normal(long), and uses an existing 5D rotation matrix to avoid redoing any generation work already done for 5D. There will probably be some correlation between the appearance of the 5D rotation this will build upon and the 6D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 36-element double array, meant as effectively a 6D rotation matrix
-
randomDoubleRotation7D
public static double[] randomDoubleRotation7D(long seed) Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get an angle usingTrigTools.SIN_TABLE_Dand Gaussian doubles usingDistributor.normal(long).- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 49-element double array, meant as effectively a 7D rotation matrix
-
randomDoubleRotation7D
public static double[] randomDoubleRotation7D(long seed, double[] rotation6D) Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]). Uses the given long seed to get Gaussian doubles usingDistributor.normal(long), and uses an existing 6D rotation matrix to avoid redoing any generation work already done for 6D. There will probably be some correlation between the appearance of the 6D rotation this will build upon and the 7D rotation this produces, but other factors may make this irrelevant when used for noise.- Parameters:
seed- any long; will be scrambled- Returns:
- a newly-allocated 49-element double array, meant as effectively a 7D rotation matrix
-
randomDoubleRotation
public static double[] randomDoubleRotation(long seed, int dimension) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomDoubleRotation4D(long), this doesn't allocate per dimension. For dimension 2, this only allocates the array it returns.
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(double[], double[], double[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
seed- any long; will be scrambleddimension- will be clamped to at minimum 2, but there is technically no maximum- Returns:
- a newly-allocated
dimension * dimension-element double array, meant as effectively adimension-D rotation matrix
-
fillRandomDoubleRotation
public static double[] fillRandomDoubleRotation(long seed, int dimension, double[] out) Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomRotation4D(long), this doesn't allocate per dimension. For dimension 2, this doesn't allocate at all ifouthas at least length 4 (so it can store the resulting matrix).
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(double[], double[], double[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
seed- any long; will be scrambleddimension- will be clamped to at minimum 2, but there is technically no maximumout- a float array that should have at leastdimension * dimensionelements; will be modified- Returns:
out, after modifications, unless it was too small or null (then this returns a new array)
-
rotateStep
This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number generator, and uses the seed and some matrix operations to generate a random rotation based onsmall. This allocates a newtargetSize * targetSize-element double array on every call and returns it. It also allocates some more temporary double arrays to work with.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
random- random number generator; anyRandomfrom the JDK or from the juniper library workssmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1targetSize- the side length of the square matrix to be returned- Returns:
- a 1D double array that can be treated as a rotation matrix for inputs of size
targetSize
-
rotateStep
public static double[] rotateStep(Random random, double[] small, int targetSize, double[] gauss, double[] house, double[] large, double[] out) This is just part of a larger rotation generator; it takes a target size (the side length of the matrix this will return), another matrixsmall(with a side length 1 less thantargetSize), and a random number seed, and uses the seed and some matrix operations to generate a random rotation based onsmall. To avoid allocating arrays on each call to this, this method also takes four double arrays that this will clear and modify, to be used as temporary workspace. As long as the last four arguments have enough length, their contents don't matter. Whilegaussmust have length of at leasttargetSize, the last three must have length of at leasttargetSize * targetSize.
This is not meant for usage outside this class, but if you are copying or modifying parts of the code in here, then you will probably need at least one of the rotateStep() methods.
See Stack Exchange's links here, and Graphics Gems III (specifically, the part about fast random rotation matrices, not the part about the subgroup algorithm).- Parameters:
random- random number generator; anyRandomfrom the JDK or from the juniper library workssmall- a smaller square matrix than the result should be; must have side lengthtargetSize - 1, and will not be modifiedtargetSize- the side length of the square matrix to be returnedgauss- a temporary double array that will be cleared; must have length of at leasttargetSizehouse- a temporary double array that will be cleared; must have length of at leasttargetSize * targetSizelarge- a temporary double array that will be cleared; must have length of at leasttargetSize * targetSizeout- the double array that will be cleared and returned; must have length of at leasttargetSize * targetSize- Returns:
out, which can be treated as a rotation matrix for inputs of sizetargetSize
-
randomDoubleRotation2D
Creates a new 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D.- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 4-element double array, meant as effectively a 2D rotation matrix
-
fillRandomDoubleRotation2D
Fillsoutwith a 1D double array that can be used as a 2D rotation matrix byrotate(double[], double[], double[]). Scrambles the given seed withrandomize(long), then gets an angle usingTrigTools.SIN_TABLE_DandTrigTools.COS_TABLE_D.- Parameters:
random- anyRandomfrom the JDK or from the juniper libraryout- a double array that must have at least 4 elements; will be cleared and returned- Returns:
out, meant as effectively a 2D rotation matrix
-
randomDoubleRotation3D
Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 9-element double array, meant as effectively a 3D rotation matrix
-
randomDoubleRotation3D
Creates a new 1D double array that can be used as a 3D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 16-element double array, meant as effectively a 4D rotation matrix
-
randomDoubleRotation4D
Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 16-element double array, meant as effectively a 4D rotation matrix
-
randomDoubleRotation4D
Creates a new 1D double array that can be used as a 4D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 16-element double array, meant as effectively a 4D rotation matrix
-
randomDoubleRotation5D
Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 25-element double array, meant as effectively a 5D rotation matrix
-
randomDoubleRotation5D
Creates a new 1D double array that can be used as a 5D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 25-element double array, meant as effectively a 5D rotation matrix
-
randomDoubleRotation6D
Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 36-element double array, meant as effectively a 6D rotation matrix
-
randomDoubleRotation6D
Creates a new 1D double array that can be used as a 6D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 36-element double array, meant as effectively a 6D rotation matrix
-
randomDoubleRotation7D
Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 49-element double array, meant as effectively a 7D rotation matrix
-
randomDoubleRotation7D
Creates a new 1D double array that can be used as a 7D rotation matrix byrotate(double[], double[], double[]). Uses the givenRandomto get an angle usingTrigTools.SIN_TABLE_D, and also callsRandom.nextGaussian().- Parameters:
random- anyRandomfrom the JDK or from the juniper library- Returns:
- a newly-allocated 49-element double array, meant as effectively a 7D rotation matrix
-
randomDoubleRotation
Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomDoubleRotation4D(long), this doesn't allocate per dimension. For dimension 2, this only allocates the array it returns.
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(double[], double[], double[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
random- anyRandomfrom the JDK or from the juniper librarydimension- will be clamped to at minimum 2, but there is technically no maximum- Returns:
- a newly-allocated
dimension * dimension-element double array, meant as effectively adimension-D rotation matrix
-
fillRandomDoubleRotation
Iteratively calculates a rotation matrix for the givendimension, randomly generating it with the givenseed. For dimensions 3 and higher, this allocates some temporary arrays once per call, but unlike methods such asrandomRotation4D(long), this doesn't allocate per dimension. For dimension 2, this doesn't allocate at all ifouthas at least length 4 (so it can store the resulting matrix).
If allocation is a concern because you are making many random rotations, you may want to consider creating aRotationTools.Rotatorand using it to rotate vectors instead of usingrotate(double[], double[], double[])directly. Rotator allocates its memory upon construction and doesn't allocate after that.- Parameters:
random- anyRandomfrom the JDK or from the juniper librarydimension- will be clamped to at minimum 2, but there is technically no maximumout- a float array that should have at leastdimension * dimensionelements; will be modified- Returns:
out, after modifications, unless it was too small or null (then this returns a new array)
-