00001 #include "stdDomains.h"
00002 #include "../fileUtil.h"
00003
00004 enum { MinDomSize=8, MinRngSize=4 };
00005
00006 using namespace std;
00007
00008
00010 namespace NOSPACE {
00011 using namespace MatrixWalkers;
00014 void shrinkToHalf( CSMatrix src, SMatrix dest, int width, int height ) {
00015 walkOperate( Checked<SReal>(dest,Block(0,0,width,height))
00016 , HalfShrinker<const SReal>(src), ReverseAssigner() );
00017 }
00020 void shrinkHorizontally( CSMatrix src, SMatrix dest, int width, int height ) {
00021 walkOperate( Checked<SReal>(dest,Block(0,0,width,height))
00022 , HorizShrinker<const SReal>(src), ReverseAssigner() );
00023 }
00026 void shrinkVertically( CSMatrix src, SMatrix dest, int width, int height ) {
00027 walkOperate( Checked<SReal>(dest,Block(0,0,width,height))
00028 , VertShrinker<const SReal>(src), ReverseAssigner() );
00029 }
00033 void shrinkToDiamond( CSMatrix src, SMatrix dest, int side ) {
00034 walkOperate( Checked<SReal>(dest,Block(0,0,side,side))
00035 , DiamShrinker<const SReal>(src,side), ReverseAssigner() );
00036 }
00037 }
00038
00039
00040 namespace NOSPACE {
00042 struct PoolTypeLevelComparator {
00043 typedef MStdDomains::Pool Pool;
00044 bool operator()(const Pool &a,const Pool &b) {
00045 if (a.type!=b.type)
00046 return a.type<b.type;
00047 else
00048 return a.level<b.level;
00049 }
00050 };
00051
00052 inline static int minSizeNeededForDiamond()
00053 { return 2*MinDomSize-1; }
00054 inline static int getDiamondSize(int fromSize)
00055 { return fromSize<minSizeNeededForDiamond() ? 0 : fromSize/2; }
00056 inline static int getDiamondShift(int fromSize)
00057 { return ( getDiamondSize(fromSize) - MinRngSize + 1 )*2; }
00058 }
00059 void MStdDomains::initPools(const PlaneBlock &planeBlock) {
00060 zoom= planeBlock.settings->zoom;
00061 width= rShift( planeBlock.width, zoom );
00062 height= rShift( planeBlock.height, zoom );
00063
00064 ASSERT( width>0 && height>0 && this && settings && pools.empty() );
00065 if ( min(width,height)/2 < MinDomSize )
00066
00067 return;
00068
00069 if ( settingsInt(DomPortion_Standard) )
00070 pools.push_back(Pool( width/2, height/2, DomPortion_Standard, 1, 0.25, zoom ));
00071 if ( settingsInt(DomPortion_Horiz) && width/3>=MinDomSize )
00072 pools.push_back(Pool( width/3, height/3*2, DomPortion_Horiz, 1, 2.0/9.0, zoom ));
00073 if ( settingsInt(DomPortion_Vert) && height/3>=MinDomSize )
00074 pools.push_back(Pool( width/3*2, height/3, DomPortion_Vert, 1, 2.0/9.0, zoom ));
00075
00076 if ( settingsInt(DomPortion_Diamond) ) {
00077
00078 int shorter= min(width,height);
00079 int shift= getDiamondShift(shorter);
00080
00081 for (int longer=max(width,height); longer>minSizeNeededForDiamond(); longer-=shift) {
00082 int side= getDiamondSize( min(longer,shorter) );
00083 ASSERT(side>=0);
00084 if (side)
00085 pools.push_back(Pool( side, side, DomPortion_Diamond, 1, 0.5, zoom ));
00086 else
00087 break;
00088 }
00089 }
00090
00091 if ( settingsInt(MultiDownScaling) )
00092 for (Uint i=0; i<pools.size() && i<256; ++i) {
00093 const Pool &pool= pools[i];
00094
00095 int w= rShift<int>(pool.width,zoom+1);
00096 int h= rShift<int>(pool.height,zoom+1);
00097 float cf= ldexp(pool.contrFactor,-2);
00098 if ( min(w,h) >= MinDomSize )
00099 pools.push_back( Pool( w, h, pool.type, pool.level+1, cf, zoom ) );
00100 }
00101
00102 stable_sort( pools.begin(), pools.end(), PoolTypeLevelComparator() );
00103 }
00104
00105 namespace NOSPACE {
00106 typedef MStdDomains::PoolList::const_iterator PoolIt;
00108 static inline bool halfShrinkOK(PoolIt src,PoolIt dest,int zoom) {
00109 return src->level+1 == dest->level && src->type == dest->type
00110 && rShift<int>(src->width,zoom+1) == rShift<int>(dest->width,zoom)
00111 && rShift<int>(src->height,zoom+1) == rShift<int>(dest->height,zoom);
00112 }
00113 }
00114 void MStdDomains::fillPixelsInPools(PlaneBlock &planeBlock) {
00115 ASSERT( !pools.empty() );
00116
00117 PoolList::iterator end= pools.begin();
00118 while ( end != pools.end() ) {
00119 PoolList::iterator begin= end;
00120 char type= begin->type;
00121
00122 while ( end!=pools.end() && end->type==type ) {
00123 end->summers_invalidate();
00124 ++end;
00125 }
00126
00127
00128 if (type!=DomPortion_Diamond) {
00129
00130 void (*shrinkProc)( CSMatrix , SMatrix , int, int );
00131 switch (type) {
00132 case DomPortion_Standard: shrinkProc= &shrinkToHalf; break;
00133 case DomPortion_Horiz: shrinkProc= &shrinkHorizontally;break;
00134 case DomPortion_Vert: shrinkProc= &shrinkVertically; break;
00135 default: ASSERT(false), shrinkProc=0;
00136 }
00137
00138 ASSERT( begin->level == 1 );
00139 shrinkProc( planeBlock.pixels, begin->pixels, begin->width, begin->height );
00140
00141 while (++begin != end) {
00142 ASSERT( halfShrinkOK(begin-1,begin,zoom) );
00143 shrinkToHalf( (begin-1)->pixels, begin->pixels, begin->width, begin->height );
00144 }
00145
00146 } else {
00147 PoolList::iterator it= begin;
00148
00149 bool horiz= width>=height;
00150 int shift= lShift( getDiamondShift(min(width,height)), zoom );
00151 int longerEnd= lShift( max(width,height)-minSizeNeededForDiamond(), zoom );
00152 CSMatrix source= planeBlock.pixels;
00153
00154 for (int l=0; l<=longerEnd; ++it,l+=shift) {
00155 ASSERT( it!=end && it->level==1 && it->width==it->height );
00156 shrinkToDiamond( planeBlock.pixels, it->pixels, it->width );
00157 source.shiftMatrix( (horiz?shift:0), (horiz?0:shift) );
00158 }
00159
00160 while (it!=end) {
00161
00162 while ( min(begin->width,begin->height) < 2*MinDomSize )
00163 ++begin;
00164 ASSERT( halfShrinkOK(begin,it,zoom) );
00165 shrinkToHalf( begin->pixels, it->pixels, it->width, it->height );
00166
00167 ++it;
00168 ++begin;
00169 }
00170 }
00171
00172
00173
00174 }
00175
00176
00177
00178 }
00179
00180 namespace NOSPACE {
00184 inline static int bestDomainDensity( PoolIt pool, int level, int maxCount, int zoom
00185 , vector<short> &result) {
00186 level-= zoom;
00187 ASSERT( maxCount>=0 && level>0 && zoom>=0 );
00188 int wms= rShift<int>(pool->width,zoom) -powers[level];
00189 int hms= rShift<int>(pool->height,zoom) -powers[level];
00190
00191 if ( wms<0 || hms<0 || !maxCount ) {
00192 result.push_back(0);
00193 return 0;
00194 }
00195 int dens;
00196 if (maxCount>1) {
00197 Real temp= ( wms+hms+sqrt( sqr<Real>(wms+hms) +Real(4*wms*hms)*(maxCount-1) ) )
00198 / ( 2*(maxCount-1) );
00199 dens= (int)ceil(temp);
00200 } else
00201 dens= 1+max(wms,hms);
00202
00203 if (!dens)
00204 dens= 1;
00205 ASSERT(dens>0);
00206 int count= (wms/dens+1)*(hms/dens+1);
00207 ASSERT(count<=maxCount);
00208
00209 result.push_back(dens);
00210 return count;
00211 }
00216 static int divideDomsInType( PoolIt begin, PoolIt end, int maxCount, int level
00217 , char divType, int zoom, vector<short> &results ) {
00218 ASSERT( begin!=end && divType>=0 && divType<=2 );
00219 int scaleLevels= (end-1)->level - begin->level + 1;
00220 int genCount= 0;
00221
00222 for (; begin!=end; --scaleLevels) {
00223 PoolIt it= begin+1;
00224 while ( it!=end && it->level==begin->level )
00225 ++it;
00226
00227 int toGenerate= divType==2
00228
00229 ? (maxCount-genCount)/2
00230
00231 : (maxCount-genCount)/scaleLevels ;
00232
00233
00234 genCount+= toGenerate;
00235 for (; begin!=it; ++begin)
00236 toGenerate-=
00237 bestDomainDensity( begin, level, toGenerate/(it-begin), zoom, results );
00238 genCount-= toGenerate;
00239 }
00240 return genCount;
00241 }
00242 }
00243 vector<short> MStdDomains::getLevelDensities(int level,int stdDomCountLog2) {
00244 ASSERT(level>=2);
00245
00246 int totalShares= settingsInt(DomPortion_Standard) + settingsInt(DomPortion_Horiz)
00247 + settingsInt(DomPortion_Vert) + settingsInt(DomPortion_Diamond);
00248 stdDomCountLog2-= (level-zoom-2)*settingsInt(MaxDomCountLevelDivisor);
00249
00250 if ( pools.empty() || !totalShares || stdDomCountLog2<0 )
00251 return vector<short>( pools.size(), 0 );
00252
00253 int domCountLeft= powers[stdDomCountLog2];
00254
00255 vector<short> result;
00256 result.reserve(pools.size());
00257 PoolList::iterator begin, end;
00258 end= pools.begin();
00259
00260 while ( end!=pools.end() ) {
00261 begin= end;
00262
00263 while ( end!=pools.end() && begin->type==end->type )
00264 ++end;
00265
00266 int share= settingsInt( (Settings)begin->type );
00267 domCountLeft-= divideDomsInType( begin, end, domCountLeft*share/totalShares
00268 , level, settingsInt(MultiDownScaling), zoom, result );
00269 totalShares-= share;
00270 }
00271
00272 ASSERT( result.size() == pools.size() );
00273 return result;
00274 }
00275
00276 void MStdDomains::writeSettings(ostream &file) {
00277 ASSERT( this && settings );
00278
00279 int setLength= info().setLength;
00280 for (int i=0; i<setLength; ++i)
00281 put<Uchar>( file, settingsInt(i) );
00282 }
00283
00284 void MStdDomains::readSettings(istream &file) {
00285 ASSERT( this && settings );
00286
00287 int setLength= info().setLength;
00288 for (int i=0; i<setLength; ++i)
00289 settingsInt(i)= get<Uchar>(file);
00290 }