// -*- Mode: C++ -*- // navi2ppm.cc // // Navier-Stokes Animation Maker // #include "navi.h" #include "Imag.h" class NaviPpm : public ImagBuf { public: int xUnit, yUnit; Bool bDisplayRotation, bDisplayStream; int nLinePoints; NaviPpm (void) { xUnit = 6; yUnit = 6; bDisplayRotation = True; bDisplayStream = True; nLinePoints = (xUnit > yUnit ? xUnit : yUnit) * 5 / 4; } void DrawRotationDensity (const NavierStokes & F) { // Draw rotation density for (int yFine = 0 ; yFine < ySize ; yFine++){ for (int xFine = 0 ; xFine < xSize ; xFine++) { Point p = F.fldCurrent.value (xFine/xUnit, yFine/yUnit); Real z = 0.1 * p.z; RGB col (z,0,-z); switch (p.b) { case Point::SOLID: col = RGB (0.0,1.0,0.0); break; case Point::FREE_SURFACE: col = RGB (0.0,0.6,0.0); break; } set (xFine,yFine, col); } } } void putLine (int x1, int y1, int x2, int y2) { int nMax = nLinePoints; for (int n = 0 ; n < nMax ; n++) { Real a = (double) n / (nMax - 1); int x = (int) (x1 + a * (x2-x1)), y = (int) (y1 + a * (y2-y1)); set (x,y, RGB (1,1,1)); } } static inline Bool XOR (Bool a, Bool b) { return ( !a && b ) || ( a && !b ); } void DrawSubContour (const NavierStokes & F, int x, int y) { for (int fm = 0 ; fm <= F.yMax ; fm++) { Real f = (Real) fm * F.vx * F.dy; Real f1 = F.fldCurrent.value (x ,y ).f, f2 = F.fldCurrent.value (x+1,y ).f, f3 = F.fldCurrent.value (x+1,y+1).f, f4 = F.fldCurrent.value (x ,y+1).f; Bool ma1 = (f1 > f), ma2 = (f2 > f), ma3 = (f3 > f), ma4 = (f4 > f), m1 = XOR (ma1, ma2), m2 = XOR (ma2, ma3), m3 = XOR (ma3, ma4), m4 = XOR (ma4, ma1); Real small = 0.0000000001; if (fabs(f2-f1) < small) m1 = False; if (fabs(f3-f2) < small) m2 = False; if (fabs(f3-f4) < small) m3 = False; if (fabs(f4-f1) < small) m4 = False; if (!( m1 || m2 || m3 || m4 )) continue; int X = x * xUnit + xUnit / 2, Y = y * yUnit + yUnit / 2, dx = xUnit, dy = yUnit; int x1, x2, x3, x4, y1, y2, y3, y4; if (m1) { x1 = (int) (X + (f-f1)/(f2-f1)*dx); y1 = (int) Y; } if (m2) { x2 = (int) (X + dx); y2 = (int) (Y + (f-f2)/(f3-f2)*dy); } if (m3) { x3 = (int) (X + (f-f4)/(f3-f4)*dx); y3 = (int) (Y + dy); } if (m4) { x4 = (int) X; y4 = (int) (Y + (f-f1)/(f4-f1)*dy); } if (m1 && m2) putLine (x1,y1, x2,y2); if (m1 && m3) putLine (x1,y1, x3,y3); if (m1 && m4) putLine (x1,y1, x4,y4); if (m2 && m3) putLine (x2,y2, x3,y3); if (m2 && m4) putLine (x2,y2, x4,y4); if (m3 && m4) putLine (x3,y3, x4,y4); } } void DrawStreamLine (const NavierStokes & F) { for (int y = 0 ; y < F.yMax ; y++){ for (int x = 0 ; x < F.xMax ; x++) { Point::BoundaryType b = F.fldCurrent.value (x,y).b; switch (b) { case Point::FREE: case Point::UP_SURFACE: case Point::DOWN_SURFACE: case Point::RIGHT_SURFACE: case Point::LEFT_SURFACE: // case Point::FREE_SURFACE: DrawSubContour (F, x,y); } } } } void draw (const NavierStokes & F) { setSize (F.xMax*xUnit, F.yMax*yUnit); // Draw rotation density if (bDisplayRotation) DrawRotationDensity (F); // Draw Conter of stream function if (bDisplayStream) DrawStreamLine (F); } }; void main (int nArgc, char *pszArgv[]) { NavierStokes F; int nStart = 0, nEnd = -1; String szMessage = "Available options: [-start ##] [-end ##] [-file FILE_NAME]\n"; pszArgv++; for (; nArgc > 1 && (*pszArgv)[0] == '-' ; nArgc--, pszArgv++) { if (!strcmp (*pszArgv, "-start")) { nArgc--; pszArgv++; if (nArgc <= 0) Error (szMessage); nStart = atoi (*pszArgv); continue; } if (!strcmp (*pszArgv, "-end")) { nArgc--; pszArgv++; if (nArgc <= 0) Error (szMessage); nEnd = atoi (*pszArgv); continue; } if (!strcmp (*pszArgv, "-file")) { nArgc--; pszArgv++; if (nArgc <= 0) Error (szMessage); F.szLoadFileName = *pszArgv; continue; } Error (szMessage); } NaviPpm imag; cerr << "Data File Name is <" << F.szLoadFileName << ">" << endl; for (int n = 0 ; F.ReadFileOneUnit () ; n++) { if (n < nStart) continue; if (0 <= nEnd && nEnd < n) break; imag.draw (F); char szFileNameHead [64]; sprintf (szFileNameHead, "x%03d", n); imag.putImag (szFileNameHead); } }