//--------------------------------------------------------------------------- // // Project: OpenWalnut ( http://www.openwalnut.org ) // // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS // For more information see http://www.openwalnut.org/copying // // This file is part of OpenWalnut. // // OpenWalnut is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // OpenWalnut is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenWalnut. If not, see . // //--------------------------------------------------------------------------- #ifndef WGRIDREGULAR3D_H #define WGRIDREGULAR3D_H #include #include #include #include #include #include #include #include #include "../common/exceptions/WOutOfBounds.h" #include "../common/exceptions/WPreconditionNotMet.h" #include "../common/math/WLinearAlgebraFunctions.h" #include "../common/math/WMatrix.h" #include "../common/math/linearAlgebra/WLinearAlgebra.h" #include "../common/WBoundingBox.h" #include "../common/WCondition.h" #include "../common/WDefines.h" #include "../common/WProperties.h" #include "WGrid.h" #include "WGridTransformOrtho.h" /** * A grid that has parallelepiped cells which all have the same proportion. I.e. * the samples along a single axis are equidistant. The distance of samples may * vary between axes. * * \warning Positions on the upper bounddaries in x, y and z are considered outside the grid. * \ingroup dataHandler */ template< typename T > class WGridRegular3DTemplate : public WGrid // NOLINT { // this (friend) is necessary to allow casting template friend class WGridRegular3DTemplate; /** * Only test are allowed as friends. */ friend class WGridRegular3DTest; public: /** * Convenience typedef for 3d vectors of the appropriate numerical type. */ typedef WMatrixFixed< T, 3, 1 > Vector3Type; /** * Convenience typedef for a boost::shared_ptr< WGridRegular3DTemplate >. */ typedef boost::shared_ptr< WGridRegular3DTemplate > SPtr; /** * Convenience typedef for a boost::shared_ptr< const WGridRegular3DTemplate >. */ typedef boost::shared_ptr< const WGridRegular3DTemplate > ConstSPtr; /** * Convenience typedef for a boost::array< size_t, 8 >. Return type of getCellVertexIds. */ typedef boost::array< size_t, 8 > CellVertexArray; /** * Copy constructor. * Copies the data from an WGridRegular3DTemplate object with arbitary numerical type. * * \param rhs A WGridRegular3DTemplate object, which mustn't have the same numerical type. */ template< typename InputType > WGridRegular3DTemplate( WGridRegular3DTemplate< InputType > const& rhs ); // NOLINT -- no explicit, this allows casts /** * Defines the number of samples in each coordinate direction as ints, * and the transformation of the grid via a grid transform. * * \param nbPosX number of positions along first axis * \param nbPosY number of positions along second axis * \param nbPosZ number of positions along third axis * \param transform a grid transformation */ WGridRegular3DTemplate( unsigned int nbPosX, unsigned int nbPosY, unsigned int nbPosZ, WGridTransformOrthoTemplate< T > const transform = WGridTransformOrthoTemplate< T >() ); /** * Returns the number of samples in x direction. * \return The number of samples in x direction. */ unsigned int getNbCoordsX() const; /** * Returns the number of samples in y direction. * \return The number of samples in y direction. */ unsigned int getNbCoordsY() const; /** * Returns the number of samples in z direction. * \return The number of samples in z direction. */ unsigned int getNbCoordsZ() const; /** * Returns the distance between samples in x direction. * \return The distance between samples in x direction. */ T getOffsetX() const; /** * Returns the distance between samples in y direction. * \return The distance between samples in y direction. */ T getOffsetY() const; /** * Returns the distance between samples in z direction. * \return The distance between samples in z direction. */ T getOffsetZ() const; /** * Returns the vector determining the direction of samples in x direction. * Adding this vector to a grid position in world coordinates yields the position of the next sample * along the grids (world coordinate) x-axis. * \return The vector determining the direction of samples in x direction. */ Vector3Type getDirectionX() const; /** * Returns the vector determining the direction of samples in y direction. * Adding this vector to a grid position in world coordinates yields the position of the next sample * along the grids (world coordinate) y-axis. * \return The vector determining the direction of samples in y direction. */ Vector3Type getDirectionY() const; /** * Returns the vector determining the direction of samples in z direction. * Adding this vector to a grid position in world coordinates yields the position of the next sample * along the grids (world coordinate) z-axis. * \return The vector determining the direction of samples in z direction. */ Vector3Type getDirectionZ() const; /** * Returns the vector determining the unit (normalized) direction of samples in x direction. * \return The vector determining the unit (normalized) direction of samples in x direction. */ Vector3Type getUnitDirectionX() const; /** * Returns the vector determining the unit (normalized) direction of samples in y direction. * \return The vector determining the unit (normalized) direction of samples in y direction. */ Vector3Type getUnitDirectionY() const; /** * Returns the vector determining the unit (normalized) direction of samples in z direction. * \return The vector determining the unit (normalized) direction of samples in z direction. */ Vector3Type getUnitDirectionZ() const; /** * Returns the position of the origin of the grid. * \return The position of the origin of the grid. */ Vector3Type getOrigin() const; /** * Returns a 4x4 matrix that represents the grid's transformation. * \return The grid's transformation. */ WMatrix< T > getTransformationMatrix() const; /** * \copybrief WGrid::getBoundingBox() * \return \copybrief WGrid::getBoundingBox() */ WBoundingBox getBoundingBox() const; /** * Returns the i-th position on the grid. * \param i id of position to be obtained * \return i-th position of the grid. */ Vector3Type getPosition( unsigned int i ) const; /** * Returns the position that is the iX-th in x direction, the iY-th in * y direction and the iZ-th in z direction. * \param iX id along first axis of position to be obtained * \param iY id along second axis of position to be obtained * \param iZ id along third axis of position to be obtained * \return Position (iX,iY,iZ) */ Vector3Type getPosition( unsigned int iX, unsigned int iY, unsigned int iZ ) const; /** * Transforms world coordinates to texture coordinates. * \param point The point with these coordinates will be transformed. * \return point transformed into texture coordinate system */ Vector3Type worldCoordToTexCoord( Vector3Type point ); /** * Returns the i'th voxel where the given position belongs too. * * A voxel is a cuboid which surrounds a point on the grid. * * \verbatim Voxel: ______________ ____ (0.5, 0.5, 0.5) /: /| / : / | / : / | / : / | _/____:_ ___ __/ | | : | | | : *<--|--------- grid point (0, 0, 0) | :........|....|__ dz == 1| / | / | / | / dy == 1 | / | / _|/____________|/__ |<- dx == 1 ->| -0.5,-0.5,-0.5 \endverbatim * * Please note the first voxel has only 1/8 of the size a normal voxel * would have since all positions outside the grid do not belong * to any voxel. Note: a cell is different to a voxel in terms of position. * A voxel has a grid point as center whereas a cell has grid points as * corners. * \param pos Position for which we want to have the voxel number. * * \return Voxel number or -1 if the position refers to a point outside of * the grid. */ int getVoxelNum( const Vector3Type& pos ) const; /** * returns the voxel index for a given discrete position in the grid * * \param x Position for which we want to have the voxel number. * \param y Position for which we want to have the voxel number. * \param z Position for which we want to have the voxel number. * * \return Voxel number or -1 if the position refers to a point outside of * the grid. */ int getVoxelNum( const size_t x, const size_t y, const size_t z ) const; /** * Computes the X coordinate of that voxel that contains the * position pos. * * \param pos The position which selects the voxel for which the X * coordinate is computed. * * \return The X coordinate or -1 if pos refers to point outside of the * grid. */ int getXVoxelCoord( const Vector3Type& pos ) const; /** * Computes the Y coordinate of that voxel that contains the * position pos. * * \param pos The position which selects the voxel for which the Y * coordinate is computed. * * \return The Y coordinate or -1 if pos refers to point outside of the * grid. */ int getYVoxelCoord( const Vector3Type& pos ) const; /** * Computes the Z coordinate of that voxel that contains the * position pos. * * \param pos The position which selects the voxel for which the Z * coordinate is computed. * * \return The Z coordinate or -1 if pos refers to point outside of the * grid. */ int getZVoxelCoord( const Vector3Type& pos ) const; /** * Computes the voxel coordinates of that voxel which contains * the position pos. * * \param pos The position selecting the voxel. * * \return A vector of ints where the first component is the X voxel * coordinate, the second the Y component voxel coordinate and the last the * Z component of the voxel coordinate. If the selecting position is * outside of the grid then -1 -1 -1 is returned. */ WVector3i getVoxelCoord( const Vector3Type& pos ) const; /** * Computes the id of the cell containing the position pos. Note that the upper * bound of the grid does not belong to any cell * * \param pos The position selecting the cell. * \param success True if the position pos is inside the grid. * * \return id of the containing the position. */ size_t getCellId( const Vector3Type& pos, bool* success ) const; /** * Computes the ids of the vertices of a cell given by its id. * * \param cellId The id of the cell we want to know ther vertices of. * * \return Ids of vertices belonging to cell with given cellId. * \verbatim z-axis y-axis | / | 6___/_7 |/: /| 4_:___5 | | :...|.| |.2 | 3 |_____|/ ____x-axis 0 1 \endverbatim * */ CellVertexArray getCellVertexIds( size_t cellId ) const; /** * Computes the vertices for a voxel cuboid around the given point: * * \verbatim z-axis y-axis | / | h___/_g |/: /| d_:___c | | :...|.| |.e | f |_____|/ ____x-axis a b \endverbatim * * As you can see the order of the points is: a, b, c, d, e, f, g, h. * * \param point Center of the cuboid which must not necesarrily be a point * of the grid. * \param margin If you need to shrink the Voxel put here the delta > 0. * * \return Reference to a list of vertices which are the corner points of * the cube. Note this must not be a voxel, but has the same size of the an * voxel. If you need voxels at grid positions fill this function with * voxel center positions aka grid points. */ boost::shared_ptr< std::vector< Vector3Type > > getVoxelVertices( const Vector3Type& point, const T margin = 0.0 ) const; /** * Return the list of neighbour voxels. * * \throw WOutOfBounds If the voxel id is outside of the grid. * * \param id Number of the voxel for which the neighbours should be computed * * \return Vector of voxel ids which are all neighboured */ std::vector< size_t > getNeighbours( size_t id ) const; /** * Return the list of all neighbour voxels. * * \throw WOutOfBounds If the voxel id is outside of the grid. * * \param id Number of the voxel for which the neighbours should be computed * * \return Vector of voxel ids which are all neighboured */ std::vector< size_t > getNeighbours27( size_t id ) const; /** * Return the list of all neighbour voxels. * * \throw WOutOfBounds If the voxel id is outside of the grid. * * \param id Number of the voxel for which the neighbours should be computed * * \param range neighborhood range selected. It specifies the distance to count as neighbour in each direction. * * \return Vector of voxel ids which are all neighboured */ std::vector< size_t > getNeighboursRange( size_t id, size_t range ) const; /** * Return the list of all neighbour voxels. * * \throw WOutOfBounds If the voxel id is outside of the grid. * * \param id Number of the voxel for which the neighbours should be computed * * \return Vector of voxel ids which are all neighboured along the XY plane */ std::vector< size_t > getNeighbours9XY( size_t id ) const; /** * Return the list of all neighbour voxels. * * \throw WOutOfBounds If the voxel id is outside of the grid. * * \param id Number of the voxel for which the neighbours should be computed * * \return Vector of voxel ids which are all neighboured along the YZ plane */ std::vector< size_t > getNeighbours9YZ( size_t id ) const; /** * Return the list of all neighbour voxels. * * \throw WOutOfBounds If the voxel id is outside of the grid. * * \param id Number of the voxel for which the neighbours should be computed * * \return Vector of voxel ids which are all neighboured along the XZ plane */ std::vector< size_t > getNeighbours9XZ( size_t id ) const; /** * Decides whether a certain position is inside this grid or not. * * \param pos Position to test * * \return True if and only if the given point is inside or on boundary of this grid, otherwise false. */ bool encloses( const Vector3Type& pos ) const; /** * Return whether the transformations of the grid are only translation and/or scaling * \return Transformation does not contain rotation? */ bool isNotRotated() const; /** * Returns the transformation used by this grid. * \return The transformation. */ WGridTransformOrthoTemplate< T > const getTransform() const; protected: private: /** * Computes for the n'th component of the voxel coordinate where the voxel * contains the position pos. * * \param pos The position for which the n'th component of the voxel * coordinates should be computed. * \param axis The number of the component. (0 == x-axis, 1 == y-axis, ...) * * \return The n'th component of the voxel coordinate */ int getNVoxelCoord( const Vector3Type& pos, size_t axis ) const; /** * Adds the specific information of this grid type to the * informational properties. */ void initInformationProperties(); unsigned int m_nbPosX; //!< Number of positions in x direction unsigned int m_nbPosY; //!< Number of positions in y direction unsigned int m_nbPosZ; //!< Number of positions in z direction //! The grid's transformation. WGridTransformOrthoTemplate< T > const m_transform; }; // Convenience typedefs typedef WGridRegular3DTemplate< double > WGridRegular3D; typedef WGridRegular3DTemplate< double > WGridRegular3DDouble; typedef WGridRegular3DTemplate< float > WGridRegular3DFloat; template< typename T > template< typename InputType > WGridRegular3DTemplate< T >::WGridRegular3DTemplate( WGridRegular3DTemplate< InputType > const& rhs ) : WGrid( rhs.m_nbPosX * rhs.m_nbPosY * rhs.m_nbPosZ ), m_nbPosX( rhs.m_nbPosX ), m_nbPosY( rhs.m_nbPosY ), m_nbPosZ( rhs.m_nbPosZ ), m_transform( rhs.m_transform ) { initInformationProperties(); } template< typename T > WGridRegular3DTemplate< T >::WGridRegular3DTemplate( unsigned int nbPosX, unsigned int nbPosY, unsigned int nbPosZ, WGridTransformOrthoTemplate< T > const transform ) : WGrid( nbPosX * nbPosY * nbPosZ ), m_nbPosX( nbPosX ), m_nbPosY( nbPosY ), m_nbPosZ( nbPosZ ), m_transform( transform ) { initInformationProperties(); } template< typename T > inline unsigned int WGridRegular3DTemplate< T >::getNbCoordsX() const { return m_nbPosX; } template< typename T > inline unsigned int WGridRegular3DTemplate< T >::getNbCoordsY() const { return m_nbPosY; } template< typename T > inline unsigned int WGridRegular3DTemplate< T >::getNbCoordsZ() const { return m_nbPosZ; } template< typename T > inline T WGridRegular3DTemplate< T >::getOffsetX() const { return m_transform.getOffsetX(); } template< typename T > inline T WGridRegular3DTemplate< T >::getOffsetY() const { return m_transform.getOffsetY(); } template< typename T > inline T WGridRegular3DTemplate< T >::getOffsetZ() const { return m_transform.getOffsetZ(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getDirectionX() const { return m_transform.getDirectionX(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getDirectionY() const { return m_transform.getDirectionY(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getDirectionZ() const { return m_transform.getDirectionZ(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getUnitDirectionX() const { return m_transform.getUnitDirectionX(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getUnitDirectionY() const { return m_transform.getUnitDirectionY(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getUnitDirectionZ() const { return m_transform.getUnitDirectionZ(); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getOrigin() const { return m_transform.getOrigin(); } template< typename T > inline WMatrix< T > WGridRegular3DTemplate< T >::getTransformationMatrix() const { return m_transform.getTransformationMatrix(); } template< typename T > inline WBoundingBox WGridRegular3DTemplate< T >::getBoundingBox() const { WBoundingBox result; result.expandBy( m_transform.positionToWorldSpace( Vector3Type( 0.0, 0.0, 0.0 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( getNbCoordsX() - 1, 0.0, 0.0 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( 0.0, getNbCoordsY() - 1, 0.0 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( getNbCoordsX() - 1, getNbCoordsY() - 1, 0.0 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( 0.0, 0.0, getNbCoordsZ() - 1 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( getNbCoordsX() - 1, 0.0, getNbCoordsZ() - 1 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( 0.0, getNbCoordsY() - 1, getNbCoordsZ() - 1 ) ) ); result.expandBy( m_transform.positionToWorldSpace( Vector3Type( getNbCoordsX() - 1, getNbCoordsY() - 1, getNbCoordsZ() - 1 ) ) ); return result; } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getPosition( unsigned int i ) const { return getPosition( i % m_nbPosX, ( i / m_nbPosX ) % m_nbPosY, i / ( m_nbPosX * m_nbPosY ) ); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::getPosition( unsigned int iX, unsigned int iY, unsigned int iZ ) const { Vector3Type i( iX, iY, iZ ); return m_transform.positionToWorldSpace( i ); } template< typename T > inline typename WGridRegular3DTemplate< T >::Vector3Type WGridRegular3DTemplate< T >::worldCoordToTexCoord( WGridRegular3DTemplate< T >::Vector3Type point ) // NOLINT -- too long line { Vector3Type r( m_transform.positionToGridSpace( point ) ); // Scale to [0,1] r[0] = r[0] / m_nbPosX; r[1] = r[1] / m_nbPosY; r[2] = r[2] / m_nbPosZ; // Correct the coordinates to have the position at the center of the texture voxel. r[0] += 0.5 / m_nbPosX; r[1] += 0.5 / m_nbPosY; r[2] += 0.5 / m_nbPosZ; return r; } template< typename T > inline int WGridRegular3DTemplate< T >::getVoxelNum( const Vector3Type& pos ) const { // Note: the reason for the +1 is that the first and last Voxel in a x-axis // row are cut. // // y-axis // _|_______ ___ this is the 3rd Voxel // 1 | | | v // |............... // _|_:_|_:_|_:_|_:____ x-axis // | : | : | : | : // |.:...:...:...:. // 0 1 2 int xVoxelCoord = getXVoxelCoord( pos ); int yVoxelCoord = getYVoxelCoord( pos ); int zVoxelCoord = getZVoxelCoord( pos ); if( xVoxelCoord == -1 || yVoxelCoord == -1 || zVoxelCoord == -1 ) { return -1; } return xVoxelCoord + yVoxelCoord * ( m_nbPosX ) + zVoxelCoord * ( m_nbPosX ) * ( m_nbPosY ); } template< typename T > inline int WGridRegular3DTemplate< T >::getVoxelNum( const size_t x, const size_t y, const size_t z ) const { // since we use size_t here only a check for the upper bounds is needed if( x > m_nbPosX || y > m_nbPosY || z > m_nbPosZ ) { return -1; } return x + y * ( m_nbPosX ) + z * ( m_nbPosX ) * ( m_nbPosY ); } template< typename T > inline int WGridRegular3DTemplate< T >::getXVoxelCoord( const WGridRegular3DTemplate< T >::Vector3Type& pos ) const { // the current get*Voxel stuff is too complicated anyway Vector3Type v = m_transform.positionToGridSpace( pos ); // this part could be refactored into an inline function T d; v[ 2 ] = std::modf( v[ 0 ] + T( 0.5 ), &d ); int i = static_cast< int >( v[ 0 ] >= T( 0.0 ) && v[ 0 ] < m_nbPosX - T( 1.0 ) ); return -1 + i * static_cast< int >( T( 1.0 ) + d ); } template< typename T > inline int WGridRegular3DTemplate< T >::getYVoxelCoord( const WGridRegular3DTemplate< T >::Vector3Type& pos ) const { Vector3Type v = m_transform.positionToGridSpace( pos ); T d; v[ 0 ] = std::modf( v[ 1 ] + T( 0.5 ), &d ); int i = static_cast< int >( v[ 1 ] >= T( 0.0 ) && v[ 1 ] < m_nbPosY - T( 1.0 ) ); return -1 + i * static_cast< int >( T( 1.0 ) + d ); } template< typename T > inline int WGridRegular3DTemplate< T >::getZVoxelCoord( const WGridRegular3DTemplate< T >::Vector3Type& pos ) const { Vector3Type v = m_transform.positionToGridSpace( pos ); T d; v[ 0 ] = std::modf( v[ 2 ] + T( 0.5 ), &d ); int i = static_cast< int >( v[ 2 ] >= T( 0.0 ) && v[ 2 ] < m_nbPosZ - T( 1.0 ) ); return -1 + i * static_cast< int >( T( 1.0 ) + d ); } template< typename T > inline WVector3i WGridRegular3DTemplate< T >::getVoxelCoord( const WGridRegular3DTemplate< T >::Vector3Type& pos ) const { WVector3i result; result[0] = getXVoxelCoord( pos ); result[1] = getYVoxelCoord( pos ); result[2] = getZVoxelCoord( pos ); return result; } template< typename T > inline size_t WGridRegular3DTemplate< T >::getCellId( const WGridRegular3DTemplate< T >::Vector3Type& pos, bool* success ) const { Vector3Type v = m_transform.positionToGridSpace( pos ); T xCellId = floor( v[0] ); T yCellId = floor( v[1] ); T zCellId = floor( v[2] ); *success = xCellId >= 0 && yCellId >=0 && zCellId >= 0 && xCellId < m_nbPosX - 1 && yCellId < m_nbPosY -1 && zCellId < m_nbPosZ -1; return xCellId + yCellId * ( m_nbPosX - 1 ) + zCellId * ( m_nbPosX - 1 ) * ( m_nbPosY - 1 ); } template< typename T > inline typename WGridRegular3DTemplate< T >::CellVertexArray WGridRegular3DTemplate< T >::getCellVertexIds( size_t cellId ) const { typename WGridRegular3DTemplate< T >::CellVertexArray vertices; size_t minVertexIdZ = cellId / ( ( m_nbPosX - 1 ) * ( m_nbPosY - 1 ) ); size_t remainderXY = cellId - minVertexIdZ * ( ( m_nbPosX - 1 ) * ( m_nbPosY - 1 ) ); size_t minVertexIdY = remainderXY / ( m_nbPosX - 1 ); size_t minVertexIdX = remainderXY % ( m_nbPosX - 1 ); size_t minVertexId = minVertexIdX + minVertexIdY * m_nbPosX + minVertexIdZ * m_nbPosX * m_nbPosY; vertices[0] = minVertexId; vertices[1] = vertices[0] + 1; vertices[2] = minVertexId + m_nbPosX; vertices[3] = vertices[2] + 1; vertices[4] = minVertexId + m_nbPosX * m_nbPosY; vertices[5] = vertices[4] + 1; vertices[6] = vertices[4] + m_nbPosX; vertices[7] = vertices[6] + 1; return vertices; } template< typename T > boost::shared_ptr< std::vector< typename WGridRegular3DTemplate< T >::Vector3Type > > WGridRegular3DTemplate< T >::getVoxelVertices( const WGridRegular3DTemplate< T >::Vector3Type& point, const T margin ) const // NOLINT -- too long line { typedef boost::shared_ptr< std::vector< Vector3Type > > ReturnType; ReturnType result = ReturnType( new std::vector< Vector3Type > ); result->reserve( 8 ); T halfMarginX = getOffsetX() / 2.0 - std::abs( margin ); T halfMarginY = getOffsetY() / 2.0 - std::abs( margin ); T halfMarginZ = getOffsetZ() / 2.0 - std::abs( margin ); result->push_back( Vector3Type( point[0] - halfMarginX, point[1] - halfMarginY, point[2] - halfMarginZ ) ); // a result->push_back( Vector3Type( point[0] + halfMarginX, point[1] - halfMarginY, point[2] - halfMarginZ ) ); // b result->push_back( Vector3Type( point[0] + halfMarginX, point[1] - halfMarginY, point[2] + halfMarginZ ) ); // c result->push_back( Vector3Type( point[0] - halfMarginX, point[1] - halfMarginY, point[2] + halfMarginZ ) ); // d result->push_back( Vector3Type( point[0] - halfMarginX, point[1] + halfMarginY, point[2] - halfMarginZ ) ); // e result->push_back( Vector3Type( point[0] + halfMarginX, point[1] + halfMarginY, point[2] - halfMarginZ ) ); // f result->push_back( Vector3Type( point[0] + halfMarginX, point[1] + halfMarginY, point[2] + halfMarginZ ) ); // g result->push_back( Vector3Type( point[0] - halfMarginX, point[1] + halfMarginY, point[2] + halfMarginZ ) ); // h return result; } template< typename T > std::vector< size_t > WGridRegular3DTemplate< T >::getNeighbours( size_t id ) const { std::vector< size_t > neighbours; size_t x = id % m_nbPosX; size_t y = ( id / m_nbPosX ) % m_nbPosY; size_t z = id / ( m_nbPosX * m_nbPosY ); if( x >= m_nbPosX || y >= m_nbPosY || z >= m_nbPosZ ) { std::stringstream ss; ss << "This point: " << id << " is not part of this grid: "; ss << " nbPosX: " << m_nbPosX; ss << " nbPosY: " << m_nbPosY; ss << " nbPosZ: " << m_nbPosZ; throw WOutOfBounds( ss.str() ); } // for every neighbour we must check if its not on the boundary, it will be skipped otherwise if( x > 0 ) { neighbours.push_back( id - 1 ); } if( x < m_nbPosX - 1 ) { neighbours.push_back( id + 1 ); } if( y > 0 ) { neighbours.push_back( id - m_nbPosX ); } if( y < m_nbPosY - 1 ) { neighbours.push_back( id + m_nbPosX ); } if( z > 0 ) { neighbours.push_back( id - ( m_nbPosX * m_nbPosY ) ); } if( z < m_nbPosZ - 1 ) { neighbours.push_back( id + ( m_nbPosX * m_nbPosY ) ); } return neighbours; } template< typename T > std::vector< size_t > WGridRegular3DTemplate< T >::getNeighbours27( size_t id ) const { std::vector< size_t > neighbours; size_t x = id % m_nbPosX; size_t y = ( id / m_nbPosX ) % m_nbPosY; size_t z = id / ( m_nbPosX * m_nbPosY ); if( x >= m_nbPosX || y >= m_nbPosY || z >= m_nbPosZ ) { std::stringstream ss; ss << "This point: " << id << " is not part of this grid: "; ss << " nbPosX: " << m_nbPosX; ss << " nbPosY: " << m_nbPosY; ss << " nbPosZ: " << m_nbPosZ; throw WOutOfBounds( ss.str() ); } // for every neighbour we must check if its not on the boundary, it will be skipped otherwise std::vector< int >tempResult; tempResult.push_back( getVoxelNum( x , y , z ) ); tempResult.push_back( getVoxelNum( x , y - 1, z ) ); tempResult.push_back( getVoxelNum( x , y + 1, z ) ); tempResult.push_back( getVoxelNum( x - 1, y , z ) ); tempResult.push_back( getVoxelNum( x - 1, y - 1, z ) ); tempResult.push_back( getVoxelNum( x - 1, y + 1, z ) ); tempResult.push_back( getVoxelNum( x + 1, y , z ) ); tempResult.push_back( getVoxelNum( x + 1, y - 1, z ) ); tempResult.push_back( getVoxelNum( x + 1, y + 1, z ) ); tempResult.push_back( getVoxelNum( x , y , z - 1 ) ); tempResult.push_back( getVoxelNum( x , y - 1, z - 1 ) ); tempResult.push_back( getVoxelNum( x , y + 1, z - 1 ) ); tempResult.push_back( getVoxelNum( x - 1, y , z - 1 ) ); tempResult.push_back( getVoxelNum( x - 1, y - 1, z - 1 ) ); tempResult.push_back( getVoxelNum( x - 1, y + 1, z - 1 ) ); tempResult.push_back( getVoxelNum( x + 1, y , z - 1 ) ); tempResult.push_back( getVoxelNum( x + 1, y - 1, z - 1 ) ); tempResult.push_back( getVoxelNum( x + 1, y + 1, z - 1 ) ); tempResult.push_back( getVoxelNum( x , y , z + 1 ) ); tempResult.push_back( getVoxelNum( x , y - 1, z + 1 ) ); tempResult.push_back( getVoxelNum( x , y + 1, z + 1 ) ); tempResult.push_back( getVoxelNum( x - 1, y , z + 1 ) ); tempResult.push_back( getVoxelNum( x - 1, y - 1, z + 1 ) ); tempResult.push_back( getVoxelNum( x - 1, y + 1, z + 1 ) ); tempResult.push_back( getVoxelNum( x + 1, y , z + 1 ) ); tempResult.push_back( getVoxelNum( x + 1, y - 1, z + 1 ) ); tempResult.push_back( getVoxelNum( x + 1, y + 1, z + 1 ) ); for( size_t k = 0; k < tempResult.size(); ++k ) { if( tempResult[k] != -1 ) { neighbours.push_back( tempResult[k] ); } } return neighbours; } template< typename T > std::vector< size_t > WGridRegular3DTemplate< T >::getNeighboursRange( size_t id, size_t range ) const { std::vector< size_t > neighbours; size_t x = id % m_nbPosX; size_t y = ( id / m_nbPosX ) % m_nbPosY; size_t z = id / ( m_nbPosX * m_nbPosY ); if( x >= m_nbPosX || y >= m_nbPosY || z >= m_nbPosZ ) { std::stringstream ss; ss << "This point: " << id << " is not part of this grid: "; ss << " nbPosX: " << m_nbPosX; ss << " nbPosY: " << m_nbPosY; ss << " nbPosZ: " << m_nbPosZ; throw WOutOfBounds( ss.str() ); } // for every neighbour we must check if its not on the boundary, it will be skipped otherwise std::vector< int >tempResult; for( size_t xx = x - range; xx < x + range + 1; ++xx ) { for( size_t yy = y - range; yy < y + range + 1; ++yy ) { for( size_t zz = z - range; zz < z + range + 1; ++zz ) { tempResult.push_back( getVoxelNum( xx, yy, zz ) ); } } } for( size_t k = 0; k < tempResult.size(); ++k ) { if( tempResult[k] != -1 ) { neighbours.push_back( tempResult[k] ); } } return neighbours; } template< typename T > std::vector< size_t > WGridRegular3DTemplate< T >::getNeighbours9XY( size_t id ) const { std::vector< size_t > neighbours; size_t x = id % m_nbPosX; size_t y = ( id / m_nbPosX ) % m_nbPosY; size_t z = id / ( m_nbPosX * m_nbPosY ); if( x >= m_nbPosX || y >= m_nbPosY || z >= m_nbPosZ ) { std::stringstream ss; ss << "This point: " << id << " is not part of this grid: "; ss << " nbPosX: " << m_nbPosX; ss << " nbPosY: " << m_nbPosY; ss << " nbPosZ: " << m_nbPosZ; throw WOutOfBounds( ss.str() ); } // boundary check now happens in the getVoxelNum function int vNum; vNum = getVoxelNum( x - 1, y, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x - 1, y - 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y - 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x + 1, y - 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x + 1, y, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x + 1, y + 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y + 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x - 1, y + 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } return neighbours; } template< typename T > std::vector< size_t > WGridRegular3DTemplate< T >::getNeighbours9YZ( size_t id ) const { std::vector< size_t > neighbours; size_t x = id % m_nbPosX; size_t y = ( id / m_nbPosX ) % m_nbPosY; size_t z = id / ( m_nbPosX * m_nbPosY ); if( x >= m_nbPosX || y >= m_nbPosY || z >= m_nbPosZ ) { std::stringstream ss; ss << "This point: " << id << " is not part of this grid: "; ss << " nbPosX: " << m_nbPosX; ss << " nbPosY: " << m_nbPosY; ss << " nbPosZ: " << m_nbPosZ; throw WOutOfBounds( ss.str() ); } // boundary check now happens in the getVoxelNum function int vNum; vNum = getVoxelNum( x, y, z - 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y - 1, z - 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y - 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y - 1, z + 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y, z + 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y + 1, z + 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y + 1, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y + 1, z - 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } return neighbours; } template< typename T > std::vector< size_t > WGridRegular3DTemplate< T >::getNeighbours9XZ( size_t id ) const { std::vector< size_t > neighbours; size_t x = id % m_nbPosX; size_t y = ( id / m_nbPosX ) % m_nbPosY; size_t z = id / ( m_nbPosX * m_nbPosY ); if( x >= m_nbPosX || y >= m_nbPosY || z >= m_nbPosZ ) { std::stringstream ss; ss << "This point: " << id << " is not part of this grid: "; ss << " nbPosX: " << m_nbPosX; ss << " nbPosY: " << m_nbPosY; ss << " nbPosZ: " << m_nbPosZ; throw WOutOfBounds( ss.str() ); } // boundary check now happens in the getVoxelNum function int vNum; vNum = getVoxelNum( x, y, z - 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x - 1, y, z - 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x - 1, y, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x - 1, y, z + 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x, y, z + 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x + 1, y, z + 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x + 1, y, z ); if( vNum != -1 ) { neighbours.push_back( vNum ); } vNum = getVoxelNum( x + 1, y, z - 1 ); if( vNum != -1 ) { neighbours.push_back( vNum ); } return neighbours; } template< typename T > inline bool WGridRegular3DTemplate< T >::encloses( WGridRegular3DTemplate< T >::Vector3Type const& pos ) const { Vector3Type v = m_transform.positionToGridSpace( pos ); if( v[ 0 ] < T( 0.0 ) || v[ 0 ] >= static_cast< T >( m_nbPosX - 1 ) ) { return false; } if( v[ 1 ] < T( 0.0 ) || v[ 1 ] >= static_cast< T >( m_nbPosY - 1 ) ) { return false; } if( v[ 2 ] < T( 0.0 ) || v[ 2 ] >= static_cast< T >( m_nbPosZ - 1 ) ) { return false; } return true; } template< typename T > inline bool WGridRegular3DTemplate< T >::isNotRotated() const { return m_transform.isNotRotated(); } template< typename T > inline WGridTransformOrthoTemplate< T > const WGridRegular3DTemplate< T >::getTransform() const { return m_transform; } template< typename T > void WGridRegular3DTemplate< T >::initInformationProperties() { WPropInt xDim = m_infoProperties->addProperty( "X dimension: ", "The x dimension of the grid.", static_cast( getNbCoordsX() ) ); WPropInt yDim = m_infoProperties->addProperty( "Y dimension: ", "The y dimension of the grid.", static_cast( getNbCoordsY() ) ); WPropInt zDim = m_infoProperties->addProperty( "Z dimension: ", "The z dimension of the grid.", static_cast( getNbCoordsZ() ) ); WPropDouble xOffset = m_infoProperties->addProperty( "X offset: ", "The distance between samples in x direction", static_cast< double >( getOffsetX() ) ); WPropDouble yOffset = m_infoProperties->addProperty( "Y offset: ", "The distance between samples in y direction", static_cast< double >( getOffsetY() ) ); WPropDouble zOffset = m_infoProperties->addProperty( "Z offset: ", "The distance between samples in z direction", static_cast< double >( getOffsetZ() ) ); WPropMatrix4X4 transformation = m_infoProperties->addProperty( "Transformation", "The transformation of this grid.", static_cast< WMatrix4d >( getTransform() ) ); } // +----------------------+ // | non-member functions | // +----------------------+ /** * Convinience function returning all offsets per axis. * 0 : xAxis, 1 : yAxis, 2 : zAxis * \param grid The grid having the information. * \note Implementing this as NonMemberNonFriend was intentional. * \return Array of number of samples per axis. */ template< typename T > inline boost::array< T, 3 > getOffsets( boost::shared_ptr< const WGridRegular3DTemplate< T > > grid ) { boost::array< T, 3 > result = { { grid->getOffsetX(), grid->getOffsetY(), grid->getOffsetZ() } }; // NOLINT curly braces return result; } /** * Convinience function returning all number coords per axis. * 0 : xAxis, 1 : yAxis, 2 : zAxis * \param grid The grid having the information. * \note Implementing this as NonMemberNonFriend was intentional. * \return Array of number of samples per axis. */ template< typename T > inline boost::array< unsigned int, 3 > getNbCoords( boost::shared_ptr< const WGridRegular3DTemplate< T > > grid ) { boost::array< unsigned int, 3 > result = { { grid->getNbCoordsX(), grid->getNbCoordsY(), grid->getNbCoordsZ() } }; // NOLINT curly braces return result; } /** * Convinience function returning all axis directions. * 0 : xAxis, 1 : yAxis, 2 : zAxis * \param grid The grid having the information. * \note Implementing this as NonMemberNonFriend was intentional. * \return The direction of each axis as array */ template< typename T > inline boost::array< typename WGridRegular3DTemplate< T >::Vector3Type, 3 > getDirections( boost::shared_ptr< const WGridRegular3DTemplate< T > > grid ) // NOLINT -- too long line { boost::array< typename WGridRegular3DTemplate< T >::Vector3Type, 3 > result = { { grid->getDirectionX(), grid->getDirectionY(), grid->getDirectionZ() } }; // NOLINT curly braces return result; } /** * Convinience function returning all axis unit directions. * 0 : xAxis, 1 : yAxis, 2 : zAxis * \param grid The grid having the information. * \note Implementing this as NonMemberNonFriend was intentional. * \return The direction of each axis as array */ template< typename T > inline boost::array< typename WGridRegular3DTemplate< T >::Vector3Type, 3 > getUnitDirections( boost::shared_ptr< const WGridRegular3DTemplate< T > > grid ) // NOLINT -- too long line { boost::array< typename WGridRegular3DTemplate< T >::Vector3Type, 3 > result = { { grid->getUnitDirectionX(), grid->getUnitDirectionY(), grid->getUnitDirectionZ() } }; // NOLINT curly braces return result; } #endif // WGRIDREGULAR3D_H