From 28412ff01e6101d39645b76dcc93d46ba10dc187 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= Date: Sun, 19 Apr 2009 22:04:31 +0200 Subject: [PATCH] Reimplemented things working with summed pixels, other fixes. --- debug.cpp | 36 +++- debug.h | 1 + fractal.pro | 5 +- headers.h | 2 + interfaces.cpp | 26 +-- interfaces.h | 215 +++++++++----------- kdTree.h | 7 +- matrixUtil.h | 490 +++++++++++++++++++++++++-------------------- modules/colorModel.cpp | 52 ++--- modules/colorModel.h | 27 ++- modules/quadTree.cpp | 21 +- modules/quadTree.h | 4 +- modules/root.cpp | 24 +-- modules/root.h | 2 +- modules/saupePredictor.cpp | 12 +- modules/squarePixels.cpp | 102 +++++----- modules/squarePixels.h | 26 +-- modules/stdDomains.cpp | 89 ++++---- modules/stdDomains.h | 8 +- modules/stdEncoder.cpp | 36 ++-- util.h | 9 +- 21 files changed, 642 insertions(+), 552 deletions(-) diff --git a/debug.cpp b/debug.cpp index c1cf1e9..2ec4ed9 100644 --- a/debug.cpp +++ b/debug.cpp @@ -27,17 +27,43 @@ QWidget* MRoot::debugModule(QPixmap &pixmap,const QPoint &click) { return dlg; } +namespace NOSPACE { + struct PlaneFinder { + typedef const IColorTransformer::PlaneSettings CPlSet; + + CPlSet* const plSet; + + PlaneFinder(CPlSet *plSet2find): plSet(plSet2find) {} + bool operator()(const IColorTransformer::Plane &plane) + { return plane.settings==plSet; } + }; +} QWidget* MSquarePixels::debugModule(QPixmap &pixmap,const QPoint &click) { + ASSERT( !planeList.empty() ); // create a tab widget QTabWidget *tabs= new QTabWidget; // fill one tab for every job by three sub-tabs with the three modules for (int i=0; i<(int)jobs.size(); ++i) { - if ( jobs[i].ranges->getRangeList().size() == 1 ) + Job &job= jobs[i]; + if ( job.ranges->getRangeList().size() == 1 ) + continue; + // find the plane which is the job from + PlaneList::const_iterator plane= + find_if( planeList.begin(), planeList.end(), PlaneFinder(job.settings) ); + ASSERT( plane != planeList.end() ); + // find out the position of the job in the plane + int xShift=-1, yShift; + plane->pixels.getPosition(job.pixels.start,xShift,yShift); + ASSERT(xShift>=0); + QPoint jobClick= click-QPoint(xShift,yShift); + if ( jobClick.x()<0 || jobClick.y()<0 + || jobClick.x()>=job.width || jobClick.y()>=job.height ) continue; + // make children do the work QTabWidget *tabs2= new QTabWidget; - tabs2->addTab( jobs[i].encoder->debugModule(pixmap,click) , "Encoder" ); - tabs2->addTab( jobs[i].ranges->debugModule(pixmap,click), "Ranges" ); - tabs2->addTab( jobs[i].domains->debugModule(pixmap,click), "Domains" ); + tabs2->addTab( job.encoder->debugModule(pixmap,jobClick) , "Encoder" ); + tabs2->addTab( job.ranges->debugModule(pixmap,jobClick), "Ranges" ); + tabs2->addTab( job.domains->debugModule(pixmap,jobClick), "Domains" ); tabs->addTab( tabs2, QString("Job %1").arg(i+1) ); } @@ -192,7 +218,7 @@ QWidget* MStandardEncoder::debugModule(QPixmap &pixmap,const QPoint &click) { layout->addWidget( new QLabel(msg) ); } - int maxLevel= 1 +log2ceil(max( planeBlock->width(), planeBlock->height() )); + int maxLevel= 1 +log2ceil( max(planeBlock->width,planeBlock->height) ); QTableWidget *table= new QTableWidget( maxLevel-2, 3 ); table->setHorizontalHeaderLabels diff --git a/debug.h b/debug.h index 681b4f5..7dfd6fe 100644 --- a/debug.h +++ b/debug.h @@ -48,4 +48,5 @@ template inline T debugCast(U toCast) { inline void STREAM_POS(std::ios&) {} #endif + #endif // DEBUG_HEADER_ diff --git a/fractal.pro b/fractal.pro index 13793ef..9f64dc6 100644 --- a/fractal.pro +++ b/fractal.pro @@ -21,9 +21,10 @@ CONFIG(debug,debug|release) { } QMAKE_CXXFLAGS_DEBUG *= -ggdb -#-pg +#QMAKE_CXXFLAGS_RELEASE -= -ggdb -QMAKE_CXXFLAGS_RELEASE -= -ggdb +QMAKE_CXXFLAGS_RELEASE *= -frepo -ffunction-sections -msse2 +# profiling support #QMAKE_CXXFLAGS_RELEASE *= -ggdb -pg #QMAKE_LFLAGS_RELEASE *= -ggdb -pg diff --git a/headers.h b/headers.h index 7c68b8f..9f82266 100644 --- a/headers.h +++ b/headers.h @@ -31,3 +31,5 @@ class QWidget; typedef unsigned char Uchar; typedef unsigned short Uint16; typedef unsigned int Uint32; +typedef ptrdiff_t PtrInt; +typedef size_t Uint; diff --git a/interfaces.cpp b/interfaces.cpp index 52dcd0d..f9110fd 100644 --- a/interfaces.cpp +++ b/interfaces.cpp @@ -3,18 +3,8 @@ using namespace std; -const IColorTransformer::Plane IColorTransformer::Plane -::Empty(SMatrix(),-1,-1,-1,0,UpdateInfo()); - -void IQuality2SquareError::completeSquareRangeErrors -( float quality, int levelEnd, float *errors ) { - ASSERT( checkBoundsFunc(0,quality,1)==quality && levelEnd>2 && errors ); - - float (IQuality2SquareError::*func)(float,int)= &IQuality2SquareError::rangeSE; - - for (int level=2; level*func)( quality, powers[level*2] ); -} +//const IColorTransformer::PlaneSettings IColorTransformer::PlaneSettings +//::Empty(0,0,-1,-1,-1,0,UpdateInfo()); bool IRoot::allSettingsToFile(const char *fileName) { try { @@ -41,3 +31,15 @@ bool IRoot::allSettingsFromFile(const char *fileName) { return false; } } + + + +void IQuality2SquareError +::completeSquareRangeErrors( float quality, int levelEnd, float *errors ) { + ASSERT( checkBoundsFunc(0,quality,1)==quality && levelEnd>2 && errors ); + + float (IQuality2SquareError::*func)(float,int)= &IQuality2SquareError::rangeSE; + + for (int level=2; level*func)( quality, powers[level*2] ); +} diff --git a/interfaces.h b/interfaces.h index 18ef73b..9cd338c 100644 --- a/interfaces.h +++ b/interfaces.h @@ -20,20 +20,24 @@ namespace MTypes { typedef double Real; ///< The floating-point type in which most computations are made typedef float SReal; ///< The floating-point type for long-term pixel-value storage - typedef MatrixSummer BlockSummer; ///< Summer instanciation used for pixels - typedef Matrix SMatrix; - typedef Matrix CSMatrix; - typedef std::vector< Matrix > MatrixList; + //typedef MatrixSummer BlockSummer; ///< Summer instanciation used for pixels + typedef MatrixSlice SMatrix; + typedef SMatrix::Const CSMatrix; + typedef std::vector MatrixList; enum DecodeAct { Clear, Iterate }; ///< Possible decoding actions struct PlaneBlock; + + typedef SummedMatrix SummedPixels; } namespace NOSPACE { using namespace std; using namespace MTypes; } + + /** \defgroup interfaces Interfaces for coding modules * @{ */ @@ -47,8 +51,8 @@ struct IRoot: public Interface { Decode ///< contains an image decoded from a file }; - static const Uint16 Magic= 65535-4063 /// magic number - integer identifying FIC files - , SettingsMagic= Magic^12345; /// magic number - integer identifying settings files + static const Uint16 Magic= 65535-4063 /// magic number - integer identifying FIC files + , SettingsMagic= Magic^12345; ///< magic number - integer identifying settings files /** A status-query method */ virtual Mode getMode() =0; @@ -62,7 +66,7 @@ struct IRoot: public Interface { /** Saves an encoded image into a stream, returns true on success */ virtual bool toStream(std::ostream &file) =0; - /** Loads image from a file - returns true on success (to be run on a shallow module), + /** Loads image from a file - returns true on success (to be run on in Clear state), * can load in bigger size: dimension == orig_dim*2^\p zoom */ virtual bool fromStream(std::istream &file,int zoom=0) =0; @@ -81,58 +85,64 @@ struct IRoot: public Interface { bool allSettingsToFile(const char *fileName); /** Loads all settings from a file (to be run on a shallow module), returns true on success */ bool allSettingsFromFile(const char *fileName); -}; +}; // IRoot interface + /** Interface for modules performing color transformations, * following modules always work with single-color (greyscale) images */ struct IColorTransformer: public Interface { - /** Describes a rectangular single-color image, includes some compression setings */ - struct Plane { + /** Contains some setings for one color plane of an image */ + struct PlaneSettings { typedef IQuality2SquareError ModuleQ2SE; - static const Plane Empty; ///< an empty instance - - SMatrix pixels; ///< a Matrix of pixels with values in [0,1], not owned (shared) - SReal quality; ///< encoding quality for the plane, in [0,1] (higher is better) - int domainCountLog2 /// 2-logarithm of the maximum domain count - , zoom; ///< the zoom + //static const PlaneSettings Empty; ///< an empty instance + + int width /// the width of the image (zoomed) + , height /// the height of the image (zoomed) + , domainCountLog2 /// 2-logarithm of the maximum domain count + , zoom; ///< the zoom (dimensions multiplied by 2^zoom) + SReal quality; ///< encoding quality for the plane, in [0,1] (higher is better) ModuleQ2SE *moduleQ2SE; ///< pointer to the module computing maximum SE (not owned) UpdateInfo updateInfo; ///< structure for communication with user - + /** A simple constructor, only initializes the values from the parameters */ - Plane( SMatrix pixels_, float quality_, int domainCountLog2_ - , int zoom_, ModuleQ2SE *moduleQ2SE_, const UpdateInfo &updateInfo_ ) - : pixels(pixels_), quality(quality_), domainCountLog2(domainCountLog2_) - , zoom(zoom_), moduleQ2SE(moduleQ2SE_), updateInfo(updateInfo_) {} + PlaneSettings( int width_, int height_, int domainCountLog2_, int zoom_ + , SReal quality_=numeric_limits::quiet_NaN() + , ModuleQ2SE *moduleQ2SE_=0, const UpdateInfo &updateInfo_=UpdateInfo() ) + : width(width_), height(height_) + , domainCountLog2(domainCountLog2_), zoom(zoom_) + , quality(quality_), moduleQ2SE(moduleQ2SE_), updateInfo(updateInfo_) {} + }; // PlaneSettings struct + + struct Plane { + mutable SMatrix pixels; ///< a matrix of pixels with values in [0,1], not owned + const PlaneSettings *settings; ///< the settings for the plane, not owned }; - /** List of planes */ + + /** List of planes, in returned vectors the pointed to memory is owned by the module */ typedef std::vector PlaneList; - /** Splits an image into color-planes and adjusts their quality and max.\ domain count */ - virtual PlaneList image2planes(const QImage &toEncode,const Plane &prototype) =0; - /** Merges planes back into a color image */ - virtual QImage planes2image(const MatrixList &pixels,int width,int height) =0; + /** Splits an image into color-planes and adjusts their settings (from \p prototype) */ + virtual PlaneList image2planes(const QImage &toEncode,const PlaneSettings &prototype) =0; + /** Merges planes back into a color image (only useful when decoding) */ + virtual QImage planes2image() =0; /** Writes any data needed for plane reconstruction to a stream */ virtual void writeData(std::ostream &file) =0; - /** Reads any data needed for plane reconstruction from a stream and creates the plane list - * (the dimensions are already zoomed) */ - virtual PlaneList readData( std::istream &file, const Plane &prototype - , int width, int height ) =0; -}; + /** Reads any data needed for plane reconstruction from a stream and creates the plane list */ + virtual PlaneList readData( std::istream &file, const PlaneSettings &prototype ) =0; +}; // IColorTransformer interface + /** Interface for modules handling pixel-shape changes * and/or splitting the single-color planes into independently processed parts */ struct IShapeTransformer: public Interface { typedef IColorTransformer::PlaneList PlaneList; - /** Creates jobs from the list of color planes (the dimensions are zoomed, - * takes the ownership of pixels and returns job count) */ - virtual int createJobs( const PlaneList &planes, int width, int height ) =0; + /** Creates jobs from the list of color planes, returns job count */ + virtual int createJobs(const PlaneList &planes) =0; /** Returns the number of jobs */ virtual int jobCount() =0; - /** Creates a plane list referencing current decoding state */ - virtual MatrixList collectJobs() =0; /** Starts encoding a job - thread-safe (for different jobs) */ virtual void jobEncode(int jobIndex) =0; @@ -148,19 +158,20 @@ struct IShapeTransformer: public Interface { /** Returns the number of phases (progressive encoding), only depends on settings */ virtual int phaseCount() =0; /** Writes any data needed for reconstruction of every job, phase parameters - * determine the interval of saved phases */ + * determine the range of saved phases */ virtual void writeJobs(std::ostream &file,int phaseBegin,int phaseEnd) =0; /** Reads all data needed for reconstruction of every job and prepares for encoding, * parameters like #writeJobs */ virtual void readJobs (std::istream &file,int phaseBegin,int phaseEnd) =0; - /** Shortcut - default parametres "phaseBegin=0,phaseEnd=phaseCount()" */ + /** Shortcut - default parameters "phaseBegin=0,phaseEnd=phaseCount()" */ void writeJobs(std::ostream &file,int phaseBegin=0) { writeJobs( file, phaseBegin, phaseCount() ); } - /** Shortcut - default parametres "phaseBegin=0,phaseEnd=phaseCount()" */ + /** Shortcut - default parameters "phaseBegin=0,phaseEnd=phaseCount()" */ void readJobs(std::istream &file,int phaseBegin=0) { readJobs( file, phaseBegin, phaseCount() ); } -}; +}; // IShapeTransformer interface + /** Interface for modules deciding how the max.\ SE will depend on block size * (parametrized by quality) */ @@ -172,12 +183,13 @@ struct IQuality2SquareError: public Interface { void completeSquareRangeErrors(float quality,int levelEnd,float *squareErrors); }; + /** Interface for modules that control how the image - * will be split into (mostly) square range blocks */ + * will be split into rectangular (mostly square) range blocks */ struct ISquareRanges: public Interface { /** Structure representing a rectangular range block (usually square) */ struct RangeNode: public Block { - /** A common base for data stored by encoders */ + /** A common base type for data stored by encoders */ struct EncoderData { float bestSE; }; @@ -189,7 +201,7 @@ struct ISquareRanges: public Interface { /** Checks whether the block has regular shape (dimensions equal to 2^level) */ bool isRegular() const - { return width()==powers[(int)level] && height()==powers[(int)level]; } + { return width()==powers[level] && height()==powers[level]; } protected: /** Constructor - initializes #encoderData to zero, to be used by derived classes */ RangeNode(const Block &block,int level_) @@ -209,46 +221,27 @@ struct ISquareRanges: public Interface { /** Writes data needed for reconstruction (except for settings) */ virtual void writeData(std::ostream &file) =0; - /** Reads data from a stream and reconstructs range blocks. + /** Reads data from a stream and reconstructs the positions of range blocks. * \param file the stream to read from * \param block the position and size of the block in the plane to be reconstructed (with zoom) * \param zoom the zoom to decode with */ - virtual void readData_buildRanges( std::istream &file, const Block &block, int zoom ) =0; -}; + virtual void readData_buildRanges( std::istream &file, const PlaneBlock &block ) =0; +}; // ISquareRanges interface + /** Interface for modules deciding what will square domain blocks look like */ struct ISquareDomains: public Interface { /** Describes one domain pool */ - struct Pool { - short width /// The width of the pool (zoomed) - , height; ///< The height of the pool (zoomed) - SMatrix pixels; /// PoolList; @@ -256,7 +249,7 @@ struct ISquareDomains: public Interface { /** Initializes the pools for given PlaneBlock, assumes settings are OK */ virtual void initPools(const PlaneBlock &planeBlock) =0; /** Prepares domains in already initialized pools (and fills summers, etc.) */ - virtual void fillPixelsInPools(const PlaneBlock &planeBlock) =0; + virtual void fillPixelsInPools(PlaneBlock &planeBlock) =0; /** Returns a reference to internal list of domain pools */ virtual const PoolList& getPools() const =0; @@ -273,7 +266,8 @@ struct ISquareDomains: public Interface { virtual void writeData(std::ostream &file) =0; /** Reads all data, assumes the settings have already been read */ virtual void readData(std::istream &file) =0; -}; +}; // ISquareDomains interface + /** Interface for square encoders - maintaining mappings from square domains to square ranges */ struct ISquareEncoder: public Interface { @@ -309,7 +303,7 @@ struct ISquareEncoder: public Interface { /** Reads one phase of data needed for recostruction, * assumes the settings have been read previously via #readSettings */ virtual void readData(std::istream &file,int phase) =0; -}; +}; // ISquareEncoder interface /** Interface for domain-range mapping predictors for MStandardEncoder */ struct IStdEncPredictor: public Interface { @@ -367,7 +361,7 @@ struct IStdEncPredictor: public Interface { virtual IOneRangePredictor* newPredictor(const NewPredictorData &data) =0; /** Releases common resources (called when encoding is complete) */ virtual void cleanUp() =0; -}; +}; // IStdEncPredictor interface /** Integer sequences (de)coder interface */ struct IIntCodec: public Interface { @@ -385,56 +379,33 @@ struct IIntCodec: public Interface { }; /// @} - interfaces defgroup + namespace MTypes { - /** Represents a rectangle in a color plane (using square pixels), - * the inherited Block represents zoomed coordinates */ - struct PlaneBlock: public ISquareEncoder::Plane, public Block { - BlockSummer summers[2]; ///< normal and squares summers for the pixels + /** Represents a rectangular piece of single-color image to be encoded/decoded. + * TODO... */ + struct PlaneBlock: public SummedPixels { + typedef IColorTransformer::PlaneSettings PlaneSettings; + + const PlaneSettings *settings; ///< the settings for the plane, not owned ISquareRanges *ranges; ///< module for range blocks generation ISquareDomains *domains;///< module for domain blocks generation ISquareEncoder *encoder;///< module for encoding (maintaining domain-range mappings) - - /** Simple constructor, just initializes members with parameters and checks for zeroes */ - PlaneBlock( const Plane &plane, const Block &range - , ISquareRanges *ranges_, ISquareDomains *domains_, ISquareEncoder *encoder_ ) - : Plane(plane), Block(range), ranges(ranges_), domains(domains_), encoder(encoder_) - { ASSERT( ranges && domains && encoder ); } - /** Just deletes the modules (the destructor is empty, - * #free has to be called explicitly if needed) */ - void free() { - delete ranges; - delete domains; - delete encoder; - } - - /** Returns #pixels shifted into the correct position */ - CSMatrix getShiftedPixels() const { - CSMatrix result= pixels; - result.shiftMatrix(x0,y0); - return result; + + /** Just deletes the modules and calls SummedPixels::free + * (the destructor is empty, #free has to be called explicitly if needed) */ + void free(bool freePixels=true) { + delete ranges; ranges= 0; + delete domains; domains= 0; + delete encoder; encoder= 0; + settings= 0; + SummedPixels::free(freePixels); + //TODO zeroing in debug mode only?? } - /** A simple integrity test - needs nonzero modules and pixel-matrix */ bool isReady() const - { return this && ranges && domains && encoder && pixels.isValid() && moduleQ2SE; } - /** Just validates both summers (if needed) */ - void summers_makeValid() const { - for (int i=0; i<2; ++i) - if ( !summers[i].isValid() ) - constCast(summers[i]).fill - ( pixels, (BlockSummer::SumType)i, width(), height(), x0, y0 ); - } - /** Justs invalidates both summers (to be called after changes in the pixel-matrix) */ - void summers_invalidate() const { - constCast(summers[0]).invalidate(); - constCast(summers[1]).invalidate(); - } - /** A shortcut for getting sums from summers relative to the block's coordinates */ - BlockSummer::Result getSum( const Block &block, BlockSummer::SumType type ) const { - return summers[type].getSum( block.x0-x0, block.y0-y0, block.xend-x0, block.yend-y0 ); - } - };// PlaneBlock struct + { return this && ranges && domains && encoder && pixels.isValid(); } + + }; // PlaneBlock struct } - #endif // INTERFACES_HEADER_ diff --git a/kdTree.h b/kdTree.h index 46cdc3d..f8d738c 100644 --- a/kdTree.h +++ b/kdTree.h @@ -259,7 +259,7 @@ void KDTree::PointHeap::makeTopLeaf() { // exit if there's a leaf on the top already if ( !(heap[0].nodeIndex0 && count>1 && chooser && data ); + ASSERT( length>0 && count>0 && chooser && data ); // create the index-vector, coumpute the bounding box, build the tree for (int i=0; i1) + buildNode(1,dataIDs,dataIDs+count,depth); delete[] chooserTmp; DEBUG_ONLY( chooserTmp= 0; ) } diff --git a/matrixUtil.h b/matrixUtil.h index 8b10a13..c1527bf 100644 --- a/matrixUtil.h +++ b/matrixUtil.h @@ -24,42 +24,29 @@ struct Block { /** A simple generic template for matrices of fixed size, uses shallow copying * and manual memory management */ -template class Matrix { -public: - friend class Matrix< typename NonConstType::Result, I >; ///< because of conversion - typedef Matrix ConstMatrix; ///< the class is convertible to ConstMatrix +template struct MatrixSlice { + typedef MatrixSlice Const; ///< the class is convertible to Const type -protected: T *start; ///< pointer to the top-left pixel I colSkip; ///< how many pixels to skip to get in the next column - DEBUG_ONLY(I width;); -public: - /** Initializes an empty matrix */ - Matrix() - : start(0) {} - - /** Allocates a matrix of given size via #allocate (see for details) */ - Matrix( I width_, I height_, T *memory=0 ) - : start(0) - { allocate(width_,height_,memory); } - - /** Creates a shallow copy */ - Matrix(const Matrix &m) - : start(m.start), colSkip(m.colSkip) - { DEBUG_ONLY( width= m.width; ); } + + /** Initializes an empty slice */ + MatrixSlice(): start(0) {} + + /** Creates a shallow copy (deleting one destroys all copies) */ + MatrixSlice(const MatrixSlice &m): start(m.start), colSkip(m.colSkip) {} /** Converts to a matrix of constant objects (shallow copy) */ - operator ConstMatrix() const { - ConstMatrix result; + operator Const() const { + Const result; result.start= start; result.colSkip= colSkip; - DEBUG_ONLY( result.width= width; ) return result; } /** Indexing operator - returns pointer to a column */ T* operator[](I column) { - ASSERT( start && /*column>=0 &&*/ column0 && height>0 ); free(); - start= memory ? memory : new T[width_*height_]; - colSkip= height_; - DEBUG_ONLY( width= width_; ) + start= memory ? memory : new T[width*height]; + colSkip= height; } /** Releases the memory */ void free() { @@ -87,7 +74,7 @@ public: /** Fills a submatrix of a valid matrix with a value */ void fillSubMatrix(const Block &block,T value) { - ASSERT( isValid() && T(block.xend)<=width ); + ASSERT( isValid() ); // compute begin and end column starts T *begin= start+block.y0+colSkip*block.x0 , *end= start+block.y0+colSkip*block.xend; @@ -95,281 +82,349 @@ public: for (T *it= begin; it!=end; it+= colSkip) std::fill( it, it+block.height(), value ); } -/** \name Low-level functions - * mainly for use by image iterators, etc. - * @{ */ /** Shifts the indexing of this matrix - dangerous. * After calling this, only addressing or more shifts can be done (not checked). * Also shifts out of the allocated matrix aren't detected */ - void shiftMatrix(I x0,I y0) { + MatrixSlice& shiftMatrix(I x0,I y0) { ASSERT( isValid() ); - start+= x0+y0*colSkip; - DEBUG_ONLY( width-= x0; ); - ASSERT(width>0); + start+= x0*colSkip+y0; + return *this; } - /** Returns internal pointer #start */ - T* getStart() { return start; } - /** Returns internal value #colSkip */ - I getColSkip() const { return colSkip; } -/// @} -}; // Matrix class template - + /** Computes relative position of a pointer in the matrix (always 0 <= \p y < #colSkip) */ + void getPosition(const T *elem,int &x,int &y) const { + ASSERT( isValid() ); + PtrInt diff= elem-start; + if (diff>=0) { + x= diff/colSkip; + y= diff%colSkip; + } else { + x= -((-diff-1)/colSkip) -1; + y= colSkip - (-diff-1)%colSkip -1; + } + } +}; // MatrixSlice class template /** MatrixSummer objects store partial sums of a matrix, allowing quick computation * of sum of any rectangle in the matrix. It's parametrized by "type of the result", - * "type of the input" and "indexing type" (defaults to size_t) */ -template class MatrixSummer { -public: + * "type of the input" and "indexing type" (defaults to Int) */ +template struct MatrixSummer { typedef T Result; - typedef Matrix InpMatrix; - /** The type of filling the summer - normal sums, sums of squares */ - enum SumType { Values=0, Squares=1 }; -private: - Matrix sums; ///< Internal matrix containing precomputed partial sums + MatrixSlice sums; ///< Internal matrix containing precomputed partial sums -public: +#ifndef NDEBUG /** Creates an empty summer */ MatrixSummer() {} - /** Creates a summer filled from a matrix */ - MatrixSummer( InpMatrix m, SumType sumType, I width, I height ) - { fill(m,sumType,width,height); } - /** Frees the resources */ - ~MatrixSummer() - { sums.free(); } - /** Only empty objects are allowed to be copied (assertion) */ - MatrixSummer( const MatrixSummer &DEBUG_ONLY(other) ) + MatrixSummer( const MatrixSummer &other ) { ASSERT( !other.isValid() ); } /** Only empty objects are allowed to be assigned (assertion) */ - MatrixSummer& operator=( const MatrixSummer &DEBUG_ONLY(other) ) - { return ASSERT( !other.isValid() && !isValid() ), *this; } + MatrixSummer& operator=( const MatrixSummer &other ) + { ASSERT( !other.isValid() && !isValid() ); return *this; } +#endif /** Returns whether the object is filled with data */ - bool isValid() const - { return sums.isValid(); } + bool isValid() const { return sums.isValid(); } /** Clears the object */ - void invalidate() - { sums.free(); }; + void free() { sums.free(); }; - /** Prepares object to make sums for a matrix. If the summer has already been used before, - * the method assumes it was for a matrix of the same size */ - void fill(InpMatrix m,SumType sumType,I width,I height,I x0=0,I y0=0) { - ASSERT( m.isValid() && (sumType==Values || sumType==Squares) ); - - m.shiftMatrix(x0,y0); + /** Computes the sum of a rectangle (in constant time) */ + Result getSum(I x0,I y0,I xend,I yend) const { + ASSERT( sums.isValid() ); + return sums[xend][yend] -sums[x0][yend] -sums[xend][y0] +sums[x0][y0]; + } + /** A shortcut to get the sum of a block */ + Result getSum(const Block &b) const + { return getSum( b.x0, b.y0, b.xend, b.yend ); } + /** Prepares object to make sums for a matrix. If the summer has already been + * used before, the method assumes it was for a matrix of the same size */ + template void fill(Input inp,I width,I height) { if ( !sums.isValid() ) sums.allocate(width+1,height+1); - I yEnd= height+y0; // fill the edges with zeroes for (I i=0; i<=width; ++i) sums[i][0]= 0; for (I j=1; j<=height; ++j) sums[0][j]= 0; // acummulate in the y-growing direction - if (sumType==Values) - for (I i=1; i<=width; ++i) - for (I j=1; j<=yEnd; ++j) - sums[i][j]= sums[i][j-1]+m[i-1][j-1]; - else // sumType==Squares - for (I i=1; i<=width; ++i) - for (I j=1+y0; j<=yEnd; ++j) - sums[i][j]= sums[i][j-1]+sqr(m[i-1][j-1]); + for (I i=1; i<=width; ++i) + for (I j=1; j<=height; ++j) + sums[i][j]= sums[i][j-1] + Result(inp[i-1][j-1]); // acummulate in the x-growing direction for (I i=2; i<=width; ++i) - for (I j=1+y0; j<=yEnd; ++j) + for (I j=1; j<=height; ++j) sums[i][j]+= sums[i-1][j]; } - - /** Computes the sum of a rectangle (in constant time) */ - Result getSum(I x0,I y0,I xend,I yend) const { - ASSERT( sums.isValid() && xend>x0 && yend>y0 ); /*x0>=0 && y0>=0 && xend>=0 && yend>=0 &&*/ - return sums[xend][yend] -sums[x0][yend] -sums[xend][y0] +sums[x0][y0]; - } }; // MatrixSummer class template -/** Contains various iterators for matrices (see Matrix) - * to be used in walkOperate() and walkOperateCheckRotate() */ -namespace MatrixWalkers { - - /** Performs manipulations with rotation codes 0-7 (dihedral group of order eight) */ - struct Rotation { - /** Asserts the parameter is within 0-7 */ - static void check(int DEBUG_ONLY(r)) { - ASSERT( 0<=r && r<8 ); - } - /** Returns inverted rotation (the one that takes this one back to identity) */ - static int invert(int r) { - check(r); - return (4-r/2)%4 *2 +r%2; - } - /** Computes rotation equal to projecting at first with \p r1 and the result with \p r2 */ - static int compose(int r1,int r2) { - check(r1); check(r2); - if (r2%2) - r1= invert(r1); - return (r1/2 + r2/2) %4 *2+ ( (r1%2)^(r2%2) ); - } - }; - - /** Checked_ iterator for a rectangle in a matrix, no rotation */ - template class Checked { - public: - typedef Matrix TMatrix; - protected: - I colSkip /// offset of the "next row" - , height; ///< height of the iterated rectangle - T *col /// pointer the current column - , *colEnd /// pointer to the end column - , *elem /// pointer to the current element - , *elemsEnd; ///< pointer to the end element of the current column - - public: - /** Initializes a new iterator for a \p block of \p pixels */ - Checked( TMatrix pixels, const Block &block ) - : colSkip ( pixels.getColSkip() ) - , height ( block.height() ) - , col ( pixels.getStart()+block.y0+colSkip*block.x0 ) - , colEnd ( pixels.getStart()+block.y0+colSkip*block.xend ) { - DEBUG_ONLY( elem= elemsEnd= 0; ) - ASSERT( block.xend>block.x0 && block.yend>block.y0 ); +/** Helper structuree for computing with value and squared sums at once */ +template struct DoubleNum { + Num value, square; + + DoubleNum() + { DEBUG_ONLY( value= square= std::numeric_limits::quiet_NaN(); ) } + + DoubleNum(Num val) + : value(val), square(sqr(val)) {} + + DoubleNum(const DoubleNum &other) + : value(other.value), square(other.square) {} + + void unpack(Num &val,Num &sq) const { val= value; sq= square; } + + DoubleNum& operator+=(const DoubleNum &other) { + value+= other.value; + square+= other.square; + return *this; + } + DoubleNum& operator-=(const DoubleNum &other) { + value-= other.value; + square-= other.square; + return *this; + } + friend DoubleNum operator+(const DoubleNum &a,const DoubleNum &b) + { return DoubleNum(a)+= b; } + friend DoubleNum operator-(const DoubleNum &a,const DoubleNum &b) + { return DoubleNum(a)-= b; } +}; // DoubleNum template struct + + +template< class SumT, class PixT, class I=PtrInt > +struct SummedMatrix { + typedef DoubleNum BSumRes; + typedef MatrixSummer BSummer; + + I width /// The width of #pixels + , height; ///< The height of #pixels + MatrixSlice pixels; ///< The matrix of pixels + BSummer summer; ///< Summer for values and squares of #pixels + bool sumsValid; ///< Indicates whether the summer values are valid + + /** Sets the size of #pixels, optionally allocates memory */ + void setSize( I width_, I height_, bool allocPixels=true ) { + free(); + width= width_; + height= height_; + if (allocPixels) + pixels.allocate(width,height); + } + /** Frees the memory */ + void free(bool freePixels=true) { + if (freePixels) + pixels.free(); + else + pixels.start= 0; + summer.free(); + sumsValid= false; + } + + /** Just validates both summers (if needed) */ + void summers_makeValid() const { + ASSERT(pixels.isValid()); + if (!sumsValid) { + constCast(summer).fill(pixels,width,height); + constCast(sumsValid)= true; } + } + /** Justs invalidates both summers (to be called after changes in the pixel-matrix) */ + void summers_invalidate() + { sumsValid= false; } + /** A shortcut for getting sums of a block */ + BSumRes getSums(const Block &block) const + { return getSums( block.x0, block.y0, block.xend, block.yend ); } + /** Gets both sums of a nonempty rectangle in #pixels, the summer isn't validated */ + BSumRes getSums( I x0, I y0, I xend, I yend ) const { + ASSERT( sumsValid && x0>=0 && y0>=0 && xend>x0 && yend>y0 + && xend<=width && yend<=height ); + return summer.getSum(x0,y0,xend,yend); + } +}; // SummedPixels template struct - bool outerCond() { return col!=colEnd; } - void outerStep() { col+= colSkip; } - - void innerInit() { elem= col; elemsEnd= col+height; } - bool innerCond() { return elem!=elemsEnd; } - void innerStep() { ++elem; } - - T& get() { return *elem; } - }; // Checked class template - - /** Checked_ iterator for a whole QImage; no rotation, but always transposed */ - template struct CheckedImage { - typedef T QImage; - typedef U QRgb; - protected: - QImage &img; ///< reference to the image - int lineIndex; ///< index of the current line - QRgb *line /// pointer to the current pixel - , *lineEnd; ///< pointer to the end of the line - - public: - /** Initializes a new iterator for an instance of QImage (Qt class) */ - CheckedImage(QImage &image) - : img(image), lineIndex(0) - { DEBUG_ONLY(line=lineEnd=0;) } - bool outerCond() { return lineIndex struct RotBase { + template struct RotBase { public: - typedef Matrix MType; + typedef MatrixSlice TMatrix; protected: - const I colSkip; ///< the number of elements to skip to get on the next column - T *list /// points to the beginning of the current column/row - , *elem; ///< points to the current element + TMatrix current; ///< matrix starting on the current element + T *lastStart; ///< the place of the last enter of the inner loop public: - RotBase( MType matrix, I x0, I y0 ) - : colSkip( matrix.getColSkip() ), list( matrix.getStart()+y0+colSkip*x0 ) - { DEBUG_ONLY( elem= 0; ) } + RotBase( TMatrix matrix, int x0, int y0 ) + : current( matrix.shiftMatrix(x0,y0) ), lastStart(current.start) { + DEBUG_ONLY( current.start= 0; ) + ASSERT( matrix.isValid() ); + } - void innerInit() { elem= list; } - T& get() { return *elem; } + void innerInit() { current.start= lastStart; } + T& get() { return *current.start; } }; // RotBase class template #define ROTBASE_INHERIT \ - using RotBase::colSkip; \ - using RotBase::list; \ - using RotBase::elem; \ - typedef Matrix MType; - + typedef typename RotBase::TMatrix TMatrix; \ + using RotBase::current; \ + using RotBase::lastStart; /** No rotation: x->, y-> */ template struct Rotation_0: public RotBase { ROTBASE_INHERIT - Rotation_0( MType matrix, const Block &block ) + Rotation_0( TMatrix matrix, const Block &block ) : RotBase( matrix, block.x0, block.y0 ) {} - void outerStep() { list+= colSkip; } - void innerStep() { ++elem; } + void outerStep() { lastStart+= current.colSkip; } + void innerStep() { ++current.start; } }; /** Rotated 90deg\. cw\., transposed: x<-, y-> */ template struct Rotation_1_T: public RotBase { ROTBASE_INHERIT - Rotation_1_T( MType matrix, const Block &block ) + Rotation_1_T( TMatrix matrix, const Block &block ) : RotBase( matrix, block.xend-1, block.y0 ) {} - void outerStep() { list-= colSkip; } - void innerStep() { ++elem; } + void outerStep() { lastStart-= current.colSkip; } + void innerStep() { ++current.start; } }; /** Rotated 180deg\. cw\.: x<-, y<- */ template struct Rotation_2: public RotBase { ROTBASE_INHERIT - Rotation_2( MType matrix, const Block &block ) + Rotation_2( TMatrix matrix, const Block &block ) : RotBase( matrix, block.xend-1, block.yend-1 ) {} - void outerStep() { list-= colSkip; } - void innerStep() { --elem; } + void outerStep() { lastStart-= current.colSkip; } + void innerStep() { --current.start; } }; /** Rotated 270deg\. cw\., transposed: x->, y<- */ template struct Rotation_3_T: public RotBase { ROTBASE_INHERIT - Rotation_3_T( MType matrix, const Block &block ) + Rotation_3_T( TMatrix matrix, const Block &block ) : RotBase( matrix, block.x0, block.yend-1 ) {} - void outerStep() { list+= colSkip; } - void innerStep() { --elem; } + void outerStep() { lastStart+= current.colSkip; } + void innerStep() { --current.start; } }; /** No rotation, transposed: y->, x-> */ template struct Rotation_0_T: public RotBase { ROTBASE_INHERIT - Rotation_0_T( MType matrix, const Block &block ) + Rotation_0_T( TMatrix matrix, const Block &block ) : RotBase( matrix, block.x0, block.y0 ) {} - void outerStep() { ++list; } - void innerStep() { elem+= colSkip; } + void outerStep() { ++lastStart; } + void innerStep() { current.start+= current.colSkip; } }; /** Rotated 90deg\. cw\.: y->, x<- */ template struct Rotation_1: public RotBase { ROTBASE_INHERIT - Rotation_1( MType matrix, const Block &block ) + Rotation_1( TMatrix matrix, const Block &block ) : RotBase( matrix, block.xend-1, block.y0 ) {} - void outerStep() { ++list; } - void innerStep() { elem-= colSkip; } + void outerStep() { ++lastStart; } + void innerStep() { current.start-= current.colSkip; } }; /** Rotated 180deg\. cw\., transposed: y<-, x<- */ template struct Rotation_2_T: public RotBase { ROTBASE_INHERIT - Rotation_2_T( MType matrix, const Block &block ) + Rotation_2_T( TMatrix matrix, const Block &block ) : RotBase( matrix, block.xend-1, block.yend-1 ) {} - void outerStep() { --list; } - void innerStep() { elem-= colSkip; } + void outerStep() { --lastStart; } + void innerStep() { current.start-= current.colSkip; } }; /** Rotated 270deg\. cw\.: y<-, x-> */ template struct Rotation_3: public RotBase { ROTBASE_INHERIT - Rotation_3( MType matrix, const Block &block ) + Rotation_3( TMatrix matrix, const Block &block ) : RotBase( matrix, block.x0, block.yend-1 ) {} - void outerStep() { --list; } - void innerStep() { elem+= colSkip; } + void outerStep() { --lastStart; } + void innerStep() { current.start+= current.colSkip; } }; + + + /** Performs manipulations with rotation codes 0-7 (dihedral group of order eight) */ + struct Rotation { + /** Asserts the parameter is within 0-7 */ + static void check(int DEBUG_ONLY(r)) { + ASSERT( 0<=r && r<8 ); + } + /** Returns inverted rotation (the one that takes this one back to identity) */ + static int invert(int r) { + check(r); + return (4-r/2)%4 *2 +r%2; + } + /** Computes rotation equal to projecting at first with \p r1 and the result with \p r2 */ + static int compose(int r1,int r2) { + check(r1); check(r2); + if (r2%2) + r1= invert(r1); + return (r1/2 + r2/2) %4 *2+ ( (r1%2)^(r2%2) ); + } + }; // Rotation struct + + /** Checked_ iterator for a rectangle in a matrix, no rotation */ + template struct Checked: public Rotation_0 { + typedef MatrixSlice TMatrix; + typedef Rotation_0 Base; + using Base::current; + using Base::lastStart; + + T *colEnd /// the end of the current column + , *colsEndStart; ///< the start of the end column + + /** Initializes a new iterator for a \p block of \p pixels */ + Checked( TMatrix pixels, const Block &block ) + : Base( pixels, block ), colEnd( pixels.start+pixels.colSkip*block.x0+block.yend ) + , colsEndStart( pixels.start+pixels.colSkip*block.xend+block.y0 ) { + ASSERT( block.xend>block.x0 && block.yend>block.y0 ); + } + + bool outerCond() { + ASSERT(lastStart<=colsEndStart); + return lastStart!=colsEndStart; + } + void outerStep() { + colEnd+= current.colSkip; + Base::outerStep(); + } + bool innerCond() { + ASSERT(current.start<=colEnd); + return current.start!=colEnd; + } + }; // Checked class template + + /** Checked_ iterator for a whole QImage; no rotation, but always transposed */ + template struct CheckedImage { + typedef T QImage; + typedef U QRgb; + protected: + QImage &img; ///< reference to the image + int lineIndex /// index of the current line + , width /// the width of the image + , height; ///< the height of the image + QRgb *line /// pointer to the current pixel + , *lineEnd; ///< pointer to the end of the line + + public: + /** Initializes a new iterator for an instance of QImage (Qt class) */ + CheckedImage(QImage &image) + : img(image), lineIndex(0), width(image.width()), height(image.height()) + { DEBUG_ONLY(line=lineEnd=0;) } + + bool outerCond() { return lineIndex inline Operator walkOperateCheckRotate - ( Check checked, Operator oper, Matrix pixels2, const Block &block2, char rotation) { - typedef size_t I; + template + inline Operator walkOperateCheckRotate( Check checked, Operator oper + , MatrixSlice pixels2, const Block &block2, char rotation) { + typedef PtrInt I; switch (rotation) { - case 0: return walkOperate( checked, Rotation_0 (pixels2,block2) , oper ); - case 1: return walkOperate( checked, Rotation_0_T(pixels2,block2) , oper ); - case 2: return walkOperate( checked, Rotation_1 (pixels2,block2) , oper ); - case 3: return walkOperate( checked, Rotation_1_T(pixels2,block2) , oper ); - case 4: return walkOperate( checked, Rotation_2 (pixels2,block2) , oper ); - case 5: return walkOperate( checked, Rotation_2_T(pixels2,block2) , oper ); - case 6: return walkOperate( checked, Rotation_3 (pixels2,block2) , oper ); - case 7: return walkOperate( checked, Rotation_3_T(pixels2,block2) , oper ); - default: ASSERT(false); return oper; + case 0: return walkOperate( checked, Rotation_0 (pixels2,block2) , oper ); + case 1: return walkOperate( checked, Rotation_0_T(pixels2,block2) , oper ); + case 2: return walkOperate( checked, Rotation_1 (pixels2,block2) , oper ); + case 3: return walkOperate( checked, Rotation_1_T(pixels2,block2) , oper ); + case 4: return walkOperate( checked, Rotation_2 (pixels2,block2) , oper ); + case 5: return walkOperate( checked, Rotation_2_T(pixels2,block2) , oper ); + case 6: return walkOperate( checked, Rotation_3 (pixels2,block2) , oper ); + case 7: return walkOperate( checked, Rotation_3_T(pixels2,block2) , oper ); + default: ASSERT(false); return oper; } } diff --git a/modules/colorModel.cpp b/modules/colorModel.cpp index 672e1ce..833d99d 100644 --- a/modules/colorModel.cpp +++ b/modules/colorModel.cpp @@ -19,17 +19,18 @@ const SReal }; -MColorModel::PlaneList MColorModel::image2planes(const QImage &image,const Plane &prototype) { - ASSERT( !image.isNull() ); +MColorModel::PlaneList MColorModel +::image2planes( const QImage &image, const PlaneSettings &prototype ) { + ASSERT( !image.isNull() && ownedPlanes.empty() ); // get the dimensions and create the planes int width= image.width(), height= image.height(); - PlaneList result= createPlanes(IRoot::Encode,prototype,width,height); + ownedPlanes= createPlanes(IRoot::Encode,prototype); // get the correct coefficients and plane count const SReal (*coeffs)[4]= (colorModel() ? YCbCrCoeffs : RGBCoeffs); - int planeCount= result.size(); + int planeCount= ownedPlanes.size(); // fill pixels in all planes for (int i=0; i=0 && colorModel()=0 && colorModel()(file); checkThrow( 0<=colorModel() && colorModel()0 && height>0 && mode!=IRoot::Clear ); +MColorModel::PlaneList MColorModel +::createPlanes( IRoot::Mode DEBUG_ONLY(mode), const PlaneSettings &prototype ) { + ASSERT( 0<=colorModel() && colorModel()pixels.free(); + delete it->settings; + } + } public: static const SReal RGBCoeffs[][4] /** RGB color coefficients */ , YCbCrCoeffs[][4]; /**< YCbCr color coefficients */ public: /** \name IColorTransformer interface * @{ */ - PlaneList image2planes(const QImage &toEncode,const Plane &prototype); - QImage planes2image(const MatrixList &pixels,int width,int height); + PlaneList image2planes(const QImage &toEncode,const PlaneSettings &prototype); + QImage planes2image(); void writeData(std::ostream &file) - { put( file , colorModel() ); } - PlaneList readData(std::istream &file,const Plane &prototype,int width,int height); + { put( file, colorModel() ); } + PlaneList readData(std::istream &file,const PlaneSettings &prototype); /// @} private: /** Creates a list of planes according to \p prototype, - * makes new matrices and adjusts encoding parameters (takes zoomed dimensions) */ - PlaneList createPlanes(IRoot::Mode mode,const Plane &prototype,int zwidth,int zheight); + * makes new matrices and adjusts encoding parameters */ + PlaneList createPlanes(IRoot::Mode mode,const PlaneSettings &prototype); }; diff --git a/modules/quadTree.cpp b/modules/quadTree.cpp index 3b963ed..9578d8f 100644 --- a/modules/quadTree.cpp +++ b/modules/quadTree.cpp @@ -27,7 +27,7 @@ void MQuadTree::encode(const PlaneBlock &toEncode) { if ( heuristicAllowed() ) toEncode.summers_makeValid(); // create a new root, encode it via a recursive routine - root= new Node(toEncode); + root= new Node( Block(0,0,toEncode.width,toEncode.height) ); root->encode(toEncode); // generate the fringe, let the encoder process it root->getHilbertList(fringe); @@ -45,16 +45,16 @@ void MQuadTree::writeData(ostream &file) { root->toFile(bitWriter,extremes); } -void MQuadTree::readData_buildRanges(istream &file,const Block &block,int zoom_) { +void MQuadTree::readData_buildRanges(istream &file,const PlaneBlock &block) { ASSERT( fringe.empty() && !root ); - zoom= zoom_; + zoom= block.settings->zoom; // get from the stream the minimal and the maximal used level NodeExtremes extremes; extremes.min= get(file)+zoom; extremes.max= get(file)+zoom; // build the range tree BitReader bitReader(file); - root= new Node(block); + root= new Node( Block(0,0,block.width,block.height) ); root->fromFile(bitReader,extremes); // generate the fringe of the range tree root->getHilbertList(fringe); @@ -149,22 +149,23 @@ int MQuadTree::Node::getSonCount() const { return count; } bool MQuadTree::Node::encode(const PlaneBlock &toEncode) { - if (*toEncode.updateInfo.terminate) + if (*toEncode.settings->updateInfo.terminate) throw exception(); MQuadTree *mod= debugCast(toEncode.ranges); ASSERT( mod && level>=mod->minLevel() ); + const IColorTransformer::PlaneSettings &plSet= *toEncode.settings; int pixCount= size(); // check for minimal level -> cannot be divided, find the best domain if ( level == mod->minLevel() ) { // try to find the best mapping, not restricting the max.\ SE and exit toEncode.encoder->findBestSE(*this,true); - toEncode.updateInfo.incProgress(pixCount); + plSet.updateInfo.incProgress(pixCount); return false; } // TODO: regular ranges optimization - float maxSE= toEncode.moduleQ2SE->rangeSE( toEncode.quality, pixCount ); + float maxSE= plSet.moduleQ2SE->rangeSE( plSet.quality, pixCount ); bool tryEncode= true; if ( level > mod->maxLevel() ) @@ -172,14 +173,14 @@ bool MQuadTree::Node::encode(const PlaneBlock &toEncode) { else { // if heuirstic dividing is allowed and signals dividing, don't try to encode if ( mod->heuristicAllowed() ) { - float rSum= toEncode.getSum(*this,BlockSummer::Values); - float r2Sum= toEncode.getSum(*this,BlockSummer::Squares); + Real rSum, r2Sum; + toEncode.getSums(*this).unpack(rSum,r2Sum); if ( ldexp( r2Sum-sqr(rSum)/pixCount, -4 ) * level > maxSE ) tryEncode= false; } // if we decided to try to encode, do it and return if the quality is sufficient if ( tryEncode && toEncode.encoder->findBestSE(*this) <= maxSE ) { - toEncode.updateInfo.incProgress(pixCount); + plSet.updateInfo.incProgress(pixCount); return false; } #ifndef NDEBUG diff --git a/modules/quadTree.h b/modules/quadTree.h index ef18cb2..648483d 100644 --- a/modules/quadTree.h +++ b/modules/quadTree.h @@ -43,7 +43,7 @@ private: Node *root; ///< Quad-tree's root node std::vector fringe; ///< List of quad-tree's leaves int zoom; ///< The zoom -#ifndef NDEBUG +#ifndef NDEBUG /* things needed for showing debugging info */ int badDivides, triedMerges, badTries; #endif @@ -70,7 +70,7 @@ public: void readSettings(std::istream&) {} void writeData(std::ostream &file); - void readData_buildRanges(std::istream &file,const Block &block,int zoom); + void readData_buildRanges(std::istream &file,const PlaneBlock &block); /// @} protected: struct NodeExtremes; diff --git a/modules/root.cpp b/modules/root.cpp index e339f3b..9c6007f 100644 --- a/modules/root.cpp +++ b/modules/root.cpp @@ -9,19 +9,20 @@ using namespace std; QImage MRoot::toImage() { ASSERT( getMode()!=Clear && settings && moduleColor() && moduleShape() ); - return moduleColor()->planes2image( moduleShape()->collectJobs() , width, height ); + return moduleColor()->planes2image(); } bool MRoot::encode(const QImage &toEncode,const UpdateInfo &updateInfo) { ASSERT( getMode()==Clear && settings && moduleColor() && moduleShape() ); zoom= 0; -// get the plane list, create the jobs from it - Plane planeProto( SMatrix(), quality(), settingsInt(DomainCountLog2) - , 0/*zoom*/, moduleQuality(), updateInfo ); - PlaneList planes= moduleColor()->image2planes( toEncode, planeProto ); this->width= toEncode.width(); this->height= toEncode.height(); - int jobCount= moduleShape()->createJobs( planes, width, height ); +// get the plane list, create the jobs from it + PlaneSettings planeProto( width, height, settingsInt(DomainCountLog2), 0/*zoom*/ + , quality(), moduleQuality(), updateInfo ); + PlaneList planes= moduleColor()->image2planes( toEncode, planeProto ); + + int jobCount= moduleShape()->createJobs(planes); // process the jobs if ( maxThreads() == 1 ) try { @@ -55,7 +56,7 @@ bool MRoot::toStream(std::ostream &file) { file.exceptions( ofstream::eofbit | ofstream::failbit | ofstream::badbit ); STREAM_POS(file); - // put the magic, the dimensions and child-module IDs + // put the magic, the dimensions (not zoomed) and child-module IDs put(file,Magic); put( file, rShift(width,zoom) ); put( file, rShift(height,zoom) ); @@ -101,19 +102,18 @@ bool MRoot::fromStream(istream &file,int newZoom) { STREAM_POS(file); // create the planes and get settings common for all the jobs - Plane planeProto(Plane::Empty); - planeProto.zoom= zoom; - planeProto.domainCountLog2= settingsInt(DomainCountLog2)= get(file); + settingsInt(DomainCountLog2)= get(file); + PlaneSettings planeProto( width, height, settingsInt(DomainCountLog2), zoom ); STREAM_POS(file); - PlaneList planes= moduleColor()->readData(file,planeProto,width,height); + PlaneList planes= moduleColor()->readData(file,planeProto); STREAM_POS(file); moduleShape()->readSettings(file); STREAM_POS(file); // create the jobs (from the plane list) and get their data - moduleShape()->createJobs(planes,width,height); + moduleShape()->createJobs(planes); moduleShape()->readJobs(file); STREAM_POS(file); diff --git a/modules/root.h b/modules/root.h index d76302b..ad4397b 100644 --- a/modules/root.h +++ b/modules/root.h @@ -57,7 +57,7 @@ private: IQuality2SquareError* moduleQuality() const { return debugCast(settings[ModuleQuality].m); } - typedef IColorTransformer::Plane Plane; + typedef IColorTransformer::PlaneSettings PlaneSettings; typedef IColorTransformer::PlaneList PlaneList; private: diff --git a/modules/saupePredictor.cpp b/modules/saupePredictor.cpp index 39f1f34..a4dce83 100644 --- a/modules/saupePredictor.cpp +++ b/modules/saupePredictor.cpp @@ -55,8 +55,7 @@ MSaupePredictor::Tree* MSaupePredictor::createTree(const NewPredictorData &data) for (int y0=0; y0 currRangeMatrix( sideLength, sideLength, points+rot*tree.length ); + MatrixSlice currRangeMatrix; + currRangeMatrix.allocate( sideLength, sideLength, points+rot*tree.length ); // fill it with normalized data using namespace MatrixWalkers; walkOperateCheckRotate( Checked(data.rangePixels,*data.rangeBlock) @@ -151,7 +151,7 @@ MSaupePredictor::OneRangePredictor::OneRangePredictor MSaupePredictor::Predictions& MSaupePredictor::OneRangePredictor ::getChunk(float maxPredictedSE,Predictions &store) { - ASSERT( heaps.size()==(size_t)heapCount && infoHeap.size()<=(size_t)heapCount ); + ASSERT( PtrInt(heaps.size())==heapCount && PtrInt(infoHeap.size())<=heapCount ); if ( infoHeap.empty() || predsRemain<=0 ) { store.clear(); return store; diff --git a/modules/squarePixels.cpp b/modules/squarePixels.cpp index eb7aa17..fc94b48 100644 --- a/modules/squarePixels.cpp +++ b/modules/squarePixels.cpp @@ -3,56 +3,61 @@ using namespace std; -int MSquarePixels::createJobs( const PlaneList &planes, int width, int height ) { - ASSERT( ownedMatrices.empty() && jobs.empty() - && moduleRanges() && moduleDomains() && moduleEncoder() ); +int MSquarePixels::createJobs(const PlaneList &planes) { + ASSERT( jobs.empty() && !planes.empty() + && moduleRanges() && moduleDomains() && moduleEncoder() ); + DEBUG_ONLY( planeList= planes; ) -// create the joblist - int maxPixels= powers[maxPartSize()+2*planes.front().zoom]; // the zoom only affects maxPixels - if ( width*height <= maxPixels ) - // not dividing the planes -> pass them as they are - for (PlaneList::const_iterator it=planes.begin(); it!=planes.end(); ++it) - jobs.push_back(makeJob( *it, Block(0,0,width,height) )); - else { // dividing the planes - // compute the dividing pattern - vector pattern; - pattern.push_back( Block(0,0,width,height) ); - - size_t i= 0; - while ( i < pattern.size() ) - if ( pattern[i].size() <= maxPixels ) - // the part is small enough, move on - ++i; - else { // divide the part - // splitting the longer coordinate - bool xdiv= ( pattern[i].width() >= pattern[i].height() ); - int longer= ( xdiv ? pattern[i].width() : pattern[i].height() ); - // get the place to split (at least one of the parts will have size 2^q) - int bits= log2ceil(longer); - int divsize= ( longer >= powers[bits-1]+powers[bits-2] - ? powers[bits-1] - : powers[bits-2] ); - // split the part in the pattern (reusing the splitted-one's space) - pattern.push_back(pattern[i]); - if (xdiv) { - pattern[i].xend-= divsize; - pattern.back().x0+= divsize; - } else { - pattern[i].yend-= divsize; - pattern.back().y0+= divsize; - } + for (PlaneList::const_iterator plane= planes.begin(); plane!=planes.end(); ++plane) { + // convert the Plane into a PlaneBlock (containing the whole contents) + const IColorTransformer::PlaneSettings *plSet= plane->settings; + Job job; + job.width= plSet->width; + job.height= plSet->height; + job.pixels= plane->pixels; + job.sumsValid= false; + job.settings= plSet; + DEBUG_ONLY( job.ranges= 0; job.domains= 0; job.encoder= 0; ) + // append the result to the jobs + jobs.push_back(job); + } + +// the zoom only affects maxPixels (zoom is assumed to be the same for all planes) + int maxPixels= powers[maxPartSize()+2*jobs.front().settings->zoom]; +// split jobs until they're small enough + Uint i= 0; + while ( i < jobs.size() ) + if ( jobs[i].width*jobs[i].height <= maxPixels ) { + ++i; // the part is small enough, move on + } else { + + // divide the job + // splitting the longer coordinate + bool xdiv= ( jobs[i].width >= jobs[i].height ); + int longer= ( xdiv ? jobs[i].width : jobs[i].height ); + // get the place to split (at least one of the parts will have size 2^q) + int bits= log2ceil(longer); + int divSize= ( longer >= powers[bits-1]+powers[bits-2] + ? powers[bits-1] + : powers[bits-2] ); + // split the job (reusing the splitted-one's space and appending the second one) + jobs.push_back(jobs[i]); + if (xdiv) { + jobs[i].width= divSize; // reducing the width of the first job + jobs.back().pixels.shiftMatrix(divSize,0); // shifting the second job + jobs.back().width-= divSize; // reducing the width of the second job + } else { + jobs[i].height= divSize; // reducing the height of the first job + jobs.back().pixels.shiftMatrix(0,divSize); // shifting the second job + jobs.back().height-= divSize; // reducing the height of the second job } - // we have the pattern, apply it to every plane (jobs sharing pixel matrices) - vector::iterator patIt; - for (PlaneList::const_iterator it=planes.begin(); it!=planes.end(); ++it) - for (patIt=pattern.begin(); patIt!=pattern.end(); ++patIt) - jobs.push_back(makeJob( *it, *patIt )); - } // if(!)... else... + } -// take the ownership of the matrices - for (PlaneList::const_iterator it=planes.begin(); it!=planes.end(); ++it) { - ownedMatrices.push_back(it->pixels); - it->updateInfo.incMaxProgress(width*height); +// create the modules in the jobs by cloning those from module's settings + for (JobIterator job=jobs.begin(); job!=jobs.end(); ++job) { + job->ranges= clone(moduleRanges()); + job->domains= clone(moduleDomains()); + job->encoder= clone(moduleEncoder()); } return jobs.size(); @@ -106,7 +111,7 @@ void MSquarePixels::readJobs(istream &file,int phaseBegin,int phaseEnd) { if (!phaseBegin) for (JobIterator it=jobs.begin(); it!=jobs.end(); ++it) { STREAM_POS(file); - it->ranges->readData_buildRanges(file,*it,it->zoom); + it->ranges->readData_buildRanges(file,*it); STREAM_POS(file); it->domains->readData(file); it->encoder->initialize(IRoot::Decode,*it); @@ -115,5 +120,4 @@ void MSquarePixels::readJobs(istream &file,int phaseBegin,int phaseEnd) { for (int phase=phaseBegin; phaseencoder->readData(file,phase); - } diff --git a/modules/squarePixels.h b/modules/squarePixels.h index 0f41f5d..1cf23e1 100644 --- a/modules/squarePixels.h +++ b/modules/squarePixels.h @@ -50,36 +50,26 @@ private: private: // Module's data - std::vector jobs; ///< Encoding jobs - one part of one color plane makes one job - MatrixList ownedMatrices; ///< List of owned pixel matrices + std::vector jobs; ///< Encoding jobs - one part of one color plane makes one job + DEBUG_ONLY( PlaneList planeList; ) //< needed for creating debug info -private: - /** Creates a new job on a block in a plane - the three modules are cloned from this object */ - Job makeJob(const Plane &plane,const Block &block) { - return Job( plane, block, clone(moduleRanges()), clone(moduleDomains()) - , clone(moduleEncoder()) ); - } protected: // Construction and destruction - /** Only deletes #ownedMatrices and frees #jobs */ + /** Only frees #jobs */ ~MSquarePixels() { - for_each( ownedMatrices.begin(), ownedMatrices.end() - , mem_fun_ref(&MatrixList::value_type::free) ); - for_each( jobs.begin(), jobs.end(), mem_fun_ref(&Job::free) ); + // can't free the whole jobs, because the pixels are NOT owned (can be only a part) + for (JobIterator it=jobs.begin(); it!=jobs.end(); ++it) + it->free(false); } public: /** \name IShapeTransformer interface * @{ */ - int createJobs( const PlaneList &planes, int width, int height ); + int createJobs(const PlaneList &planes); int jobCount() { return jobs.size(); } - MatrixList collectJobs() { - ASSERT( !ownedMatrices.empty() ); - return ownedMatrices; - } - + void jobEncode(int jobIndex) { ASSERT( jobIndex>=0 && jobIndexzoom; + width= rShift( planeBlock.width, zoom ); + height= rShift( planeBlock.height, zoom ); // checks some things ASSERT( width>0 && height>0 && this && settings && pools.empty() ); if ( min(width,height) < MinDomSize*2 ) @@ -69,7 +69,7 @@ void MStdDomains::initPools(const PlaneBlock &planeBlock) { int shorter= min(width,height); int shift= getDiamondShift(shorter); // generate the pool sizes - for (int longer=max(width,height); longer>0; longer-=shift) { + for (int longer=max(width,height); longer>minSizeNeededForDiamond(); longer-=shift) { int side= getDiamondSize( min(longer,shorter) ); ASSERT(side>=0); if (side) @@ -80,7 +80,7 @@ void MStdDomains::initPools(const PlaneBlock &planeBlock) { } // if allowed, create more downscaled domains (at most 256 pools) if ( settingsInt(MultiDownScaling) ) - for (size_t i=0; i(pool.width,zoom+1); @@ -107,7 +107,7 @@ namespace NOSPACE { static void shrinkVertically ( CSMatrix src, SMatrix dest, int width, int height ); static void shrinkToDiamond ( CSMatrix src, SMatrix dest, int side ); } -void MStdDomains::fillPixelsInPools(const PlaneBlock &planeBlock) { +void MStdDomains::fillPixelsInPools(PlaneBlock &planeBlock) { ASSERT( !pools.empty() ); // assuming initPools has already been called // iterate over pool types PoolList::iterator end= pools.begin(); @@ -116,8 +116,7 @@ void MStdDomains::fillPixelsInPools(const PlaneBlock &planeBlock) { char type= begin->type; // find the end of the same-pool-type block and invalidate the summers on the way while ( end!=pools.end() && end->type==type ) { - end->summers[0].invalidate(); - end->summers[1].invalidate(); + end->summers_invalidate(); ++end; } @@ -133,7 +132,7 @@ void MStdDomains::fillPixelsInPools(const PlaneBlock &planeBlock) { } // we have the right procedure -> fill the first pool ASSERT( begin->level == 1 ); - shrinkProc( planeBlock.getShiftedPixels(), begin->pixels + shrinkProc( planeBlock.pixels, begin->pixels , begin->width, begin->height ); // fill the rest (in the same-type interval) while (++begin != end) { @@ -147,7 +146,7 @@ void MStdDomains::fillPixelsInPools(const PlaneBlock &planeBlock) { bool horiz= width>=height; int shift= lShift( getDiamondShift(min(width,height)), zoom ); int longerEnd= lShift( max(width,height)-minSizeNeededForDiamond(), zoom ); - CSMatrix source= planeBlock.getShiftedPixels(); + CSMatrix source= planeBlock.pixels; for (int l=0; l<=longerEnd; ++it,l+=shift) { ASSERT( it!=end && it->level==1 && it->width==it->height ); @@ -329,40 +328,58 @@ namespace MatrixWalkers { template void operator()(R1 &dest,R2 src) const { dest= src; } }; - template struct HalfShrinker: public RotBase { ROTBASE_INHERIT - HalfShrinker(MType matrix) - : RotBase( matrix, 0, 0 ) {} + template + struct HalfShrinker: public Rotation_0 { ROTBASE_INHERIT + typedef Rotation_0 Base; + + HalfShrinker(TMatrix matrix) + : Base( matrix, Block(0,0,0,0) ) {} - T get() { return ldexp( elem[0] + elem[1] + elem[colSkip] + elem[colSkip+1], -2 ); } - void outerStep() { list+= 2*colSkip; } - void innerStep() { elem+= 2; } + T get() { + TMatrix &c= current; + T *cs= c.start; + return ldexp( cs[0] + cs[1] + cs[c.colSkip] + cs[c.colSkip+1], -2 ); + } + void outerStep() { Base::outerStep(); Base::outerStep(); } + void innerStep() { Base::innerStep(); Base::innerStep(); } }; - template struct HorizShrinker: public RotBase { ROTBASE_INHERIT - HorizShrinker(MType matrix) - : RotBase( matrix, 0, 0 ) {} + template + struct HorizShrinker: public Rotation_0 { ROTBASE_INHERIT + typedef Rotation_0 Base; + + HorizShrinker(TMatrix matrix) + : Base( matrix, Block(0,0,0,0) ) {} - T get() { return ldexp( elem[0] + elem[colSkip], -1 ); } - void outerStep() { list+= 2*colSkip; } - void innerStep() { ++elem; } + T get() { return ldexp( current.start[0] + current.start[current.colSkip], -1 ); } + void outerStep() { Base::outerStep(); Base::outerStep(); } }; - template struct VertShrinker: public RotBase { ROTBASE_INHERIT - VertShrinker(MType matrix) - : RotBase( matrix, 0, 0 ) {} + template + struct VertShrinker: public Rotation_0 { ROTBASE_INHERIT + typedef Rotation_0 Base; + + VertShrinker(TMatrix matrix) + : Base( matrix, Block(0,0,0,0) ) {} - T get() { return ldexp( elem[0] + elem[1], -1 ); } - void outerStep() { list+= colSkip; } - void innerStep() { elem+= 2; } + T get() { return ldexp( current.start[0] + current.start[1], -1 ); } + void innerStep() { Base::innerStep(); Base::innerStep(); } }; - template struct DiamShrinker: public RotBase { ROTBASE_INHERIT - DiamShrinker(MType matrix,I side) - : RotBase( matrix, side, 0 ) {} // the diamond begins on top-middle + template + struct DiamShrinker: public Rotation_0 { ROTBASE_INHERIT + typedef Rotation_0 Base; + + DiamShrinker(TMatrix matrix,I side) + : Base( matrix, Block(side-1,0,0,0) ) {} // the diamond begins on top-middle - T get() { return ldexp( elem[0] + elem[1] + elem[colSkip] + elem[colSkip+1], -2 ); } - void outerStep() { list+= colSkip+1; } - void innerStep() { elem+= 1-colSkip; } + T get() { + TMatrix &c= current; + T *cs= c.start; + return ldexp( cs[0] + cs[1] + cs[c.colSkip] + cs[c.colSkip+1], -2 ); + } + void outerStep() { lastStart+= current.colSkip+1; } + void innerStep() { current.start+= 1-current.colSkip; } }; }// MatrixWalkers namespace diff --git a/modules/stdDomains.h b/modules/stdDomains.h index 1d4b8ea..338f318 100644 --- a/modules/stdDomains.h +++ b/modules/stdDomains.h @@ -60,14 +60,16 @@ protected: MStdDomains(): width(-1), height(-1), zoom(-1) {} #endif /** Only frees the #pools */ - ~MStdDomains() - { for_each( pools.begin(), pools.end(), mem_fun_ref(&Pool::free) ); } + ~MStdDomains() { + for (PoolList::iterator it=pools.begin(); it!=pools.end(); ++it) + it->free(); + } public: /** \name ISquareDomains interface * @{ */ void initPools(const PlaneBlock &planeBlock); - void fillPixelsInPools(const PlaneBlock &planeBlock); + void fillPixelsInPools(PlaneBlock &planeBlock); const PoolList& getPools() const { return pools; } diff --git a/modules/stdEncoder.cpp b/modules/stdEncoder.cpp index 0e80c13..9b4167a 100644 --- a/modules/stdEncoder.cpp +++ b/modules/stdEncoder.cpp @@ -134,7 +134,7 @@ void MStandardEncoder::initialize( IRoot::Mode mode, PlaneBlock &planeBlock_ ) { // prepare the domains-module planeBlock->domains->initPools(*planeBlock); - int maxLevel= 1 +log2ceil(max( planeBlock->width(), planeBlock->height() )); + int maxLevel= 1 +log2ceil(max( planeBlock->width, planeBlock->height )); // prepare levelPoolInfos levelPoolInfos.resize(maxLevel); @@ -147,8 +147,8 @@ void MStandardEncoder::initialize( IRoot::Mode mode, PlaneBlock &planeBlock_ ) { // prepare maximum SquareErrors allowed for regular range blocks stdRangeSEs.resize(maxLevel+1); - planeBlock->moduleQ2SE->completeSquareRangeErrors - ( planeBlock->quality, maxLevel+1, &stdRangeSEs.front() ); + planeBlock->settings->moduleQ2SE->completeSquareRangeErrors + ( planeBlock->settings->quality, maxLevel+1, &stdRangeSEs.front() ); } } @@ -166,8 +166,8 @@ namespace NOSPACE { #endif BestInfo() - : error( numeric_limits::max() ) {} - IStdEncPredictor::Prediction& prediction() + : Prediction(), error( numeric_limits::max() ) {} + IStdEncPredictor::Prediction& prediction() { return *this; } }; } // namespace NOSPACE @@ -259,7 +259,7 @@ bool MStandardEncoder::EncodingInfo::exactCompareProc( Prediction prediction ) { domBlock= adjustDomainForIncompleteRange ( *stable.rangeBlock, prediction.rotation, domBlock ); Real dSum, d2Sum; - pool.getSums(domBlock,dSum,d2Sum); + pool.getSums(domBlock).unpack(dSum,d2Sum); // compute the denominator common to most formulas Real test= stable.pixCount*d2Sum - sqr(dSum); if (test<=0) // skip too flat domains @@ -320,6 +320,7 @@ bool MStandardEncoder::EncodingInfo::exactCompareProc( Prediction prediction ) { float MStandardEncoder::findBestSE(const RangeNode &range,bool allowHigherSE) { ASSERT( planeBlock && !stdRangeSEs.empty() && !range.encoderData ); + const IColorTransformer::PlaneSettings *plSet= planeBlock->settings; // initialize an encoding-info object EncodingInfo info; @@ -332,7 +333,7 @@ float MStandardEncoder::findBestSE(const RangeNode &range,bool allowHigherSE) { info.stable.poolInfos= &levelPoolInfos[range.level]; // check the level has been initialized if ( info.stable.poolInfos->empty() ) { - buildPoolInfos4aLevel(range.level,planeBlock->zoom); + buildPoolInfos4aLevel(range.level,plSet->zoom); ASSERT( !info.stable.poolInfos->empty() ); } @@ -346,8 +347,7 @@ float MStandardEncoder::findBestSE(const RangeNode &range,bool allowHigherSE) { } info.stable.bigScaleCoeff= settingsFloat(BigScaleCoeff); - info.stable.rSum= planeBlock->getSum(range,BlockSummer::Values); - info.stable.r2Sum= planeBlock->getSum(range,BlockSummer::Squares); + planeBlock->getSums(range).unpack( info.stable.rSum, info.stable.r2Sum ); info.stable.pixCount= range.size(); info.stable.rnDev2= info.stable.pixCount*info.stable.r2Sum - sqr(info.stable.rSum); if (info.stable.rnDev2<0) @@ -375,7 +375,7 @@ float MStandardEncoder::findBestSE(const RangeNode &range,bool allowHigherSE) { } info.targetSE= info.maxSE2Predict= info.stable.isRegular ? stdRangeSEs[range.level] - : planeBlock->moduleQ2SE->rangeSE( planeBlock->quality, range.size() ); + : plSet->moduleQ2SE->rangeSE( plSet->quality, range.size() ); ASSERT(info.targetSE>=0); if (allowHigherSE) info.maxSE2Predict= numeric_limits::max(); @@ -414,7 +414,7 @@ float MStandardEncoder::findBestSE(const RangeNode &range,bool allowHigherSE) { void MStandardEncoder::buildPoolInfos4aLevel(int level,int zoom) { // get the real maximum domain count (divide by the number of rotations) - int domainCountLog2= planeBlock->domainCountLog2; + int domainCountLog2= planeBlock->settings->domainCountLog2; if ( settingsInt(AllowedRotations) ) domainCountLog2-= 3; // get the per-domain-pool densities @@ -648,7 +648,7 @@ void MStandardEncoder::readData(istream &file,int phase) { int bits= domBits[level]; if (bits<0) { // yet unused level -> initialize it and get the right bits - buildPoolInfos4aLevel(level,planeBlock->zoom); + buildPoolInfos4aLevel(level,planeBlock->settings->zoom); bits= domBits[level] = log2ceil( levelPoolInfos[level].back().indexBegin ); ASSERT( bits>0 ); @@ -678,7 +678,8 @@ void MStandardEncoder::decodeAct( DecodeAct action, int count ) { ASSERT(false); case Clear: ASSERT(count==1); - planeBlock->pixels.fillSubMatrix( *planeBlock, 0.5f ); + planeBlock->pixels.fillSubMatrix + ( Block(0,0,planeBlock->width,planeBlock->height), 0.5f ); planeBlock->summers_invalidate(); break; case Iterate: @@ -694,7 +695,7 @@ void MStandardEncoder::decodeAct( DecodeAct action, int count ) { } // get domain sums and the pixel count Real dSum, d2Sum; - info.decAccel.pool->getSums( info.decAccel.domBlock, dSum, d2Sum ); + info.decAccel.pool->getSums(info.decAccel.domBlock).unpack(dSum,d2Sum); Real pixCount= (*it)->size(); Real linCoeff= (info.inverted ? -pixCount : pixCount) @@ -720,6 +721,7 @@ void MStandardEncoder::initRangeInfoAccelerators() { // get references that are the same for all range blocks const RangeList &ranges= planeBlock->ranges->getRangeList(); const ISquareDomains::PoolList &pools= planeBlock->domains->getPools(); + int zoom= planeBlock->settings->zoom; // iterate over the ranges (and their accelerators) for ( RangeList::const_iterator it=ranges.begin(); it!=ranges.end(); ++it ) { // get range level, reference to the range's info and to the level's pool infos @@ -729,10 +731,10 @@ void MStandardEncoder::initRangeInfoAccelerators() { continue; const PoolInfos &poolInfos= levelPoolInfos[level]; // build pool infos for the level (if neccesary), fill info's accelerators - if ( poolInfos.empty() ) - buildPoolInfos4aLevel(level,planeBlock->zoom), ASSERT( !poolInfos.empty() ); + if ( poolInfos.empty() ) + buildPoolInfos4aLevel(level,zoom), ASSERT( !poolInfos.empty() ); info.decAccel.pool= &getDomainData - ( **it, pools, poolInfos, info.domainID, planeBlock->zoom, info.decAccel.domBlock ); + ( **it, pools, poolInfos, info.domainID, zoom, info.decAccel.domBlock ); // adjust domain's block if the range isn't regular if ( !(*it)->isRegular() ) info.decAccel.domBlock= adjustDomainForIncompleteRange diff --git a/util.h b/util.h index 0e9963e..8776026 100644 --- a/util.h +++ b/util.h @@ -115,7 +115,7 @@ class BulkAllocator { enum { bulkCount=(bulkKb*1024)/sizeof(T) }; std::vector pools; - size_t nextIndex; + PtrInt nextIndex; public: BulkAllocator() @@ -135,7 +135,7 @@ public: } return & (pools.back()[nextIndex++]); } - T* makeField(size_t count) { + T* makeField(PtrInt count) { // check for errors ASSERT(nextIndex<=bulkCount); @@ -175,7 +175,10 @@ struct UpdateInfo { /** Initializes the structure from supplied parametres */ UpdateInfo( const bool &terminate_= noTerminate, IncInt incMaxProgress_= &emptyFunction , IncInt incProgress_= &emptyFunction ) - : terminate(&terminate_), incMaxProgress(incMaxProgress_), incProgress(incProgress_) {} + : terminate(&terminate_), incMaxProgress(incMaxProgress_), incProgress(incProgress_) + { ASSERT(isValid()); } + + bool isValid() const { return terminate && incMaxProgress && incProgress; } }; #endif // UTIL_HEADER_ -- 2.11.4.GIT