Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

SPalette.cpp

Go to the documentation of this file.
00001 
00004 #include <ctype.h>
00005 #include "SPalette.h"
00006 #define USE_ERRORMAT            // use difference matrix for error minimize.
00007 /* note on USE_ERRORMAT
00008    - former uses of errorminmat produced ill-conditioned matrix
00009    - there is another method just using 31->RGB and 31->7->RGB conversion
00010      independently, which looked more stable (variant B)
00011    - freecolour isn't implemented correctly for this workaround version
00012    - a rotten old matrix has been found in vuColour7a.h
00013    - now variant A also works and is compatible with freecolour
00014    that's it. so, no use to read these notes ;-)
00015    - maybe I make freecolours work with variant B...
00016  */
00017 
00018 #define SQRT_31         5.5677643628300219221194712989185
00019 
00020 namespace coool 
00021 {
00022     using namespace coool;
00023 
00024 SPalette::SPalette() : 
00025     m_UseV7(false), m_WSmoothness(0.0f), m_WErrorMin(0.0f),
00026     m_CXF31toRGB(3,31,vuColourRGBa::getCXF31toRGB()),
00027     m_CXF7toRGB(3,7,vuColourRGBa::getCXF7toRGB()),
00028     m_CXF31to7(7,31,vuColour7a::getCXF31to7())
00029 {
00030     // add white reference spectra to each list
00031     SSpectrum tmp(vuColour31a(1.0f));
00032     m_Lights.add(tmp);
00033     m_Refls.add(tmp);
00034 }
00035 
00036 SPalette::~SPalette()
00037 {
00038     //vuDVectors destruct themselves :-)
00039 }
00040 
00041 void SPalette::reset()
00042 {
00043     m_Lights.removeRange(0,m_Lights.getLength());
00044     m_Refls.removeRange(0,m_Refls.getLength());
00045 }
00046 
00047 int SPalette::addLight(const vuColour31a& light)
00048 {
00049     dword index = m_Lights.getLength(); //vuDVector always adds to the end
00050     SSpectrum tmp(light,index);
00051     m_Lights.add(tmp);
00052     //update m_DesCol dimensions and entries
00053     SDesignColour dcol;
00054     dword nrefl = m_Refls.getLength();
00055     for(dword i=0;i<nrefl;i++)
00056         m_DesCol[i][index] = dcol;
00057     return (int)index;
00058 }
00059 
00060 void SPalette::removeLight(word index)
00061 {
00062     m_Lights.remove(index);
00063     dword nrefl = m_Refls.getLength();
00064     for(dword i=0;i<nrefl;i++)
00065         m_DesCol[i].remove(index);
00066 }
00067 
00068 int SPalette::addReflectance(const vuColour31a& refl)
00069 {
00070     dword index = m_Refls.getLength();  //vuDVector always adds to the end
00071     SSpectrum tmp(refl,index);
00072     m_Refls.add(tmp);
00073     //update m_DesCol dimensions and entries
00074     SDesignColour dcol;
00075     int nlights = (int)m_Lights.getLength();
00076     for(int i=nlights-1;i>=0;i--)
00077     {
00078         m_DesCol[index][i] = dcol;
00079     }
00080     return (int)index;
00081 }
00082 
00083 void SPalette::removeReflectance(word index)
00084 {
00085     m_Refls.remove(index);
00086     m_DesCol.remove(index);     // just remove a row from the 2D array
00087 }
00088 
00090 vuColourRGBa SPalette::getRLColour(dword rid, dword lid, bool useV7)
00091 {
00092     if(rid<m_Refls.getLength() && lid<m_Lights.getLength())
00093     {
00094         if(useV7)
00095             return vuColourRGBa(vuColour7a(m_Lights[lid].spec)*
00096                                 vuColour7a(m_Refls[rid].spec)
00097                                 ).clampTo01();
00098         else
00099             return vuColourRGBa(m_Lights[lid].spec*m_Refls[rid].spec
00100                                 ).clampTo01();
00101     }
00102     return vuColourRGBa(0.0f);
00103 }
00104 
00105 void SPalette::setDesignRGBW(dword rid, dword lid, const vuColourRGBa& col)
00106 {
00107     if(rid<m_Refls.getLength() && lid<m_Lights.getLength())
00108     {
00109         m_DesCol[rid][lid].rgbw = col;
00110         m_DesCol[rid][lid].design = true;
00111     }
00112 }
00113 
00115 vuColourRGBa& SPalette::getDesignRGBW(dword rid, dword lid)
00116 {
00117     if(rid<m_Refls.getLength() && lid<m_Lights.getLength())
00118         return m_DesCol[rid][lid].rgbw;
00119     else throw "vuSpecPalette::getDesignRGBW: Out of bounds!";
00120 }
00121 
00122 void SPalette::attachFreeColour(dword rid, dword lid, int fcid)
00123 {
00124     if(rid<m_Refls.getLength() && lid<m_Lights.getLength()) {
00125         if(fcid >= (int)m_FreeCol.getLength()) 
00126             setFreeColour(fcid);
00127         m_DesCol[rid][lid].freecolour = fcid;
00128     };
00129 }
00130 
00131 void SPalette::setFreeColour(dword fcid, 
00132                              const vuColourRGBa& lb, const vuColourRGBa& ub)
00133 {
00134     SFreeColour tmp(fcid,lb,ub);
00135     m_FreeCol[fcid] = tmp;
00136 }
00137 
00139 void SPalette::matchDesignColours()
00140 {
00141     for(dword r=0;r<getNRefls();r++)
00142         for(dword l=0;l<getNLights();l++)
00143         {
00144             vuColourRGBa rgbw(getRLColour(r,l,m_UseV7));
00145             rgbw[3] = 1;
00146             setDesignRGBW(r,l,rgbw);
00147         }
00148 }
00149 
00151 bool SPalette::load(const char* filename)
00152 {
00153     ifstream is(filename);
00154     if(is.good()) {
00155         reset();
00156         try{
00157             while(!is.eof())
00158             {
00159                 char rl='x';
00160                 is>>ws;         // remove leading whitespace
00161                 is>>rl;
00162                 switch(tolower(rl)) {
00163                     case 'r': 
00164                     {
00165                         int id = addReflectance(vuColour31a());
00166                         is>>m_Refls[id];
00167                     } break;
00168                     case 'l':
00169                     {
00170                         int id = addLight(vuColour31a());
00171                         is>>m_Lights[id];
00172                     } break;
00173                     case 'x':
00174                         //we're done very soon...
00175                         break;
00176                     default:
00177                         cout << "Error in palette definition" << endl;
00178                         cout << "char: " << rl << endl;
00179                         return false;
00180                 }
00181             }
00182         } catch (const char* msg) {
00183             cout << "Error loading palette: " << msg <<endl;
00184             return false;
00185         }
00186     } else return false;
00187     return true;
00188 }
00189 
00191 bool SPalette::save(const char* filename)
00192 {
00193     ofstream os(filename);
00194     if(os.good()) {
00195         try{
00196             for(int id=0;id<(int)m_Refls.getLength();id++)
00197                 os << 'r' << m_Refls[id] << endl;
00198             for(int id=0;id<(int)m_Lights.getLength();id++)
00199                 os << 'l' << m_Lights[id] << endl;
00200         } catch (const char* msg) {
00201             cout << "Error saving palette: " << msg <<endl;
00202             return false;
00203         }
00204     } else return false;
00205     return true;
00206 }
00209 bool SPalette::loadSpectrum(int rid, int lid, const char* filename)
00210 {
00211     if(rid<(int)m_Refls.getLength() && lid<(int)m_Lights.getLength())
00212     {
00213                 ifstream is(filename);
00214                 if(is.good()) {
00215                         SSpectrum &specrec = getSpecRec(rid, lid);
00216                         try{
00217                                 is>>specrec;
00218                         } catch (const char* msg) {
00219                                 cerr << "Error loading spectrum: " << msg <<endl;
00220                         return false;
00221                         }
00222                 } else return false;
00223     } else return false;
00224     return true;
00225 }
00226 
00229 bool SPalette::saveSpectrum(int rid, int lid, const char* filename)
00230 {
00231     if(rid<(int)m_Refls.getLength() && lid<(int)m_Lights.getLength())
00232     {
00233         ofstream os(filename);
00234         if(os.good()) {
00235             SSpectrum &specrec = getSpecRec(rid, lid);
00236             try{
00237                 os<<specrec;
00238             } catch (const char* msg) {
00239                 cout << "Error saving spectrum: " << msg <<endl;
00240                 return false;
00241             }
00242         } else return false;
00243     } else return false;
00244     return true;
00245 }
00246 
00247 
00250 bool SPalette::checkSetup()
00251 {
00252     for(dword c=0;c<m_FreeCol.getLength();c++)
00253         m_FreeCol[c].used=0;
00254     for(dword c=0;c<m_Lights.getLength();c++)
00255         m_Lights[c].used=0;
00256     for(dword c=0;c<m_Refls.getLength();c++)
00257         m_Refls[c].used=0;
00258 
00259     m_NDesCol=0;
00260     for(dword r=0;r<m_Refls.getLength();r++)
00261     {
00262         for(dword l=0;l<m_Lights.getLength();l++)
00263         {
00264             if(m_DesCol[r][l].getWeight()>0 && m_DesCol[r][l].design)
00265             {
00266                 //we can't design a light and a reflectance if
00267                 //their colour is a design criterium
00268                 if(m_Lights[l].design && m_Refls[r].design)
00269                     return false;
00270                 else if(m_Lights[l].design || m_Refls[r].design)
00271                 {
00272                     m_NDesCol++;
00273                     if(m_DesCol[r][l].freecolour>=0)
00274                         m_FreeCol[m_DesCol[r][l].freecolour].used++;
00275                     if(m_Lights[l].design)
00276                         m_Lights[l].used++;
00277                     else //if(m_Refls[r].design)
00278                         m_Refls[r].used++;
00279                     //cout<<r<<"r   (checksetup)  l"<<l<<endl;
00280                 }
00281             } else m_DesCol[r][l].design=false;
00282         }
00283     }
00284     if(m_WSmoothness == 0) m_UseSmoothness = false;
00285     if(m_WErrorMin == 0) m_UseErrorMin = false;
00286     
00287     return true;
00288 }
00289 
00291 void SPalette::setSmoothnessWeight(float weight) {
00292     if(weight <= 0.0) {
00293         m_WSmoothness = 0.0f;
00294         m_UseSmoothness = false;
00295     } else {
00296         m_WSmoothness = weight;
00297         m_UseSmoothness = true;
00298     }
00299 };
00300 
00302 void SPalette::setErrorMinWeight(float weight) {
00303     if(weight <= 0.0) {
00304         m_WErrorMin = 0;
00305         m_UseErrorMin = false;
00306     } else {
00307         m_UseErrorMin = true;
00308         m_WErrorMin = weight;
00309     }
00310 };
00311 
00313 SMatrix SPalette::makeErrorMat(const vuColour31a& diag)
00314 {
00315     SMatrix res(3,31);
00316     SMatrix dmat31(31,31);
00317     dmat31.makeDiag(SVector(31,diag.getData()));
00318     res = m_CXF31toRGB*dmat31;
00319     SMatrix dmat7(7,7);
00320     //cout << "light7: " << m_CXF31to7*SVector(31,diag.getData()) << endl;
00321     dmat7.makeDiag(m_CXF31to7*SVector(31,diag.getData()));
00322     //cout << "DIAG7: " << dmat7 << cout;
00323     
00324     res -= (m_CXF7toRGB*dmat7*m_CXF31to7);
00325     res *= m_WErrorMin;
00326     return res;
00327 }
00328 
00330 SMatrix SPalette::makeSmoothingMat()
00331 {
00332     SMatrix res(31,31);
00333 /* we don't use 1st derivative
00334     static float vd1[] = {1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00335                           0,0,0,0,0,0,0,0,0,0,0,0,0};
00336     res.makeToeplitz(SVector(31,vd2),false);
00337 */  
00338     static float vd2data[] = {2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00339                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00340     SVector vd2(31,vd2data);
00341     vd2 *= 1/vd2.norm()/SQRT_31; //sqrt(31.0f);
00342     res.makeToeplitz(vd2,true);
00343     res *= m_WSmoothness;
00344     return res;
00345 }
00346 
00351 SMatrix SPalette::makeCXFMat(const vuColour31a& diag, bool useV7)
00352 {
00353     if(useV7) {
00354         SMatrix dmat7(7,7);
00355         dmat7.makeDiag(m_CXF31to7*SVector(diag));
00356         return m_CXF7toRGB*dmat7*m_CXF31to7;
00357     } else {
00358         SMatrix dmat31(31,31);
00359         dmat31.makeDiag(SVector(diag));
00360         return m_CXF31toRGB*dmat31;
00361     }
00362 }
00363 
00367 bool SPalette::createSpectrum()
00368 {
00369   try{
00370         
00371     if(!checkSetup()) return false;
00372     
00373 // determine column of design matrix for this 'free colour'
00374     dword posfc=0;
00375     for(dword c=0;c<m_FreeCol.getLength();c++)
00376         if(m_FreeCol[c].used) m_FreeCol[c].position = (posfc++);
00377     dword ndesl=0;
00378     for(dword c=0;c<m_Lights.getLength();c++)
00379         if(m_Lights[c].used) ndesl++;
00380     dword ndesr=0;
00381     for(dword c=0;c<m_Refls.getLength();c++)
00382         if(m_Refls[c].used) ndesr++;
00383 
00384     if(ndesr+ndesl == 0) return false;
00385     
00386 //prepare M and y for constrained minimization of |Mx - y|
00387     dword nrows = ( 3*m_NDesCol + (m_UseErrorMin?3:0)*m_NDesCol +
00388               (m_UseSmoothness?31:0)*(ndesr+ndesl));
00389     dword ncols = 3*posfc + 31*ndesl + 31*ndesr;
00390     SMatrix M(nrows,ncols,0.0f);
00391     SVector y(nrows,0.0f);
00392 
00393 //make upper and lower bounds
00394     SVector lb(ncols,-SPAL_RANGE),ub(ncols,SPAL_RANGE);
00395     bool useBounds = false;
00396     posfc=0;
00397     for(dword c=0;c<m_FreeCol.getLength();c++)
00398         if(m_FreeCol[c].used) {
00399             useBounds=true;
00400             ub.insert(SVector(3,m_FreeCol[c].ub.getData()), 3*posfc);
00401             lb.insert(SVector(3,m_FreeCol[c].lb.getData()), 3*posfc);
00402             posfc++;
00403         }
00404     //ub.insert(SVector(posfc*3,1.0f)); //ub for 'free colours' = 1    
00405 
00406     SMatrix id33(3,3);
00407     id33.makeIdentity();
00408     dword curcol=3*posfc;
00409     dword currow=0;
00410 //make matrix for the lights that have to be designed
00411     for(dword l=0;l<m_Lights.getLength();l++)
00412         if(m_Lights[l].used) 
00413         {
00414             SSpectrum &speclig = m_Lights[l];
00415             if(speclig.useBounds) {
00416                 useBounds=true;
00417                 ub.insert(SVector(speclig.ub),curcol);
00418                 lb.insert(SVector(speclig.lb),curcol);
00419             }
00420             for(dword r=0;r<m_Refls.getLength();r++)
00421                 if(m_DesCol[r][l].design)
00422                 {
00423                     float weight = m_DesCol[r][l].getWeight();
00424                     SSpectrum &specrec = m_Refls[r];
00425                     M.insert(weight * makeCXFMat(specrec.spec,m_UseV7),
00426                              currow,curcol);
00427                     if(m_DesCol[r][l].freecolour>=0) 
00428                     {
00429                         SFreeColour& fc = m_FreeCol[m_DesCol[r][l].freecolour];
00430                         M.insert(-weight*id33,currow,
00431                                  3*fc.position);
00432                     } else                  
00433                         y.insert(weight*m_DesCol[r][l].getCol(),currow);
00434                     
00435                     currow+=3;
00436                     if(m_UseErrorMin)
00437                     {
00438 #ifdef USE_ERRORMAT
00439                         M.insert(weight*makeErrorMat(specrec.spec),
00440                                  currow,curcol);
00441 #else
00442                         M.insert((m_WErrorMin*weight) * 
00443                                  makeCXFMat(specrec.spec,!m_UseV7),
00444                                  currow,curcol);
00445                         y.insert((m_WErrorMin*weight)*
00446                                  m_DesCol[r][l].getCol(),currow);
00447 #endif  // of USE_ERRORMAT
00448                         currow+=3;
00449                     }
00450                 }
00451             if(m_UseSmoothness)
00452             {
00453                 M.insert(makeSmoothingMat(),currow,curcol);
00454                 currow+=31;
00455             }
00456             curcol+=31;
00457         }
00458     
00459 //make matrix for the reflectances that have to be designed
00460     for(dword r=0;r<m_Refls.getLength();r++)
00461         if(m_Refls[r].used) 
00462         {
00463             SSpectrum &specref = m_Refls[r];
00464             if(specref.useBounds) {
00465                 useBounds=true;
00466                 ub.insert(SVector(specref.ub),curcol);
00467                 lb.insert(SVector(specref.lb),curcol);
00468             }
00469             for(dword l=0;l<m_Lights.getLength();l++)
00470                 if(m_DesCol[r][l].design)
00471                 {
00472                     float weight = m_DesCol[r][l].getWeight();
00473                     SSpectrum &specrec = m_Lights[l];
00474                     M.insert(weight * makeCXFMat(specrec.spec,m_UseV7),
00475                              currow,curcol);
00476                     if(m_DesCol[r][l].freecolour>=0) {
00477                         SFreeColour& fc = m_FreeCol[m_DesCol[r][l].freecolour];
00478                         M.insert(-weight*id33,currow,
00479                                  3*fc.position);
00480                     } else
00481                         y.insert(weight*m_DesCol[r][l].getCol(),currow);
00482 
00483                     currow+=3;
00484                     if(m_UseErrorMin)
00485                     {
00486 #ifdef USE_ERRORMAT
00487                         M.insert(weight*makeErrorMat(specrec.spec),
00488                                  currow, curcol);
00489 #else
00490                         M.insert((m_WErrorMin*weight)*
00491                                  makeCXFMat(specrec.spec,!m_UseV7),
00492                                  currow, curcol);
00493                         y.insert((m_WErrorMin*weight)*
00494                                  m_DesCol[r][l].getCol(),currow);
00495 #endif
00496                         currow+=3;
00497                     }
00498                 }
00499             if(m_UseSmoothness)
00500             {
00501                 M.insert(makeSmoothingMat(),currow,curcol);
00502                 currow+=31;
00503             }
00504             curcol+=31;
00505         }
00506 
00507 //show stuff
00508 //      cout << lb << "-----" << endl;
00509 //      cout << ub << "-----" << endl;
00510 //      cout << M << "-----" << endl;
00511 //      cout << y << "-----" << endl;
00512 //    m_Optimizer.setVerbose();
00513     
00514     
00515 //optimize using constraints
00516     SVector x;
00517     if(useBounds)
00518         x = m_Optimizer.minimize(M,y,lb,ub);    // constrained opt.
00519     else 
00520         x = m_Optimizer.minimize(M,y);          // unconstrained opt.
00521     
00522 //read results into light and reflectance slots
00523     double *res = x.getData() + 3*posfc;        // skip free colours
00524     for(dword l=0;l<m_Lights.getLength();l++)
00525         if(m_Lights[l].used) 
00526         {
00527             m_Lights[l].spec = vuColour31a (res);
00528             res+=31;
00529         }
00530     
00531     for(dword r=0;r<m_Refls.getLength();r++)
00532         if(m_Refls[r].used) 
00533         {
00534             m_Refls[r].spec = vuColour31a (res);
00535             res+=31;
00536         }
00537   }catch (const char* msg)
00538   {
00539       cout << "SPalette::createSpectrum() EXCEPTION: " << msg <<endl;
00540       return false;
00541   }
00542   
00543   return true;
00544 }
00545  
00546 }
00547 

Generated on Wed Dec 15 21:20:31 2004 for vuVolume by  doxygen 1.3.9.1