Files
tenmon/3rdparty/include/pcl/Matrix.h
T
2022-04-12 08:17:18 +02:00

3750 lines
121 KiB
C++

// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ PixInsight Class Library
// /_/ \____//_____/ PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/Matrix.h - Released 2022-03-12T18:59:29Z
// ----------------------------------------------------------------------------
// This file is part of the PixInsight Class Library (PCL).
// PCL is a multiplatform C++ framework for development of PixInsight modules.
//
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
//
// Redistribution and use in both source and binary forms, with or without
// modification, is permitted provided that the following conditions are met:
//
// 1. All redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. All redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
// of their contributors, may be used to endorse or promote products derived
// from this software without specific prior written permission. For written
// permission, please contact info@pixinsight.com.
//
// 4. All products derived from this software, in any form whatsoever, must
// reproduce the following acknowledgment in the end-user documentation
// and/or other materials provided with the product:
//
// "This product is based on software from the PixInsight project, developed
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
//
// Alternatively, if that is where third-party acknowledgments normally
// appear, this acknowledgment must be reproduced in the product itself.
//
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------
#ifndef __PCL_Matrix_h
#define __PCL_Matrix_h
/// \file pcl/Matrix.h
#include <pcl/Defs.h>
#include <pcl/Diagnostics.h>
#include <pcl/Container.h>
#include <pcl/Exception.h>
#include <pcl/Math.h>
#include <pcl/Memory.h>
#include <pcl/ReferenceCounter.h>
#include <pcl/Rotate.h> // pcl::Reverse()
#include <pcl/Utility.h>
#include <pcl/Vector.h>
#ifndef __PCL_NO_MATRIX_STATISTICS
# include <pcl/Selection.h>
# include <pcl/Sort.h>
#endif
#if !defined( __PCL_NO_MATRIX_IMAGE_RENDERING ) && !defined( __PCL_NO_MATRIX_IMAGE_CONVERSION )
# include <pcl/Image.h>
# include <pcl/ImageVariant.h>
#endif
#if !defined( __PCL_NO_MATRIX_PHASE_MATRICES ) && !defined( __PCL_NO_VECTOR_INSTANTIATE )
# include <pcl/Complex.h>
#endif
/*
* Valid filter kernel sizes are odd integers >= 3. This macro is used for the
* KernelFilter and SeparableFilter classes to ensure validity of filter
* matrices and vectors.
*/
#define PCL_VALID_KERNEL_SIZE( n ) (n ? Max( 3, n|1 ) : 0)
namespace pcl
{
// ----------------------------------------------------------------------------
/*!
* \class GenericMatrix
* \brief Generic dynamic matrix of arbitrary dimensions.
*
* %GenericMatrix is a lightweight template class implementing a matrix of
* arbitrary size. This class provides the following main features:
*
* \li Implicit data sharing with reference counting and copy-on-write
* functionality. %GenericMatrix instances can safely be passed as function
* return values and by-value function arguments.
*
* \li Thread-safe. %GenericMatrix instances can safely be accessed from
* multiple threads. The reference counter implements atomic reference and
* dereference operations.
*
* \li Efficient matrix storage and access to matrix elements. %Matrix
* elements are dynamically allocated as a single, contiguous memory block.
*
* \li Support for a comprehensive set of matrix operations, including matrix
* inversion and transposition, scalar-to-matrix and matrix-to-matrix
* arithmetic operations, and image to/from matrix conversions.
*
* \li Calculation of a variety of descriptive statistics for matrix elements.
*
* \sa GenericVector, \ref matrix_operators, \ref matrix_types
*/
template <typename T>
class PCL_CLASS GenericMatrix : public DirectContainer<T>
{
public:
/*!
* Represents a matrix element.
*/
typedef T element;
/*!
* Represents a vector of matrix elements.
*/
typedef GenericVector<element> vector;
/*!
* Represents a mutable matrix block iterator. In a matrix of n rows and m
* columns, a block iterator allows iteration on the entire set of matrix
* elements from {0,0} to {n-1,m-1} in row-column order.
*/
typedef element* block_iterator;
/*!
* Represents an immutable matrix block iterator. In a matrix of n rows and
* m columns, a block iterator allows iteration on the entire set of matrix
* elements from {0,0} to {n-1,m-1} in row-column order.
*/
typedef const element* const_block_iterator;
/*!
* Constructs an empty matrix.
* An empty matrix has no elements and zero dimensions.
*/
GenericMatrix()
{
m_data = new Data;
}
/*!
* Constructs an uninitialized matrix.
*
* \param rows Number of matrix rows (&ge; 0).
* \param cols Number of matrix columns (&ge; 0).
*
* Matrix elements are not initialized by this constructor; the newly
* created matrix will contain unpredictable values.
*/
GenericMatrix( int rows, int cols )
{
PCL_PRECONDITION( rows >= 0 && cols >= 0 )
m_data = new Data( rows, cols );
}
/*!
* Constructs a matrix and fills it with a constant value.
*
* \param x Initial value for all matrix elements.
* \param rows Number of matrix rows (&ge; 0).
* \param cols Number of matrix columns (&ge; 0).
*/
GenericMatrix( const element& x, int rows, int cols )
{
PCL_PRECONDITION( rows >= 0 && cols >= 0 )
m_data = new Data( rows, cols );
pcl::Fill( m_data->Begin(), m_data->End(), x );
}
/*!
* Constructs a matrix and initializes it with values from a static buffer.
*
* \param a Address of the first item of a static array for
* initialization of matrix elements. The array must provide
* at least \a rows x \a cols consecutive elements stored in
* row order (all elements of the first matrix row followed
* by all elements of the second row, and so on).
*
* \param rows Number of matrix rows (&ge; 0).
*
* \param cols Number of matrix columns (&ge; 0).
*/
template <typename T1>
GenericMatrix( const T1* a, int rows, int cols )
{
PCL_PRECONDITION( rows >= 0 && cols >= 0 )
m_data = new Data( rows, cols );
if ( a != nullptr )
{
block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
const T1* __restrict__ k = a;
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = element( *k );
}
}
/*!
* Constructs a 3x3 matrix initialized with the specified element values.
*
* The resulting square matrix will be initialized as follows:
*
* <pre>
* a00, a01, a02
* a10, a11, a12
* a20, a21, a22
* </pre>
*/
template <typename T1>
GenericMatrix( const T1& a00, const T1& a01, const T1& a02,
const T1& a10, const T1& a11, const T1& a12,
const T1& a20, const T1& a21, const T1& a22 )
{
m_data = new Data( 3, 3 );
block_iterator __restrict__ v = m_data->Begin();
v[0] = element( a00 ); v[1] = element( a01 ); v[2] = element( a02 );
v[3] = element( a10 ); v[4] = element( a11 ); v[5] = element( a12 );
v[6] = element( a20 ); v[7] = element( a21 ); v[8] = element( a22 );
}
/*!
* Copy constructor. This object will reference the same data that is being
* referenced by the specified matrix \a x.
*/
GenericMatrix( const GenericMatrix& x )
: m_data( x.m_data )
{
m_data->Attach();
}
/*!
* Move constructor.
*/
GenericMatrix( GenericMatrix&& x )
: m_data( x.m_data )
{
x.m_data = nullptr;
}
/*!
* Constructs a matrix as a copy of a rectangular subset of another matrix.
*
* \param x Source matrix from which this object will acquire element
* values.
*
* \param i0 Starting row in \a x. Corresponds to the first (top) row
* of this matrix.
*
* \param j0 Starting column in \a x. Corresponds to the first
* (leftmost) column of this matrix.
*
* \param rows Number of matrix rows.
*
* \param cols Number of matrix columns.
*
* If the specified submatrix is invalid, i.e. if the specified row or
* column don't exist, or if the specified number of rows and columns exceed
* the dimensions of the source matrix \a x, this constructor constrains the
* submatrix coordinates and dimensions to the nearest valid values,
* possibly constructing an empty matrix.
*/
GenericMatrix( const GenericMatrix& x, int i0, int j0, int rows, int cols )
{
i0 = Range( i0, 0, Max( 0, x.Rows()-1 ) );
j0 = Range( j0, 0, Max( 0, x.Cols()-1 ) );
rows = Range( rows, 0, Max( 0, x.Rows()-i0 ) );
cols = Range( cols, 0, Max( 0, x.Cols()-j0 ) );
m_data = new Data( rows, cols );
for ( int i = 0; i < m_data->Rows(); ++i, ++i0 )
for ( int j = 0; j < m_data->Cols(); ++j, ++j0 )
m_data->v[i][j] = x.m_data->v[i0][j0];
}
#ifndef __PCL_NO_MATRIX_IMAGE_CONVERSION
/*!
* Constructs a matrix from image pixel samples.
*
* This constructor converts pixel sample values to matrix elements for a
* rectangular region of a channel of the specified \a image.
*
* \param image %Image from which matrix elements will be generated.
*
* \param rect A rectangular region in image pixel coordinates, from
* which this matrix will be generated. If this parameter is
* not specified, or if an empty rectangle is specified, this
* function will perform the matrix conversion for the
* current rectangular selection in the image, that is, for
* image.SelectedRectangle().
*
* \param channel Channel index. Must be the zero-based index of an existing
* channel in the image, or an integer < 0. If this parameter
* is not specified, or if a negative integer is specified,
* this function will perform the matrix conversion for the
* currently selected channel in the image, that is, for
* image.SelectedChannel().
*
* The newly created matrix is a representation of the intersection of the
* specified (or implicitly selected) rectangular region with the image for
* the scalar data type T of this matrix instantiation. All predefined pixel
* sample types are supported, including integer, real and complex pixels.
*
* If there is no intersection between the rectangular region and the image,
* this constructor yields an empty matrix.
*
* Note that if the source image is of a floating point type (either real or
* complex) and the scalar type T of this matrix instantiation is of an
* integer type, out-of-range matrix elements will be truncated to either
* zero or to the maximum integer value, if the corresponding source pixel
* sample is outside the normalized [0,1] range.
*/
template <class P>
GenericMatrix( const GenericImage<P>& image, const Rect& rect = Rect( 0 ), int channel = -1 )
{
GenericMatrix M = FromImage( image, rect, channel );
pcl::Swap( m_data, M.m_data );
}
/*!
* Constructs a matrix from image pixel samples.
*
* This constructor converts pixel sample values to matrix elements for a
* rectangular region of a channel of the image transported by the specified
* %ImageVariant.
*
* If the specified %ImageVariant object does not transport an image, this
* constructor yields an empty matrix.
*
* Refer to the documentation for
* GenericMatrix::GenericMatrix( const GenericImage&, const Rect&, int ) for
* more information about the conversion performed by this constructor.
*/
GenericMatrix( const ImageVariant& image, const Rect& rect = Rect( 0 ), int channel = -1 )
{
GenericMatrix M = FromImage( image, rect, channel );
pcl::Swap( m_data, M.m_data );
}
#endif // !__PCL_NO_MATRIX_IMAGE_CONVERSION
/*!
* Destroys a %GenericMatrix object. This destructor dereferences the matrix
* data. If the matrix data becomes unreferenced, it is destroyed and
* deallocated immediately.
*/
virtual ~GenericMatrix()
{
if ( m_data != nullptr )
{
DetachFromData();
m_data = nullptr;
}
}
/*!
* Deallocates matrix data, yielding an empty matrix.
*/
void Clear()
{
if ( !IsEmpty() )
if ( m_data->IsUnique() )
m_data->Deallocate();
else
{
Data* newData = new Data( 0, 0 );
DetachFromData();
m_data = newData;
}
}
/*!
* Copy assignment operator. Returns a reference to this object.
*
* If this instance and the specified source instance \a x reference
* different matrix data, the data previously referenced by this object is
* dereferenced. If the previous data becomes unreferenced, it is destroyed
* and deallocated. Then the data being referenced by \a x is also
* referenced by this object.
*
* If this instance and the specified source instance \a x already reference
* the same matrix data, then this function does nothing.
*/
GenericMatrix& operator =( const GenericMatrix& x )
{
Assign( x );
return *this;
}
/*!
* Assigns a matrix \a x to this object.
*
* If this instance and the specified source instance \a x reference
* different matrix data, the data previously referenced by this object is
* dereferenced. If the previous data becomes unreferenced, it is destroyed
* and deallocated. Then the data being referenced by \a x is also
* referenced by this object.
*
* If this instance and the specified source instance \a x already reference
* the same matrix data, then this function does nothing.
*/
void Assign( const GenericMatrix& x )
{
x.m_data->Attach();
DetachFromData();
m_data = x.m_data;
}
/*!
* Move assignment operator. Returns a reference to this object.
*/
GenericMatrix& operator =( GenericMatrix&& x )
{
Transfer( x );
return *this;
}
/*!
* Transfers data from another matrix \a x to this object.
*
* Decrements the reference counter of the current matrix data. If the data
* becomes unreferenced, it is destroyed and deallocated. The matrix data
* referenced by the source object \a x is then transferred to this object,
* and the source object \a x is left empty.
*
* \warning The source matrix \a x will be an invalid object after calling
* this function, and hence should be destroyed immediately. Any attempt to
* access an invalid object will most likely lead to a crash.
*/
void Transfer( GenericMatrix& x )
{
DetachFromData();
m_data = x.m_data;
x.m_data = nullptr;
}
/*!
* Transfers data from another matrix \a x to this object.
*
* Decrements the reference counter of the current matrix data. If the data
* becomes unreferenced, it is destroyed and deallocated. The matrix data
* referenced by the source object \a x is then transferred to this object,
* and the source object \a x is left empty.
*
* \warning The source matrix \a x will be an invalid object after calling
* this function, and hence should be destroyed immediately. Any attempt to
* access an invalid object will most likely lead to a crash.
*/
void Transfer( GenericMatrix&& x )
{
DetachFromData();
m_data = x.m_data;
x.m_data = nullptr;
}
/*!
* Exchanges two matrices \a x1 and \a x2.
*
* This function is efficient because it simply swaps the internal matrix
* data pointers owned by the objects.
*/
friend void Swap( GenericMatrix& x1, GenericMatrix& x2 ) noexcept
{
pcl::Swap( x1.m_data, x2.m_data );
}
/*!
* Assigns a constant scalar \a x to all elements of this matrix. Returns a
* reference to this object.
*
* Before assigning a constant value to all matrix elements, this function
* ensures that this instance uniquely references its matrix data,
* generating a new matrix data block if necessary.
*/
GenericMatrix& operator =( const element& x )
{
if ( !IsUnique() )
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
DetachFromData();
m_data = newData;
}
pcl::Fill( m_data->Begin(), m_data->End(), x );
return *this;
}
#define IMPLEMENT_SCALAR_ASSIGN_OP( op ) \
if ( IsUnique() ) \
{ \
block_iterator __restrict__ i = m_data->Begin(); \
const_block_iterator __restrict__ j = m_data->End(); \
PCL_IVDEP \
for ( ; i < j; ++i ) \
*i op##= x; \
} \
else \
{ \
Data* newData = new Data( m_data->Rows(), m_data->Cols() ); \
block_iterator __restrict__ i = newData->Begin(); \
const_block_iterator __restrict__ j = newData->End(); \
const_block_iterator __restrict__ k = m_data->Begin(); \
PCL_IVDEP \
for ( ; i < j; ++i, ++k ) \
*i = *k op x; \
DetachFromData(); \
m_data = newData; \
} \
return *this;
/*!
* Adds a constant scalar \a x to all elements of this matrix. Returns a
* reference to this object.
*
* Before adding a constant value to all matrix elements, this function
* ensures that this instance uniquely references its matrix data,
* generating a duplicate if necessary.
*/
GenericMatrix& operator +=( const element& x )
{
IMPLEMENT_SCALAR_ASSIGN_OP( + )
}
/*!
* Subtracts a constant scalar \a x from all elements of this matrix.
* Returns a reference to this object.
*
* Before subtracting a constant value from all matrix elements, this
* function ensures that this instance uniquely references its matrix data,
* generating a duplicate if necessary.
*/
GenericMatrix& operator -=( const element& x )
{
IMPLEMENT_SCALAR_ASSIGN_OP( - )
}
/*!
* Multiplies all elements of this matrix by a constant scalar \a x. Returns
* a reference to this object.
*
* Before multiplying all matrix elements by a constant value, this function
* ensures that this instance uniquely references its matrix data,
* generating a duplicate if necessary.
*/
GenericMatrix& operator *=( const element& x )
{
IMPLEMENT_SCALAR_ASSIGN_OP( * )
}
/*!
* Divides all elements of this matrix by a constant scalar \a x. Returns a
* reference to this object.
*
* Before dividing all matrix elements by a constant value, this function
* ensures that this instance uniquely references its matrix data,
* generating a duplicate if necessary.
*/
GenericMatrix& operator /=( const element& x )
{
IMPLEMENT_SCALAR_ASSIGN_OP( / )
}
/*!
* Raises all elements of this matrix to a constant scalar \a x. Returns a
* reference to this object.
*
* Before raising all matrix elements to a constant value, this function
* ensures that this instance uniquely references its matrix data,
* generating a duplicate if necessary.
*/
GenericMatrix& operator ^=( const element& x )
{
if ( IsUnique() )
{
block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
PCL_IVDEP
for ( ; i < j; ++i )
*i = pcl::Pow( *i, x );
}
else
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = newData->Begin();
const_block_iterator __restrict__ j = newData->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Pow( *k, x );
DetachFromData();
m_data = newData;
}
return *this;
}
#undef IMPLEMENT_SCALAR_ASSIGN_OP
#ifndef __PCL_NO_MATRIX_ELEMENT_WISE_ARITHMETIC_OPERATIONS
#define IMPLEMENT_ELEMENT_WISE_ASSIGN_OP( op ) \
if ( IsUnique() ) \
{ \
block_iterator __restrict__ i = m_data->Begin(); \
const_block_iterator __restrict__ j = pcl::Min( m_data->End(), \
m_data->Begin() + x.NumberOfElements() ); \
const_block_iterator __restrict__ k = x.m_data->Begin(); \
PCL_IVDEP \
for ( ; i < j; ++i, ++k ) \
*i op##= *k; \
} \
else \
{ \
Data* newData = new Data( m_data->Rows(), m_data->Cols() ); \
block_iterator __restrict__ i = newData->Begin(); \
const_block_iterator __restrict__ j = pcl::Min( newData->End(), \
newData->Begin() + x.NumberOfElements() ); \
const_block_iterator __restrict__ k = x.m_data->Begin(); \
const_block_iterator __restrict__ t = m_data->Begin(); \
PCL_IVDEP \
for ( ; i < j; ++i, ++k, ++t ) \
*i = *t op *k; \
DetachFromData(); \
m_data = newData; \
} \
return *this;
/*!
* Performs the element-wise addition of a matrix \a x to this matrix.
* Returns a reference to this object.
*
* The specified operand matrix \a x should have at least the same number of
* elements as this matrix. Otherwise the operation will be aborted upon
* reaching the end of the operand matrix, but no exception will be thrown.
*
* This function ensures that this instance uniquely references its matrix
* data before the element-wise addition operation, generating a duplicate
* if necessary.
*/
GenericMatrix& operator +=( const GenericMatrix& x )
{
IMPLEMENT_ELEMENT_WISE_ASSIGN_OP( + )
}
/*!
* Performs the element-wise subtraction of a matrix \a x to this matrix.
* Returns a reference to this object.
*
* The specified operand matrix \a x should have at least the same number of
* elements as this matrix. Otherwise the operation will be aborted upon
* reaching the end of the operand matrix, but no exception will be thrown.
*
* This function ensures that this instance uniquely references its matrix
* data before the element-wise subtraction operation, generating a
* duplicate if necessary.
*/
GenericMatrix& operator -=( const GenericMatrix& x )
{
IMPLEMENT_ELEMENT_WISE_ASSIGN_OP( - )
}
/*!
* Performs the element-wise multiplication of a matrix \a x with this
* matrix. Returns a reference to this object.
*
* The specified operand matrix \a x should have at least the same number of
* elements as this matrix. Otherwise the operation will be aborted upon
* reaching the end of the operand matrix, but no exception will be thrown.
*
* This function ensures that this instance uniquely references its matrix
* data before the element-wise multiplication operation, generating a
* duplicate if necessary.
*/
GenericMatrix& operator *=( const GenericMatrix& x )
{
IMPLEMENT_ELEMENT_WISE_ASSIGN_OP( * )
}
/*!
* Performs the element-wise division of this matrix by a matrix \a x.
* Returns a reference to this object.
*
* The specified operand matrix \a x should have at least the same number of
* elements as this matrix. Otherwise the operation will be aborted upon
* reaching the end of the operand matrix, but no exception will be thrown.
*
* This function ensures that this instance uniquely references its matrix
* data before the element-wise division operation, generating a duplicate
* if necessary.
*/
GenericMatrix& operator /=( const GenericMatrix& x )
{
IMPLEMENT_ELEMENT_WISE_ASSIGN_OP( / )
}
/*!
* Performs the element-wise exponentiation of this matrix by a matrix \a x.
* Returns a reference to this object.
*
* The specified matrix \a x must have at least the same number of elements
* as this matrix. Otherwise an Error exception will be thrown.
*
* This function ensures that this instance uniquely references its matrix
* data before the element-wise raise operation, generating a duplicate if
* necessary.
*/
GenericMatrix& operator ^=( const GenericMatrix& x )
{
if ( IsUnique() )
{
block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = pcl::Min( m_data->End(),
m_data->Begin() + x.NumberOfElements() );
const_block_iterator __restrict__ k = x.m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Pow( *i, *k );
}
else
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = newData->Begin();
const_block_iterator __restrict__ j = pcl::Min( newData->End(),
newData->Begin() + x.NumberOfElements() );
const_block_iterator __restrict__ k = x.m_data->Begin();
const_block_iterator __restrict__ t = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k, ++t )
*i = pcl::Pow( *t, *k );
DetachFromData();
m_data = newData;
}
return *this;
}
#undef IMPLEMENT_ELEMENT_WISE_ASSIGN_OP
#endif // __PCL_NO_MATRIX_ELEMENT_WISE_ARITHMETIC_OPERATIONS
/*!
* Returns the square of this matrix. The result is a new matrix of the same
* dimensions where each element is the square of its counterpart in this
* matrix.
*/
GenericMatrix Sqr() const
{
GenericMatrix R( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = R.m_data->Begin();
const_block_iterator __restrict__ j = R.m_data->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = *k * *k;
return R;
}
/*!
* Replaces all elements of this matrix with their squares.
*
* Before performing its task, this function ensures that this instance
* uniquely references its matrix data, generating a duplicate if necessary.
*/
void SetSqr()
{
if ( IsUnique() )
{
block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
PCL_IVDEP
for ( ; i < j; ++i )
*i *= *i;
}
else
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = newData->Begin();
const_block_iterator __restrict__ j = newData->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = *k * *k;
DetachFromData();
m_data = newData;
}
}
/*!
* Returns the square root of this matrix. The result is a new matrix of the
* same dimensions where each element is the square root of its counterpart
* in this matrix.
*/
GenericMatrix Sqrt() const
{
GenericMatrix R( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = R.m_data->Begin();
const_block_iterator __restrict__ j = R.m_data->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Sqrt( *k );
return R;
}
/*!
* Replaces all elements of this matrix with their square roots.
*
* Before performing its task, this function ensures that this instance
* uniquely references its matrix data, generating a duplicate if necessary.
*/
void SetSqrt()
{
if ( IsUnique() )
{
block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
PCL_IVDEP
for ( ; i < j; ++i )
*i = pcl::Sqrt( *i );
}
else
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = newData->Begin();
const_block_iterator __restrict__ j = newData->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Sqrt( *k );
DetachFromData();
m_data = newData;
}
}
/*!
* Returns the absolute value of this matrix. The result is a new matrix of
* the same dimensions where each element is the absolute value of its
* counterpart in this matrix.
*/
GenericMatrix Abs() const
{
GenericMatrix R( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = R.m_data->Begin();
const_block_iterator __restrict__ j = R.m_data->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Abs( *k );
return R;
}
/*!
* Replaces all elements of this matrix with their absolute values.
*
* Before performing its task, this function ensures that this instance
* uniquely references its matrix data, generating a duplicate if necessary.
*/
void SetAbs()
{
if ( IsUnique() )
{
block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
PCL_IVDEP
for ( ; i < j; ++i )
*i = pcl::Abs( *i );
}
else
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
block_iterator __restrict__ i = newData->Begin();
const_block_iterator __restrict__ j = newData->End();
const_block_iterator __restrict__ k = m_data->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Abs( *k );
DetachFromData();
m_data = newData;
}
}
/*!
* Returns true iff this instance uniquely references its matrix data.
*/
bool IsUnique() const noexcept
{
return m_data->IsUnique();
}
/*!
* Returns true iff this instance references (shares) the same matrix data as
* another instance \a x.
*/
bool IsAliasOf( const GenericMatrix& x ) const noexcept
{
return m_data == x.m_data;
}
/*!
* Ensures that this instance uniquely references its matrix data.
*
* If necessary, this member function generates a duplicate of the matrix
* data, references it, and then decrements the reference counter of the
* original matrix data.
*/
void EnsureUnique()
{
if ( !IsUnique() )
{
Data* newData = new Data( m_data->Rows(), m_data->Cols() );
const_block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
block_iterator __restrict__ k = newData->Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*k = *i;
DetachFromData();
m_data = newData;
}
}
/*!
* Returns the number of rows in this matrix. If this object is an empty
* matrix, this member function returns zero.
*/
int Rows() const noexcept
{
return m_data->Rows();
}
/*!
* Returns the number of columns in this matrix. If this object is an empty
* matrix, this member function returns zero.
*/
int Cols() const noexcept
{
return m_data->Cols();
}
/*!
* Returns the number of columns in this matrix. If this object is an empty
* matrix, this member function returns zero.
*
* This function is a synonym for Cols().
*/
int Columns() const noexcept
{
return Cols();
}
/*!
* Returns true only if this matrix is valid. A matrix is valid if it
* references an internal matrix structure, even if it is an empty matrix.
*
* In general, all %GenericMatrix objects are valid with only two
* exceptions:
*
* \li Objects that have been move-copied or move-assigned to other
* matrices.
* \li Objects that have been invalidated explicitly by calling Transfer().
*
* An invalid matrix object cannot be used and should be destroyed
* immediately. Invalid matrices are always destroyed automatically during
* move construction and move assignment operations.
*/
bool IsValid() const noexcept
{
return m_data != nullptr;
}
/*!
* Returns true iff this is an empty matrix. An empty matrix has no elements,
* and hence its dimensions are zero.
*/
bool IsEmpty() const noexcept
{
return Rows() == 0 || Cols() == 0;
}
/*!
* Returns true iff this matrix is not empty. This operator is equivalent to:
*
* \code !IsEmpty(); \endcode
*/
operator bool() const noexcept
{
return !IsEmpty();
}
/*!
* Returns the total number of matrix elements in this object, or
* Rows()*Cols().
*/
size_type NumberOfElements() const noexcept
{
return m_data->NumberOfElements();
}
/*!
* Returns the total number of bytes required to store the data contained in
* this matrix.
*/
size_type Size() const noexcept
{
return m_data->Size();
}
/*!
* Equality operator. Returns true if this matrix is equal to another matrix
* \a x.
*
* %Matrix comparisons are performed element-wise. Two matrices are equal if
* both have the same dimensions and identical element values.
*/
bool operator ==( const GenericMatrix& x ) const noexcept
{
return IsAliasOf( x ) || SameDimensions( x ) && pcl::Equal( Begin(), x.Begin(), x.End() );
}
/*!
* Less than relational operator. Returns true if this matrix is less than
* another matrix \a x.
*
* In this operator, matrix comparisons are performed element-wise,
* irrespective of matrix dimensions, until either two matrix elements
* differ, or until the end of one of the matrices is reached. In the latter
* case the shortest matrix is the lesser one.
*/
bool operator <( const GenericMatrix& x ) const noexcept
{
return !IsAliasOf( x ) && pcl::Compare( Begin(), End(), x.Begin(), x.End() ) < 0;
}
/*!
* Returns true iff this matrix has the same dimensions, i.e. the same number
* of rows and columns, as another matrix \a x.
*/
bool SameDimensions( const GenericMatrix& x ) const noexcept
{
return Rows() == x.Rows() && Cols() == x.Cols();
}
/*!
* Returns true iff this matrix has the same elements as another matrix \a x.
*
* In this member function, matrix comparisons are performed element-wise,
* irrespective of matrix dimensions. Note that two matrices can have
* exactly the same elements even if their dimensions, i.e. their number of
* rows and columns, are different. Only the number and order of elements
* are relevant for this comparison.
*/
bool SameElements( const GenericMatrix& x ) const noexcept
{
if ( unlikely( IsAliasOf( x ) ) )
return true;
if ( unlikely( NumberOfElements() != x.NumberOfElements() ) )
return false;
const_block_iterator __restrict__ i = Begin();
const_block_iterator __restrict__ j = End();
const_block_iterator __restrict__ k = x.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
if ( *i != *k )
return false;
return true;
}
/*!
* Returns a reference to the matrix element at row \a i and column \a j.
*
* Before returning, this function ensures that this instance uniquely
* references its matrix data.
*/
element& Element( int i, int j )
{
EnsureUnique();
return m_data->Element( i, j );
}
/*!
* Returns a reference to the immutable matrix element at row \a i and
* column \a j.
*/
const element& Element( int i, int j ) const noexcept
{
return m_data->Element( i, j );
}
/*!
* Returns a pointer to the first matrix element of row \a i.
*
* All elements in row \a i are guaranteed to be stored at consecutive
* locations addressable from the pointer returned by this function.
*
* Before returning, this function ensures that this instance uniquely
* references its matrix data.
*/
block_iterator operator []( int i )
{
EnsureUnique();
return m_data->v[i];
}
/*!
* Returns a pointer to the immutable first matrix element of row \a i.
*
* All elements in row \a i are guaranteed to be stored at consecutive
* locations addressable from the pointer returned by this function.
*/
const_block_iterator operator []( int i ) const noexcept
{
return m_data->v[i];
}
/*!
* Returns a pointer to the first matrix element, that is to the element at
* row 0 and column 0 of this matrix.
*
* All matrix elements are guaranteed to be stored at consecutive locations
* addressable from the pointer returned by this function. Matrix elements
* are stored in row order: all elements of row 0 followed by all elements
* of row 1, and so on.
*
* Before returning, this function ensures that this instance uniquely
* references its matrix data.
*/
block_iterator Begin()
{
EnsureUnique();
return m_data->Begin();
}
/*!
* Returns a pointer to the immutable first matrix element, that is to the
* element at row 0 and column 0 of this matrix.
*
* All matrix elements are guaranteed to be stored at consecutive locations
* addressable from the pointer returned by this function. Matrix elements
* are stored in row order: all elements of row 0 followed by all elements
* of row 1, and so on.
*/
const_block_iterator Begin() const noexcept
{
return m_data->Begin();
}
/*!
* A synonym for Begin() const.
*/
const_block_iterator ConstBegin() const noexcept
{
return Begin();
}
/*!
* Returns a pointer to the first matrix element, that is to the element at
* row 0 and column 0 of this matrix.
*
* This member function is a convenience alias to Begin().
*/
block_iterator operator *()
{
return Begin();
}
/*!
* Returns a pointer to the immutable first matrix element, that is to the
* element at row 0 and column 0 of this matrix.
*
* This member function is a convenience alias to Begin() const.
*/
const_block_iterator operator *() const noexcept
{
return Begin();
}
/*!
* Returns a pointer past the last matrix element, that is a pointer to an
* (nonexistent) element located at row=Rows()-1 and column=Cols().
*
* All matrix elements are guaranteed to be stored in reverse order at
* consecutive locations addressable from the pointer returned by this
* function. Matrix elements are stored in row order (all elements of row n
* followed by all elements of row n-1, and so on).
*
* Before returning, this function ensures that this instance uniquely
* references its matrix data.
*/
block_iterator End()
{
EnsureUnique();
return m_data->End();
}
/*!
* Returns a pointer past the last immutable matrix element, that is a
* pointer to an immutable (and nonexistent) element located at row=Rows()-1
* and column=Cols().
*
* All matrix elements are guaranteed to be stored in reverse order at
* consecutive locations addressable from the pointer returned by this
* function. Matrix elements are stored in row order (all elements of row n
* followed by all elements of row n-1, and so on).
*/
const_block_iterator End() const noexcept
{
return m_data->End();
}
/*!
* A synonym for End() const.
*/
const_block_iterator ConstEnd() const noexcept
{
return End();
}
/*!
* Returns a pointer to a pointer to the first element in this matrix.
*
* The returned pointer can be used as a common C array, where all matrix
* rows are guaranteed to be addressable through consecutive pointers
* starting from the pointer returned by this function.
*
* This member function does nothing to ensure that this instance uniquely
* references its matrix data. Consequently, the caller must take into
* account that all modifications made to matrix elements accessed through
* the value returned by this function will apply to all instances sharing
* the same matrix data.
*
* This function can be used to perform fast operations on matrix elements,
* avoiding the overhead caused by deep copies of matrix data, when such
* copies are not necessary. Typically this happens when two or more threads
* work simultaneously on non-overlapping regions of the same matrix.
*/
block_iterator* DataPtr() noexcept
{
return m_data->v;
}
/*!
* Returns a pointer to the first matrix element of row \a i.
*
* All elements in row \a i are guaranteed to be stored at consecutive
* locations addressable from the pointer returned by this function.
*
* This member function does not ensure that the data referenced by this
* matrix is unique. See DataPtr() for more information on how to use this
* member function.
*/
block_iterator RowPtr( int i ) noexcept
{
return m_data->v[i];
}
#ifndef __PCL_NO_STL_COMPATIBLE_ITERATORS
/*!
* STL-compatible iteration. Equivalent to Begin().
*/
block_iterator begin()
{
return Begin();
}
/*!
* STL-compatible iteration. Equivalent to Begin() const.
*/
const_block_iterator begin() const noexcept
{
return Begin();
}
/*!
* STL-compatible iteration. Equivalent to End().
*/
block_iterator end()
{
return End();
}
/*!
* STL-compatible iteration. Equivalent to End() const.
*/
const_block_iterator end() const noexcept
{
return End();
}
#endif // !__PCL_NO_STL_COMPATIBLE_ITERATORS
/*!
* Returns a vector with the matrix elements at the specified row \a i.
*/
vector RowVector( int i ) const
{
vector r( m_data->Cols() );
for ( int j = 0; j < m_data->Cols(); ++j )
r[j] = m_data->v[i][j];
return r;
}
/*!
* Returns a vector with the matrix elements at the specified column \a j.
*/
vector ColumnVector( int j ) const
{
vector c( m_data->Rows() );
for ( int i = 0; i < m_data->Rows(); ++i )
c[i] = m_data->v[i][j];
return c;
}
/*!
* Returns a vector with the matrix elements at the specified column \a j.
*
* This member function is an alias for ColumnVector().
*/
vector ColVector( int j ) const
{
return ColumnVector( j );
}
/*!
* Assigns the components of a vector \a r to the corresponding elements of
* a matrix row \a i.
*/
template <class V>
void SetRow( int i, const V& r )
{
EnsureUnique();
for ( int j = 0; j < m_data->Cols() && j < r.Length(); ++j )
m_data->v[i][j] = element( r[j] );
}
/*!
* Assigns the components of a vector \a c to the corresponding elements of
* a matrix column \a i.
*/
template <class V>
void SetColumn( int j, const V& c )
{
EnsureUnique();
for ( int i = 0; i < m_data->Rows() && i < c.Length(); ++i )
m_data->v[i][j] = element( c[i] );
}
/*!
* Assigns the components of a vector \a c to the corresponding elements of
* a matrix column \a i.
*
* This member function is an alias for SetColumn().
*/
template <class V>
void SetCol( int j, const V& c )
{
SetColumn( j, c );
}
/*!
* Returns a matrix whose first row is a copy of the specified vector \a r.
* The rest of matrix elements are set to zero. The returned object is a
* square matrix whose dimensions are equal to the length of \a r.
*/
static GenericMatrix FromRowVector( const vector& r )
{
GenericMatrix R( element( 0 ), r.Length(), r.Length() );
for ( int j = 0; j < r.Length(); ++j )
R.m_data->v[0][j] = r[j];
return R;
}
/*!
* Returns a matrix whose first column is a copy of the specified vector
* \a c. The rest of matrix elements are set to zero. The returned object is
* a square matrix whose dimensions are equal to the length of \a c.
*/
static GenericMatrix FromColumnVector( const vector& c )
{
GenericMatrix C( element( 0 ), c.Length(), c.Length() );
for ( int i = 0; i < c.Length(); ++i )
C.m_data->v[i][0] = c[i];
return C;
}
/*!
* This member function is an alias for FromColumnVector().
*/
static GenericMatrix FromColVector( const vector& c )
{
return FromColumnVector( c );
}
/*!
* Returns a unit matrix of size \a n.
*
* A unit matrix is an <em>n</em> x <em>n</em> square matrix whose elements
* are ones on its main diagonal and zeros elsewhere.
*/
static GenericMatrix UnitMatrix( int n )
{
GenericMatrix One( element( 0 ), n, n );
for ( int i = 0; i < n; ++i )
One[i][i] = element( 1 );
return One;
}
/*!
* Returns the transpose of this matrix.
*
* The transpose of a matrix A is another matrix A<sup>T</sup> whose rows
* are the columns of A (or, equivalently, whose columns are the rows of A).
*/
GenericMatrix Transpose() const
{
GenericMatrix Tr( m_data->Cols(), m_data->Rows() );
for ( int i = 0; i < m_data->Rows(); ++i )
for ( int j = 0; j < m_data->Cols(); ++j )
Tr.m_data->v[j][i] = m_data->v[i][j];
return Tr;
}
/*!
* Returns the inverse of this matrix.
*
* When a square matrix is multiplied by its inverse, the result is the
* identity matrix. Non-square matrices do not have inverses.
*
* If this is an empty or non-square matrix, or if it is singular (i.e. if
* its determinant is zero or insignificant), then this function throws the
* appropriate Error exception.
*/
GenericMatrix Inverse() const;
/*!
* Inverts this matrix.
*
* When a square matrix is multiplied by its inverse, the result is the
* identity matrix. Non-square matrices do not have inverses.
*
* If this is an empty or non-square matrix, or if it is singular (i.e. if
* its determinant is zero or insignificant), then this function throws the
* appropriate Error exception.
*/
void Invert();
/*!
* Flips this matrix. Flipping a matrix consists of rotating its elements by
* 180 degrees.
*
* This function ensures that this instance uniquely references its matrix
* data before performing matrix rotation.
*/
void Flip()
{
EnsureUnique();
pcl::Reverse( m_data->Begin(), m_data->End() );
}
/*!
* Returns a flipped copy of this matrix. Flipping a matrix consists of
* rotating its elements by 180 degrees.
*/
GenericMatrix Flipped() const
{
GenericMatrix Tf( m_data->Cols(), m_data->Rows() );
pcl::CopyReversed( Tf.m_data->End(), m_data->Begin(), m_data->End() );
return Tf;
}
/*!
* Returns a 3x3 rotation matrix about the X axis.
*
* \param sphi Sine of the rotation angle.
*
* \param cphi Cosine of the rotation angle.
*
* Positive rotation angles apply anticlockwise rotations about the X axis,
* as seen looking towards the origin from positive x.
*
* The returned matrix is:
*
* <pre>
* 1 0 0
* 0 +cphi +sphi
* 0 -sphi +cphi
* </pre>
*
* \sa RotationX( double )
*/
static GenericMatrix RotationX( double sphi, double cphi )
{
return GenericMatrix( element( 1 ), element( 0 ), element( 0 ),
element( 0 ), element( +cphi ), element( +sphi ),
element( 0 ), element( -sphi ), element( +cphi ) );
}
/*!
* Returns a 3x3 rotation matrix about the X axis by the specified angle
* \a phi in radians.
*
* Calling this function is equivalent to:
*
* \code RotationX( Sin( phi ), Cos( phi ) ) \endcode
*/
static GenericMatrix RotationX( double phi )
{
double sphi, cphi;
SinCos( phi, sphi, cphi );
return RotationX( sphi, cphi );
}
/*!
* Returns a 3x3 rotation matrix about the Y axis.
*
* \param sphi Sine of the rotation angle.
*
* \param cphi Cosine of the rotation angle.
*
* Positive rotation angles apply anticlockwise rotations about the Y axis,
* as seen looking towards the origin from positive y.
*
* The returned matrix is:
*
* <pre>
* +cphi 0 -sphi
* 0 1 0
* +sphi 0 +cphi
* </pre>
*
* \sa RotationY( double )
*/
static GenericMatrix RotationY( double sphi, double cphi )
{
return GenericMatrix( element( +cphi ), element( 0 ), element( -sphi ),
element( 0 ), element( 1 ), element( 0 ),
element( +sphi ), element( 0 ), element( +cphi ) );
}
/*!
* Returns a 3x3 rotation matrix about the Y axis by the specified angle
* \a phi in radians.
*
* Calling this function is equivalent to:
*
* \code RotationY( Sin( phi ), Cos( phi ) ) \endcode
*/
static GenericMatrix RotationY( double phi )
{
double sphi, cphi;
SinCos( phi, sphi, cphi );
return RotationY( sphi, cphi );
}
/*!
* Returns a 3x3 rotation matrix about the Z axis.
*
* \param sphi Sine of the rotation angle.
*
* \param cphi Cosine of the rotation angle.
*
* Positive rotation angles apply anticlockwise rotations about the Z axis,
* as seen looking towards the origin from positive z.
*
* The returned matrix is:
*
* <pre>
* +cphi +sphi 0
* -sphi +cphi 0
* 0 0 1
* </pre>
*
* \sa RotationZ( double )
*/
static GenericMatrix RotationZ( double sphi, double cphi )
{
return GenericMatrix( element( +cphi ), element( +sphi ), element( 0 ),
element( -sphi ), element( +cphi ), element( 0 ),
element( 0 ), element( 0 ), element( 1 ) );
}
/*!
* Returns a 3x3 rotation matrix about the Z axis by the specified angle
* \a phi in radians.
*
* Calling this function is equivalent to:
*
* \code RotationZ( Sin( phi ), Cos( phi ) ) \endcode
*/
static GenericMatrix RotationZ( double phi )
{
double sphi, cphi;
SinCos( phi, sphi, cphi );
return RotationZ( sphi, cphi );
}
/*!
* Rotates this 3x3 matrix about the X axis.
*
* \param sphi Sine of the rotation angle.
*
* \param cphi Cosine of the rotation angle.
*
* Positive rotation angles apply anticlockwise rotations about the X axis,
* as seen looking towards the origin from positive x. The applied
* transformation can be represented by the matrix:
*
* <pre>
* 1 0 0
* 0 +cphi +sphi
* 0 -sphi +cphi
* </pre>
*
* If this matrix has dimensions different from 3 rows and 3 columns, this
* function invokes undefined behavior. For the sake of performance, this
* condition is not explicitly verified.
*
* \sa RotateX( double ), RotatedX()
*/
void RotateX( double sphi, double cphi )
{
PCL_PRECONDITION( Rows() == 3 && Cols() == 3 )
EnsureUnique();
block_iterator __restrict__ A1 = m_data->v[1];
block_iterator __restrict__ A2 = m_data->v[2];
double a10 = cphi*A1[0] + sphi*A2[0];
double a11 = cphi*A1[1] + sphi*A2[1];
double a12 = cphi*A1[2] + sphi*A2[2];
double a20 = -sphi*A1[0] + cphi*A2[0];
double a21 = -sphi*A1[1] + cphi*A2[1];
double a22 = -sphi*A1[2] + cphi*A2[2];
A1[0] = element( a10 );
A1[1] = element( a11 );
A1[2] = element( a12 );
A2[0] = element( a20 );
A2[1] = element( a21 );
A2[2] = element( a22 );
}
/*!
* Rotates this 3x3 matrix about the X axis by the specified angle \a phi in
* radians.
*
* Calling this function is equivalent to:
*
* \code RotateX( Sin( phi ), Cos( phi ) ) \endcode
*/
void RotateX( double phi )
{
double sphi, cphi;
SinCos( phi, sphi, cphi );
RotateX( sphi, cphi );
}
/*!
* Returns a rotated copy of this 3x3 matrix about the X axis by a rotation
* angle given by its sine \a sphi and cosine \a cphi.
* See RotateX( double, double ).
*/
GenericMatrix RotatedX( double sphi, double cphi ) const
{
GenericMatrix R( *this );
R.RotateX( sphi, cphi );
return R;
}
/*!
* Returns a rotated copy of this 3x3 matrix about the X axis by the
* specified rotation angle \a phi in radians. See RotateX( double ).
*/
GenericMatrix RotatedX( double phi ) const
{
GenericMatrix R( *this );
R.RotateX( phi );
return R;
}
/*!
* Rotates this 3x3 matrix about the Y axis.
*
* \param sphi Sine of the rotation angle.
*
* \param cphi Cosine of the rotation angle.
*
* Positive rotation angles apply anticlockwise rotations about the Y axis,
* as seen looking towards the origin from positive y. The applied
* transformation can be represented by the matrix:
*
* <pre>
* +cphi 0 -sphi
* 0 1 0
* +sphi 0 +cphi
* </pre>
*
* If this matrix has dimensions different from 3 rows and 3 columns, this
* function invokes undefined behavior. For the sake of performance, this
* condition is not explicitly verified.
*
* \sa RotateY( double ), RotatedY()
*/
void RotateY( double sphi, double cphi )
{
PCL_PRECONDITION( Rows() == 3 && Cols() == 3 )
EnsureUnique();
block_iterator __restrict__ A0 = m_data->v[0];
block_iterator __restrict__ A2 = m_data->v[2];
double a00 = cphi*A0[0] - sphi*A2[0];
double a01 = cphi*A0[1] - sphi*A2[1];
double a02 = cphi*A0[2] - sphi*A2[2];
double a20 = sphi*A0[0] + cphi*A2[0];
double a21 = sphi*A0[1] + cphi*A2[1];
double a22 = sphi*A0[2] + cphi*A2[2];
A0[0] = a00;
A0[1] = a01;
A0[2] = a02;
A2[0] = a20;
A2[1] = a21;
A2[2] = a22;
}
/*!
* Rotates this 3x3 matrix about the Y axis by the specified angle \a phi in
* radians.
*
* Calling this function is equivalent to:
*
* \code RotateY( Sin( phi ), Cos( phi ) ) \endcode
*/
void RotateY( double phi )
{
double sphi, cphi;
SinCos( phi, sphi, cphi );
RotateY( sphi, cphi );
}
/*!
* Returns a rotated copy of this 3x3 matrix about the Y axis by a rotation
* angle given by its sine \a sphi and cosine \a cphi.
* See RotateY( double, double ).
*/
GenericMatrix RotatedY( double sphi, double cphi ) const
{
GenericMatrix R( *this );
R.RotateY( sphi, cphi );
return R;
}
/*!
* Returns a rotated copy of this 3x3 matrix about the Y axis by the
* specified rotation angle \a phi in radians. See RotateY( double ).
*/
GenericMatrix RotatedY( double phi ) const
{
GenericMatrix R( *this );
R.RotateY( phi );
return R;
}
/*!
* Rotates this 3x3 matrix about the Z axis.
*
* \param sphi Sine of the rotation angle.
*
* \param cphi Cosine of the rotation angle.
*
* Positive rotation angles apply anticlockwise rotations about the Z axis,
* as seen looking towards the origin from positive z. The applied
* transformation can be represented by the matrix:
*
* <pre>
* +cphi +sphi 0
* -sphi +cphi 0
* 0 0 1
* </pre>
*
* If this matrix has dimensions different from 3 rows and 3 columns, this
* function invokes undefined behavior. For the sake of performance, this
* condition is not explicitly verified.
*
* \sa RotateZ( double ), RotatedZ()
*/
void RotateZ( double sphi, double cphi )
{
PCL_PRECONDITION( Rows() == 3 && Cols() == 3 )
EnsureUnique();
block_iterator __restrict__ A0 = m_data->v[0];
block_iterator __restrict__ A1 = m_data->v[1];
double a00 = cphi*A0[0] + sphi*A1[0];
double a01 = cphi*A0[1] + sphi*A1[1];
double a02 = cphi*A0[2] + sphi*A1[2];
double a10 = -sphi*A0[0] + cphi*A1[0];
double a11 = -sphi*A0[1] + cphi*A1[1];
double a12 = -sphi*A0[2] + cphi*A1[2];
A0[0] = a00;
A0[1] = a01;
A0[2] = a02;
A1[0] = a10;
A1[1] = a11;
A1[2] = a12;
}
/*!
* Rotates this 3x3 matrix about the Z axis by the specified angle \a phi in
* radians.
*
* Calling this function is equivalent to:
*
* \code RotateZ( Sin( phi ), Cos( phi ) ) \endcode
*/
void RotateZ( double phi )
{
double sphi, cphi;
SinCos( phi, sphi, cphi );
RotateZ( sphi, cphi );
}
/*!
* Returns a rotated copy of this 3x3 matrix about the Z axis by a rotation
* angle given by its sine \a sphi and cosine \a cphi.
* See RotateZ( double, double ).
*/
GenericMatrix RotatedZ( double sphi, double cphi ) const
{
GenericMatrix R( *this );
R.RotateZ( sphi, cphi );
return R;
}
/*!
* Returns a rotated copy of this 3x3 matrix about the Z axis by the
* specified rotation angle \a phi in radians. See RotateZ( double ).
*/
GenericMatrix RotatedZ( double phi ) const
{
GenericMatrix R( *this );
R.RotateZ( phi );
return R;
}
/*!
* Truncates all matrix elements to the specified range.
*
* \param f0 Lower bound of the truncation range. If not specified, the
* default value is zero.
*
* \param f1 Upper bound of the truncation range. If not specified, the
* default value is one.
*
* After calling this member function, all matrix elements will be within
* the [\a f0,\a f1] range.
*/
void Truncate( const element& f0 = element( 0 ), const element& f1 = element( 1 ) )
{
EnsureUnique();
block_iterator __restrict__ i = m_data->Begin();
block_iterator __restrict__ j = m_data->End();
PCL_IVDEP
for ( ; i < j; ++i )
if ( *i < f0 )
*i = f0;
else if ( *i > f1 )
*i = f1;
}
/*!
* Returns a truncated copy of this matrix. See Truncate().
*/
GenericMatrix Truncated( const element& f0 = element( 0 ), const element& f1 = element( 1 ) ) const
{
GenericMatrix R( *this );
R.Truncate( f0, f1 );
return R;
}
/*!
* Rescales all matrix elements to the specified range.
*
* \param f0 Lower bound of the rescaling range. If not specified, the
* default value is zero.
*
* \param f1 Upper bound of the rescaling range. If not specified, the
* default value is one.
*
* The rescaling operation is as follows. if \a m and \a M are the minimum
* and maximum element values in this matrix, respectively, then for each
* matrix element s, its rescaled value r is given by:
*
* \a r = \a f0 + (\a s - \a m)*(\a f1 - \a f0)/(\a M - \a m)
*/
void Rescale( const element& f0 = element( 0 ), const element& f1 = element( 1 ) )
{
element v0 = MinElement();
element v1 = MaxElement();
if ( v0 != f0 || v1 != f1 )
{
EnsureUnique();
if ( v0 != v1 )
{
if ( f0 != f1 )
{
block_iterator __restrict__ i = m_data->Begin();
block_iterator __restrict__ j = m_data->End();
double d = (double( f1 ) - double( f0 ))/(double( v1 ) - double( v0 ));
if ( f0 == element( 0 ) )
{
PCL_IVDEP
for ( ; i < j; ++i )
*i = element( d*(*i - v0) );
}
else
{
PCL_IVDEP
for ( ; i < j; ++i )
*i = element( d*(*i - v0) + f0 );
}
}
else
pcl::Fill( m_data->Begin(), m_data->End(), f0 );
}
else
pcl::Fill( m_data->Begin(), m_data->End(), pcl::Range( v0, f0, f1 ) );
}
}
/*!
* Returns a rescaled copy of this matrix. See Rescale().
*/
GenericMatrix Rescaled( const element& f0 = element( 0 ), const element& f1 = element( 1 ) ) const
{
GenericMatrix R( *this );
R.Rescale( f0, f1 );
return R;
}
/*!
* Sorts the elements of this matrix in ascending order.
*/
void Sort()
{
EnsureUnique();
pcl::Sort( m_data->Begin(), m_data->End() );
}
/*!
* Returns a sorted copy of this matrix.
*/
GenericMatrix Sorted() const
{
GenericMatrix R( *this );
R.Sort();
return R;
}
/*!
* Sorts the elements of this matrix in reverse (descending) order.
*/
void ReverseSort()
{
EnsureUnique();
pcl::Sort( m_data->Begin(), m_data->End(),
[]( const element& a, const element& b ){ return b < a; } );
}
/*!
* Returns a reverse sorted copy of this matrix.
*/
GenericMatrix ReverseSorted() const
{
GenericMatrix R( *this );
R.ReverseSort();
return R;
}
/*!
* Sorts the elements of this matrix in ascending order. Ordering of matrix
* elements is defined such that for any pair a, b of matrix elements, the
* specified binary predicate p( a, b ) is true if a precedes b.
*/
template <class BP>
void Sort( BP p )
{
EnsureUnique();
pcl::Sort( m_data->Begin(), m_data->End(), p );
}
/*!
* Returns a sorted copy of this matrix, where ordering of matrix elements
* is defined by the specified binary predicate \a p. See Sort( BP p ).
*/
template <class BP>
GenericMatrix Sorted( BP p ) const
{
GenericMatrix R( *this );
R.Sort( p );
return R;
}
/*!
* Returns a pointer to the first immutable matrix element with the
* specified value \a x, or nullptr if this matrix does not contain such
* value.
*/
const_block_iterator Find( const element& x ) const noexcept
{
const_block_iterator p = pcl::LinearSearch( m_data->Begin(), m_data->End(), x );
return (p != m_data->End()) ? p : nullptr;
}
/*!
* Returns a pointer to the first immutable matrix element with the
* specified value \a x, or nullptr if this matrix does not contain such
* value. This function is an alias to Find().
*/
const_block_iterator FindFirst( const element& x ) const noexcept
{
return Find( x );
}
/*!
* Returns a pointer to the last immutable matrix element with the specified
* value \a x, or nullptr if this matrix does not contain such value.
*/
const_block_iterator FindLast( const element& x ) const noexcept
{
const_block_iterator p = pcl::LinearSearchLast( m_data->Begin(), m_data->End(), x );
return (p != m_data->End()) ? p : nullptr;
}
/*!
* Returns true iff this matrix contains the specified value \a x.
*/
bool Contains( const element& x ) const noexcept
{
return pcl::LinearSearch( m_data->Begin(), m_data->End(), x ) != m_data->End();
}
#ifndef __PCL_NO_MATRIX_STATISTICS
/*!
* Returns the value of the minimum element in this matrix.
* For empty matrices, this function returns zero.
*/
element MinElement() const noexcept
{
if ( !IsEmpty() )
return *MinItem( m_data->Begin(), m_data->End() );
return element( 0 );
}
/*!
* Returns the value of the minimum element in this matrix and its
* coordinates in the specified point \a p.
* For empty matrices, this function returns zero and assigns zero to the
* point coordinates.
*/
element MinElement( Point& p ) const noexcept
{
if ( !IsEmpty() )
{
const_block_iterator m = MinItem( m_data->Begin(), m_data->End() );
distance_type d = m - m_data->Begin();
p.y = int( d/m_data->Cols() );
p.x = int( d%m_data->Cols() );
return *m;
}
p = 0;
return element( 0 );
}
/*!
* Returns the value of the maximum element in this matrix.
* For empty matrices, this function returns zero.
*/
element MaxElement() const noexcept
{
if ( !IsEmpty() )
return *MaxItem( m_data->Begin(), m_data->End() );
return element( 0 );
}
/*!
* Returns the value of the maximum element in this matrix and its
* coordinates in the specified point \a p.
* For empty matrices, this function returns zero and assigns zero to the
* point coordinates.
*/
element MaxElement( Point& p ) const noexcept
{
if ( !IsEmpty() )
{
const_block_iterator m = MaxItem( m_data->Begin(), m_data->End() );
int d = m - m_data->Begin();
p.y = d/m_data->Cols();
p.x = d%m_data->Cols();
return *m;
}
p = 0;
return element( 0 );
}
/*!
* Returns the sum of all matrix elements.
*
* For empty matrices, this function returns zero.
*/
double Sum() const noexcept
{
return pcl::Sum( m_data->Begin(), m_data->End() );
}
/*!
* Computes the sum of all matrix elements using a numerically stable
* summation algorithm to minimize roundoff error.
*
* For empty matrices, this function returns zero.
*/
double StableSum() const noexcept
{
return pcl::StableSum( m_data->Begin(), m_data->End() );
}
/*!
* Returns the sum of the absolute values of all matrix elements.
*
* For empty matrices, this function returns zero.
*/
double Modulus() const noexcept
{
return pcl::Modulus( m_data->Begin(), m_data->End() );
}
/*!
* Computes the sum of the absolute values of all matrix elements using a
* numerically stable summation algorithm to minimize roundoff error.
*
* For empty matrices, this function returns zero.
*/
double StableModulus() const noexcept
{
return pcl::StableModulus( m_data->Begin(), m_data->End() );
}
/*!
* Returns the sum of the squares of all matrix elements.
*
* For empty matrices, this function returns zero.
*/
double SumOfSquares() const noexcept
{
return pcl::SumOfSquares( m_data->Begin(), m_data->End() );
}
/*!
* Computes the sum of the squares of all matrix elements using a
* numerically stable summation algorithm to minimize roundoff error.
*
* For empty matrices, this function returns zero.
*/
double StableSumOfSquares() const noexcept
{
return pcl::StableSumOfSquares( m_data->Begin(), m_data->End() );
}
/*!
* Returns the mean of the element values in this matrix.
*
* For empty matrices, this function returns zero.
*/
double Mean() const noexcept
{
return pcl::Mean( m_data->Begin(), m_data->End() );
}
/*!
* Computes the mean of the element values in this matrix using a
* numerically stable summation algorithm to minimize roundoff error.
*
* For empty matrices, this function returns zero.
*/
double StableMean() const noexcept
{
return pcl::StableMean( m_data->Begin(), m_data->End() );
}
/*!
* Computes the two-sided, asymmetric trimmed mean of the values in this
* matrix. See pcl::TrimmedMean() for a complete description of the
* implemented algorithm with information on function parameters.
*
* For empty matrices, this function returns zero.
*/
double TrimmedMean( distance_type l = 1, distance_type h = 1 ) const noexcept
{
return pcl::TrimmedMean( m_data->Begin(), m_data->End(), l, h );
}
/*!
* Computes the two-sided, asymmetric trimmed mean of the squared values in
* this matrix. See pcl::TrimmedMeanOfSquares() for a complete description
* of the implemented algorithm with information on function parameters.
*
* For empty matrices, this function returns zero.
*/
double TrimmedMeanOfSquares( distance_type l = 1, distance_type h = 1 ) const noexcept
{
return pcl::TrimmedMeanOfSquares( m_data->Begin(), m_data->End(), l, h );
}
/*!
* Returns the variance from the mean for the values in this matrix.
*
* For matrices with less than two elements, this function returns zero.
*/
double Variance() const noexcept
{
return pcl::Variance( m_data->Begin(), m_data->End() );
}
/*!
* Returns the standard deviation from the mean for the values in this
* matrix.
*
* For matrices with less than two elements, this function returns zero.
*/
double StdDev() const noexcept
{
return pcl::StdDev( m_data->Begin(), m_data->End() );
}
/*!
* Returns the median of element values in this matrix.
*
* For matrices with less than two elements, this function returns zero.
*/
double Median() const
{
return pcl::Median( m_data->Begin(), m_data->End() );
}
/*!
* Returns the average absolute deviation with respect to the specified
* \a center value.
*
* When the median of the matrix elements is used as the center value, this
* function returns the average absolute deviation from the median, which is
* a well-known estimator of dispersion.
*
* For matrices with less than two elements, this function returns zero.
*
* \note To make the average absolute deviation about the median consistent
* with the standard deviation of a normal distribution, it must be
* multiplied by the constant 1.2533.
*/
double AvgDev( double center ) const noexcept
{
return pcl::AvgDev( m_data->Begin(), m_data->End(), center );
}
/*!
* Computes the average absolute deviation with respect to the specified
* \a center value, using a numerically stable summation algorithm to
* minimize roundoff error.
*
* When the median of the matrix elements is used as the center value, this
* function returns the average absolute deviation from the median, which is
* a well-known estimator of dispersion.
*
* For matrices with less than two elements, this function returns zero.
*
* \note To make the average absolute deviation about the median consistent
* with the standard deviation of a normal distribution, it must be
* multiplied by the constant 1.2533.
*/
double StableAvgDev( double center ) const noexcept
{
return pcl::StableAvgDev( m_data->Begin(), m_data->End(), center );
}
/*!
* Returns the average absolute deviation from the median.
*
* The mean absolute deviation from the median is a well-known estimator of
* dispersion.
*
* For matrices with less than two elements, this function returns zero.
*
* \note To make the average absolute deviation about the median consistent
* with the standard deviation of a normal distribution, it must be
* multiplied by the constant 1.2533.
*/
double AvgDev() const
{
return pcl::AvgDev( m_data->Begin(), m_data->End() );
}
/*!
* Computes the average absolute deviation from the median using a
* numerically stable summation algorithm to minimize roundoff error.
*
* The mean absolute deviation from the median is a well-known estimator of
* dispersion.
*
* For matrices with less than two elements, this function returns zero.
*
* \note To make the average absolute deviation about the median consistent
* with the standard deviation of a normal distribution, it must be
* multiplied by the constant 1.2533.
*/
double StableAvgDev() const
{
return pcl::StableAvgDev( m_data->Begin(), m_data->End() );
}
/*!
* Returns the two-sided average absolute deviation with respect to the
* specified \a center value.
*
* See AvgDev( double ) for more information.
*/
TwoSidedEstimate TwoSidedAvgDev( double center ) const noexcept
{
return pcl::TwoSidedAvgDev( m_data->Begin(), m_data->End(), center );
}
/*!
* Returns the two-sided average absolute deviation from the median.
*
* See AvgDev() for more information.
*/
TwoSidedEstimate TwoSidedAvgDev() const
{
return pcl::TwoSidedAvgDev( m_data->Begin(), m_data->End() );
}
/*!
* Returns the median absolute deviation (MAD) with respect to the specified
* \a center value.
*
* The MAD is a well-known robust estimator of scale.
*
* For matrices with less than two elements, this function returns zero.
*
* \note To make the MAD estimator consistent with the standard deviation of
* a normal distribution, it must be multiplied by the constant 1.4826.
*/
double MAD( double center ) const
{
return pcl::MAD( m_data->Begin(), m_data->End(), center );
}
/*!
* Returns the median absolute deviation from the median (MAD).
*
* The MAD is a well-known robust estimator of scale.
*
* For matrices with less than two elements, this function returns zero.
*
* \note To make the MAD estimator consistent with the standard deviation of
* a normal distribution, it must be multiplied by the constant 1.4826.
*/
double MAD() const
{
return pcl::MAD( m_data->Begin(), m_data->End() );
}
/*!
* Returns the two-sided median absolute deviation (MAD) with respect to the
* specified \a center value.
*
* See MAD( double ) for more information.
*/
TwoSidedEstimate TwoSidedMAD( double center ) const
{
return pcl::TwoSidedMAD( m_data->Begin(), m_data->End(), center );
}
/*!
* Returns the two-sided median absolute deviation from the median (MAD).
*
* See MAD() for more information.
*/
TwoSidedEstimate TwoSidedMAD() const
{
return pcl::TwoSidedMAD( m_data->Begin(), m_data->End() );
}
/*!
* Returns the biweight midvariance (BWMV).
*
* \param center Reference center value. Normally, the median of the matrix
* elements should be used.
*
* \param sigma A reference estimate of dispersion. Normally, the median
* absolute deviation from the median (MAD) of the matrix
* elements should be used.
*
* \param k Rejection limit in sigma units. The default value is k=9.
*
* \param reducedLength If true, reduce the sample size to exclude
* rejected matrix elements. This tends to approximate the
* true dispersion of the data more accurately for relatively
* small samples, or samples with large amounts of outliers.
* Note that this departs from the standard definition of
* biweight midvariance, where the total number of data items
* is used to scale the variance estimate. If false, use the
* full number of matrix elements, including rejected
* elements, which gives a standard biweight midvariance
* estimate.
*
* The square root of the biweight midvariance is a robust estimator of
* scale. It is an efficient estimator with respect to many statistical
* distributions (about 87% Gaussian efficiency), and appears to have a
* breakdown point close to 0.5 (the same as MAD).
*
* For matrices with less than two elements, this function returns zero.
*
* \b References
*
* Rand R. Wilcox (2017), <em>Introduction to Robust Estimation and
* Hypothesis Testing, 4th Edition</em>, Elsevier Inc., Section 3.12.1.
*/
double BiweightMidvariance( double center, double sigma, int k = 9, bool reducedLength = false ) const noexcept
{
return pcl::BiweightMidvariance( m_data->Begin(), m_data->End(), center, sigma, k, reducedLength );
}
/*!
* Returns the biweight midvariance (BWMV) with respect to the median and
* the median absolute deviation from the median (MAD).
*
* \param k Rejection limit in sigma units. The default value is k=9.
*
* \param reducedLength If true, reduce the sample size to exclude
* rejected matrix elements. This tends to approximate the
* true dispersion of the data more accurately for relatively
* small samples, or samples with large amounts of outliers.
* Note that this departs from the standard definition of
* biweight midvariance, where the total number of data items
* is used to scale the variance estimate. If false, use the
* full number of matrix elements, including rejected
* elements, which gives a standard biweight midvariance
* estimate.
*
* The square root of the biweight midvariance is a robust estimator of
* scale. It is an efficient estimator with respect to many statistical
* distributions (about 87% Gaussian efficiency), and appears to have a
* breakdown point close to 0.5 (the same as MAD).
*
* For matrices with less than two elements, this function returns zero.
*
* \b References
*
* Rand R. Wilcox (2017), <em>Introduction to Robust Estimation and
* Hypothesis Testing, 4th Edition</em>, Elsevier Inc., Section 3.12.1.
*/
double BiweightMidvariance( int k = 9, bool reducedLength = false ) const
{
double center = Median();
return BiweightMidvariance( center, MAD( center ), k, reducedLength );
}
/*!
* Returns the two-sided biweight midvariance (BWMV).
*
* \param center Reference center value. Normally, the median of the vector
* components should be used.
*
* \param sigma A two-sided reference estimate of dispersion. Normally,
* the two-sided median absolute deviation from the median
* (MAD) of the vector components should be used. See the
* TwoSidedMAD() member function.
*
* See BiweightMidvariance( double, double, int, bool ) for more information
* on the rest of parameters and references.
*/
TwoSidedEstimate TwoSidedBiweightMidvariance( double center, const TwoSidedEstimate& sigma,
int k = 9, bool reducedLength = false ) const noexcept
{
return pcl::TwoSidedBiweightMidvariance( m_data->Begin(), m_data->End(), center, sigma, k, reducedLength );
}
/*!
* Returns the two-sided biweight midvariance (BWMV) with respect to the
* median and the two-sided median absolute deviation from the median (MAD).
*
* See BiweightMidvariance( int, bool ) for more information and references.
*/
TwoSidedEstimate TwoSidedBiweightMidvariance( int k = 9, bool reducedLength = false ) const
{
double center = Median();
return TwoSidedBiweightMidvariance( center, TwoSidedMAD( center ), k, reducedLength );
}
/*!
* Returns a percentage bend midvariance (PBMV).
*
* \param center Reference center value. Normally, the median of the matrix
* elements should be used.
*
* \param beta Rejection parameter in the [0,0.5] range. Higher values
* improve robustness to outliers (i.e., increase the
* breakdown point of the estimator) at the expense of lower
* efficiency. The default value is beta=0.2.
*
* The square root of the percentage bend midvariance is a robust estimator
* of scale. With the default beta=0.2, its Gaussian efficiency is 67%. With
* beta=0.1, its efficiency is 85% but its breakdown is only 0.1.
*
* For matrices with less than two elements, this function returns zero.
*
* \b References
*
* Rand R. Wilcox (2017), <em>Introduction to Robust Estimation and
* Hypothesis Testing, 4th Edition</em>, Elsevier Inc., Section 3.12.3.
*/
double BendMidvariance( double center, double beta = 0.2 ) const
{
return pcl::BendMidvariance( m_data->Begin(), m_data->End(), center, beta );
}
/*!
* Returns a percentage bend midvariance (PBMV) with respect to the median.
*
* \param beta Rejection parameter in the [0,0.5] range. Higher values
* improve robustness to outliers (i.e., increase the
* breakdown point of the estimator) at the expense of lower
* efficiency. The default value is beta=0.2.
*
* The square root of the percentage bend midvariance is a robust estimator
* of scale. With the default beta=0.2, its Gaussian efficiency is 67%. With
* beta=0.1, its efficiency is 85% but its breakdown is only 0.1.
*
* For matrices with less than two elements, this function returns zero.
*
* \b References
*
* Rand R. Wilcox (2012), <em>Introduction to Robust Estimation and
* Hypothesis Testing, 3rd Edition</em>, Elsevier Inc., Section 3.12.3.
*/
double BendMidvariance( double beta = 0.2 ) const
{
return pcl::BendMidvariance( m_data->Begin(), m_data->End(), Median(), beta );
}
/*!
* Returns the Sn scale estimator of Rousseeuw and Croux:
*
* <pre>
* Sn = c * low_median( high_median( |x_i - x_j| ) )
* </pre>
*
* where low_median() is the order statistic of rank (n + 1)/2, and
* high_median() is the order statistic of rank n/2 + 1.
*
* For matrices with less than two elements, this function returns zero.
*
* The constant c = 1.1926 must be used to make the Sn estimator converge to
* the standard deviation of a pure normal distribution. However, this
* implementation does not apply it (it uses c=1 implicitly), for
* consistency with other implementations of scale estimators.
*
* \b References
*
* P.J. Rousseeuw and C. Croux (1993), <em>Alternatives to the Median
* Absolute Deviation,</em> Journal of the American Statistical Association,
* Vol. 88, pp. 1273-1283.
*/
double Sn() const
{
GenericMatrix A( *this );
return pcl::Sn( A.Begin(), A.End() );
}
/*!
* Returns the Qn scale estimator of Rousseeuw and Croux:
*
* <pre>
* Qn = c * first_quartile( |x_i - x_j| : i < j )
* </pre>
*
* where first_quartile() is the order statistic of rank (n + 1)/4.
*
* For matrices with less than two elements, this function returns zero.
*
* The constant c = 2.2219 must be used to make the Qn estimator converge to
* the standard deviation of a pure normal distribution. However, this
* implementation does not apply it (it uses c=1 implicitly), for
* consistency with other implementations of scale estimators.
*
* \b References
*
* P.J. Rousseeuw and C. Croux (1993), <em>Alternatives to the Median Absolute
* Deviation,</em> Journal of the American Statistical Association, Vol. 88,
* pp. 1273-1283.
*/
double Qn() const
{
GenericMatrix A( *this );
return pcl::Qn( A.Begin(), A.End() );
}
#endif // !__PCL_NO_MATRIX_STATISTICS
/*!
* Returns a 64-bit non-cryptographic hash value computed for this matrix.
*
* This function calls pcl::Hash64() for the internal matrix data.
*
* The \a seed parameter can be used to generate repeatable hash values. It
* can also be set to a random value in compromised environments.
*/
uint64 Hash64( uint64 seed = 0 ) const noexcept
{
return pcl::Hash64( m_data->Begin(), m_data->Size(), seed );
}
/*!
* Returns a 32-bit non-cryptographic hash value computed for this matrix.
*
* This function calls pcl::Hash32() for the internal matrix data.
*
* The \a seed parameter can be used to generate repeatable hash values. It
* can also be set to a random value in compromised environments.
*/
uint32 Hash32( uint32 seed = 0 ) const noexcept
{
return pcl::Hash32( m_data->Begin(), m_data->Size(), seed );
}
/*!
* Returns a non-cryptographic hash value computed for this matrix. This
* function is a synonym for Hash64().
*/
uint64 Hash( uint64 seed = 0 ) const noexcept
{
return Hash64( seed );
}
/*!
* Generates a sequence of string tokens separated with the specified
* \a separator string. Returns a reference to the target string \a s.
*
* For each matrix element, this function appends a string representation
* (known as a \e token) to the target string \a s. If the matrix contains
* more than one element, successive tokens are separated with the specified
* \a separator.
*
* The string type S must have a meaningful %Append() member function and
* type conversion semantics to transform a matrix element to a string. The
* standard String and IsoString PCL classes provide the required
* functionality for most scalar types, although it is probably better to
* use String::ToSeparated() and IsoString::ToSeparated() instead of calling
* these functions directly.
*/
template <class S, typename SP>
S& ToSeparated( S& s, SP separator ) const
{
const_block_iterator i = m_data->Begin(), j = m_data->End();
if ( i < j )
{
s.Append( S( *i ) );
if ( ++i < j )
do
{
s.Append( separator );
s.Append( S( *i ) );
}
while ( ++i < j );
}
return s;
}
/*!
* Generates a sequence of string tokens separated with the specified
* \a separator string by calling an \a append function. Returns a reference
* to the target string \a s.
*
* For each matrix element x, this function appends a string representation
* (known as a \e token) to the target string \a s by calling the \a append
* function:
*
*\code append( s, S( x ) ); \endcode
*
* If the matrix has more than one element, successive tokens are separated
* by calling:
*
* \code append( s, S( separator ) ); \endcode
*
* The string type S must have type conversion semantics to transform a
* matrix element to a string. The standard String and IsoString PCL classes
* provide the required functionality for most scalar types, although it is
* probably better to use String::ToSeparated() and IsoString::ToSeparated()
* instead of calling these functions directly.
*/
template <class S, typename SP, class AF>
S& ToSeparated( S& s, SP separator, AF append ) const
{
const_block_iterator i = m_data->Begin(), j = m_data->End();
if ( i < j )
{
append( s, S( *i ) );
if ( ++i < j )
{
S p( separator );
do
{
append( s, p );
append( s, S( *i ) );
}
while ( ++i < j );
}
}
return s;
}
/*!
* Generates a comma-separated sequence of string tokens. Returns a
* reference to the target string \a s.
*
* This function is equivalent to:
*
* \code ToSeparated( s, ',' ); \endcode
*/
template <class S>
S& ToCommaSeparated( S& s ) const
{
return ToSeparated( s, ',' );
}
/*!
* Generates a space-separated sequence of string tokens. Returns a
* reference to the target string \a s.
*
* This function is equivalent to:
*
* \code ToSeparated( s, ' ' ); \endcode
*/
template <class S>
S& ToSpaceSeparated( S& s ) const
{
return ToSeparated( s, ' ' );
}
/*!
* Generates a tabulator-separated sequence of string tokens. Returns a
* reference to the target string \a s.
*
* This function is equivalent to:
*
* \code ToSeparated( s, '\t' ); \endcode
*/
template <class S>
S& ToTabSeparated( S& s ) const
{
return ToSeparated( s, '\t' );
}
#ifndef __PCL_NO_MATRIX_PHASE_MATRICES
/*!
* Returns the phase correlation matrix for two matrices \a A and \a B.
* \ingroup phase_matrices
*/
static GenericMatrix PhaseCorrelationMatrix( const GenericMatrix& A, const GenericMatrix& B )
{
if ( B.Rows() != A.Rows() || B.Cols() != A.Cols() )
throw Error( "Invalid matrix dimensions in PhaseCorrelationMatrix()" );
GenericMatrix R( A.Rows(), A.Cols() );
PhaseCorrelationMatrix( R.Begin(), R.End(), A.Begin(), B.Begin() );
return R;
}
/*!
* Returns the cross power spectrum matrix for two matrices \a A and \a B.
* \ingroup phase_matrices
*/
static GenericMatrix CrossPowerSpectrumMatrix( const GenericMatrix& A, const GenericMatrix& B )
{
if ( B.Rows() != A.Rows() || B.Cols() != A.Cols() )
throw Error( "Invalid matrix dimensions in CrossPowerSpectrumMatrix()" );
GenericMatrix R( A.Rows(), A.Cols() );
CrossPowerSpectrumMatrix( R.Begin(), R.End(), A.Begin(), B.Begin() );
return R;
}
#endif // !__PCL_NO_MATRIX_PHASE_MATRICES
#ifndef __PCL_NO_MATRIX_IMAGE_RENDERING
/*!
* Renders this matrix as an image.
*
* The contents of the specified \a image will be replaced with a grayscale
* rendition of this matrix, where the value of each pixel sample will be
* proportional to its corresponding matrix component counterpart.
*
* Note that if this matrix has out-of-range values for the pixel sample
* type of the target image, pixel saturation will occur at either the white
* or black points, or both. This only happens when the target image is of
* an integer type and this matrix contains floating point values outside
* the normalized [0,1] range.
*
* If the target image is of a floating-point type (either real or complex)
* and this matrix also stores floating point values, the output image may
* require a rescaling or normalization operation to constrain all pixel
* values to the normalized [0,1] range after calling this member function.
*/
template <class P>
void ToImage( GenericImage<P>& image ) const
{
image.AllocateData( Cols(), Rows() );
typename P::sample* __restrict__ v = *image;
const_block_iterator __restrict__ i = m_data->Begin();
const_block_iterator __restrict__ j = m_data->End();
PCL_IVDEP
for ( ; i < j; ++i, ++v )
*v = P::ToSample( *i );
}
/*!
* Renders this matrix as an image.
*
* The contents of the image transported by the specified %ImageVariant
* object will be replaced with a grayscale rendition of this matrix, where
* the value of each pixel sample will be proportional to its corresponding
* matrix component counterpart.
*
* If the specified %ImageVariant does not transport an image, a new one
* will be created in 32-bit floating point format.
*
* Also take into account the information given for
* ToImage( GenericImage& ), relative to out-of-range values, which is
* entirely applicable to this member function.
*/
void ToImage( ImageVariant& image ) const
{
if ( !image )
image.CreateFloatImage();
if ( image.IsFloatSample() )
switch ( image.BitsPerSample() )
{
case 32: ToImage( static_cast<Image&>( *image ) ); break;
case 64: ToImage( static_cast<DImage&>( *image ) ); break;
}
else if ( image.IsComplexSample() )
switch ( image.BitsPerSample() )
{
case 32: ToImage( static_cast<ComplexImage&>( *image ) ); break;
case 64: ToImage( static_cast<DComplexImage&>( *image ) ); break;
}
else
switch ( image.BitsPerSample() )
{
case 8: ToImage( static_cast<UInt8Image&>( *image ) ); break;
case 16: ToImage( static_cast<UInt16Image&>( *image ) ); break;
case 32: ToImage( static_cast<UInt32Image&>( *image ) ); break;
}
}
#endif // !__PCL_NO_MATRIX_IMAGE_RENDERING
#ifndef __PCL_NO_MATRIX_IMAGE_CONVERSION
/*!
* Creates a matrix from image pixel samples.
*
* This static member function converts pixel sample values to matrix
* elements for a rectangular region of a channel of the specified \a image.
*
* \param image Image from which matrix elements will be generated.
*
* \param rect A rectangular region in image pixel coordinates, from
* which the returned matrix will be generated. If this
* parameter is not specified, or if an empty rectangle is
* specified, this function will perform the matrix
* conversion for the current rectangular selection in the
* image, that is, for image.SelectedRectangle().
*
* \param channel Channel index. Must be the zero-based index of an existing
* channel in the image, or an integer < 0. If this parameter
* is not specified, or if a negative integer is specified,
* this function will perform the matrix conversion for the
* currently selected channel in the image, that is, for
* image.SelectedChannel().
*
* The returned matrix is a representation of the intersection of the
* specified (or implicitly selected) rectangular region with the image for
* the scalar data type T of this matrix instantiation. All predefined pixel
* sample types are supported, including integer, real and complex pixels.
*
* If there is no intersection between the rectangular region and the image,
* or if an invalid channel index is specified, this function returns an
* empty matrix.
*
* Note that if the source image is of a floating point type (either real or
* complex) and the scalar type T of this matrix instantiation is of an
* integer type, out-of-range matrix elements will be truncated to either
* zero or to the maximum integer value, if the corresponding source pixel
* sample is outside the normalized [0,1] range.
*/
template <class P>
static GenericMatrix FromImage( const GenericImage<P>& image, const Rect& rect = Rect( 0 ), int channel = -1 )
{
Rect r = rect;
if ( !image.ParseSelection( r, channel ) )
return GenericMatrix();
if ( r == image.Bounds() )
{
GenericMatrix M( image.Height(), image.Width() );
const typename P::sample* __restrict__ v = image[channel];
block_iterator __restrict__ i = M.m_data->Begin();
const_block_iterator __restrict__ j = M.m_data->End();
PCL_IVDEP
for ( ; i < j; ++i, ++v )
P::FromSample( *i, *v );
return M;
}
else
{
int w = r.Width();
int h = r.Height();
GenericMatrix M( h, w );
block_iterator __restrict__ m = M.m_data->Begin();
PCL_IVDEP
for ( int i = r.y0; i < r.y1; ++i )
{
const typename P::sample* __restrict__ v = image.PixelAddress( r.x0, i, channel );
PCL_IVDEP
for ( int j = 0; j < w; ++j )
P::FromSample( *m++, *v++ );
}
return M;
}
}
/*!
* Creates a matrix from image pixel samples.
*
* This static member function converts pixel sample values to matrix
* elements for a rectangular region of a channel of the image transported
* by the specified %ImageVariant.
*
* If the specified %ImageVariant object does not transport an image, this
* member function returns an empty matrix.
*
* Refer to the documentation for
* FromImage( const GenericImage&, const Rect&, int ) for more information
* about the conversion performed by this member function.
*/
static GenericMatrix FromImage( const ImageVariant& image, const Rect& rect = Rect( 0 ), int channel = -1 )
{
if ( image )
if ( image.IsFloatSample() )
switch ( image.BitsPerSample() )
{
case 32: return FromImage( static_cast<const Image&>( *image ), rect, channel );
case 64: return FromImage( static_cast<const DImage&>( *image ), rect, channel );
}
else if ( image.IsComplexSample() )
switch ( image.BitsPerSample() )
{
case 32: return FromImage( static_cast<const ComplexImage&>( *image ), rect, channel );
case 64: return FromImage( static_cast<const DComplexImage&>( *image ), rect, channel );
}
else
switch ( image.BitsPerSample() )
{
case 8: return FromImage( static_cast<const UInt8Image&>( *image ), rect, channel );
case 16: return FromImage( static_cast<const UInt16Image&>( *image ), rect, channel );
case 32: return FromImage( static_cast<const UInt32Image&>( *image ), rect, channel );
}
return GenericMatrix();
}
#endif // !__PCL_NO_MATRIX_IMAGE_CONVERSION
private:
/*!
* \struct Data
* \internal
* Reference-counted matrix data structure.
*/
struct Data : public ReferenceCounter
{
int n = 0; //!< Number of matrix rows
int m = 0; //!< Number of matrix columns
block_iterator* v = nullptr; //!< Pointer to a pointer to a contiguous block of matrix elements
Data() = default;
Data( int rows, int cols )
{
if ( rows > 0 && cols > 0 )
Allocate( rows, cols );
}
~Data()
{
Deallocate();
}
int Rows() const noexcept
{
return n;
}
int Cols() const noexcept
{
return m;
}
size_type NumberOfElements() const noexcept
{
return size_type( n )*size_type( m );
}
size_type Size() const noexcept
{
return NumberOfElements()*sizeof( element );
}
block_iterator Begin() const
{
block_iterator p = (v != nullptr) ? *v : nullptr;
if ( likely( std::is_scalar<element>::value ) )
return reinterpret_cast<block_iterator>( PCL_ASSUME_ALIGNED_32( p ) );
return p;
}
block_iterator End() const noexcept
{
return (v != nullptr) ? *v + NumberOfElements() : nullptr;
}
element& Element( int i, int j ) const noexcept
{
return v[i][j];
}
void Allocate( int rows, int cols )
{
n = rows;
m = cols;
v = new block_iterator[ n ];
if ( likely( std::is_scalar<element>::value ) )
{
*v = reinterpret_cast<block_iterator>( PCL_ALIGNED_MALLOC( Size(), 32 ) );
if ( unlikely( *v == nullptr ) )
{
delete [] v;
v = nullptr;
n = m = 0;
throw std::bad_alloc();
}
}
else
*v = new element[ NumberOfElements() ];
for ( int i = 1; i < n; ++i )
v[i] = v[i-1] + m;
}
void Deallocate()
{
PCL_PRECONDITION( refCount == 0 )
if ( v != nullptr )
{
if ( likely( std::is_scalar<element>::value ) )
PCL_ALIGNED_FREE( *v );
else
delete [] *v;
delete [] v;
v = nullptr;
n = m = 0;
}
}
};
/*!
* \internal
* The reference-counted matrix data.
*/
Data* m_data = nullptr;
/*!
* \internal
* Dereferences matrix data and disposes it if it becomes garbage.
*/
void DetachFromData()
{
if ( !m_data->Detach() )
delete m_data;
}
/*!
* \internal
* Inverts a small matrix of dimension <= 3.
*/
static bool Invert( block_iterator* Ai, const_block_iterator const* A, int n ) noexcept
{
switch ( n )
{
case 1:
if ( 1 + **A == 1 )
return false;
**Ai = 1/(**A);
break;
case 2:
{
const_block_iterator __restrict__ A0 = A[0];
const_block_iterator __restrict__ A1 = A[1];
element d = A0[0]*A1[1] - A0[1]*A1[0];
if ( 1 + d == 1 )
return false;
Ai[0][0] = A1[1]/d;
Ai[0][1] = -A0[1]/d;
Ai[1][0] = -A1[0]/d;
Ai[1][1] = A0[0]/d;
}
break;
case 3:
{
const_block_iterator __restrict__ A0 = A[0];
const_block_iterator __restrict__ A1 = A[1];
const_block_iterator __restrict__ A2 = A[2];
element d1 = A1[1]*A2[2] - A1[2]*A2[1];
element d2 = A1[2]*A2[0] - A1[0]*A2[2];
element d3 = A1[0]*A2[1] - A1[1]*A2[0];
element d = A0[0]*d1 + A0[1]*d2 + A0[2]*d3;
if ( 1 + d == 1 )
return false;
Ai[0][0] = d1/d;
Ai[0][1] = (A2[1]*A0[2] - A2[2]*A0[1])/d;
Ai[0][2] = (A0[1]*A1[2] - A0[2]*A1[1])/d;
Ai[1][0] = d2/d;
Ai[1][1] = (A2[2]*A0[0] - A2[0]*A0[2])/d;
Ai[1][2] = (A0[2]*A1[0] - A0[0]*A1[2])/d;
Ai[2][0] = d3/d;
Ai[2][1] = (A2[0]*A0[1] - A2[1]*A0[0])/d;
Ai[2][2] = (A0[0]*A1[1] - A0[1]*A1[0])/d;
}
break;
default: // ?!
return false;
}
return true;
}
};
// ### N.B.: Visual C++ is unable to compile the next two member functions if
// the following external function declarations are placed within the
// member function bodies. This forces us to implement them after the
// GenericMatrix<> class declaration.
void PCL_FUNC InPlaceGaussJordan( GenericMatrix<double>&, GenericMatrix<double>& );
void PCL_FUNC InPlaceGaussJordan( GenericMatrix<float>&, GenericMatrix<float>& );
template <typename T> inline
GenericMatrix<T> GenericMatrix<T>::Inverse() const
{
if ( Rows() != Cols() || Rows() == 0 )
throw Error( "Invalid matrix inversion: Non-square or empty matrix." );
/*
* - Use direct formulae to invert 1x1, 2x2 and 3x3 matrices.
* - Use Gauss-Jordan elimination to invert 4x4 and larger matrices.
*/
if ( Rows() < 4 )
{
GenericMatrix Ai( Rows(), Rows() );
if ( !Invert( Ai.m_data->v, m_data->v, Rows() ) )
throw Error( "Invalid matrix inversion: Singular matrix." );
return Ai;
}
else
{
GenericMatrix Ai( *this );
GenericMatrix B = UnitMatrix( Rows() );
InPlaceGaussJordan( Ai, B );
return Ai;
}
}
template <typename T> inline
void GenericMatrix<T>::Invert()
{
if ( Rows() <= 3 )
Transfer( Inverse() );
else
{
if ( Rows() != Cols() || Rows() == 0 )
throw Error( "Invalid matrix inversion: Non-square or empty matrix." );
EnsureUnique();
GenericMatrix B = UnitMatrix( Rows() );
InPlaceGaussJordan( *this, B );
}
}
// ----------------------------------------------------------------------------
/*!
* \defgroup matrix_operators Matrix Operators
*
* This section includes scalar-to-matrix and matrix-to-matrix arithmetic
* operator functions that are not members of the GenericMatrix template class.
*/
/*!
* Returns the sum of two matrices \a A and \a B.
*
* If the specified matrices are incompatible for matrix addition (because
* their dimensions are different), this function throws an Error exception.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator +( const GenericMatrix<T>& A, const GenericMatrix<T>& B )
{
if ( B.Rows() != A.Rows() || B.Cols() != A.Cols() )
throw Error( "Invalid matrix addition." );
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ t = B.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k, ++t )
*i = *k + *t;
return R;
}
/*!
* Returns the sum of a matrix \a A and a scalar \a x.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator +( const GenericMatrix<T>& A, const T& x )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = *k + x;
return R;
}
/*!
* Returns the sum of a scalar \a x and a matrix \a A.
*
* This function exists to implement the commutative property of
* scalar-to-matrix addition. It is equivalent to A + x.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator +( const T& x, const GenericMatrix<T>& A )
{
return A + x;
}
// ----------------------------------------------------------------------------
/*!
* Returns the result of subtracting a matrix \a B from another matrix \a A.
*
* If the specified matrices are incompatible for matrix subtraction (because
* their dimensions are different), this function throws an Error exception.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator -( const GenericMatrix<T>& A, const GenericMatrix<T>& B )
{
if ( B.Rows() != A.Rows() || B.Cols() != A.Cols() )
throw Error( "Invalid matrix subtraction." );
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ t = B.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k, ++t )
*i = *k - *t;
return R;
}
/*!
* Returns the subtraction of a scalar \a x from a matrix \a A.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator -( const GenericMatrix<T>& A, const T& x )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = *k - x;
return R;
}
/*!
* Returns the subtraction of a matrix \a A from a scalar \a x.
*
* This function exists because scalar-to-matrix subtraction is not a
* commutative operation. A - x is not equal to x - A (the resulting matrix
* elements have the same magnitudes but opposite signs).
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator -( const T& x, const GenericMatrix<T>& A )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = x - *k;
return R;
}
// ----------------------------------------------------------------------------
/*!
* Returns the product of two matrices \a A and \a B.
*
* If the specified matrices are incompatible for matrix multiplication
* (because the number of rows in \a B is not equal to the number of columns in
* \a A), this function throws an appropriate Error exception.
*
* Bear in mind that matrix multiplication has O(N^3) complexity. This is
* relevant to multiply large matrices.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator *( const GenericMatrix<T>& A, const GenericMatrix<T>& B )
{
int n = A.Rows();
int m = B.Cols();
int p = A.Cols();
if ( B.Rows() != p )
throw Error( "Invalid matrix multiplication." );
GenericMatrix<T> R( n, m );
for ( int i = 0; i < n; ++i )
for ( int j = 0; j < m; ++j )
{
T rij = 0;
for ( int k = 0; k < p; ++k )
rij += A[i][k] * B[k][j];
R[i][j] = rij;
}
return R;
}
/*!
* Returns the product of a matrix \a A by a vector \a x.
*
* If the specified objects are incompatible for multiplication (because the
* number of components in \a x is not equal to the number of columns in \a A),
* this function throws the appropriate Error exception.
*
* The result of the product of a matrix with \e m rows and \e n columns by a
* vector of \e n components is a vector of \e m components.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericVector<T> operator *( const GenericMatrix<T>& A, const GenericVector<T>& x )
{
int n = A.Cols();
int m = A.Rows();
if ( x.Length() != n )
throw Error( "Invalid matrix-vector multiplication." );
GenericVector<T> r( m );
for ( int i = 0; i < m; ++i )
{
T ri = 0;
for ( int j = 0; j < n; ++j )
ri += A[i][j] * x[j];
r[i] = ri;
}
return r;
}
/*!
* Returns the product of a matrix \a A and a scalar \a x.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator *( const GenericMatrix<T>& A, const T& x )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = *k * x;
return R;
}
/*!
* Returns the product of a scalar \a x and a matrix \a A.
*
* This function exists to implement the commutative property of
* scalar-to-matrix multiplication. It is equivalent to A * x.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator *( const T& x, const GenericMatrix<T>& A )
{
return A * x;
}
// ----------------------------------------------------------------------------
/*!
* Returns the result of dividing a matrix \a A by a scalar \a x.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator /( const GenericMatrix<T>& A, const T& x )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = *k / x;
return R;
}
/*!
* Returns the result of dividing a scalar \a x by a matrix \a A.
*
* This function exists because scalar-to-matrix division is not a
* commutative operation. A/x is not equal to x/A.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator /( const T& x, const GenericMatrix<T>& A )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = x / *k;
return R;
}
// ----------------------------------------------------------------------------
/*!
* Returns the result of raising a matrix \a A to a scalar \a x.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator ^( const GenericMatrix<T>& A, const T& x )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Pow( *k, x );
return R;
}
/*!
* Returns the result of raising a scalar \a x to a matrix \a A.
*
* This function exists because scalar-to-matrix exponentiation is not a
* commutative operation. A^x is not equal to x^A.
*
* \ingroup matrix_operators
*/
template <typename T> inline
GenericMatrix<T> operator ^( const T& x, const GenericMatrix<T>& A )
{
GenericMatrix<T> R( A.Rows(), A.Cols() );
typename GenericMatrix<T>::block_iterator __restrict__ i = R.Begin();
typename GenericMatrix<T>::const_block_iterator __restrict__ j = R.End();
typename GenericMatrix<T>::const_block_iterator __restrict__ k = A.Begin();
PCL_IVDEP
for ( ; i < j; ++i, ++k )
*i = pcl::Pow( x, *k );
return R;
}
// ----------------------------------------------------------------------------
#ifndef __PCL_NO_MATRIX_INSTANTIATE
/*!
* \defgroup matrix_types Matrix Types
*/
/*!
* \class pcl::I8Matrix
* \ingroup matrix_types
* \brief 8-bit signed integer matrix.
*
* %I8Matrix is a template instantiation of GenericMatrix for \c int8.
*/
typedef GenericMatrix<int8> I8Matrix;
/*!
* \class pcl::CharMatrix
* \ingroup matrix_types
* \brief 8-bit signed integer matrix.
*
* %CharMatrix is an alias for I8Matrix. It is a template instantiation of
* GenericMatrix for \c int8.
*/
typedef I8Matrix CharMatrix;
/*!
* \class pcl::UI8Matrix
* \ingroup matrix_types
* \brief 8-bit unsigned integer matrix.
*
* %UI8Matrix is a template instantiation of GenericMatrix for \c uint8.
*/
typedef GenericMatrix<uint8> UI8Matrix;
/*!
* \class pcl::ByteMatrix
* \ingroup matrix_types
* \brief 8-bit unsigned integer matrix.
*
* %ByteMatrix is an alias for UI8Matrix. It is a template instantiation of
* GenericMatrix for \c uint8.
*/
typedef UI8Matrix ByteMatrix;
/*!
* \class pcl::I16Matrix
* \ingroup matrix_types
* \brief 16-bit signed integer matrix.
*
* %I16Matrix is a template instantiation of GenericMatrix for \c int16.
*/
typedef GenericMatrix<int16> I16Matrix;
/*!
* \class pcl::UI16Matrix
* \ingroup matrix_types
* \brief 16-bit unsigned integer matrix.
*
* %UI16Matrix is a template instantiation of GenericMatrix for \c uint16.
*/
typedef GenericMatrix<uint16> UI16Matrix;
/*!
* \class pcl::I32Matrix
* \ingroup matrix_types
* \brief 32-bit signed integer matrix.
*
* %I32Matrix is a template instantiation of GenericMatrix for \c int32.
*/
typedef GenericMatrix<int32> I32Matrix;
/*!
* \class pcl::IMatrix
* \ingroup matrix_types
* \brief 32-bit signed integer matrix.
*
* %IMatrix is an alias for I32Matrix. It is a template instantiation of
* GenericMatrix for \c int32.
*/
typedef I32Matrix IMatrix;
/*!
* \class pcl::UI32Matrix
* \ingroup matrix_types
* \brief 32-bit unsigned integer matrix.
*
* %UI32Matrix is a template instantiation of GenericMatrix for \c uint32.
*/
typedef GenericMatrix<uint32> UI32Matrix;
/*!
* \class pcl::UIMatrix
* \ingroup matrix_types
* \brief Unsigned integer matrix.
*
* %UIMatrix is an alias for UI32Matrix. It is a template instantiation of
* GenericMatrix for \c uint32.
*/
typedef UI32Matrix UIMatrix;
/*!
* \class pcl::I64Matrix
* \ingroup matrix_types
* \brief 64-bit integer matrix.
*
* %I64Matrix is a template instantiation of GenericMatrix for \c int64.
*/
typedef GenericMatrix<int64> I64Matrix;
/*!
* \class pcl::UI64Matrix
* \ingroup matrix_types
* \brief 64-bit unsigned integer matrix.
*
* %UI64Matrix is a template instantiation of GenericMatrix for \c uint64.
*/
typedef GenericMatrix<uint64> UI64Matrix;
/*!
* \class pcl::F32Matrix
* \ingroup matrix_types
* \brief 32-bit floating point real matrix.
*
* %F32Matrix is a template instantiation of GenericMatrix for \c float.
*/
typedef GenericMatrix<float> F32Matrix;
/*!
* \class pcl::FMatrix
* \ingroup matrix_types
* \brief 32-bit floating point real matrix.
*
* %FMatrix is an alias for F32Matrix. It is a template instantiation of
* GenericMatrix for \c float.
*/
typedef F32Matrix FMatrix;
/*!
* \class pcl::F64Matrix
* \ingroup matrix_types
* \brief 64-bit floating point real matrix.
*
* %F64Matrix is a template instantiation of GenericMatrix for \c double.
*/
typedef GenericMatrix<double> F64Matrix;
/*!
* \class pcl::DMatrix
* \ingroup matrix_types
* \brief 64-bit floating point real matrix.
*
* %DMatrix is an alias for F64Matrix. It is a template instantiation of
* GenericMatrix for \c double.
*/
typedef F64Matrix DMatrix;
/*!
* \class pcl::Matrix
* \ingroup matrix_types
* \brief 64-bit floating point real matrix.
*
* %Matrix is an alias for DMatrix. It is a template instantiation of
* GenericMatrix for the \c double type.
*/
typedef DMatrix Matrix;
/*!
* \class pcl::C32Matrix
* \ingroup matrix_types
* \brief 32-bit floating point complex matrix.
*
* %C32Matrix is a template instantiation of GenericMatrix for \c Complex32.
*/
typedef GenericMatrix<Complex32> C32Matrix;
/*!
* \class pcl::C64Matrix
* \ingroup matrix_types
* \brief 64-bit floating point complex matrix.
*
* %C64Matrix is a template instantiation of GenericMatrix for \c Complex64.
*/
typedef GenericMatrix<Complex64> C64Matrix;
#ifndef _MSC_VER
/*!
* \class pcl::F80Matrix
* \ingroup matrix_types
* \brief 80-bit extended precision floating point real matrix.
*
* %F80Matrix is a template instantiation of GenericMatrix for \c long
* \c double.
*
* \note This template instantiation is not available on Windows with Visual
* C++ compilers.
*/
typedef GenericMatrix<long double> F80Matrix;
/*!
* \class pcl::LDMatrix
* \ingroup matrix_types
* \brief 80-bit extended precision floating point real matrix.
*
* %LDMatrix is an alias for F80Matrix. It is a template instantiation of
* GenericMatrix for \c long \c double.
*
* \note This template instantiation is not available on Windows with Visual
* C++ compilers.
*/
typedef F80Matrix LDMatrix;
#endif // !_MSC_VER
#endif // !__PCL_NO_MATRIX_INSTANTIATE
// ----------------------------------------------------------------------------
} // pcl
#endif // __PCL_Matrix_h
// ----------------------------------------------------------------------------
// EOF pcl/Matrix.h - Released 2022-03-12T18:59:29Z