C:/Projekte/C++/FlowVIS_107/src/StreamLine.cpp

Go to the documentation of this file.
00001 #include "StreamLine.h"
00002 #include "Texture.h"
00003 #include "Shader.h"
00004 
00005 // needed for random-feed
00006 #include <ctime>
00007 
00008 // needed for writing log-file
00009 #include <iostream>
00010 #include <fstream>
00011 
00012 
00013 StreamLine::StreamLine( FlowData *fd )
00014 {
00015   //cout << "New streamline..." << endl;
00016 
00017   m_flowData = fd;
00018   m_flowGeometry = m_flowData->getGeometry();
00019 
00020   m_dSep  = 0.05f;
00021   m_dTest = m_dSep * 0.5f;
00022 
00023   reset();
00024 }
00025 
00026 
00027 StreamLine::~StreamLine()
00028 {
00029   cout << "Delete streamline..." << endl;
00030 }
00031 
00032 
00033 void StreamLine::create()
00034 {
00035   //cout << "Create streamlines..." << endl;
00036 
00037   /*
00038     - create sl-grid
00039     - find random start-point
00040 
00041     repeat
00042       - create streamline
00043       - create seed-points
00044       - take next seed-point, remove it from queue and check if (still) valid
00045         - if valid -> make new streamline
00046           else -> take next seed-point
00047     until no more seed-points
00048 
00049   */
00050 
00051   //cout << "\n\n -- create SL -- " << endl;
00052 
00053   // reset streamlines
00054   reset();
00055 
00056   // set global parameters
00057   m_d = m_dTest * 0.8f;
00058   m_maxSteps = 1000;
00059   m_maxLines = 5000;
00060   m_maxLineThickness = 0.005f;
00061 
00062   if ( m_dSep==0 ) m_dSep = 0.001f;
00063 
00064   cout << "dsep: " << m_dSep << ", dTest: " << m_dTest << ", d: " << m_d << "\n";
00065 
00066   // just for testing
00067   //setTestParameters();
00068 
00069   // create the initial streamline
00070   m_slgGrid = new StreamLineGrid( m_dSep );
00071   createInitialStreamLine();
00072   createSeedPoints();
00073 
00074   int nrStreamLines = 1;
00075 
00076   // while there are seed-points, create more streamlines
00077   while ( ( nrStreamLines < m_maxLines ) && (!m_seedPoints.empty()) )
00078   {
00079     vec3 startPos = m_seedPoints.at(0);
00080     m_seedPoints.erase( m_seedPoints.begin() );
00081 
00082     // check if valid seedpoint
00083     if ( isValidSeedPoint( startPos ) )
00084     {
00085       createStreamLine( startPos );
00086       createSeedPoints();
00087       ++nrStreamLines;
00088     }
00089   }
00090 
00091   // TEST
00092   //m_slgGrid->printGrid();
00093 
00094   //cout << "\n -- finished SL -- \n" << endl;
00095 
00096 }
00097 
00098 
00099 void StreamLine::create( float dSep, float dTest, bool linesActive, bool taperingActive, bool glyphActive )
00100 {
00101   // set global parameters
00102   m_dSep  = dSep;
00103   m_dTest = dTest;
00104 
00105   m_isLinesActive    = linesActive;
00106   m_isTaperingActive = taperingActive;
00107   m_isGlyphActive    = glyphActive;
00108 
00109   // create the streamline
00110   create();
00111 }
00112 
00113 
00114 void StreamLine::reset()
00115 {
00116   cout << "Reseting streamlines...\n";
00117 
00118   // delete all streamlines
00119   for ( int i=0; i<(int)m_streamLines.size(); i++ )
00120     m_streamLines.at(i).streamLine.clear();
00121 
00122   m_streamLines.clear();
00123   //delete m_slgGrid;
00124 
00125   // delete glyph-texture
00126   if ( m_glyphTexId > 0 )
00127     glDeleteTextures( 1, &m_glyphTexId );
00128 
00129 
00130   // set default values
00131   float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
00132   setLineColor( color );
00133   setGlyphColor( color );
00134 
00135   setGlyphSize( 100 );
00136   m_glyphDistance = 5;
00137 
00138   //m_dSep  = 0.05f;
00139   //m_dTest = m_dSep * 0.5f;
00140 
00141   m_isLinesActive    = true;
00142   m_isTaperingActive = false;
00143   m_isGlyphActive    = false;
00144 
00145   m_glyphTexId = 0;
00146   m_integrationMethod = EULER;
00147 }
00148 
00149 
00150 void StreamLine::draw()
00151 {
00152   cout << "Draw streamlines..." << endl;
00153 
00154   glPushMatrix();
00155 
00156   // draw streamlines
00157   if ( m_isLinesActive )
00158   {
00159       drawStreamLines();
00160   }
00161 
00162   // draw glyphs
00163   if ( m_isGlyphActive )
00164   {
00165     bool haveGlyphTexture = false;
00166 
00167     if ( m_glyphTexId == 0 ) 
00168       // no texture created yet -> create it
00169       haveGlyphTexture = createGlyphTexture();
00170     else
00171       haveGlyphTexture = true;
00172 
00173     if ( haveGlyphTexture ) drawGlyphs();
00174   }
00175 
00176 /*
00177   // TEST
00178   glTranslatef( -0.5f, 0.0f, 0.0f );
00179   glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
00180   glTranslatef(  0.5f, 0.0f, 0.0f );
00181 */
00182   
00183   glPopMatrix();
00184 
00185 }
00186 
00187 
00188 void StreamLine::drawStreamLines() 
00189 {
00190   // save old color
00191   float *oldColor = new float[4];
00192   glGetFloatv( GL_CURRENT_COLOR, oldColor );
00193 
00194   // enable blending
00195   glEnable( GL_BLEND );
00196   glBlendFunc( GL_SRC_ALPHA, GL_ONE );
00197 
00198   // set SL-color
00199   glColor4fv( m_lineColor );
00200 
00201   // with or without tapering
00202   if ( m_isTaperingActive )
00203     drawStreamLinesWithTapering();
00204   else
00205     drawStreamLinesWithoutTapering();
00206 
00207   glDisable( GL_BLEND );
00208 
00209   // restore old color
00210   glColor4fv( oldColor );
00211 }
00212 
00213 
00214 void StreamLine::drawStreamLinesWithTapering()
00215 {
00216   // draw all streamlines with tapering
00217   for ( int j=0; j<(int)m_streamLines.size(); j++ )
00218   {
00219     glBegin( GL_QUAD_STRIP );
00220     for ( int i=0; i<(int)m_streamLines.at(j).streamLine.size(); i++ )
00221     {
00222       glVertex3f( m_streamLines.at(j).streamLine.at( i ).point[X], 
00223                   m_streamLines.at(j).streamLine.at( i ).point[Y],
00224                   0.0f );
00225 
00226       glVertex3f( m_streamLines.at(j).streamLine.at( i ).tPoint[X], 
00227                   m_streamLines.at(j).streamLine.at( i ).tPoint[Y],
00228                   0.0f );
00229     } // for all points of streamline
00230     glEnd();
00231   } // for
00232 
00233 /*
00234   // TEST ---
00235   for ( int j=0; j<(int)m_streamLines.size(); j++ )
00236   {
00237     //TEST
00238     //float r =  (float)((float)j / (float)m_streamLines.size());
00239     //glColor4f( r, 0.0f, 0.0f, 0.0f );
00240 
00241     cout << " pts: " << m_streamLines.at(j).streamLine.size() << "\n";
00242 
00243     glBegin( GL_POINTS );
00244     for ( int i=0; i<(int)m_streamLines.at(j).streamLine.size(); i++ )
00245     {
00246       //TEST
00247       int sz = (int)m_streamLines.at(j).streamLine.size();
00248       float g =  (float) ( (float)i / (float)sz );
00249       //cout << "g: " << g << ", sz: " << sz <<"\n";
00250       glColor4f( 1.0f, g, 0.0f, 0.0f );
00251 
00252       glVertex3f( m_streamLines.at(j).streamLine.at( i ).point[X], 
00253                   m_streamLines.at(j).streamLine.at( i ).point[Y],
00254                   0.0f );
00255 /
00256       glVertex3f( m_streamLines.at(j).streamLine.at( i ).tPoint[X], 
00257                   m_streamLines.at(j).streamLine.at( i ).tPoint[Y],
00258                   0.0f );*
00259     } // for all points of streamline
00260     glEnd();
00261   } // for
00262   // end TEST
00263 */
00264 
00265 }
00266 
00267 
00268 void StreamLine::drawStreamLinesWithoutTapering()
00269 {
00270   // draw all streamlines
00271   for ( int j=0; j<(int)m_streamLines.size(); j++ )
00272   {
00273     glBegin( GL_LINE_STRIP );
00274     for ( int i=0; i<(int)m_streamLines.at(j).streamLine.size(); i++ )
00275     {
00276       glVertex3f( m_streamLines.at(j).streamLine.at( i ).point[X], 
00277                   m_streamLines.at(j).streamLine.at( i ).point[Y],
00278                   0.0f );
00279     } // for all points of streamline
00280     glEnd();
00281   } // for 
00282 }
00283 
00284 
00285 void StreamLine::drawGlyphs() 
00286 {
00287   // NOTE: don't expect any nice code here... very "hacky" :(
00288 
00289   cout << "drawGlyphs...\n";
00290 
00291   glPushMatrix();
00292 
00293   // enable blending
00294   glEnable( GL_BLEND );
00295   glBlendFunc( GL_SRC_ALPHA, GL_ONE );
00296 
00297   // save old color
00298   float *oldColor = new float[4];
00299   glGetFloatv( GL_CURRENT_COLOR, oldColor );
00300 
00301   // set color
00302   glColor4fv( m_glyphColor );
00303 
00304   // configure texture-unit
00305   glActiveTexture( GL_TEXTURE0 );
00306   glEnable( GL_TEXTURE_2D );
00307   glEnable( GL_POINT_SPRITE_ARB );
00308 
00309   // prepare texture
00310   glBindTexture( GL_TEXTURE_2D, m_glyphTexId );
00311   glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );
00312   glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_NONE );
00313 
00314 
00315   // initialise some parameters
00316   glPointSize( m_glyphSize );
00317 
00318   if ( m_glyphDistance == 0 ) m_glyphDistance = 1;
00319 
00320   int n = m_glyphDistance; // display glyphs for every n'th point of the streamline
00321   int m = m_glyphDistance; // display glyphs for every m'th streamline
00322 
00323   vec3 pos( -1.0f, -1.0f, -1.0f );
00324   float angle = 0;
00325 
00326 
00327   // --- point-sprite-shader --- 
00328 
00329   Shader *shader = new Shader();
00330   shader->Load( "sprite.vert", "sprite.frag" );
00331 
00332   GLint spriteTexLoc = glGetUniformLocation( shader->GetProgram(), "SpriteTexture" );
00333   GLint angleLoc     = glGetUniformLocation( shader->GetProgram(), "angle" );
00334 
00335   int nrSls = (int)m_streamLines.size(); // number of streamlines
00336 
00337   // for all streamlines
00338   for ( int j=0; j<nrSls; j=j+m )
00339   {
00340     int nrPts = (int)m_streamLines.at(j).streamLine.size();  // number of points per streamline
00341 
00342     //cout << "max glyphs: " << nrPts << " / sls: " << nrSls << "\n";
00343 
00344     // print glyphs
00345     for ( int i=0; i<nrPts; i=i+n )
00346     {
00347       pos = m_streamLines.at( j ).streamLine.at( i ).point;
00348       angle = atan2( m_streamLines.at(j).streamLine.at(i).direction[Y], m_streamLines.at(j).streamLine.at(i).direction[X] );
00349 
00350       //cout << "glyph nr: " << i << ", angle: " << angle << "\n";
00351 
00352       shader->Bind();  
00353 
00354       glUniform1i( spriteTexLoc, 0 );
00355       glUniform1f( angleLoc, angle ); 
00356 
00357       glBegin( GL_POINTS );
00358         glVertex3fv( pos.v );
00359       glEnd();
00360 
00361       shader->Unbind();
00362     } // for all points in one streamline
00363   } // for all streamlines
00364 
00365   // --- ( end shader ) --- 
00366 
00367 
00368   // disable gl-properties
00369   glDisable( GL_POINT_SPRITE_ARB );
00370   glDisable( GL_TEXTURE_2D );
00371   glDisable( GL_BLEND );
00372 
00373   glPopMatrix();
00374 
00375   // restore old color
00376   glColor4fv( oldColor );
00377 }
00378 
00379 
00380 void StreamLine::createInitialStreamLine()
00381 {
00382   // create random start-point
00383   vec3 pos( getRandomFloat( 654321 ), getRandomFloat( 123456 ), 0.0f );
00384   cout << "Initial streamline starting at: " << pos << endl;
00385 
00386   createStreamLine( pos );
00387 
00388   // TEST
00389   //createStreamLine( vec3( 0.478145f, 0.35, 0.0f ) );
00390   //createStreamLine( vec3( 0.478145f, 0.312874f, 0.0f ) ); // -> null-vel-vec!
00391 }
00392 
00393 
00394 void StreamLine::createStreamLine( vec3 pos )
00395 {
00396   // create forward-integration and backward-integration
00397   vector<slSamplePoint> fwdInt = doIntegration( pos, FORWARD );
00398   vector<slSamplePoint> bwdInt = doIntegration( pos, BACKWARD );
00399 
00400   // merge fwdInt- and bwdInt-points to one streamline
00401   vector<slSamplePoint> allSamplePoints;
00402   allSamplePoints.clear();
00403 
00404   // add inverted bwdInt
00405   int nrBwdPts = (int)bwdInt.size();
00406   for ( int i=nrBwdPts-1; i>=0; i-- )
00407     allSamplePoints.push_back( bwdInt.at(i) );
00408 
00409   // add fwdInt-points
00410   int nrFwdPts = (int)fwdInt.size();
00411   for ( int i=0; i<nrFwdPts; i++ )
00412     // i=1 -> don't add startPoint twice!
00413     allSamplePoints.push_back( fwdInt.at(i) );
00414 
00415 /*  if ( allSamplePoints.empty() ) 
00416   {
00417     cout << "don't add empty streamline\n";
00418   }
00419   else
00420   {*/
00421     // add this streamline to the streamlines-list
00422     slStreamLine sl;
00423     sl.streamLine = allSamplePoints;
00424 
00425     m_streamLines.push_back( sl );
00426   //}
00427 }
00428 
00429 
00430 vector<slSamplePoint> StreamLine::doIntegration( vec3 pos, bool integration )
00431 {
00432   //cout << "New Streamline starting at: " << pos << endl;
00433 
00434   // do some initialisation
00435   int i=0;
00436   bool stopLine = false;
00437   vec3 lastSamplePoint(-1, -1, -1);
00438   vector<slSamplePoint> samplePoints;
00439 
00440 
00441   // create samplepoints
00442   while ( i<m_maxSteps && !stopLine )
00443   {
00444     //cout << " ---\n";
00445     vec3 velocity[1];
00446 
00447     // get interpolated velocity-vector at given position
00448     if ( !m_flowGeometry->getInterpolationAt( pos, velocity, m_flowData ) )
00449     {
00450       // we seem to be out of the image or velocity-vector == (0, 0, 0) -> stop streamline
00451       //cout << "Stop SL - interpolation out of range!" << endl;
00452       //cout << "stop at i: " << i <<  "\n";
00453       stopLine = true;
00454     }
00455     else
00456     {
00457       if ( velocity[0][X] == 0.0f && velocity[0][Y] == 0.0f ) 
00458       {
00459         //cout << "Null-Vector!!\n";
00460         stopLine = true;
00461       }
00462       else {
00463 
00464         // if backward-integration, change direction
00465         if ( integration == BACKWARD )
00466           velocity[0] *= -1.0f;
00467 
00468         // normalize vector
00469         velocity[0].normalize();
00470 
00471         // calculate new position
00472         if ( m_integrationMethod == EULER )
00473         {
00474           pos = calculateEulerPosition( pos, velocity[0] );
00475         }
00476         else // RUNGE_KUTTA2
00477         {
00478           pos = calculateRungeKutta2Position( pos, velocity[0], integration );
00479         }
00480         //cout << "newPos: " << pos << " at iteration " << i << endl;
00481 
00482 
00483         // check if still in range
00484         if ( pos[X] < 0.0f || pos[X] > 1.0f ||
00485              pos[Y] < 0.0f || pos[Y] > 1.0f )
00486         {
00487           //cout << "Stop SL - new position out of range at sample-point " << i << "!" << endl;
00488           stopLine = true;
00489 
00490           // TODO: Move point to border, so that line doesn't stop before image-border
00491           // Primitive variant: just clamp outside-value to border value (we make a little error than, but quick to implement)
00492 
00493         }
00494         else 
00495         {
00496           // still in range...
00497 
00498           // check distance
00499           float minDist = m_slgGrid->getMinimalDistance( pos, lastSamplePoint );
00500           //cout << "minDist: " << minDist << "\n";
00501 
00502           if ( (minDist != -1) && (minDist < m_dTest) ) 
00503           {
00504             // there are points too close to this one -> stop line
00505             //cout << "Stop SL - other points too close to sample-point " << i << "!" << endl;
00506             stopLine = true;
00507           }
00508           else
00509           {
00510             // valid sample-point...
00511 
00512             slSamplePoint sp;
00513             sp.point = pos;
00514 
00515             // calculate tapering
00516             if ( true /*m_isTaperingActive*/ ) // -> always do this, so we don't have to recalculate everytime on (un-)checking
00517             {
00518               // calculate a 2nd point for tapering
00519 
00520               // rotate velocity-vector 90°
00521               vec3 tDist = rotateVector( velocity[0], PI/2 );
00522 
00523               // calculate line-thickness
00524               float currentThickness = m_maxLineThickness * calculateThicknessCoeff( minDist );
00525             
00526               // add offset and save point
00527               sp.tPoint = pos + ( tDist * currentThickness );
00528             }
00529 
00530             // store direction for glyphs
00531             sp.direction = velocity[0];
00532 
00533             // if backward-integration, change direction
00534             if ( integration == BACKWARD )
00535               sp.direction *= -1.0f;
00536 
00537             // finally add points
00538             samplePoints.push_back( sp );
00539             m_slgGrid->addPoint( pos );
00540 
00541             lastSamplePoint = pos;
00542             ++i;
00543           }
00544         } 
00545       }
00546     }
00547   } // while
00548 
00549   //cout << "finished a line with i: " << i << "\n";
00550   return samplePoints;
00551 }
00552 
00553 
00554 void StreamLine::createSeedPoints()
00555 {
00556   int currentStreamLine = (int)m_streamLines.size()-1; 
00557   int nrPts             = (int)m_streamLines.at( currentStreamLine ).streamLine.size();
00558 
00559 
00560   // for every sample-point, generate two seed-points
00561   for ( int i=0; i<nrPts; i++ )
00562   {
00563     vec3 samplePoint = m_streamLines.at( currentStreamLine ).streamLine.at( i ).point;
00564     vec3 direction[1];
00565 
00566     // get the direction, which is the velocity-vector, to calculate the normals
00567     if ( !m_flowGeometry->getInterpolationAt( samplePoint, direction, m_flowData ) )
00568       // continue with next sample-point on error (should never happen anyway, but u never know)... 
00569       // dirty, but works :)
00570       continue;
00571 
00572     //cout << "samplepoint: " << samplePoint << ", direction: " << direction[0] << "\n";
00573 
00574     // rotate vel vec 90° and 270°
00575     vec3 normal = rotateVector( direction[0], PI/2 );
00576     vec3 seedPoint = samplePoint + (normal * m_dSep);
00577     
00578     //cout << "new seedpoint: " << seedPoint << "\n";
00579     m_seedPoints.push_back( seedPoint );
00580 
00581     normal = rotateVector( direction[0], 3*PI/2 );
00582     seedPoint = samplePoint + (normal * m_dSep);
00583 
00584     //cout << "new seedpoint: " << seedPoint << "\n";
00585     m_seedPoints.push_back( seedPoint );
00586   }
00587 
00588   //cout << "done with creating seed-points.\n";
00589 }
00590 
00591 
00592 bool StreamLine::isValidSeedPoint( vec3 point )
00593 {
00594   float minDist = m_slgGrid->getMinimalDistance( point, vec3(-1, -1, -1) );
00595 
00596   if ( minDist == -1 ) return true;
00597   if ( minDist < m_dSep ) return false;
00598   return true;
00599 }
00600 
00601 
00602 vec3 StreamLine::calculateEulerPosition( vec3 pos, vec3 vel )
00603 {
00604   return pos + ( vel * m_d );
00605 }
00606 
00607 
00608 vec3 StreamLine::calculateRungeKutta2Position( vec3 pos1, vec3 vel1, bool integration )
00609 {
00610   vec3 pos = pos1;
00611   vec3 pos2 = calculateEulerPosition( pos1, vel1 );
00612   vec3 vel2[1];
00613 
00614   // get interpolated velocity-vector at position 2
00615   if ( !m_flowGeometry->getInterpolationAt( pos2, vel2, m_flowData ) )
00616   {
00617     // we seem to be out of the image -> just use euler at the border
00618     pos = calculateEulerPosition( pos1, vel1 );
00619   }
00620   else
00621   {
00622     // if backward-integration, change direction
00623     if ( integration == BACKWARD )
00624       vel2[0] *= -1.0f;
00625 
00626     pos = pos1 + ( vel1 + vel2[0] ) * ( m_d * 0.5f );
00627   }
00628   
00629   return pos;
00630 }
00631 
00632 
00633 float StreamLine::calculateThicknessCoeff( float distance )
00634 {
00635   float thicknessCoeff = 1.0f;
00636 
00637   if ( (distance != -1) && (distance < m_dSep) )
00638   {
00639     thicknessCoeff = ( distance - m_dTest ) / ( m_dSep - m_dTest );
00640   }
00641 
00642   return thicknessCoeff;
00643 }
00644 
00645 
00646 bool StreamLine::createGlyphTexture()
00647 {
00648   cout << "Create glyph-texture...\n";
00649 
00650   Texture tex;
00651   m_glyphTexId = tex.CreateGlyph();
00652 
00653   if ( m_glyphTexId != 0 ) return true;
00654 
00655   return false;
00656 }
00657 
00658 
00659 float StreamLine::getRandomFloat( int rnd )
00660 {
00661   srand( (unsigned)time(0) * rnd );
00662   return rand() / ( float(RAND_MAX) + 1 );
00663 }
00664 
00665 
00666 float StreamLine::toRad( float grad )
00667 {
00668   return (float)(2*PI* grad /360 );
00669 }
00670 
00671 
00672 vec3 StreamLine::rotateVector( vec3 vector, float phi )
00673 {
00674   vec3 rotVec( 0.0f, 0.0f, 0.0f );
00675 
00676   rotVec[X] = vector[X] * cos( phi ) - vector[Y] * sin( phi );
00677   rotVec[Y] = vector[X] * sin( phi ) + vector[Y] * cos( phi );
00678 
00679   rotVec.normalize();
00680   return rotVec;
00681 }
00682 
00683 
00684 void StreamLine::setTestParameters()
00685 {
00686   // TEST
00687 
00688   m_dSep  = 0.01f;
00689   m_dTest = m_dSep  * 0.5f;
00690   m_d     = m_dTest * 1.0f;
00691 
00692   //m_isTaperingActive = true;
00693   //m_isGlyphActive = true;
00694   //m_integrationMethod = EULER; // RUNGE_KUTTA2; // EULER; 
00695 
00696 /*
00697   // set global parameters
00698   m_maxSteps = 10000;
00699   m_maxLines = 10000;
00700   m_maxLineThickness = 0.001f;
00701 */
00702   /*
00703   float c[] = { 1.0f, 0.0f, 0.0f, 0.0f };
00704   setLineColor( c );
00705   setGlyphColor( c );
00706 
00707 */
00708 }
00709 
00710 
00711 

Generated on Mon Jan 21 14:50:12 2008 for VisLU by  doxygen 1.5.4