fshake3d  0.0.1
FreeformDensity3DSurfaceEditor
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines
scene_FunctionMixer.cpp
Go to the documentation of this file.
00001 #include "scene_FunctionMixer.hpp"
00002 #include "opengl.hpp"
00003 #include <boost/bind.hpp>
00004 #include <float.h>
00005 
00006 // --- constructor -----------------------------------------------------------
00007 
00008 FunctionMixer::FunctionMixer()
00009 : mpElevationGrid(0)
00010 , mSelectHotSpot(0)
00011 , mPointSize(1.0)
00012 , mTex(-1)
00013 , mList(-1)
00014 , mLayerMask(~0U)
00015 , mDefaultXSD(10.0)
00016 , mDefaultYSD(10.0)
00017 , mDefaultAlpha(0.0)
00018 , mPointSizeChanged(true)
00019 {
00020   initControls();
00021   setElevationGrid(0);
00022 }
00023 
00024 // --- initialize ui ---------------------------------------------------------
00025 
00026 void FunctionMixer::initControls()
00027 {
00028   Vec4d bgcolor(0.0,0.0,0.0,0.2);
00029   Vec4d colorx(0.8,0.8,0.8,0.3);
00030   Vec4d colory(0.8,0.8,0.8,0.3);
00031   Vec4d colorz(0.8,0.8,0.8,0.3);
00032 
00033   mControlZ.setBorder(mPointSize);
00034   mControlZ.setEnabled(false);
00035   mControlZ.setAxis(AXIS_Z);
00036   mControlZ.setUpAxis(AXIS_X);
00037   mControlZ.setColor(colorz);
00038   mControlZ.setBGColor(bgcolor);
00039   mControlZ.setAbsMode(ABSMODE_POSITIVE);  
00040   mControlZ.setKnobType(KNOB_TRANSLATE);
00041   // BUG: sensor volume is not displayed using  ( -DBL_MAX , DBL_MAX ) 
00042   // mControlZ.setMinValue(-DBL_MAX);
00043   // mControlZ.setMaxValue(DBL_MAX);
00044   mControlZ.setMinValue(-10000);
00045   mControlZ.setMaxValue(10000);
00046   mControlZ.setSlotValueChange( boost::bind( &FunctionMixer::updateHotSpotZ, this, _1 ) );  
00047   
00048   mControlXSD.setBorder(mPointSize);
00049   mControlXSD.setEnabled(false);
00050   mControlXSD.setAxis(AXIS_X);
00051   mControlXSD.setUpAxis(AXIS_Z);
00052   mControlXSD.setColor(colorx);
00053   mControlXSD.setBGColor(bgcolor);
00054   mControlXSD.setAbsMode(ABSMODE_MIRROR);
00055   mControlXSD.setKnobType(KNOB_STRETCH);
00056   mControlXSD.setMinValue(-10000);
00057   mControlXSD.setMaxValue(10000);
00058   // mControlXSD.setMinValue(DBL_MIN);
00059   // mControlXSD.setMaxValue(DBL_MAX);
00060   mControlXSD.setSlotValueChange( boost::bind( &FunctionMixer::setXSD, this, _1 ) );
00061 
00062   mControlYSD.setBorder(mPointSize);
00063   mControlYSD.setEnabled(false);
00064   mControlYSD.setAxis(AXIS_Y);
00065   mControlYSD.setUpAxis(AXIS_Z);
00066   mControlYSD.setColor(colory);
00067   mControlYSD.setBGColor(bgcolor);
00068   mControlYSD.setAbsMode(ABSMODE_MIRROR);
00069   mControlYSD.setKnobType(KNOB_STRETCH);
00070   mControlYSD.setMinValue(-10000);
00071   mControlYSD.setMaxValue(10000);
00072   // mControlYSD.setMinValue(DBL_MIN);
00073   // mControlYSD.setMaxValue(DBL_MAX);
00074   mControlYSD.setSlotValueChange( boost::bind( &FunctionMixer::setYSD, this, _1 ) );
00075 
00076   mPlotX.setEnabled(false);
00077   mPlotX.setColor(colorx);
00078   mPlotX.setSteps(100);
00079   mPlotX.setXAxis(0);
00080   mPlotX.setYAxis(2);
00081   mPlotX.setYScale(1000.0);
00082 
00083   mPlotY.setEnabled(false);
00084   mPlotY.setColor(colory);
00085   mPlotY.setSteps(100);
00086   mPlotY.setXAxis(1);
00087   mPlotY.setYAxis(2);
00088   mPlotY.setYScale(1000.0);
00089 
00090   if (mpElevationGrid)
00091   {
00092     mPlotX.setXLimits( mpElevationGrid->getXLimits() );
00093     mPlotY.setXLimits( mpElevationGrid->getYLimits() );
00094   }
00095 
00096 }
00097 
00098 // --- model -----------------------------------------------------------------
00099 
00100 void FunctionMixer::clear()
00101 {
00102   unselect();
00103 
00104   size_t n = getHotSpotCount();
00105   for (size_t i = 0; i < n ; ++i )
00106   {
00107     delete &getHotSpotAtIndex(i);
00108   }
00109   mHotSpots.clear();
00110   mHotSpotMap.clear();
00111   updateElevationGrid();
00112 }
00113 
00114 HotSpot* FunctionMixer::getHotSpotAtPoint2d(const Point2d& p)
00115 {
00116   std::map< Point2d, HotSpot*>::iterator i = mHotSpotMap.find(p);
00117   if ( i == mHotSpotMap.end() )
00118   {
00119     HotSpot* pHotSpot = new HotSpot(p[0],p[1],mDefaultXSD,mDefaultYSD,mDefaultAlpha);
00120     addHotSpot(pHotSpot);
00121     return pHotSpot;
00122   }
00123   return i->second;
00124 
00125 }
00126 
00127 
00128 void FunctionMixer::setElevationGrid(ElevationGrid* pElevationGrid)
00129 {
00130   unselect();
00131   mpElevationGrid = pElevationGrid;
00132   if (mpElevationGrid)
00133   {
00134     mPlotX.setXLimits( mpElevationGrid->getXLimits() );
00135     mPlotY.setXLimits( mpElevationGrid->getYLimits() );
00136   }
00137 }
00138 
00139 void FunctionMixer::addHotSpot(HotSpot* pHotSpot)
00140 {
00141   mHotSpots.push_back(pHotSpot);
00142   mHotSpotMap[ Point2d( pHotSpot->getXMean(), pHotSpot->getYMean() ) ] = pHotSpot;
00143 }
00144 
00145 void FunctionMixer::removeHotSpot(HotSpot* pHotSpot)
00146 {
00147   std::vector<HotSpot*>::iterator i = std::find( mHotSpots.begin(), mHotSpots.end(), pHotSpot );
00148   if ( i != mHotSpots.end() )
00149   {
00150     mHotSpots.erase(i);
00151   }
00152   std::map<Point2d,HotSpot*>::iterator j = mHotSpotMap.find( Point2d( pHotSpot->getXMean(), pHotSpot->getYMean() ) );
00153   if ( j != mHotSpotMap.end() )
00154   {
00155     mHotSpotMap.erase(j);
00156   }
00157   delete pHotSpot;
00158   updateElevationGrid();
00159 }
00160 
00161 // --- (re-) compute elevation grid ------------------------------------------
00162 
00163 double FunctionMixer::computeAt(double x, double y)
00164 {
00165   double z = 0;
00166   for ( std::vector<HotSpot*>::iterator i = mHotSpots.begin(), end = mHotSpots.end() ; i != end ; ++i )
00167   {
00168     z += (*i)->compute(x,y);
00169   }  
00170   return z;
00171 }
00172 
00173 double FunctionMixer::computeAtWithout(double x, double y, HotSpot* pHotSpot)
00174 {
00175   double z = 0;
00176   for ( std::vector<HotSpot*>::iterator i = mHotSpots.begin(), end = mHotSpots.end() ; i != end ; ++i )
00177   {
00178     if (*i != pHotSpot)
00179       z += (*i)->compute(x,y);
00180   }  
00181   return z;
00182 }
00183 
00184 
00189 void FunctionMixer::updateElevationGrid()
00190 {
00191   if (mpElevationGrid)
00192   {
00193     Vec2d xlim   = mpElevationGrid->getXLimits();
00194     Vec2d ylim   = mpElevationGrid->getYLimits();
00195     double xsize = xlim[1]-xlim[0];
00196     double ysize = ylim[1]-ylim[0];
00197     int nysteps  = mpElevationGrid->getYSteps();
00198     int nxsteps  = mpElevationGrid->getXSteps();
00199 
00200     for(int iy = 0; iy < nysteps ; ++iy )
00201     {
00202       double y = ylim[0] + (ysize/(nysteps-1))*iy;
00203       for (int ix = 0; ix < nxsteps ; ++ix )
00204       {
00205         double x = xlim[0] + (xsize/(nxsteps-1))*ix;
00206         
00207         double z = 0;
00208         for ( std::vector<HotSpot*>::iterator i = mHotSpots.begin(), end = mHotSpots.end() ; i != end ; ++i )
00209         {
00210           z += (*i)->compute(x,y);
00211         }
00212         mpElevationGrid->updatePositionZ(ix,iy,z);
00213       }
00214     }
00215     mpElevationGrid->computeNormals();
00216   }
00217 }
00218 
00219 // --- hotspot control -------------------------------------------------------
00220 
00221 void FunctionMixer::selectHotSpot(const Point2d& p)
00222 {
00223   mSelectHotSpot = getHotSpotAtPoint2d(p);
00224   if ( mSelectHotSpot )
00225   {
00226     mSelectPoint    = Vec3d(p[0],p[1], computeAt(p[0],p[1]) );
00227     mSelectHotSpotZ = mSelectHotSpot->computeBase(mSelectPoint[0],mSelectPoint[1]);
00228     mSelectBaseZ    = mSelectPoint[2] - mSelectHotSpot->compute(mSelectPoint[0],mSelectPoint[1]);
00229  
00230     // some coordinates:
00231     Point3d controlPosition( mSelectPoint[0], mSelectPoint[1], -0.1 );
00232     Point3d basePosition( mSelectPoint[0],mSelectPoint[1], 0.0 );
00233 
00234     // setup hotspot z control
00235 
00236     mControlZ.setPosition( basePosition );
00237     mControlZ.setValue( mSelectPoint[2] );
00238     mControlZ.setEnabled(true);
00239 
00240     // setup hotspot x/y standard deviation controls
00241 
00242     mControlXSD.setPosition( controlPosition );
00243     mControlXSD.setValue( mSelectHotSpot->getXSD() );
00244     mControlXSD.setEnabled(true);
00245 
00246     mControlYSD.setPosition( controlPosition );
00247     mControlYSD.setValue( mSelectHotSpot->getYSD() );
00248     mControlYSD.setEnabled(true);
00249 
00250     // setup plot controls
00251 
00252     mPlotX.setPosition( basePosition );
00253     mPlotY.setPosition( basePosition );
00254     mPlotX.setFunction( boost::bind( &HotSpot::computeX, mSelectHotSpot, _1 ) );
00255     mPlotY.setFunction( boost::bind( &HotSpot::computeY, mSelectHotSpot, _1 ) );
00256     // mPlotX.setEnabled(true);
00257     // mPlotY.setEnabled(true);
00258   }
00259 }
00260 
00261 // --- manipulate z ----------------------------------------------------------
00262 
00263 void FunctionMixer::updateHotSpotZ(double z)
00264 {
00265   if (mpElevationGrid)
00266   {
00267     if (mSelectHotSpot)
00268     {
00269       double restz = computeAtWithout(mSelectPoint[0],mSelectPoint[1], mSelectHotSpot);
00270       mSelectHotSpot->setAlpha( (z - restz) / mSelectHotSpot->computeBase(mSelectPoint[0],mSelectPoint[1]) );
00271       mSelectPoint[2] = computeAt(mSelectPoint[0],mSelectPoint[1]);
00272       updateElevationGrid();  
00273     }
00274   }
00275 }
00276 
00277 // --- manipulate sd ---------------------------------------------------------
00278 
00279 /*
00280 template<typename T>
00281 inline T filter_sd(T x)
00282 {
00283   return clamp<T>( abs(x), 0.0000000001, 100);
00284 }
00285 */
00286 
00287 void FunctionMixer::setXSD(double xsd)
00288 {
00289   if (mSelectHotSpot)
00290   {    
00291     // update hotspot   
00292     mSelectHotSpot->setXSD( xsd );
00293 
00294     // update alpha
00295     updateHotSpotZ( mSelectPoint[2] );
00296   }
00297 }
00298 
00299 void FunctionMixer::setYSD(double ysd)
00300 {
00301   if (mSelectHotSpot)
00302   {
00303     // update hotspot   
00304     mSelectHotSpot->setYSD( ysd );
00305 
00306     // update alpha
00307     updateHotSpotZ( mSelectPoint[2] );
00308   }
00309 }
00310 
00311 // --- user-input ------------------------------------------------------------
00312 
00313 void FunctionMixer::setPointSize(double pointsize)
00314 {
00315   mPointSize = pointsize;
00316   mControlZ.setBorder(mPointSize);
00317   mControlXSD.setBorder(mPointSize);
00318   mControlYSD.setBorder(mPointSize);
00319   mPointSizeChanged = true;  
00320 }
00321 
00322 
00323 void FunctionMixer::removeSelected()
00324 {
00325   if (mSelectHotSpot)
00326   {
00327     HotSpot* hs = mSelectHotSpot;
00328     unselect();
00329     removeHotSpot(hs);
00330   }
00331 }
00332 
00333 bool FunctionMixer::select(const Rayd& ray, SceneView& view)
00334 {
00335   if (mpElevationGrid)
00336   {
00337     double t;
00338     Slider* pNear = 0;
00339     double  tnear = DBL_MAX;
00340 
00341     if ( mControlZ.hit(ray, t) )
00342     {
00343       pNear = &mControlZ;
00344       tnear = t;
00345     }
00346 
00347     if ( mControlXSD.hit(ray, t) )
00348     {
00349       if ( t < tnear)
00350       {
00351         pNear = &mControlXSD;
00352         tnear = t;
00353       }
00354     }
00355 
00356     if (mControlYSD.hit(ray,t) )
00357     {
00358       if (t < tnear)
00359       {
00360         pNear = &mControlYSD;
00361         tnear = t;
00362       }
00363     }
00364 
00365     if (pNear)
00366     {
00367       pNear->select(ray,view);
00368       return true;
00369     }
00370 
00371     int x,y;
00372     if ( mpElevationGrid->intersect(ray, x, y, mPointSize ) )
00373     {
00374       Point3d p = mpElevationGrid->getPoint(x,y);
00375       selectHotSpot( Point2d(p[0],p[1]) );
00376       mControlZ.select(ray,view);
00377       return true;
00378     }
00379   }
00380   unselect();
00381   return false;
00382 }
00383 
00384 void FunctionMixer::unselect()
00385 {
00386   mSelectHotSpot = 0;
00387   mControlZ.setEnabled(false);
00388   mControlXSD.setEnabled(false);
00389   mControlYSD.setEnabled(false);
00390   mPlotX.setEnabled(false);
00391   mPlotY.setEnabled(false);
00392 }
00393 
00394 bool FunctionMixer::drag(const Rayd& ray, SceneView& view)
00395 {
00396   if (mpElevationGrid)
00397   {
00398     if ( mControlZ.drag(ray,view) ) return true;
00399     if ( mControlXSD.drag(ray,view) ) return true;
00400     if ( mControlYSD.drag(ray,view) ) return true;
00401   }
00402   return false;
00403 }
00404 
00405 // --- display ---------------------------------------------------------------
00406 
00407 
00408 void FunctionMixer::display()
00409 { 
00410   if (mpElevationGrid)
00411   {
00412     displaySurface();
00413     if (mSelectHotSpot)
00414     {
00415       displayControls();
00416     }
00417   }
00418 }
00419 
00420 void FunctionMixer::displayControls()
00421 {
00422   mControlZ.display();
00423   mControlXSD.display();
00424   mControlYSD.display();
00425   mPlotX.display();
00426   mPlotY.display();
00427 }
00428 
00429 void FunctionMixer::displayAlpha()
00430 {
00431   glPushAttrib(GL_ENABLE_BIT|GL_LINE_BIT);
00432   glEnable(GL_BLEND);
00433   glColor4d(1.0,1.0,1.0,0.5);
00434   glDisable(GL_LIGHTING);
00435   glDisable(GL_DEPTH_TEST);
00436   double x = mSelectHotSpot->getXMean();
00437   double y = mSelectHotSpot->getYMean();
00438   double z = computeAt(x,y);
00439   glLineWidth(2.0);
00440   glBegin(GL_LINES);
00441   glVertex3d(x,y,z);
00442   glVertex3d(x,y,z-mSelectHotSpot->getAlpha());
00443   glEnd();    
00444   glPopAttrib();
00445 }
00446 
00447 void FunctionMixer::displaySurface()
00448 {  
00449   // GL resources:
00450 
00451   if (mList == -1)
00452   {
00453     // init Display List
00454     mList = glGenLists(1);
00455   }
00456 
00457   if (mPointSizeChanged)
00458   {
00459     glNewList(mList, GL_COMPILE);
00460     glutSolidSphere( mPointSize , 12, 12 );
00461     glEndList();
00462     mPointSizeChanged = false;
00463   }
00464 
00465   if (mTex == -1)
00466   {
00467     // init height color 1D texture
00468     glGenTextures(1, &mTex);
00469     glBindTexture(GL_TEXTURE_1D, mTex);
00470     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00471     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00472     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00473     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00474 
00475     Vec3d cols[4] = { Vec3d(0.3,0.5,0.3),Vec3d(0.8,0.6,0.4),Vec3d(1.0,1.0,1.0),Vec3d(0.0,0.0,1.0) };
00476 
00477     // Vec3d cols[4] = { Vec3d(0.3,0.5,0.3),Vec3d(0.8,0.6,0.4),Vec3d(0.6,1.0,0.6),Vec3d(1.0,0.6,0.6) };
00478     unsigned char* colormap = new_colormap(256, &cols[0], sizeof(cols)/sizeof(Vec3d) );
00479     
00480     glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, colormap);
00481     delete [] colormap;
00482     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00483   }
00484 
00485   // display control points
00486   glEnable(GL_LIGHT0);
00487 
00488   // display hotspots
00489   if ( isLayerEnabled(LAYER_HOTSPOTS) )
00490   {
00491     glPushAttrib(GL_ENABLE_BIT);
00492 
00493     glEnable(GL_LIGHTING);
00494     glEnable(GL_DEPTH_TEST);
00495 
00496     GLfloat pointDiffuse[4] = { 0.7, 0.3, 0.3, 1.0 };
00497     GLfloat pointAmbient[4] = { 0.2, 0.2, 0.2, 1.0 };
00498     glMaterialfv(GL_FRONT, GL_DIFFUSE, pointDiffuse);
00499     glMaterialfv(GL_FRONT, GL_AMBIENT, pointAmbient);
00500 
00501     glMatrixMode(GL_MODELVIEW);
00502     for ( std::vector<HotSpot*>::iterator i = mHotSpots.begin(), end = mHotSpots.end() ; i != end ; ++i )
00503     {
00504       double x = (*i)->getXMean();
00505       double y = (*i)->getYMean();      
00506       double z = computeAt(x,y);
00507       glPushMatrix();
00508       glTranslated(x,y,z);
00509       glCallList(mList);
00510       glPopMatrix();
00511     }
00512 
00513     glPopAttrib();
00514   }
00515 
00516   if ( isLayerEnabled(LAYER_CONTROLPOINTS) )
00517   {
00518 
00519     glPushAttrib(GL_ENABLE_BIT);
00520 
00521     glEnable(GL_LIGHTING);
00522     glEnable(GL_DEPTH_TEST);
00523 
00524     GLfloat pointDiffuse[4] = { 0.5, 0.5, 0.5, 1.0 };
00525     // GLfloat pointAmbient[4] = { 0.5, 0.5, 0.5, 1.0 };
00526     GLfloat pointAmbient[4] = { 0.1, 0.1, 0.1, 1.0 };
00527     glMaterialfv(GL_FRONT, GL_DIFFUSE, pointDiffuse);
00528     glMaterialfv(GL_FRONT, GL_AMBIENT, pointAmbient);
00529 
00530     mpElevationGrid->drawPointLists(mList);
00531 
00532     glPopAttrib();
00533 
00534   }
00535 
00536   // display grid
00537 
00538   if ( isLayerEnabled(LAYER_GRID))
00539   {
00540     glPushAttrib(GL_ENABLE_BIT|GL_LINE_BIT);
00541 
00542     glEnable(GL_DEPTH_TEST);
00543     glLineWidth(1.5);
00544 
00545     glColor4d(0.0,0.0,0.0,0.5);
00546     mpElevationGrid->drawGrid();
00547 
00548     glPopAttrib();
00549   }
00550 
00551   // display surface
00552 
00553   if ( isLayerEnabled(LAYER_SURFACE) )
00554   {
00555     glPushAttrib(GL_ENABLE_BIT|GL_LIGHTING_BIT);
00556     glEnable(GL_LIGHTING);
00557     glEnable(GL_DEPTH_TEST);
00558     glEnable(GL_TEXTURE_1D);
00559     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00560 
00561     GLfloat surfaceDiffuse[4] = { 1.0, 1.0, 1.0, 1.0 };
00562     GLfloat surfaceAmbient[4] = { 0.5, 0.5, 0.5, 1.0 };
00563     glMaterialfv(GL_FRONT, GL_DIFFUSE, surfaceDiffuse);
00564     // glMaterialfv(GL_FRONT, GL_DIFFUSE, surfaceAmbient);
00565     glMaterialfv(GL_FRONT, GL_AMBIENT, surfaceAmbient);
00566 
00567     mpElevationGrid->drawQuadStripNormalT1D();
00568     glPopAttrib();
00569   }
00570 
00571   // display normals
00572   if ( isLayerEnabled(LAYER_NORMALS) )
00573   {
00574     glPushAttrib(GL_ENABLE_BIT|GL_LINE_BIT);
00575     glEnable(GL_BLEND);
00576     glEnable(GL_DEPTH_TEST);
00577     glDisable(GL_LIGHTING);
00578     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00579     glEnable(GL_DEPTH_TEST);
00580     glLineWidth(1);
00581     glColor4d(0.8,0.4,0.4,0.3);
00582     mpElevationGrid->drawNormalLines(2.0);
00583     glPopAttrib();
00584   }
00585 
00586   if ( !isLayerEnabled(LAYER_CONTROLPOINTS) )
00587   {
00588     glPushAttrib(GL_ENABLE_BIT);    
00589     glEnable(GL_DEPTH_TEST);
00590     glColor3d(0.0,0.0,0.0);
00591     glPointSize(3);
00592     mpElevationGrid->drawPoints();
00593     glPopAttrib();
00594   }
00595 }