-
Notifications
You must be signed in to change notification settings - Fork 48
cisstVector concepts
Table of Contents generated with DocToc
This document is not complete yet. It should ultimately include most of the information found in our previous documentation:
- [http://unittest.lcsr.jhu.edu/cisst/downloads/cisst/current/doc/latex/vector-user-guide.html cisstVector User Guide (html)], also available as [http://unittest.lcsr.jhu.edu/cisst/downloads/cisst/current/doc/latex/vector-user-guide.pdf pdf]
cisstVector is a collection of classes used for linear algebra. This includes vectors, matrices, multi-dimensional arrays and some classes to represent 2D and 3D transformations. For both vectors and matrices, cisstVector supports fixed size containers (i.e. stack allocated and using a size known at compilation time) and dynamic size containers (which can be resized at any time using runtime memory allocation). Fixed size containers are ideal for small objects (tens of elements). If you are using large datasets, dynamic size containers are strongly recommended. Multi-dimensional arrays use dynamic memory allocation but their dimension must be set at compilation time.
All containers in cisstVector have been designed to be flexible while remaining efficient. To do so the library strongly relies on C++ templates. The most obvious template parametrization is the type of element contained. For example, the code used for a dynamic matrix of float
s is not much different from the code for a matrix of double
s.
// declare a matrix of floats
vctDynamicMatrix<float> matrixOfFloats;
// declare a matrix of doubles
vctDynamicMatrix<double> matrixOfDoubles;
The second template parameter is the size for fixed size containers:
// declare a fixed size vector of 4 floats
vctFixedSizeVector<float, 4> vector4OfFloats;
// declare a fixed size vector of 3 ints
vctFixedSizeVector<int, 3> vector3OfInts;
cisstVector also relies on a template parameter to define the dimension of multi-dimensional arrays:
// a 3D array of doubles
vctDynamicNArray<double, 3> array3DOfDoubles;
The cisstVector containers also use templates to parametrize how memory is managed. This is used extensively to create "references" on a container or part of a container such as a column of a matrix, a slice of a multi-dimensional array, ...
Most cisstVector classes rely on templates. Since C++ template declaration can be fairly cumbersome, cisstVector provides some "shortcuts" in the form of typedefs for the most commonly used types. For example, one can use vctInt4
to declare a vector of 4 integers instead of vctFixedSizeVector<int 4>
. Since most computations are performed using double
s, cisstVector provides an even shorter notation, dropping the Double
part of the type name. For example, vctFixedSizeVector<double, 3>
can also be written as vctDouble3
or even simpler vct3
.
-
Fixed size vector:
vctFixedSizeVector<type, size>
. For example, one can declare a fixed size vector of 2 unsigned integers usingvctFixedSizeVector<unsigned int, 2> myVector
.-
vctDouble2
,vctDouble3
,vctDouble4
, ... -
vct2
,vct3
,vct4
, ... (vectors ofdouble
s) -
vctInt2
,vctInt3
,vctInt4
, ... - Supported types include
Int
,UInt
,Char
,UChar
,Bool
, ... - Supported sizes go from 1 to 9 (as of 2012, more might be added later).
- All types are defined in file
vctFixedSizeVectorTypes.h
(see current version source:/trunk/cisst/cisstVector/vctFixedSizeVectorTypes.h)
-
-
Fixed size matrix:
vctFixedSizeMatrix<type, rows, cols, storageOrder>
. For example, one can declare a 2 by 2 fixed size matrix of unsigned integers usingvctFixedSizeMatrix<unsigned int, 2, 2> myMatrix
.- The last template parameter defines the storage order, i.e. are the elements stored by row or by column. Options are
VCT_ROW_MAJOR
(implicit default across cisstVector) orVCT_COL_MAJOR
. -
vctDouble2x2
,vctDouble3x3
,vctDouble4x4
, ... -
vct2x2
,vct3x3,
vct4x4, ... (matrices of
double`s) -
vctInt2x2
,vctInt3x3
,vctInt4x4
, ... - Supported types include
Int
,Char
,Bool
, ... - Supported sizes go from 1 to 4 for either rows and columns (as of 2012, more might be added later).
- All types are defined in file
vctFixedSizeMatrixTypes.h
(see current version source:/trunk/cisst/cisstVector/vctFixedSizeMatrixTypes.h)
- The last template parameter defines the storage order, i.e. are the elements stored by row or by column. Options are
-
Dynamic vector:
vctDynamicVector<type>
. For example, one can declare a dynamic vector of unsigned integers usingvctDynamicVector<unsigned int> myVector
.-
vctDoubleVec
also known asvctVec
-
vctIntVec
, ... - Supported types include
Int
,UInt
,Char
,UChar
,Bool
, ... - All types are defined in file
vctDynamicVectorTypes.h
(see current version source:/trunk/cisst/cisstVector/vctDynamicVectorTypes.h)
-
-
Dynamic matrix:
vctDynamicMatrix<type>
. For example, one can declare a dynamic matrix of unsigned integers usingvctDynamicMatrix<unsigned int> myMatrix
.-
vctDoubleMat
also known asvctMat
-
vctIntMat
, ... - Supported types include
Int
,UInt
,Char
,UChar
,Bool
, ... - All types are defined in file
vctDynamicMatrixTypes.h
(see current version source:/trunk/cisst/cisstVector/vctDynamicMatrixTypes.h)
-
-
Dynamic multi-dimensional arrays:
vctDynamicNArray<type>
. For example one can declare a 4D array of unsigned integers usingvctDynamicNArray<unsigned int, 4> myArray
.
All types are defined in file vctTransformationTypes.h
(see current version source:/trunk/cisst/cisstVector/vctTransformationTypes.h)
-
3D rotations:
-
3D rotation matrix:
vctMatrixRotation3<type, storageOrder>
. For example, one can declare a rotation matrix using single precision floating point numbers withvctMatrixRotation3<float> myRotation
.-
vctDoubleMatRot3
or without theDouble
,vctMatRot3
vctFloatMatRot3
- Since rotations are often represented using matrices, cisstVector also provide the following "shortcut",
vctDoubleMatRot3
can be written asvctDoubleRot3
or even shortervctRot3
.
-
-
3D rotation using unit quaternion:
vctQuaternionRotation3<type>
. For example, one can declare a rotation quaternion using doubles withvctQuaternionRotation3<double> myRotation
.-
vctDoubleQuatRot3
orvctQuatRot3
vctFloatQuatRot3
-
-
3D rotation using axis and angle:
vctAxisAngleRotation3<type>
. The angle is always represented using double precision floating point. The type provided is for the axis representation.-
vctDoubleAxAnRot3
orvctAxAnRot3
vctFloatAxAnRot3
-
-
3D rotation using Rodriguez
vctRodriguezRotation3<type>
. This class uses a 3 elements vector. The vector's direction represent the axis of rotation and it's norm represents the angle (in radians).-
vctDoubleRodRot3
orvctRodRot3
vctFloatRodRot3
-
-
3D rotation using Euler angles
vctEulerRotation3<order>
.-
vctEulerZYZRotation3
(same asvctEulerRotation3<vctEulerRotation3Order::ZYZ>
) -
vctEulerZYXRotation3
(same asvctEulerRotation3<vctEulerRotation3Order::ZYX>
) - Euler rotation types are defined in file
vctEulerRotation3.h
(see current version source:/trunk/cisst/cisstVector/vctEulerRotation3.h)
-
-
-
3D transformations -- to be documented
-
2D rotations -- to be documented
-
2D transformations -- to be documented
The following section is important to understand one of the key features of the cisstVector library but it is not required for casual users.
One of the key design trait of the cisstVector containers is the ability to own or reference an existing block of memory. For example, one can see a column of a matrix as a vector. One naive implementation would be to copy the column elements to a new vector but this would first create unnecessary copies and second complicate all write commands. To avoid this, the vector class is templated by a parameter representing either a block of memory owned by the vector or a reference (internal a pointer) to an existing block of memory. It is important to note at that point that the block of memory can be owned/managed by another cisst container or an external package. This allows us to create cisstVector references to an C array, OpenCV image, VTK data block, ...
To reference an existing block of memory, one first needs to get a base pointer, i.e. a pointer on the first element. The second parameter is the offset between elements, also known as '''stride'''. For a compact block of memory, this stride is set to one, i.e. one just has to increment the element pointer by 1 to move from one element to the next. Now, if we consider the matrix example and assuming the elements of the matrix are stored contiguously and row-by-row, a column can be represented using reference with a stride equal to the number of columns. Considering a 3x3 matrix:
| m(0,0) @ p[0]
| m(0,1) @ p[1]
| m(0,2) @ p[2]
|
| m(1,0) @ p[3]
| m(1,1) @ p[4]
| m(1,2) @ p[5]
|
| m(2,0) @ p[6]
| m(2,1) @ p[7]
| m(2,2) @ p[8]
|
| m(3,0) @ p[9]
| m(3,1) @ p[10]
| m(3,2) @ p[11]
|
Using a reference one can now create multiple "views" of the data:
-
The first column is represented by a vector reference; pointer is
p[0]
, stride to next element is 3 (i.e.p[0]
,p[3]
,p[6]
, ...) and size is 4:| m(0,0) @
p[0]
| m(1,0) @p[3]
| m(2,0) @p[6]
| m(3,0) @p[9]
|-
For other columns, just change the pointer.
-
For rows, the stride is 1.
-
For the diagonal, one can use a reference vector; pointer is
p[0]
, stride is 4 (i.e.p[0]
,p[4]
,p[8]
) and size is 3 (minimum of number of rows and columns)| m(0,0) @
p[0]
| m(1,1) @p[4]
| m(2,2) @p[8]
|
-
What applies to vectors also applies to matrices and N-arrays. For a matrix, one needs two strides, a row stride which represents the memory offset to go from one element to the next in a column and the column stride which represents the offset to go from one element to the next in a row. For a multi-dimensional array, the number of strides is equal to the array dimension.
For example, the above matrix is stored in a contiguous block of memory and row-by-row so it's row stride is 3 (i.e. number of columns) and it's column stride is 1. Considering the row stride rs = 3
, the previous matrix elements can be seen as follow (in the example the column stride is implicitly 1):
| m(0,0) @ p[0 * rs + 0]
| m(0,1) @ p[0 * rs + 1]
| m(0,2) @ p[0 * rs + 2]
|
| m(1,0) @ p[1 * rs + 0]
| m(1,1) @ p[1 * rs + 1]
| m(1,2) @ p[1 * rs + 2]
|
| m(2,0) @ p[2 * rs + 0]
| m(2,1) @ p[2 * rs + 1]
| m(2,2) @ p[2 * rs + 2]
|
| m(3,0) @ p[3 * rs + 0]
| m(3,1) @ p[3 * rs + 1]
| m(3,2) @ p[3 * rs + 2]
|
Storing the matrix elements row-by-row is often the default in C/C++ while in Fortran it is common to store matrix elements column-by-column. This is called the '''storage order''', and it can either be '''row major''' or '''column major'''. The cisst matrices can use either but the default storage order is row major.
Using matrix strides also allows to create different views of the data:
-
The transpose of the matrix can be obtained by swapping the row and column strides as well as the row and column numbers:
| t(0,0) @
p[0]
| t(0,1) @p[3]
| t(0,2) @p[6]
| t(0,3) @p[9]
| | t(1,0) @p[1]
| t(1,1) @p[4]
| t(1,2) @p[7]
| t(0,3) @p[10]
| | t(2,0) @p[2]
| t(2,1) @p[5]
| t(2,2) @p[8]
| t(0,3) @p[11]
|Note that the addresses of the diagonal elements (0, 4 and 8) are unchanged as expected.
-
A sub-matrix, using the same strides but a different starting pointer and different sizes:
| s(0,0) @
p[4]
| s(0,1) @p[7]
| | s(1,0) @p[5]
| s(1,1) @p[8]
|
In this example, we are considering a 2 by 2 sub-matrix starting at m(1,1).
For all examples, we are using the following naming convention: s
stands for scalar, either integer, float, ... v
stands for vector, m
for matrix, a
for N-array and c
can be any cisstVector container (vector, matrix or N-array).
As expected, all cisstVector containers have a default and copy constructor implemented. It is important to note that:
- Default constructors for vectors, matrices and arrays don't initialize the content, their content is undefined. If you run into different behaviors with some code compiled in either "debug" or "release" mode, you might want to make sure the content of all your containers is initialized properly. One solution is to use the constructor with a default value (e.g.
vct4 v(1.0);
) - For dynamic containers (vectors, matrices and arrays), the default size is 0, i.e. no memory is allocated. One can use the
SetSize
orresize
later or the constructor with size. For examplevctDoubleVec v(10);
creates a vector of 10 elements. As mentioned above, the vector elements are still not defined so one can usevctDoubleVec v(10, 1.234)
to both set the size and initialize all elements. - For all transformations, the default constructor does initialize the content to identity.
- Copy constructors attempt to perform a deep copy for all cisstVector containers, i.e. the copy constructor will call the assignment operator for each element (
c1[i] = c2[i]
).
// fixed size vector of 3 elements
vct3 v1;
v1.SetAll(1.0); // set all elements, by default content is uninitialized!
// copy of v1
vct3 v2(v1);
// create a matrix, zero size
vctDoubleMat m1;
// create a matrix, 3 rows, 4 columns and initialized with 5.0.
vctDoubleMat m2(3, 4, 5.0);
We also provide constructors between types to simplify the users life, i.e. mostly conversions between fixed size and dynamic containers.
// create a fixed size vector and then assign to a dynamic vector
vctInt4 v1(5); // vector content is 5, 5, 5, 5
vctIntVec v2(v1); // set the vector's size to 4 and then assign the content from v1
// create a dynamic vector and then assign it's content to a fixed size vector
vctIntVec v3(3, 0); // vector content is 0, 0, 0
vctInt3 v4(v3); // size is predefined to 3, content will be set to 0, 0, 0
vctInt4 v4(v3); // this call will FAIL at runtime (std::runtime_exception thrown) because size don't match
Finally one can use the constructor based on the ellipsis (...
). These constructors should be use with extreme caution as the code relies on the ellipsis and can't perform type matching. So make sure the type of elements match the container's element type.
vctInt3 v1(1, 2, 3); // content is 1, 2, 3
vctDouble3x3 m1(1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0); // content is set to identity
// note that in previous example we used "1.0", not "1" to indicate a double is used.
vctFloat6 v2(0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f);
// we have to use "0.0f", not just "0.0" which would be doubles
Failure to provide the right number of arguments and/or provide arguments of the wrong type will likely lead to stack corruptions or at least undesired results.
This section only applies to dynamic containers which own their memory, i.e. vctDynamicVector
, vctDynamicMatrix
and vctDynamicNArray
. The following two methods are available to resize a container after it has been instantiated:
-
SetSize
: this methods doesn't guarantee that data is preserved. -
resize
: this methods attempts to preserve the data, i.e. if the new size if smaller that the previous size, part of the data is copied. If the new size if larger than the previous size, all the data is copied. Newly added elements are uninitialized!
Both methods check if the new size is different from the previous. If both sizes are equal, memory is not freed nor allocated and the containers content remains unchanged.
vctDoubleMat m1;
m1.SetSize(4, 3); // 4 rows, 3 columns
m1.resize(4, 3); // does nothing, same size
// multiple dimension arrays are a bit different
// sizes are provided using a vector of values (using fixed size vectors)
typedef vctDynamicNArray<short, 3> ArrayType;
typedef ArrayType::nsize_type SizeType;
// create an array and allocate memory
SizeType a1size(128, 256, 256);
ArrayType a1(a1Size);
// alternative to set size and allocate
ArrayType a2;
a2.SetSize(SizeType(100, 100, 100));
Constructors, SetSize VCT_DEFAULT_STORAGE, VCT_ROW_MAJOR, VCT_COL_MAJOR, VCT_FORTRAN_ORDER
-- IsCompact, IsRowMajor, IsColumnMajor, IsFortran, StorageOrder, stride, ...
-- Assign and operator =, ForceAssign used set size ...
-- random access -- iterators
-- to be documented, 2 strategies, templated or refs with implicit constructors
-- operators, note on vctDynamicVectorReturn ...
-- create local variables, setsize vs Resize -- random access versus iterative access (note on pointer arithmetic)
cisstVector uses the following convention to convert from a type of transformation to another, e.g. convert from a 3D rotation represented by a matrix to and from a unit quaternion. Let vctTypeA
and vctTypeB
be two types of equivalent transformations. The following methods should be used to convert back and forth:
-
transformA.From(transformB)
: this method will convert from type B to A but an exception will be thrown if the input is not valid, i.e. not normalized. The goal is to make sure one can detect issues at runtime using atry
/catch
block. If the conversion failed, the state oftransformA
is undefined (i.e. it might have been partially modified). -
transformA.FromNormalized(transformB)
: this method will convert from type B to A while making sure the result if valid, i.e. it will attempt to normalize the input or result. This method is the safest but can have a significant cost since normalization is performed for each conversion. -
transformA.FromRaw(transformB)
: this method will convert from type B to A without any normalization test not attempt to normalize the input or result. This method can be used when the user is confident all transformations are valid but some numerical rounding might occur. These numerical errors would trigger an exception if theFrom
method was used.
One can also use constructors to perform similar conversions:
-
vctTypeA transformA(transformB)
: constructtransformA
fromtransformB
. This constructor relies on theFrom
method and will check if the input is normalized. -
vctTypeA transformA(transformB, VCT_NORMALIZE)
: constructtransformA
fromtransformB
. This constructor relies on theFromNormalized
method. -
vctTypeA transformA(transformB, VCT_DO_NOT_NORMALIZE)
: constructtransformA
fromtransformB
. This constructor relies on theFromRaw
method.
The assignment operator (=
) is sometimes overloaded and relies on the From
method.
-- to be documented: *
, ApplyTo
, ApplyInverseTo
.
-- to be documented: Inverse
, Normalized
self and of, AlmostEqual
, AlmostEquivalent
.
-- to be documented, specific constructors, access to data
-- to be documented: vctFrameBase
, vctFrame4x4
- Home
- Libraries & components
- Download
- Compile (FAQ)
- Reference manual
- cisstCommon
- cisstVector
- cisstNumerical
- cisstOSAbstraction
- TBD
- cisstMultiTask
- cisstRobot
- cisstStereoVision
- Developers