/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2013 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLGeom/src/ICLCore/DataSegment.h ** ** Module : ICLGeom ** ** Authors: Christof Elbrechter, Patrick Nobou ** ** ** ** ** ** GNU LESSER GENERAL PUBLIC LICENSE ** ** This file may be used under the terms of the GNU Lesser General ** ** Public License version 3.0 as published by the ** ** ** ** Free Software Foundation and appearing in the file LICENSE.LGPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the license requirements will ** ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** ********************************************************************/ #pragma once #include #include #include #include #include namespace icl{ namespace core{ /// The DataSegment class defines a strided data segment (or 1D or 2D ordred array of vectors) /** Each data segment is defined by - the type of it's elements (template parameter T) - the dimension of single vectors - the number of vector elements - a flag, whether the the elements are 2D organized or not Each single vector is assumed to be packed in memory (e.g. the vector element stride is always sizeof(T)) the distance between two vector entries can be set to an arbitrary constant value (stride). Optionally, an organizedWidth value > 0 can be given, which set up the DataSegement to be 2D-organized. \section _IN_ Integration with the DataSegment base class The DataSegmentBase class is used as a generic interface for arbitrary DataSegment implementations. Since the DataSegment templates have no own data, a DataSegmentBase instance can simply be reinterpreted as a specific DataSegment-template version. For type-safe converions, the DataSegmentBase::as method can be used. This will reinterpret itself as a special DataSegment-template version and it will also use the runtime-information of the DataSegmentBase to check whether this conversion is allowed. \section _1D_ 1D Vector types The DataSegment class is specialized for 1D-vector types. In this case the access operators (index-operator for linear access, the (x,y)-operator for 2D-organized access), are adapted to not return T-references directly rather than FixedColVector references. \section _EX_ Examples Here are two examples that show some basic use of the DataSegment class. Please note, that usually, the programmes does not need to create DataSegments manually. Instead, e.g. the PointCloudObject-classes provide select-methods, that automatically create DataSegment instances. \code #include #include #include int main(){ Vec data[5]; // linear data xyzh,xyzh,... // wrapper segment for the first 3 floats of every entry/row DataSegment xyz(&data[0][0], sizeof(Vec), 5); // special segment for the last float of the segments DataSegment h(&data[0][3], sizeof(Vec), 5); // xyz.getDim() returns the number of wrapped elements for(int i=0;i(1,2,3); // vector based assginment h[i] = 1; // vector dim. is 1 -> scalar assignment } for(int i=0;i<5;++i){ std::cout << "data[" << i << "]: " << data[i].transp() << std::endl; } } \endcode Here is a more complex example, that shows how to use 2D-organized data segments: \code #include #include #include // utility structure used for demonstration struct DataPoint{ Vec xyz; // 4 floats xyzh icl8u r,g,b,a; // 4 single uchars for r,g,b and alpha Vec normal; // 4 floats for a normal vector int label; // a single int vector }; int main(){ Array2D array(4,3); DataSegment xyz(&array(0,0).xyz[0],sizeof(DataPoint), 12, 4); DataSegment h(&array(0,0).xyz[3],sizeof(DataPoint), 12, 4); DataSegment rgba(&array(0,0).r,sizeof(DataPoint), 12, 4); DataSegment n(&array(0,0).normal[0],sizeof(DataPoint), 12, 4); DataSegment l(&array(0,0).label,sizeof(DataPoint), 12, 4); for(int y=0;y<3;++y){ for(int x=0;x<4;++x){ xyz(x,y) = FixedColVector(x,y,0); h(x,y) = 1; // scalar assignment rgba(x,y) = FixedColVector(x,y,x+y,255); n(x,y) = Vec(1,0,0,1); l(x,y) = x > y ? 1 : 0; // scalar assignment } } } \endcode */ template struct DataSegment : public DataSegmentBase{ /// vector typedef typedef math::FixedColVector VectorType; /// Constructor (basically passes all parameters to the Base class) inline DataSegment(T *data=0, size_t stride=0, size_t numElements=0, icl32s organizedWidth=-1): DataSegmentBase(data,stride,numElements,organizedWidth,icl::core::getDepth(),N){} /// linear index operator inline math::FixedColVector &operator[](int idx) { return *reinterpret_cast*>(data +idx*stride); } /// linear index operator (const) inline const math::FixedColVector &operator[](int idx) const{ return const_cast *>(this)->operator[](idx); } /// 2D-index operator (only for organized data segments) inline math::FixedColVector &operator()(int x, int y) { return operator[](x + organizedWidth * y ); } /// 2D-index operator (only for organized data segments, const) inline const math::FixedColVector &operator()(int x, int y) const{ return operator[](x + organizedWidth * y ); } /// copies the data segment to into another element-wise template inline void deepCopy(DataSegment dst) const throw (utils::ICLException); /// returns whether the data is packed in memory (stride is sizeof(T)*N) inline bool isPacked() const{ return stride == sizeof(T)*N; } /// compares two data segments element wise given given maximun tollerance /** If the source and destination segments have different dimensions, isOrganized flag or organized-size, the check returns always false*/ template inline bool equals(DataSegment dst, float tollerance = 1.0e-5) const { if(getDim() != dst.getDim()) return false; if(isOrganized() != dst.isOrganized()) return false; if(isOrganized() && getSize() != dst.getSize()) return false; const int dim = getDim(); for(int i=0;i tollerance) return false; } } return true; } /// fills each scalar value of each entry with given value /** value is a template parameter, so it can also be a class that can be converted to T elements \code DataSegment ds = ..; fill(ds,URand(0,255)); \endcode */ template inline void fillScalar(Fill scalarValue){ const int dim = getDim(); for(int i=0;i inline void fill(Fill vecValue){ const int dim = getDim(); for(int i=0;i fromVector(std::vector &v){ return DataSegment(v.data(), N*sizeof(T), v.size()/N); } /// wrapps a data-segment around an std::vector (const version) /** if N is not 1, a size of the data-segment becomes v.size()/N, so it uses N consecutive elements of the vector for each entry */ static const DataSegment fromVector(const std::vector &v){ return DataSegment(v.data(), N*sizeof(T), v.size()/N); } }; /** \cond */ template struct DataSegmentDeepCopyUtil{ static void copy(const DataSegment &src, DataSegment &dst){ const int dim = src.getDim(); const bool sp = src.isPacked(), dp = dst.isPacked(); if(sp && dp){ const T *s = (const T*)src.begin(); T *d = (T*)dst.begin(); std::transform(s,s+dim*N,d,icl::utils::clipped_cast); }else if(sp){ const math::FixedColVector *srcpacked = &src[0]; for(int i=0;i *dstpacked = &dst[0]; for(int i=0;i struct DataSegmentDeepCopyUtil{ static void copy(const DataSegment &src, DataSegment &dst){ const int dim = src.getDim(); const bool sp = src.isPacked(), dp = dst.isPacked(); if(sp && dp){ memcpy(dst.getDataPointer(),src.getDataPointer(),dim*sizeof(T)*N); }else if(sp){ const math::FixedColVector *srcpacked = &src[0]; for(int i=0;i *dstpacked = &dst[0]; for(int i=0;i template inline void DataSegment::deepCopy(DataSegment dst) const throw (utils::ICLException){ ICLASSERT_THROW(getDim() == dst.getDim(), utils::ICLException("error in DataSegment::deepCopy " "(source and destination dim differ)")); DataSegmentDeepCopyUtil::copy(*this,dst); } /** \endcond */ /// template specialization for data-segments, where each entry is just 1D /** If the vector entries are 1D only, no extra vector struct is created and returned for the single vector elements. Instead, all access functions operator[idx] and operator(x,y) are will just return T-references instead of math::FixedColVector */ template struct DataSegment : public DataSegmentBase{ /// vector typedef typedef T VectorType; /// Constructor (basically passes all parameters to the Base class) inline DataSegment(T *data=0, size_t stride=0, size_t numElements=0, icl32s organizedWidth=-1): DataSegmentBase(data,stride,numElements,organizedWidth,icl::core::getDepth(),1){} /// linear index operator (specialized to return a T& directly) inline T &operator[](int idx) { return *reinterpret_cast(data +idx*stride); } /// linear index operator (specialized to return a T& directly, const) inline const T &operator[](int idx) const{ return const_cast*>(this)->operator[](idx); } /// 2D-index operator (only for organized data segments, specialized to return a T& directly) inline T &operator()(int x, int y) { return operator[](x + organizedWidth * y ); } /// 2D-index operator (only for organized data segments, specialized to return a T& directly, const) inline const T &operator()(int x, int y) const{ return operator[](x + organizedWidth * y ); } /// copies the data segment to into another element-wise template inline void deepCopy(DataSegment dst) const throw (utils::ICLException){ ICLASSERT_THROW(getDim() == dst.getDim(), utils::ICLException("error in DataSegment::deepCopy " "(source and destination dim differ)")); const int dim = getDim(); for(int i=0;i inline bool equals(DataSegment dst, float tollerance = 1.0e-5) const { if(getDim() != dst.getDim()) return false; if(isOrganized() != dst.isOrganized()) return false; if(isOrganized() && getSize() != dst.getSize()) return false; const int dim = getDim(); for(int i=0;i tollerance) return false; } return true; } /// fills each scalar value of each entry with given value /** equal to fill in this specialization */ template inline void fillScalar(Fill scalarValue){ const int dim = getDim(); for(int i=0;i inline void fill(Fill vecValue){ const int dim = getDim(); for(int i=0;i const DataSegment &DataSegmentBase::as() const{ if(dataDepth != icl::core::getDepth()) throw utils::ICLException("invalid cast of data segment (core::depth is wrong)"); if(elemDim != N) throw utils::ICLException("invalid cast of data segment (dimension is wrong)"); return (DataSegment &)(*this); } /** \endcond */ } // namespace core }