00001 #include "StreamLine.h"
00002 #include "Texture.h"
00003 #include "Shader.h"
00004
00005
00006 #include <ctime>
00007
00008
00009 #include <iostream>
00010 #include <fstream>
00011
00012
00013 StreamLine::StreamLine( FlowData *fd )
00014 {
00015
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
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 reset();
00055
00056
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
00067
00068
00069
00070 m_slgGrid = new StreamLineGrid( m_dSep );
00071 createInitialStreamLine();
00072 createSeedPoints();
00073
00074 int nrStreamLines = 1;
00075
00076
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
00083 if ( isValidSeedPoint( startPos ) )
00084 {
00085 createStreamLine( startPos );
00086 createSeedPoints();
00087 ++nrStreamLines;
00088 }
00089 }
00090
00091
00092
00093
00094
00095
00096 }
00097
00098
00099 void StreamLine::create( float dSep, float dTest, bool linesActive, bool taperingActive, bool glyphActive )
00100 {
00101
00102 m_dSep = dSep;
00103 m_dTest = dTest;
00104
00105 m_isLinesActive = linesActive;
00106 m_isTaperingActive = taperingActive;
00107 m_isGlyphActive = glyphActive;
00108
00109
00110 create();
00111 }
00112
00113
00114 void StreamLine::reset()
00115 {
00116 cout << "Reseting streamlines...\n";
00117
00118
00119 for ( int i=0; i<(int)m_streamLines.size(); i++ )
00120 m_streamLines.at(i).streamLine.clear();
00121
00122 m_streamLines.clear();
00123
00124
00125
00126 if ( m_glyphTexId > 0 )
00127 glDeleteTextures( 1, &m_glyphTexId );
00128
00129
00130
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
00139
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
00157 if ( m_isLinesActive )
00158 {
00159 drawStreamLines();
00160 }
00161
00162
00163 if ( m_isGlyphActive )
00164 {
00165 bool haveGlyphTexture = false;
00166
00167 if ( m_glyphTexId == 0 )
00168
00169 haveGlyphTexture = createGlyphTexture();
00170 else
00171 haveGlyphTexture = true;
00172
00173 if ( haveGlyphTexture ) drawGlyphs();
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183 glPopMatrix();
00184
00185 }
00186
00187
00188 void StreamLine::drawStreamLines()
00189 {
00190
00191 float *oldColor = new float[4];
00192 glGetFloatv( GL_CURRENT_COLOR, oldColor );
00193
00194
00195 glEnable( GL_BLEND );
00196 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
00197
00198
00199 glColor4fv( m_lineColor );
00200
00201
00202 if ( m_isTaperingActive )
00203 drawStreamLinesWithTapering();
00204 else
00205 drawStreamLinesWithoutTapering();
00206
00207 glDisable( GL_BLEND );
00208
00209
00210 glColor4fv( oldColor );
00211 }
00212
00213
00214 void StreamLine::drawStreamLinesWithTapering()
00215 {
00216
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 }
00230 glEnd();
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 }
00266
00267
00268 void StreamLine::drawStreamLinesWithoutTapering()
00269 {
00270
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 }
00280 glEnd();
00281 }
00282 }
00283
00284
00285 void StreamLine::drawGlyphs()
00286 {
00287
00288
00289 cout << "drawGlyphs...\n";
00290
00291 glPushMatrix();
00292
00293
00294 glEnable( GL_BLEND );
00295 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
00296
00297
00298 float *oldColor = new float[4];
00299 glGetFloatv( GL_CURRENT_COLOR, oldColor );
00300
00301
00302 glColor4fv( m_glyphColor );
00303
00304
00305 glActiveTexture( GL_TEXTURE0 );
00306 glEnable( GL_TEXTURE_2D );
00307 glEnable( GL_POINT_SPRITE_ARB );
00308
00309
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
00316 glPointSize( m_glyphSize );
00317
00318 if ( m_glyphDistance == 0 ) m_glyphDistance = 1;
00319
00320 int n = m_glyphDistance;
00321 int m = m_glyphDistance;
00322
00323 vec3 pos( -1.0f, -1.0f, -1.0f );
00324 float angle = 0;
00325
00326
00327
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();
00336
00337
00338 for ( int j=0; j<nrSls; j=j+m )
00339 {
00340 int nrPts = (int)m_streamLines.at(j).streamLine.size();
00341
00342
00343
00344
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
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 }
00363 }
00364
00365
00366
00367
00368
00369 glDisable( GL_POINT_SPRITE_ARB );
00370 glDisable( GL_TEXTURE_2D );
00371 glDisable( GL_BLEND );
00372
00373 glPopMatrix();
00374
00375
00376 glColor4fv( oldColor );
00377 }
00378
00379
00380 void StreamLine::createInitialStreamLine()
00381 {
00382
00383 vec3 pos( getRandomFloat( 654321 ), getRandomFloat( 123456 ), 0.0f );
00384 cout << "Initial streamline starting at: " << pos << endl;
00385
00386 createStreamLine( pos );
00387
00388
00389
00390
00391 }
00392
00393
00394 void StreamLine::createStreamLine( vec3 pos )
00395 {
00396
00397 vector<slSamplePoint> fwdInt = doIntegration( pos, FORWARD );
00398 vector<slSamplePoint> bwdInt = doIntegration( pos, BACKWARD );
00399
00400
00401 vector<slSamplePoint> allSamplePoints;
00402 allSamplePoints.clear();
00403
00404
00405 int nrBwdPts = (int)bwdInt.size();
00406 for ( int i=nrBwdPts-1; i>=0; i-- )
00407 allSamplePoints.push_back( bwdInt.at(i) );
00408
00409
00410 int nrFwdPts = (int)fwdInt.size();
00411 for ( int i=0; i<nrFwdPts; i++ )
00412
00413 allSamplePoints.push_back( fwdInt.at(i) );
00414
00415
00416
00417
00418
00419
00420
00421
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
00433
00434
00435 int i=0;
00436 bool stopLine = false;
00437 vec3 lastSamplePoint(-1, -1, -1);
00438 vector<slSamplePoint> samplePoints;
00439
00440
00441
00442 while ( i<m_maxSteps && !stopLine )
00443 {
00444
00445 vec3 velocity[1];
00446
00447
00448 if ( !m_flowGeometry->getInterpolationAt( pos, velocity, m_flowData ) )
00449 {
00450
00451
00452
00453 stopLine = true;
00454 }
00455 else
00456 {
00457 if ( velocity[0][X] == 0.0f && velocity[0][Y] == 0.0f )
00458 {
00459
00460 stopLine = true;
00461 }
00462 else {
00463
00464
00465 if ( integration == BACKWARD )
00466 velocity[0] *= -1.0f;
00467
00468
00469 velocity[0].normalize();
00470
00471
00472 if ( m_integrationMethod == EULER )
00473 {
00474 pos = calculateEulerPosition( pos, velocity[0] );
00475 }
00476 else
00477 {
00478 pos = calculateRungeKutta2Position( pos, velocity[0], integration );
00479 }
00480
00481
00482
00483
00484 if ( pos[X] < 0.0f || pos[X] > 1.0f ||
00485 pos[Y] < 0.0f || pos[Y] > 1.0f )
00486 {
00487
00488 stopLine = true;
00489
00490
00491
00492
00493 }
00494 else
00495 {
00496
00497
00498
00499 float minDist = m_slgGrid->getMinimalDistance( pos, lastSamplePoint );
00500
00501
00502 if ( (minDist != -1) && (minDist < m_dTest) )
00503 {
00504
00505
00506 stopLine = true;
00507 }
00508 else
00509 {
00510
00511
00512 slSamplePoint sp;
00513 sp.point = pos;
00514
00515
00516 if ( true )
00517 {
00518
00519
00520
00521 vec3 tDist = rotateVector( velocity[0], PI/2 );
00522
00523
00524 float currentThickness = m_maxLineThickness * calculateThicknessCoeff( minDist );
00525
00526
00527 sp.tPoint = pos + ( tDist * currentThickness );
00528 }
00529
00530
00531 sp.direction = velocity[0];
00532
00533
00534 if ( integration == BACKWARD )
00535 sp.direction *= -1.0f;
00536
00537
00538 samplePoints.push_back( sp );
00539 m_slgGrid->addPoint( pos );
00540
00541 lastSamplePoint = pos;
00542 ++i;
00543 }
00544 }
00545 }
00546 }
00547 }
00548
00549
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
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
00567 if ( !m_flowGeometry->getInterpolationAt( samplePoint, direction, m_flowData ) )
00568
00569
00570 continue;
00571
00572
00573
00574
00575 vec3 normal = rotateVector( direction[0], PI/2 );
00576 vec3 seedPoint = samplePoint + (normal * m_dSep);
00577
00578
00579 m_seedPoints.push_back( seedPoint );
00580
00581 normal = rotateVector( direction[0], 3*PI/2 );
00582 seedPoint = samplePoint + (normal * m_dSep);
00583
00584
00585 m_seedPoints.push_back( seedPoint );
00586 }
00587
00588
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
00615 if ( !m_flowGeometry->getInterpolationAt( pos2, vel2, m_flowData ) )
00616 {
00617
00618 pos = calculateEulerPosition( pos1, vel1 );
00619 }
00620 else
00621 {
00622
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
00687
00688 m_dSep = 0.01f;
00689 m_dTest = m_dSep * 0.5f;
00690 m_d = m_dTest * 1.0f;
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708 }
00709
00710
00711