00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <sofa/component/behaviormodel/eulerianfluid/Fluid2D.h>
00026 #include <sofa/helper/gl/template.h>
00027 #include <sofa/core/ObjectFactory.h>
00028 #include <iostream>
00029 #include <string.h>
00030 #include <sofa/helper/MarchingCubeUtility.h>
00031
00032 namespace sofa
00033 {
00034
00035 namespace component
00036 {
00037
00038 namespace behaviormodel
00039 {
00040
00041 namespace eulerianfluid
00042 {
00043
00044 SOFA_DECL_CLASS(Fluid2D)
00045
00046 int Fluid2DClass = core::RegisterObject("Eulerian 2D fluid")
00047 .add< Fluid2D >()
00048 .addLicense("LGPL")
00049 .addAuthor("Jeremie Allard")
00050 ;
00051
00052 Fluid2D::Fluid2D()
00053 : nx(16), ny(16), cellwidth(1.0f),
00054 f_nx ( initDataPtr(&f_nx, &nx, "nx", "grid size along x axis") ),
00055 f_ny ( initDataPtr(&f_ny, &ny, "ny", "grid size along y axis") ),
00056 f_cellwidth ( initDataPtr(&f_cellwidth, &cellwidth, "cellwidth", "width of each cell") ),
00057 f_height ( initData(&f_height, 5.0f, "height", "initial fluid height") ),
00058 f_dir ( initData(&f_dir, vec2(0,1), "dir", "initial fluid surface normal") ),
00059 f_tstart ( initData(&f_tstart, 0.0f, "tstart", "starting time for fluid source") ),
00060 f_tstop ( initData(&f_tstop, 60.0f, "tstop", "stopping time for fluid source") )
00061 {
00062 fluid = new Grid2D;
00063 fnext = new Grid2D;
00064 ftemp = new Grid2D;
00065 }
00066
00067 Fluid2D::~Fluid2D()
00068 {
00069 delete fluid;
00070 delete fnext;
00071 delete ftemp;
00072 }
00073
00074 void Fluid2D::init()
00075 {
00076 f_nx.beginEdit();
00077 f_ny.beginEdit();
00078 f_cellwidth.beginEdit();
00079 fluid->clear(nx,ny);
00080 fnext->clear(nx,ny);
00081 ftemp->clear(nx,ny);
00082 if (f_height.getValue() != 0)
00083 {
00084
00085 fluid->seed(f_height.getValue(), f_dir.getValue());
00086
00087 }
00088 fluid->t = -f_tstart.getValue();
00089 fluid->tend = f_tstop.getValue() - f_tstart.getValue();
00090 }
00091
00092 void Fluid2D::reset()
00093 {
00094 init();
00095 }
00096
00097 void Fluid2D::updatePosition(double dt)
00098 {
00099 fnext->step(fluid, ftemp, (real)dt);
00100 Grid2D* p = fluid; fluid=fnext; fnext=p;
00101 }
00102
00103 void Fluid2D::drawVisual()
00104 {
00105 glPushMatrix();
00106 glTranslatef(-(nx-1)*cellwidth/2,-(ny-1)*cellwidth/2,0.0f);
00107 glScalef(cellwidth,cellwidth,cellwidth);
00108
00109 {
00110 glDisable(GL_LIGHTING);
00111 glColor4f(1,1,1,1);
00112 glBegin(GL_LINES);
00113 glVertex2i( 0, 0 ); glVertex2i( nx-1, 0 );
00114 glVertex2i( 0, ny-1 ); glVertex2i( nx-1, ny-1 );
00115
00116 glVertex2i( 0, 0 ); glVertex2i( 0, ny-1 );
00117 glVertex2i( nx-1, 0 ); glVertex2i( nx-1, ny-1 );
00118 glEnd();
00119 }
00120 if (getContext()->getShowBehaviorModels())
00121 {
00122 glDisable(GL_LIGHTING);
00123 const real s = (real)getContext()->getDt()*5;
00124 glBegin(GL_LINES);
00125 for (int y=0;y<ny;y++)
00126 for (int x=0;x<nx;x++)
00127 {
00128 vec2 u = fluid->get(x,y)->u;
00129 real r;
00130 r = u[0]*s;
00131 if (rabs(r) > 0.001f)
00132 {
00133 if (r>0.9f) r=0.9f;
00134 glColor4f(1,0,0,1);
00135 glVertex2f((float)x-0.5f , (float)y);
00136 glVertex2f((float)x-0.5f+ r, (float)y);
00137 glVertex2f((float)x-0.5f+ r, (float)y);
00138 glVertex2f((float)x-0.5f+0.8f*r, (float)y+0.2f*r);
00139 glVertex2f((float)x-0.5f+ r, (float)y);
00140 glVertex2f((float)x-0.5f+0.8f*r, (float)y-0.2f*r);
00141 }
00142 r = u[1]*s;
00143 if (rabs(r) > 0.001f)
00144 {
00145 if (r>0.9f) r=0.9f;
00146 glColor4f(0,1,0,1);
00147 glVertex2f((float)x, y-0.5f );
00148 glVertex2f((float)x, y-0.5f+r);
00149 glVertex2f((float)x, y-0.5f+r);
00150 glVertex2f((float)x+0.2f*r, y-0.5f+0.8f*r);
00151 glVertex2f((float)x, y-0.5f+r);
00152 glVertex2f((float)x-0.2f*(float)r, y-0.5f+0.8f*r);
00153 }
00154 }
00155 glEnd();
00156 glPointSize(3);
00157 glBegin(GL_POINTS);
00158 for (int y=0;y<ny;y++)
00159 for (int x=0;x<nx;x++)
00160 {
00161 real l = *fluid->getlevelset(x,y);
00162 if (rabs(l)>=5) continue;
00163 if (l<0)
00164 {
00165 glColor4f(0,1+l/5,1+l/5,1);
00166 }
00167 else
00168 {
00169 glColor4f(1-l/5,1-l/5,0,1);
00170 }
00171 glVertex2i(x,y);
00172 }
00173 glEnd();
00174 glPointSize(1);
00175 }
00176 if (getContext()->getShowVisualModels())
00177 {
00178 if (getContext()->getShowWireFrame())
00179 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00180 glEnable(GL_LIGHTING);
00181
00182 static const float color[4] = { 0.0f, 1.0f, 1.0f, 1.0f};
00183 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
00184 static const float emissive[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
00185 static const float specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f};
00186 glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, emissive);
00187 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
00188 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 20);
00189
00190 glBegin(GL_TRIANGLES);
00191 for (unsigned int i=0;i<facets.size();i++)
00192 {
00193 for (int j=0;j<3;j++)
00194 {
00195 int idx = facets[i].p[j];
00196 glNormal3fv(points[idx].n.ptr());
00197 glVertex3fv(points[idx].p.ptr());
00198 }
00199 }
00200 glEnd();
00201
00202 glDisable(GL_LIGHTING);
00203 if (getContext()->getShowWireFrame())
00204 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00205 }
00206 glPopMatrix();
00207 }
00208
00209 void Fluid2D::updateVisual()
00210 {
00211 points.clear();
00212 facets.clear();
00213
00214 const real* data = fluid->levelset;
00215
00216 planes.resize(2*nx*ny);
00217 CubeData *P = &(planes[0]);
00218 CubeData *P0 = P;
00219 CubeData *P1 = P+(nx*ny);
00220
00221
00222
00224
00225 const real isoval = 0.0f;
00226 const real iso = isoval;
00227
00228 const int dx = 1;
00229 const int dy = nx;
00230 const int dz = 0;
00231 const int nz = 2;
00232 const real data2 = 5;
00233
00234 int x,y,z,i,mk;
00235 const int *tri;
00236
00237
00238 i=0;
00239
00240 memset(P1,-1,nx*ny*sizeof(CubeData));
00241 {
00242 z=0;
00243
00244 {
00245 y=0;
00246 ++i;
00247 for(x=1;x<nx;x++)
00248 {
00249 if ((data[i]>=isoval)^(data[i-dx]>=isoval))
00250 {
00251 P1[i].p[0] = addPoint<0>(x,y,z,data[i],data[i-dx],iso);
00252 }
00253 ++i;
00254 }
00255 }
00256 for(y=1;y<ny;y++)
00257 {
00258
00259 x=0;
00260 if ((data[i]>=isoval)^(data[i-dy]>=isoval))
00261 {
00262 P1[i].p[1] = addPoint<1>(x,y,z,data[i],data[i-dy],iso);
00263 }
00264 ++i;
00265
00266 for(x=1;x<nx;x++)
00267 {
00268 if ((data[i]>=isoval)^(data[i-dx]>=isoval))
00269 {
00270 P1[i].p[0] = addPoint<0>(x,y,z,data[i],data[i-dx],iso);
00271 }
00272 if ((data[i]>=isoval)^(data[i-dy]>=isoval))
00273 {
00274 P1[i].p[1] = addPoint<1>(x,y,z,data[i],data[i-dy],iso);
00275 }
00276 ++i;
00277 }
00278 }
00279 }
00280 for (z=1;z<nz;z++)
00281 {
00282 i=0; data+=dz;
00283
00284 { CubeData* p=P0; P0=P1; P1=p; }
00285 memset(P1,-1,nx*ny*sizeof(CubeData));
00286
00287 int edgepts[12];
00288 int* base = &(P[0].p[0]);
00289 edgepts[0] = &(P0[-dy].p[0])-base;
00290 edgepts[1] = &(P0[0 ].p[1])-base;
00291 edgepts[2] = &(P0[0 ].p[0])-base;
00292 edgepts[3] = &(P0[-dx].p[1])-base;
00293 edgepts[4] = &(P1[-dy].p[0])-base;
00294 edgepts[5] = &(P1[0 ].p[1])-base;
00295 edgepts[6] = &(P1[0 ].p[0])-base;
00296 edgepts[7] = &(P1[-dx].p[1])-base;
00297 edgepts[8] = &(P1[-dx-dy].p[2])-base;
00298 edgepts[9] = &(P1[ -dy].p[2])-base;
00299 edgepts[10] = &(P1[0 ].p[2])-base;
00300 edgepts[11] = &(P1[-dx ].p[2])-base;
00301
00302
00303 {
00304 y=0;
00305 x=0;
00306 if ((data2>=isoval)^(data[i-dz]>=isoval))
00307 {
00308 P1[i].p[2] = addPoint<2>(x,y,z,data2,data[i-dz],iso);
00309 }
00310 ++i;
00311 for(x=1;x<nx;x++)
00312 {
00313
00314
00315
00316
00317 if ((data2>=isoval)^(data[i-dz]>=isoval))
00318 {
00319 P1[i].p[2] = addPoint<2>(x,y,z,data2,data[i-dz],iso);
00320 }
00321 ++i;
00322 }
00323 }
00324 for(y=1;y<ny;y++)
00325 {
00326
00327 x=0;
00328
00329
00330
00331
00332 if ((data2>=isoval)^(data[i-dz]>=isoval))
00333 {
00334 P1[i].p[2] = addPoint<2>(x,y,z,data2,data[i-dz],iso);
00335 }
00336 ++i;
00337
00338 for(x=1;x<nx;x++)
00339 {
00340
00341
00342
00343
00344
00345
00346
00347
00348 if ((data2>=isoval)^(data[i-dz]>=isoval))
00349 {
00350 P1[i].p[2] = addPoint<2>(x,y,z,data2,data[i-dz],iso);
00351 }
00352
00353
00354
00355 if (data[i-dx-dy-dz]>=iso) mk = 1; else mk=0;
00356 if (data[i -dy-dz]>=iso) mk|= 2;
00357 if (data[i -dz]>=iso) mk|= 4;
00358 if (data[i-dx -dz]>=iso) mk|= 8;
00359 if (data2>=iso) mk|= 16;
00360 if (data2>=iso) mk|= 32;
00361 if (data2>=iso) mk|= 64;
00362 if (data2>=iso) mk|= 128;
00363
00364 tri= helper::MarchingCubeTriTable[mk];
00365 while (*tri>=0)
00366 {
00367 int* b = base+3*i;
00368 if (addFace(b[edgepts[tri[0]]],b[edgepts[tri[1]]],b[edgepts[tri[2]]])<0)
00369 {
00370 std::cerr << " mk=0x"<<std::hex<<mk<<std::dec<<" p1="<<tri[0]<<" p2="<<tri[1]<<" p3="<<tri[2]<<std::endl;
00371 for (int e=0;e<12;e++) std::cerr << " e"<<e<<"="<<b[edgepts[e]];
00372 std::cerr<<std::endl;
00373 for (int ddz=-1;ddz<=0;ddz++)
00374 for (int ddy=-1;ddy<=0;ddy++)
00375 for (int ddx=-1;ddx<=0;ddx++)
00376 {
00377 std::cerr << " val("<<x+ddx<<','<<y+ddy<<','<<z+ddz<<")="<<(double)data[i+ddx*dx+ddy*dy+ddz*dz]<<std::endl;
00378 }
00379 }
00380 tri+=3;
00381 }
00382 ++i;
00383 }
00384 }
00385 }
00386
00387
00388 for (unsigned int i=0;i<points.size();i++)
00389 {
00390 points[i].n.clear();
00391 }
00392
00393 for (unsigned int i=0;i<facets.size();i++)
00394 {
00395 Vec3f n = cross(points[facets[i].p[1]].p-points[facets[i].p[0]].p,points[facets[i].p[2]].p-points[facets[i].p[0]].p);
00396 n.normalize();
00397 points[facets[i].p[0]].n += n;
00398 points[facets[i].p[1]].n += n;
00399 points[facets[i].p[2]].n += n;
00400 }
00401
00402 for (unsigned int i=0;i<points.size();i++)
00403 points[i].n.normalize();
00404 }
00405
00406 bool Fluid2D::addBBox(double* minBBox, double* maxBBox)
00407 {
00408 SReal size[3] = { (nx-1)*cellwidth, (ny-1)*cellwidth, cellwidth/2 };
00409 SReal pos[3] = { -size[0]/2, -size[1]/2, 0 };
00410 for (int c=0;c<3;c++)
00411 {
00412 if (minBBox[c] > pos[c] ) minBBox[c] = pos[c];
00413 if (maxBBox[c] < pos[c]+size[c]) maxBBox[c] = pos[c]+size[c];
00414 }
00415 return true;
00416 }
00417
00418 }
00419
00420 }
00421
00422 }
00423
00424 }
00425