15
15
#include "particletracer.h"
16
16
#include "ntl_matrices.h"
17
17
#include "ntl_ray.h"
18
#include "ntl_scene.h"
18
#include "ntl_matrices.h"
23
// particle object id counter
24
int ParticleObjectIdCnt = 1;
22
26
/******************************************************************************
23
27
* Standard constructor
24
28
*****************************************************************************/
25
29
ParticleTracer::ParticleTracer() :
26
30
ntlGeometryObject(),
28
mNumParticles(0), mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0),
29
mPartSize(0.01), mTrailScale(1.0),
32
//mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0),
30
34
mStart(-1.0), mEnd(1.0),
31
35
mSimStart(-1.0), mSimEnd(1.0),
32
mPartScale(1.0) , mPartHeadDist( 0.5 ), mPartTailDist( -4.5 ), mPartSegments( 4 ),
36
mPartScale(0.1) , mPartHeadDist( 0.1 ), mPartTailDist( -0.1 ), mPartSegments( 4 ),
34
mValueCutoffTop(0.0), mValueCutoffBottom(0.0)
38
mValueCutoffTop(0.0), mValueCutoffBottom(0.0),
39
mDumpParts(0), //mDumpText(0),
41
mDumpTextInterval(0.), mDumpTextLastTime(0.), mDumpTextCount(0),
43
mNumInitialParts(0), mpTrafo(NULL),
44
mInitStart(-1.), mInitEnd(-1.),
45
mPrevs(), mTrailTimeLast(0.), mTrailInterval(-1.), mTrailLength(0)
47
debMsgStd("ParticleTracer::ParticleTracer",DM_MSG,"inited",10);
50
ParticleTracer::~ParticleTracer() {
51
debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10);
38
54
/*****************************************************************************/
39
55
//! parse settings from attributes (dont use own list!)
40
56
/*****************************************************************************/
41
57
void ParticleTracer::parseAttrList(AttributeList *att)
43
AttributeList *tempAtt = mpAttrs;
59
AttributeList *tempAtt = mpAttrs;
45
mNumParticles = mpAttrs->readInt("particles",mNumParticles, "ParticleTracer","mNumParticles", false);
46
mTrailLength = mpAttrs->readInt("traillength",mTrailLength, "ParticleTracer","mTrailLength", false);
47
mTrailInterval= mpAttrs->readInt("trailinterval",mTrailInterval, "ParticleTracer","mTrailInterval", false);
62
mNumInitialParts = mpAttrs->readInt("particles",mNumInitialParts, "ParticleTracer","mNumInitialParts", false);
63
//errMsg(" NUMP"," "<<mNumInitialParts);
49
64
mPartScale = mpAttrs->readFloat("part_scale",mPartScale, "ParticleTracer","mPartScale", false);
50
65
mPartHeadDist = mpAttrs->readFloat("part_headdist",mPartHeadDist, "ParticleTracer","mPartHeadDist", false);
51
66
mPartTailDist = mpAttrs->readFloat("part_taildist",mPartTailDist, "ParticleTracer","mPartTailDist", false);
102
/******************************************************************************
104
*****************************************************************************/
105
void ParticleTracer::initTrafoMatrix() {
106
ntlVec3Gfx scale = ntlVec3Gfx(
107
(mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]),
108
(mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]),
109
(mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])
111
ntlVec3Gfx trans = mStart;
112
if(!mpTrafo) mpTrafo = new ntlMat4Gfx(0.0);
114
for(int i=0; i<3; i++) { mpTrafo->value[i][i] = scale[i]; }
115
for(int i=0; i<3; i++) { mpTrafo->value[i][3] = trans[i]; }
78
118
/******************************************************************************
79
* set the number of timesteps to trace
119
* adapt time step by rescaling velocities
80
120
*****************************************************************************/
81
void ParticleTracer::setTimesteps(int steps)
83
steps=0; // remove warning...
121
void ParticleTracer::adaptPartTimestep(float factor) {
122
for(size_t i=0; i<mParts.size(); i++) {
123
mParts[i].setVel( mParts[i].getVel() * factor );
87
128
/******************************************************************************
88
129
* add a particle at this position
89
130
*****************************************************************************/
90
void ParticleTracer::addParticle(double x, double y, double z)
131
void ParticleTracer::addParticle(float x, float y, float z)
92
133
ntlVec3Gfx p(x,y,z);
93
134
ParticleObject part( p );
94
//mParts[0].push_back( part );
95
// TODO handle other arrays?
96
//part.setActive( false );
97
for(size_t l=0; l<mParts.size(); l++) {
98
// add deactivated particles to other arrays
99
mParts[l].push_back( part );
100
// deactivate further particles
102
//mParts[l][ mParts.size()-1 ].setActive( false );
135
mParts.push_back( part );
139
void ParticleTracer::cleanup() {
141
int last = (int)mParts.size()-1;
142
if(mDumpTextInterval>0.) { errMsg("ParticleTracer::cleanup","Skipping cleanup due to text dump..."); return; }
144
for(int i=0; i<=last; i++) {
145
if( mParts[i].getActive()==false ) {
146
ParticleObject *p = &mParts[i];
147
ParticleObject *p2 = &mParts[last];
148
*p = *p2; last--; mParts.pop_back();
109
153
/******************************************************************************
110
* save particle positions before adding a new timestep
111
* copy "one index up", newest has to remain unmodified, it will be
112
* advanced after the next smiulation step
154
*! dump particles if desired
113
155
*****************************************************************************/
114
void ParticleTracer::savePreviousPositions()
116
//debugOut(" PARTS SIZE "<<mParts.size() ,10);
117
if(mTrailIntervalCounter==0) {
118
//errMsg("spp"," PARTS SIZE "<<mParts.size() );
119
for(size_t l=mParts.size()-1; l>0; l--) {
120
if( mParts[l].size() != mParts[l-1].size() ) {
121
errFatal("ParticleTracer::savePreviousPositions","Invalid array sizes ["<<l<<"]="<<mParts[l].size()<<
122
" ["<<(l+1)<<"]="<<mParts[l+1].size() <<" , total "<< mParts.size() , SIMWORLD_GENERICERROR);
126
for(size_t i=0; i<mParts[l].size(); i++) {
127
mParts[l][i] = mParts[l-1][i];
132
mTrailIntervalCounter++;
133
if(mTrailIntervalCounter>=mTrailInterval) mTrailIntervalCounter = 0;
156
void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) {
157
debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<<this->getName()<<" frame:"<<frameNrStr<<" dumpp"<<mDumpParts<<" t"<<simtime, 10); // DEBUG
160
(dumptype==DUMP_FULLGEOMETRY)&&
162
// dump to binary file
163
std::ostringstream boutfilename("");
164
boutfilename << outfilename <<"_particles_" << frameNrStr<< ".gz";
165
debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" #"<<frameNr , 7);
167
// output to zipped file
169
gzf = gzopen(boutfilename.str().c_str(), "wb1");
172
if(sizeof(numParts)!=4) { errMsg("ParticleTracer::notifyOfDump","Invalid int size"); return; }
173
// only dump active particles
175
for(size_t i=0; i<mParts.size(); i++) {
176
if(!mParts[i].getActive()) continue;
179
gzwrite(gzf, &numParts, sizeof(numParts));
180
for(size_t i=0; i<mParts.size(); i++) {
181
if(!mParts[i].getActive()) { continue; }
182
ParticleObject *p = &mParts[i];
183
//int type = p->getType(); // export whole type info
184
int type = p->getFlags(); // debug export whole type & status info
185
ntlVec3Gfx pos = p->getPos();
186
float size = p->getSize();
188
if(type&PART_FLOAT) { // WARNING same handling for dump!
189
// add one gridcell offset
192
// display as drop for now externally
193
//else if(type&PART_TRACER) { type |= PART_DROP; }
195
pos = (*mpTrafo) * pos;
197
ntlVec3Gfx v = p->getVel();
198
v[0] *= mpTrafo->value[0][0];
199
v[1] *= mpTrafo->value[1][1];
200
v[2] *= mpTrafo->value[2][2];
201
// FIXME check: pos = (*mpTrafo) * pos;
202
gzwrite(gzf, &type, sizeof(type));
203
gzwrite(gzf, &size, sizeof(size));
204
for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); }
205
for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); }
212
void ParticleTracer::checkDumpTextPositions(double simtime) {
213
// dfor partial & full dump
214
errMsg("ParticleTracer::checkDumpTextPositions","t="<<simtime<<" last:"<<mDumpTextLastTime<<" inter:"<<mDumpTextInterval);
216
if((mDumpTextInterval>0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) {
217
// dump to binary file
218
std::ostringstream boutfilename("");
219
if(mDumpTextFile.length()>1) {
220
boutfilename << mDumpTextFile << ".cpart2";
222
boutfilename << boutfilename <<"_particles" << ".cpart2";
224
debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" " , 7);
227
// only dump bubble particles
228
for(size_t i=0; i<mParts.size(); i++) {
229
//if(!mParts[i].getActive()) continue;
230
//if(!(mParts[i].getType()&PART_BUBBLE)) continue;
234
// output to text file
237
if(mDumpTextCount==0) {
238
//gzf = gzopen(boutfilename.str().c_str(), "w0");
239
stf = fopen(boutfilename.str().c_str(), "w");
241
fprintf( stf, "\n\n# cparts generated by elbeem \n# no. of parts \nN %d \n\n",numParts);
242
// fixed time scale for now
243
fprintf( stf, "T %f \n\n", 1.0);
245
//gzf = gzopen(boutfilename.str().c_str(), "a+0");
246
stf = fopen(boutfilename.str().c_str(), "a+");
251
fprintf( stf, "\n\n# new set at frame %d,t%f,p%d --------------------------------- \n\n", mDumpTextCount, simtime, numParts );
252
fprintf( stf, "S %f \n\n", simtime );
254
for(size_t i=0; i<mParts.size(); i++) {
255
ParticleObject *p = &mParts[i];
256
ntlVec3Gfx pos = p->getPos();
257
float size = p->getSize();
259
//if(!mParts[i].getActive()) { size=0.; } // switch "off"
260
if(!mParts[i].getActive()) { infl=0.; } // switch "off"
261
if(!mParts[i].getInFluid()) { infl=0.; } // switch "off"
262
if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active...
264
pos = (*mpTrafo) * pos;
265
ntlVec3Gfx v = p->getVel();
266
v[0] *= mpTrafo->value[0][0];
267
v[1] *= mpTrafo->value[1][1];
268
v[2] *= mpTrafo->value[2][2];
270
fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] );
271
if(size!=1.0) fprintf( stf, "s %f \n", size );
272
if(infl!=1.0) fprintf( stf, "i %f \n", infl );
273
fprintf( stf, "\n" );
276
fprintf( stf, "# %d end ", mDumpTextCount );
283
mDumpTextLastTime += mDumpTextInterval;
289
void ParticleTracer::checkTrails(double time) {
290
if(mTrailLength<1) return;
291
if(time-mTrailTimeLast > mTrailInterval) {
293
if( (int)mPrevs.size() < mTrailLength) mPrevs.resize( mTrailLength );
294
for(int i=mPrevs.size()-1; i>0; i--) {
295
mPrevs[i] = mPrevs[i-1];
296
//errMsg("TRAIL"," from "<<i<<" to "<<(i-1) );
300
mTrailTimeLast += mTrailInterval;
139
305
/******************************************************************************
140
306
* Get triangles for rendering
141
307
*****************************************************************************/
142
void ParticleTracer::getTriangles( vector<ntlTriangle> *triangles,
308
void ParticleTracer::getTriangles(double time, vector<ntlTriangle> *triangles,
143
309
vector<ntlVec3Gfx> *vertices,
144
310
vector<ntlVec3Gfx> *normals, int objectId )
146
#ifdef ELBEEM_BLENDER
147
313
// suppress warnings...
148
314
vertices = NULL; triangles = NULL;
149
315
normals = NULL; objectId = 0;
150
#else // ELBEEM_BLENDER
316
#else // ELBEEM_PLUGIN
151
318
// currently not used in blender
319
objectId = 0; // remove, deprecated
321
return; // only dump, no tri-gen
153
324
const bool debugParts = false;
155
gfxReal partNormSize = 0.01 * mPartScale;
156
ntlVec3Gfx pScale = ntlVec3Gfx(
157
(mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]),
158
(mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]),
159
(mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])
161
if(debugParts) errMsg("DebugParts"," geo:"<< mSimStart<<","<<mEnd<<"; sim:"<<mSimStart<<","<<mSimEnd<<"; S "<<pScale );
162
ntlVec3Gfx org = mStart;
163
326
int segments = mPartSegments;
165
int lnewst = mTrailLength-1;
166
int loldst = mTrailLength-2;
167
// trails gehen nicht so richtig mit der
168
// richtung der partikel...
170
for(size_t i=0; i<mParts[lnewst].size(); i++) {
172
//mParts[0][i].setActive(true);
174
if( mParts[lnewst][i].getActive()==false ) continue;
175
if( mParts[loldst][i].getActive()==false ) continue;
177
ntlVec3Gfx pnew = mParts[lnewst][i].getPos();
178
ntlVec3Gfx pold = mParts[loldst][i].getPos();
179
ntlVec3Gfx pdir = pnew - pold;
327
ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2]));
328
ntlVec3Gfx trans = mStart;
329
time = 0.; // doesnt matter
331
for(size_t t=0; t<mPrevs.size()+1; t++) {
332
vector<ParticleObject> *dparts;
336
dparts = &mPrevs[t-1];
338
//errMsg("TRAILT","prevs"<<t<<"/"<<mPrevs.size()<<" parts:"<<dparts->size() );
340
gfxReal partscale = mPartScale;
342
partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1);
344
gfxReal partNormSize = 0.01 * partscale;
345
//for(size_t i=0; i<mParts.size(); i++) {
346
for(size_t i=0; i<dparts->size(); i++) {
347
ParticleObject *p = &( (*dparts)[i] ); // mParts[i];
350
// 10=show only deleted
351
if( p->getActive()==false ) continue;
353
if( p->getActive()==true ) continue;
355
int type = p->getType();
358
case 1: if(!(type&PART_BUBBLE)) continue; break;
359
case 2: if(!(type&PART_DROP)) continue; break;
360
case 3: if(!(type&PART_INTER)) continue; break;
361
case 4: if(!(type&PART_FLOAT)) continue; break;
362
case 5: if(!(type&PART_TRACER)) continue; break;
365
// by default dont display inter
366
if(type&PART_INTER) continue;
370
ntlVec3Gfx pnew = p->getPos();
371
if(type&PART_FLOAT) { // WARNING same handling for dump!
372
if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display
373
// add one gridcell offset
377
pnew[2] += 0.001; // DEBUG
378
pnew[2] += 0.009; // DEBUG
381
ntlVec3Gfx pdir = p->getVel();
180
382
gfxReal plen = normalize( pdir );
181
383
if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0);
182
ntlVec3Gfx p = org + pnew*pScale;
384
ntlVec3Gfx pos = (*mpTrafo) * pnew;
183
385
gfxReal partsize = 0.0;
184
if(debugParts) errMsg("DebugParts"," i"<<i<<" new"<<pnew<<" old"<<pold );
386
if(debugParts) errMsg("DebugParts"," i"<<i<<" new"<<pnew<<" vel"<<pdir<<" pos="<<pos );
387
//if(i==0 &&(debugParts)) errMsg("DebugParts"," i"<<i<<" new"<<pnew[0]<<" pos="<<pos[0]<<" scale="<<scale[0]<<" t="<<trans[0] );
186
389
// value length scaling?
187
390
if(mValueScale==1) {
188
partsize = mPartScale * plen;
391
partsize = partscale * plen;
189
392
} else if(mValueScale==2) {
190
393
// cut off scaling
191
394
if(plen > mValueCutoffTop) continue;
192
395
if(plen < mValueCutoffBottom) continue;
193
partsize = mPartScale * plen;
396
partsize = partscale * plen;
195
partsize = mPartScale; // no length scaling
398
partsize = partscale; // no length scaling
400
//if(type&(PART_DROP|PART_BUBBLE))
401
partsize *= p->getSize()/5.0;
198
403
ntlVec3Gfx pstart( mPartHeadDist *partsize, 0.0, 0.0 );
199
404
ntlVec3Gfx pend ( mPartTailDist *partsize, 0.0, 0.0 );
231
432
p1 = (cvmat * p1);
232
433
p2 = (cvmat * p2);
234
sceneAddTriangle( p+pstart, p+p1, p+p2,
235
ns,n1,n2, ntlVec3Gfx(0.0), 1 );
236
sceneAddTriangle( p+pend , p+p2, p+p1,
237
ns,n2,n1, ntlVec3Gfx(0.0), 1 );
435
sceneAddTriangle( pos+pstart, pos+p1, pos+p2,
436
ns,n1,n2, ntlVec3Gfx(0.0), 1, triangles,vertices,normals );
437
sceneAddTriangle( pos+pend , pos+p2, pos+p1,
438
ns,n2,n1, ntlVec3Gfx(0.0), 1, triangles,vertices,normals );
447
debMsgStd("ParticleTracer::getTriangles",DM_MSG,"Dumped "<<pcnt<<"/"<<mParts.size()<<" parts, tris:"<<tris<<", showonly:"<<mShowOnly,10);
249
//double tScale = 0.01 * mPartScale * mTrailScale;
250
double trails = 0.01 * mPartScale * mTrailScale;
251
//for(int l=0; l<mParts.size()-1; l++) {
252
for(int l=0; l<mTrailLength-2; l++) {
253
for(size_t i=0; i<mParts[0].size(); i++) {
254
int tl1 = l*mTrailInterval;
255
int tl2 = (l+1)*mTrailInterval;
256
if( mParts[tl1][i].getActive()==false ) continue;
257
if( mParts[tl2][i].getActive()==false ) continue;
258
ntlVec3Gfx p1 = org+mParts[tl1][i].getPos()*pScale;
259
ntlVec3Gfx p2 = org+mParts[tl2][i].getPos()*pScale;
260
ntlVec3Gfx n = ntlVec3Gfx(0,0,-1);
261
sceneAddTriangle( p1+ntlVec3Gfx(0,trails,0), p1+ntlVec3Gfx(0,-trails,0), p2,
262
n,n,n, ntlVec3Gfx(0.0), 1 );
263
sceneAddTriangle( p2, p1+ntlVec3Gfx(0,-trails,0), p1+ntlVec3Gfx(0,trails,0),
264
n,n,n, ntlVec3Gfx(0.0), 1 );
268
debugOut("ParticleTracer::getTriangles "<<mName<<" : Triangulated "<< (mParts[0].size()) <<" particles (triangles: "<<tris<<") ", 10);
269
//debugOut(" s"<<mStart<<" e"<<mEnd<<" ss"<<mSimStart<<" se"<<mSimEnd , 10);
271
#endif // ELBEEM_BLENDER
450
#endif // ELBEEM_PLUGIN