├── .gitignore ├── Cell2D.cpp ├── Cell2D.h ├── ExecutionTimer.h ├── Face.cpp ├── Face.h ├── FvmMesh2D.cpp ├── FvmMesh2D.h ├── GmshReader.cpp ├── GmshReader.h ├── NodeIdent.cpp ├── NodeIdent.h ├── NodeIdentMsh.cpp ├── NodeIdentMsh.h ├── Point.cpp ├── Point.h ├── README.md ├── input.dat ├── main.cpp ├── naca0012.png ├── naca_ref2.msh └── streamIO.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /Cell2D.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Cell2D.h" 3 | 4 | unsigned Cell2D::getIdent() { 5 | return this->ident; 6 | } 7 | 8 | Point Cell2D::getVertex1() { 9 | return this->vertex[0]; 10 | } 11 | 12 | Point Cell2D::getVertex2() { 13 | return this->vertex[1]; 14 | } 15 | 16 | Point Cell2D::getVertex3() { 17 | return this->vertex[2]; 18 | } 19 | 20 | Point Cell2D::getVertex4() { 21 | return this->vertex[3]; 22 | } 23 | 24 | Face Cell2D::getFace1() { 25 | return this->faces[0]; 26 | } 27 | 28 | Face Cell2D::getFace2() { 29 | return this->faces[1]; 30 | } 31 | 32 | Face Cell2D::getFace3() { 33 | return this->faces[2]; 34 | } 35 | 36 | Face Cell2D::getFace4() { 37 | return this->faces[3]; 38 | } 39 | 40 | Cell2D* Cell2D::getNeighbor1() { 41 | return neighbor1; 42 | } 43 | 44 | Cell2D* Cell2D::getNeighbor2() { 45 | return neighbor2; 46 | } 47 | 48 | Cell2D* Cell2D::getNeighbor3() { 49 | return neighbor3; 50 | } 51 | 52 | Cell2D* Cell2D::getNeighbor4() { 53 | return neighbor4; 54 | } 55 | 56 | double Cell2D::getVol() { 57 | double x1 = this->vertex[0].getX(); 58 | double x2 = this->vertex[1].getX(); 59 | double x3 = this->vertex[2].getX(); 60 | double x4 = this->vertex[3].getX(); 61 | 62 | double y1 = this->vertex[0].getY(); 63 | double y2 = this->vertex[1].getY(); 64 | double y3 = this->vertex[2].getY(); 65 | double y4 = this->vertex[3].getY(); 66 | 67 | double vol = 0.5 * ((x1 - x3)*(y2 - y4) + (x4 - x2)*(y1 - y3)); 68 | return vol; 69 | } 70 | 71 | void Cell2D::setIdent(unsigned ident) { 72 | this->ident = ident; 73 | } 74 | 75 | void Cell2D::setVertex1(Point p) { 76 | this->vertex[0] = p; 77 | } 78 | 79 | void Cell2D::setVertex2(Point p) { 80 | this->vertex[1] = p; 81 | } 82 | 83 | void Cell2D::setVertex3(Point p) { 84 | this->vertex[2] = p; 85 | } 86 | 87 | void Cell2D::setVertex4(Point p) { 88 | this->vertex[3] = p; 89 | } 90 | 91 | void Cell2D::setNeighbor1(Cell2D* currentCell) { 92 | this->neighbor1 = currentCell; 93 | } 94 | 95 | void Cell2D::setNeighbor2(Cell2D* currentCell) { 96 | this->neighbor2 = currentCell; 97 | } 98 | 99 | void Cell2D::setNeighbor3(Cell2D* currentCell) { 100 | this->neighbor3 = currentCell; 101 | } 102 | 103 | void Cell2D::setNeighbor4(Cell2D* currentCell) { 104 | this->neighbor4 = currentCell; 105 | } 106 | 107 | void Cell2D::setVol(double vol) { 108 | this->vol = vol; 109 | } 110 | -------------------------------------------------------------------------------- /Cell2D.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Cell2D.h 3 | * Author: Truong 4 | * 5 | * Created on June 12, 2021, 4:01 PM 6 | */ 7 | 8 | #pragma once 9 | #include "Face.h" 10 | 11 | class Cell2D { 12 | public: 13 | Cell2D() {}; 14 | unsigned getIdent(); 15 | Point getVertex1(); 16 | Point getVertex2(); 17 | Point getVertex3(); 18 | Point getVertex4(); 19 | Face getFace1(); 20 | Face getFace2(); 21 | Face getFace3(); 22 | Face getFace4(); 23 | Cell2D* getNeighbor1(); 24 | Cell2D* getNeighbor2(); 25 | Cell2D* getNeighbor3(); 26 | Cell2D* getNeighbor4(); 27 | double getVol(); 28 | 29 | void setIdent(unsigned); 30 | void setVertex(Point*); 31 | void setVertex1(Point); 32 | void setVertex2(Point); 33 | void setVertex3(Point); 34 | void setVertex4(Point); 35 | void setFace(Face*); 36 | void setNeighbor1(Cell2D*); 37 | void setNeighbor2(Cell2D*); 38 | void setNeighbor3(Cell2D*); 39 | void setNeighbor4(Cell2D*); 40 | void setVol(double); 41 | 42 | private: 43 | unsigned ident = 0; 44 | Point vertex[4]; 45 | Face faces[4]; 46 | Cell2D *neighbor1 = nullptr; 47 | Cell2D *neighbor2 = nullptr; 48 | Cell2D *neighbor3 = nullptr; 49 | Cell2D *neighbor4 = nullptr; 50 | double vol = 0.0; 51 | }; 52 | -------------------------------------------------------------------------------- /ExecutionTimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | 7 | /* 8 | * File: ExecutionTimer.h 9 | * Author: Truong 10 | * 11 | * Created on July 8, 2021, 10:40 PM 12 | */ 13 | 14 | #ifndef EXECUTION_TIMER_H 15 | #define EXECUTION_TIMER_H 16 | 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | template 23 | class ExecutionTimer { 24 | 25 | private: 26 | const std::chrono::high_resolution_clock::time_point mStart = std::chrono::high_resolution_clock::now(); 27 | 28 | public: 29 | ExecutionTimer() = default; 30 | ~ExecutionTimer() { 31 | const auto end = std::chrono::high_resolution_clock::now(); 32 | std::ostringstream strStream; 33 | strStream << "Destructor Elapsed: " 34 | << std::chrono::duration_cast( end - mStart ).count() 35 | << " miliSeconds." 36 | << std::endl; 37 | std::cout << strStream.str() << std::endl; 38 | } 39 | 40 | inline void stop() { 41 | const auto end = std::chrono::high_resolution_clock::now(); 42 | std::ostringstream strStream; 43 | strStream << "Stop Elapsed: " 44 | << std::chrono::duration_cast(end - mStart).count() 45 | << " miliSeconds." 46 | << std::endl; 47 | std::cout << strStream.str() << std::endl; 48 | } 49 | 50 | }; // ExecutionTimer 51 | 52 | #endif // EXECUTION_TIMER_H 53 | 54 | -------------------------------------------------------------------------------- /Face.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Face.h" 3 | 4 | void Face::setP1(Point p1) { 5 | this->p1 = p1; 6 | } 7 | 8 | Point Face::getP1() { 9 | return this->p1; 10 | } 11 | 12 | void Face::setP2(Point p2) { 13 | this->p2 = p2; 14 | } 15 | 16 | Point Face::getP2() { 17 | return this->p2; 18 | } 19 | 20 | void Face::setCentroid(Point centroid) { 21 | this->centroid = centroid; 22 | } 23 | 24 | Point Face::getCentroid() { 25 | return this->centroid; 26 | } 27 | 28 | void Face::setBcTyp(int bcTyp) { 29 | this->bcTyp = bcTyp; 30 | } 31 | 32 | int Face::getBcTyp() { 33 | return this->bcTyp; 34 | } 35 | 36 | void Face::setIdFace(unsigned idFace) { 37 | this->idFace = idFace; 38 | } 39 | 40 | unsigned Face::getIdFace() { 41 | return this->idFace; 42 | } 43 | 44 | void Face::setArea(double area) { 45 | this->area = area; 46 | } 47 | 48 | double Face::getArea() { 49 | return this->area; 50 | } -------------------------------------------------------------------------------- /Face.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Face.h 3 | * Author: Truong 4 | * 5 | * Created on June 12, 2021, 4:08 PM 6 | */ 7 | 8 | #ifndef FACE_H 9 | #define FACE_H 10 | #include "Point.h" 11 | class Face { 12 | 13 | public: 14 | Face() {}; 15 | 16 | void setP1(Point); 17 | void setP2(Point); 18 | void setCentroid(Point); 19 | void setBcTyp(int); 20 | void setIdFace(unsigned); 21 | void setArea(double); 22 | 23 | Point getP1(); 24 | Point getP2(); 25 | Point getCentroid(); 26 | int getBcTyp(); 27 | unsigned getIdFace(); 28 | double getArea(); 29 | 30 | private: 31 | Point p1, p2; 32 | int bcTyp; 33 | unsigned idFace; 34 | double area = 0.0; 35 | Point centroid; 36 | }; 37 | 38 | #endif /* FACE_H */ 39 | 40 | -------------------------------------------------------------------------------- /FvmMesh2D.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "FvmMesh2D.h" 9 | #include "GmshReader.h" 10 | 11 | using namespace std; 12 | 13 | FvmMesh2D::FvmMesh2D() { 14 | mshReader.readMesh(); 15 | mshReader.constructIdNodes(); 16 | } 17 | 18 | vector & FvmMesh2D::getCells() { 19 | return this->cells; 20 | } 21 | 22 | void FvmMesh2D::assignVertex() { 23 | vector coordNodes = mshReader.getCoordNodes(); 24 | 25 | for (unsigned i = 0; i < mshReader.getNbElm(); i++) { 26 | 27 | Cell2D aCell; 28 | 29 | aCell.setIdent(i); 30 | 31 | NodeIdent nodeIdent = mshReader.getIdNodes()[i]; 32 | unsigned idnode = nodeIdent.getIdNode()[5]; 33 | 34 | for (Point node : coordNodes) { 35 | if (idnode == node.getId()) { 36 | aCell.setVertex1(node); 37 | break; 38 | } 39 | } 40 | 41 | idnode = nodeIdent.getIdNode()[6]; 42 | 43 | for (Point node : coordNodes) { 44 | if (idnode == node.getId()) { 45 | aCell.setVertex2(node); 46 | break; 47 | } 48 | } 49 | 50 | idnode = nodeIdent.getIdNode()[7]; 51 | 52 | for (Point node : coordNodes) { 53 | if (idnode == node.getId()) { 54 | aCell.setVertex3(node); 55 | break; 56 | } 57 | } 58 | 59 | idnode = nodeIdent.getIdNode()[8]; 60 | 61 | for (Point node : coordNodes) { 62 | if (idnode == node.getId()) { 63 | aCell.setVertex4(node); 64 | break; 65 | } 66 | } 67 | 68 | this->cells.push_back(aCell); 69 | } 70 | } 71 | 72 | void FvmMesh2D::assignFaces() { 73 | for (Cell2D & cell : cells) { 74 | cell.getFace1().setP1(cell.getVertex1()); 75 | cell.getFace1().setP2(cell.getVertex2()); 76 | 77 | cell.getFace2().setP1(cell.getVertex2()); 78 | cell.getFace2().setP2(cell.getVertex3()); 79 | 80 | cell.getFace3().setP1(cell.getVertex3()); 81 | cell.getFace3().setP2(cell.getVertex4()); 82 | 83 | cell.getFace4().setP1(cell.getVertex4()); 84 | cell.getFace4().setP2(cell.getVertex1()); 85 | } 86 | } 87 | 88 | void FvmMesh2D::assignBoundaryCondition() { 89 | vector idNodeMsh = mshReader.getIdNodesMsh(); 90 | 91 | for (Cell2D & cell : cells) { 92 | unsigned idnode1 = cell.getVertex1().getId(); 93 | unsigned idnode2 = cell.getVertex2().getId(); 94 | 95 | for (auto it = idNodeMsh.begin(); it != idNodeMsh.end(); ++it) { 96 | if (it->getElemTyp() == 27) { 97 | if (it->getIdNode()[5] == idnode1 && it->getIdNode()[6] == idnode2) { 98 | cell.getFace1().setBcTyp(it->getTag1()) ; 99 | } else if (it->getIdNode()[5] == idnode2 && it->getIdNode()[6] == idnode1) { 100 | cell.getFace1().setBcTyp(it->getTag1()) ; 101 | } 102 | } 103 | } 104 | 105 | idnode1 = cell.getVertex2().getId(); 106 | idnode2 = cell.getVertex3().getId(); 107 | 108 | for (auto it = idNodeMsh.begin(); it != idNodeMsh.end(); ++it) { 109 | if (it->getElemTyp() == 27) { 110 | if (it->getIdNode()[5] == idnode1 && it->getIdNode()[6] == idnode2) { 111 | cell.getFace2().setBcTyp(it->getTag1()) ; 112 | } else if (it->getIdNode()[5] == idnode2 && it->getIdNode()[6] == idnode1) { 113 | cell.getFace2().setBcTyp(it->getTag1()) ; 114 | } 115 | } 116 | } 117 | 118 | idnode1 = cell.getVertex3().getId(); 119 | idnode2 = cell.getVertex4().getId(); 120 | 121 | for (auto it = idNodeMsh.begin(); it != idNodeMsh.end(); ++it) { 122 | if (it->getElemTyp() == 27) { 123 | if (it->getIdNode()[5] == idnode1 && it->getIdNode()[6] == idnode2) { 124 | cell.getFace3().setBcTyp(it->getTag1()) ; 125 | } else if (it->getIdNode()[5] == idnode2 && it->getIdNode()[6] == idnode1) { 126 | cell.getFace3().setBcTyp(it->getTag1()) ; 127 | } 128 | } 129 | } 130 | 131 | idnode1 = cell.getVertex4().getId(); 132 | idnode2 = cell.getVertex1().getId(); 133 | 134 | for (auto it = idNodeMsh.begin(); it != idNodeMsh.end(); ++it) { 135 | if (it->getElemTyp() == 27) { 136 | if (it->getIdNode()[5] == idnode1 && it->getIdNode()[6] == idnode2) { 137 | cell.getFace4().setBcTyp(it->getTag1()) ; 138 | } else if (it->getIdNode()[5] == idnode2 && it->getIdNode()[6] == idnode1) { 139 | cell.getFace4().setBcTyp(it->getTag1()) ; 140 | } 141 | } 142 | } 143 | 144 | } 145 | } 146 | 147 | void FvmMesh2D::calculVol() { 148 | unsigned i = 0; 149 | 150 | for (auto it = this->cells.begin(); it != this->cells.end(); ++it) { 151 | this->cells[i].setVol(this->cells[i].getVol()); 152 | i = i + 1; 153 | } 154 | } 155 | 156 | void FvmMesh2D::detectNearestNeighbor() { 157 | unsigned nbelm = mshReader.getNbElm(); 158 | 159 | for (unsigned i = 0; i < nbelm; i++) { 160 | unsigned idnode1 = this->cells[i].getVertex1().getId(); 161 | unsigned idnode2 = this->cells[i].getVertex2().getId(); 162 | 163 | Cell2D *curr_cell = &this->cells[i]; 164 | 165 | for (unsigned j = 0; j < nbelm; j++) { 166 | Cell2D *runn_cell = &this->cells[j]; 167 | 168 | if (curr_cell != runn_cell) { 169 | unsigned cnt = 0; 170 | 171 | if (idnode1 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 172 | if (idnode2 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 173 | 174 | if (idnode1 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 175 | if (idnode2 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 176 | 177 | if (idnode1 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 178 | if (idnode2 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 179 | 180 | if (idnode1 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 181 | if (idnode2 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 182 | 183 | if (cnt == 2) { 184 | this->cells[i].setNeighbor1(runn_cell); 185 | } 186 | } 187 | } 188 | } 189 | 190 | for (unsigned i = 0; i < nbelm; i++) { 191 | unsigned idnode1 = this->cells[i].getVertex2().getId(); 192 | unsigned idnode2 = this->cells[i].getVertex3().getId(); 193 | 194 | Cell2D *curr_cell = &this->cells[i]; 195 | 196 | for (unsigned j = 0; j < nbelm; j++) { 197 | Cell2D *runn_cell = &this->cells[j]; 198 | 199 | if (curr_cell != runn_cell) { 200 | unsigned cnt = 0; 201 | 202 | if (idnode1 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 203 | if (idnode2 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 204 | 205 | if (idnode1 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 206 | if (idnode2 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 207 | 208 | if (idnode1 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 209 | if (idnode2 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 210 | 211 | if (idnode1 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 212 | if (idnode2 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 213 | 214 | if (cnt == 2) { 215 | this->cells[i].setNeighbor2(runn_cell); 216 | } 217 | } 218 | } 219 | } 220 | 221 | for (unsigned i = 0; i < nbelm; i++) { 222 | unsigned idnode1 = this->cells[i].getVertex3().getId(); 223 | unsigned idnode2 = this->cells[i].getVertex4().getId(); 224 | 225 | Cell2D *curr_cell = &this->cells[i]; 226 | 227 | for (unsigned j = 0; j < nbelm; j++) { 228 | Cell2D *runn_cell = &this->cells[j]; 229 | 230 | if (curr_cell != runn_cell) { 231 | unsigned cnt = 0; 232 | 233 | if (idnode1 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 234 | if (idnode2 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 235 | 236 | if (idnode1 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 237 | if (idnode2 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 238 | 239 | if (idnode1 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 240 | if (idnode2 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 241 | 242 | if (idnode1 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 243 | if (idnode2 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 244 | 245 | if (cnt == 2) { 246 | this->cells[i].setNeighbor3(runn_cell); 247 | } 248 | } 249 | } 250 | 251 | } 252 | 253 | for (unsigned i = 0; i < nbelm; i++) { 254 | unsigned idnode1 = this->cells[i].getVertex4().getId(); 255 | unsigned idnode2 = this->cells[i].getVertex1().getId(); 256 | 257 | Cell2D *curr_cell = &this->cells[i]; 258 | 259 | for (unsigned j = 0; j < nbelm; j++) { 260 | Cell2D *runn_cell = &this->cells[j]; 261 | 262 | if (curr_cell != runn_cell) { 263 | unsigned cnt = 0; 264 | 265 | if (idnode1 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 266 | if (idnode2 == runn_cell->getVertex1().getId()) cnt = cnt + 1; 267 | 268 | if (idnode1 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 269 | if (idnode2 == runn_cell->getVertex2().getId()) cnt = cnt + 1; 270 | 271 | if (idnode1 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 272 | if (idnode2 == runn_cell->getVertex3().getId()) cnt = cnt + 1; 273 | 274 | if (idnode1 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 275 | if (idnode2 == runn_cell->getVertex4().getId()) cnt = cnt + 1; 276 | 277 | if (cnt == 2) { 278 | this->cells[i].setNeighbor4(runn_cell); 279 | } 280 | } 281 | } 282 | 283 | } 284 | } 285 | 286 | void FvmMesh2D::writeVtk() { 287 | string str = mshReader.getFname() + ".vtk"; 288 | vector coordNodes = mshReader.getCoordNodes(); 289 | vector idNodes = mshReader.getIdNodes(); 290 | unsigned nbNodes = mshReader.getNbNode(); 291 | unsigned nbElm = mshReader.getNbElm(); 292 | ofstream outfile(str); 293 | 294 | outfile.setf(ios::fixed, ios::floatfield); 295 | outfile.precision(10); 296 | outfile << "# vtk DataFile Version 2.0" << endl; 297 | outfile << "VTK Format for unstructured grid" << endl; 298 | outfile << "ASCII" << endl; 299 | outfile << "DATASET POLYDATA" << endl; 300 | outfile << "POINTS " << nbNodes << " float" << endl; 301 | 302 | for (unsigned i = 0; i < nbNodes; i++) { 303 | outfile << setw(15) << coordNodes[i].getX() << " " << setw(15) << coordNodes[i].getY() << " " << setw(15) << 0.0f << " " << endl; 304 | } 305 | 306 | outfile << "POLYGONS " << nbElm << " " << 5 * nbElm << endl; 307 | 308 | for (unsigned i = 0; i < nbElm; i++) { 309 | outfile << 4 << " " << idNodes[i].getIdNode()[5] - 1 << " " << idNodes[i].getIdNode()[6] - 1 << " " << idNodes[i].getIdNode()[7] - 1 << " " << idNodes[i].getIdNode()[8] - 1 << endl; 310 | } 311 | 312 | outfile << "CELL_DATA " << nbElm << endl; 313 | outfile << "SCALARS CELL_IDENT integer 1" << endl; 314 | outfile << "LOOKUP_TABLE default " << endl; 315 | 316 | for (unsigned i = 0; i < nbElm; i++) { 317 | outfile << this->cells[i].getIdent() << endl; 318 | } 319 | 320 | outfile << "SCALARS NEIGHBOR1 integer 1" << endl; 321 | outfile << "LOOKUP_TABLE default " << endl; 322 | 323 | for (unsigned i = 0; i < nbElm; i++) { 324 | Cell2D *curr_cell = this->cells[i].getNeighbor1(); 325 | 326 | if (curr_cell != nullptr) { 327 | outfile << curr_cell->getIdent() << endl; 328 | } else { 329 | outfile << -1 << endl; 330 | } 331 | } 332 | 333 | outfile << "SCALARS NEIGHBOR2 integer 1" << endl; 334 | outfile << "LOOKUP_TABLE default " << endl; 335 | 336 | for (unsigned i = 0; i < nbElm; i++) { 337 | Cell2D *curr_cell = this->cells[i].getNeighbor2(); 338 | 339 | if (curr_cell != nullptr) { 340 | outfile << curr_cell->getIdent() << endl; 341 | } else { 342 | outfile << -1 << endl; 343 | } 344 | } 345 | 346 | outfile << "SCALARS NEIGHBOR3 integer 1" << endl; 347 | outfile << "LOOKUP_TABLE default " << endl; 348 | 349 | for (unsigned i = 0; i < nbElm; i++) { 350 | Cell2D *curr_cell = this->cells[i].getNeighbor3(); 351 | 352 | if (curr_cell != nullptr) { 353 | outfile << curr_cell->getIdent() << endl; 354 | } else { 355 | outfile << -1 << endl; 356 | } 357 | } 358 | 359 | outfile << "SCALARS NEIGHBOR4 integer 1" << endl; 360 | outfile << "LOOKUP_TABLE default " << endl; 361 | 362 | for (unsigned i = 0; i < nbElm; i++) { 363 | Cell2D *curr_cell = this->cells[i].getNeighbor4(); 364 | 365 | if (curr_cell != nullptr) { 366 | outfile << curr_cell->getIdent() << endl; 367 | } else { 368 | outfile << -1 << endl; 369 | } 370 | } 371 | 372 | outfile.close(); 373 | } 374 | 375 | void FvmMesh2D::writeTecplot() { 376 | /* 377 | * Write converted mesh file in Tecplot 2009 compatible format 378 | */ 379 | string str = mshReader.getFname() + ".dat"; 380 | vector coordNodes = mshReader.getCoordNodes(); 381 | vector idNodes = mshReader.getIdNodes(); 382 | unsigned nbNodes = mshReader.getNbNode(); 383 | unsigned nbElm = mshReader.getNbElm(); 384 | ofstream outfile(str); 385 | 386 | outfile.setf(ios::fixed, ios::floatfield); 387 | outfile.precision(10); 388 | outfile << "VARIABLES=X,Y,CELL_IDENT,NEIGHBOR1,NEIGHBOR2,NEIGHBOR3,NEIGHBOR4" << endl; 389 | outfile << "VARIABLES=X,Y" << endl; 390 | outfile << "ZONE T=\"UNSTRUCTURED-COUNTOUR\"" << endl; 391 | outfile << "ZONETYPE=FEPOLYGON" << endl; 392 | outfile << "NODES=" << nbNodes << endl; 393 | outfile << "ELEMENTS=" << nbElm << endl; 394 | outfile << "FACES=" << nbElm * 4 << endl; 395 | outfile << "NumConnectedBoundaryFaces=0" << endl; 396 | outfile << "TotalNumBoundaryConnections=0" << endl; 397 | 398 | for (unsigned i = 0; i < nbNodes; i++) { 399 | outfile << setw(15) << coordNodes[i].getX() << endl; 400 | } 401 | 402 | for (unsigned i = 0; i < nbNodes; i++) { 403 | outfile << setw(15) << coordNodes[i].getY() << endl; 404 | } 405 | 406 | /* 407 | * Node indexes 408 | */ 409 | for (unsigned i = 0; i < nbElm; i++) { 410 | outfile << idNodes[i].getIdNode()[5] << " " << idNodes[i].getIdNode()[6] << endl; 411 | outfile << idNodes[i].getIdNode()[6] << " " << idNodes[i].getIdNode()[7] << endl; 412 | outfile << idNodes[i].getIdNode()[7] << " " << idNodes[i].getIdNode()[8] << endl; 413 | outfile << idNodes[i].getIdNode()[8] << " " << idNodes[i].getIdNode()[5] << endl; 414 | } 415 | 416 | for (unsigned i = 0; i < nbElm; i++) { 417 | outfile << i + 1 << " " << i + 1 << " " << i + 1 << " " << i + 1 << " " << endl; 418 | } 419 | 420 | for (unsigned i = 0; i < nbElm; i++) { 421 | outfile << 0 << " " << 0 << " " << 0 << " " << 0 << " " << endl; 422 | } 423 | 424 | outfile.close(); 425 | } 426 | 427 | -------------------------------------------------------------------------------- /FvmMesh2D.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FvmMesh2D.h 3 | * Author: Truong 4 | * 5 | * Created on June 12, 2021, 4:31 PM 6 | */ 7 | 8 | #ifndef FVMMESH2D_H 9 | #define FVMMESH2D_H 10 | 11 | #include 12 | #include "Cell2D.h" 13 | #include "GmshReader.h" 14 | 15 | using namespace std; 16 | 17 | class FvmMesh2D { 18 | 19 | public: 20 | FvmMesh2D(); 21 | vector & getCells(); 22 | void assignVertex(); 23 | void assignFaces(); 24 | void assignBoundaryCondition(); 25 | void detectNearestNeighbor(); 26 | void calculVol(); 27 | void writeVtk(); 28 | void writeTecplot(); 29 | 30 | private: 31 | GmshReader mshReader; 32 | vector cells; 33 | }; 34 | 35 | #endif /* FVMMESH2D_H */ 36 | 37 | -------------------------------------------------------------------------------- /GmshReader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "streamIO.h" 4 | #include "GmshReader.h" 5 | 6 | using namespace std; 7 | /* 8 | * To change this license header, choose License Headers in Project Properties. 9 | * To change this template file, choose Tools | Templates 10 | * and open the template in the editor. 11 | */ 12 | 13 | GmshReader::GmshReader() { 14 | this -> setNbNode(0); 15 | this -> setNbElm(0); 16 | this -> setNbElMsh(0); 17 | this -> setFname(""); 18 | } 19 | 20 | GmshReader* GmshReader::setNbNode(unsigned nbNode) { 21 | this->nbNode = nbNode; 22 | return this; 23 | } 24 | 25 | unsigned GmshReader::getNbNode() { 26 | return this->nbNode; 27 | } 28 | 29 | GmshReader* GmshReader::setNbElm(unsigned nbElm) { 30 | this->nbElm = nbElm; 31 | return this; 32 | } 33 | 34 | unsigned GmshReader::getNbElm() { 35 | return this->nbElm; 36 | } 37 | 38 | GmshReader* GmshReader::setNbElMsh(unsigned nbElMsh) { 39 | this->nbElMsh = nbElMsh; 40 | return this; 41 | } 42 | 43 | unsigned GmshReader::getNbElMsh() { 44 | return this->nbElMsh; 45 | } 46 | 47 | GmshReader* GmshReader::setFname(string fName) { 48 | this->fName = fName; 49 | return this; 50 | } 51 | 52 | string GmshReader::getFname() { 53 | return this->fName; 54 | } 55 | 56 | vector & GmshReader::getIdNodes() { 57 | return this->idNodes; 58 | } 59 | 60 | vector & GmshReader::getIdNodesMsh() { 61 | return this->idNodesMsh; 62 | } 63 | 64 | vector & GmshReader::getCoordNodes() { 65 | return this->coordNodes; 66 | } 67 | 68 | void GmshReader::readMesh() { 69 | // open input file 70 | setFname("input.dat"); 71 | ifstream stream( getFname() ); 72 | if (stream.fail()) throw runtime_error( "could not open input file." ); 73 | 74 | string str; 75 | str = ReadLine( stream ); 76 | setFname(str); 77 | 78 | // open mesh file .msh of GMSH 79 | string str_msh = str + ".msh"; 80 | ifstream stream_msh(str_msh); 81 | if (stream_msh.fail()) throw runtime_error("could not open mesh file"); 82 | 83 | string line; 84 | line = ReadLine(stream_msh); 85 | line = ReadLine(stream_msh); 86 | line = ReadLine(stream_msh); 87 | line = ReadLine(stream_msh); 88 | 89 | line = ReadLine(stream_msh); 90 | stringstream(line) >> nbNode; 91 | 92 | for (unsigned i = 0; i < nbNode; i++) { 93 | line = ReadLine(stream_msh); 94 | unsigned ident; 95 | double x, y, z; 96 | stringstream(line) >> ident >> x >> y >> z; 97 | Point p(x, y, z, ident); 98 | coordNodes.push_back(p); 99 | } 100 | 101 | line = ReadLine(stream_msh); 102 | line = ReadLine(stream_msh); 103 | 104 | line = ReadLine(stream_msh); 105 | stringstream(line) >> nbElMsh; 106 | 107 | for (unsigned i = 0; i < nbElMsh; i++) { 108 | line = ReadLine(stream_msh); 109 | NodeIdentMsh node_msh; 110 | //stringstream ss = stringstream(line); // no error with Visual C++ 2015, error with g++ 111 | stringstream ss(line); // this shall work with g++ 4.8.4 112 | vector line_number; 113 | while (!ss.eof()) { 114 | unsigned number; 115 | ss >> number; 116 | line_number.push_back(number); 117 | //cout << number << " "; 118 | } 119 | //cout << endl; 120 | node_msh.setIdNode(line_number); 121 | node_msh.setIdent(line_number[0]); 122 | node_msh.setElemTyp(line_number[1]); 123 | node_msh.setNbTags(line_number[2]); 124 | node_msh.setTag1(line_number[3]); 125 | node_msh.setTag2(line_number[4]); 126 | 127 | idNodesMsh.push_back(node_msh); 128 | 129 | unsigned elem_typ = idNodesMsh[i].getElemTyp(); 130 | 131 | switch (elem_typ) { 132 | case 1: // 2 - node line. 133 | break; 134 | case 3: // 4-node quadrangle. 135 | nbElm = nbElm + 1; 136 | break; 137 | case 15: // 1-node point. 138 | break; 139 | case 37: // 5-node edge quadrangle. 140 | nbElm = nbElm + 1; 141 | break; 142 | case 27: // boundary 5-node edge. 143 | break; 144 | default: 145 | throw runtime_error("Element type is not supported. Coming soon !"); 146 | break; 147 | } 148 | } 149 | 150 | } 151 | 152 | void GmshReader::constructIdNodes() { 153 | for (unsigned i = 0; i < nbElMsh; i++) { 154 | unsigned elmTyp = idNodesMsh[i].getElemTyp(); 155 | 156 | switch (elmTyp) { 157 | case 3: 158 | case 37: 159 | NodeIdent node; 160 | node.setIdNode(idNodesMsh[i].getIdNode()); 161 | idNodes.push_back(node); 162 | break; 163 | } 164 | } 165 | } 166 | 167 | -------------------------------------------------------------------------------- /GmshReader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Point.h" 5 | #include "NodeIdent.h" 6 | #include "NodeIdentMsh.h" 7 | 8 | using namespace std; 9 | 10 | class GmshReader { 11 | 12 | public: 13 | 14 | GmshReader(); 15 | void readMesh(); 16 | void constructIdNodes(); 17 | unsigned getNbNode(); 18 | unsigned getNbElMsh(); 19 | unsigned getNbElm(); 20 | string getFname(); 21 | vector & getCoordNodes(); 22 | vector & getIdNodes(); 23 | vector & getIdNodesMsh(); 24 | GmshReader* setNbNode(unsigned); 25 | GmshReader* setNbElMsh(unsigned); 26 | GmshReader* setNbElm(unsigned); 27 | GmshReader* setFname(string); 28 | 29 | private: 30 | GmshReader(const GmshReader &gmshReader); // override default copy constructor 31 | GmshReader & operator = (const GmshReader &gmshReader); // and assignment operator 32 | unsigned nbNode; 33 | unsigned nbElMsh; 34 | unsigned nbElm; 35 | string fName; 36 | vector coordNodes; 37 | vector idNodes; 38 | vector idNodesMsh; 39 | 40 | }; -------------------------------------------------------------------------------- /NodeIdent.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "NodeIdent.h" 3 | 4 | /* 5 | * To change this license header, choose License Headers in Project Properties. 6 | * To change this template file, choose Tools | Templates 7 | * and open the template in the editor. 8 | */ 9 | 10 | std::vector & NodeIdent::getIdNode() { 11 | return this->idNode; 12 | } 13 | 14 | NodeIdent* NodeIdent::setIdNode(std::vector idNodes) { 15 | this->idNode = idNodes; 16 | return this; 17 | } -------------------------------------------------------------------------------- /NodeIdent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | 7 | /* 8 | * File: NodeIdent.h 9 | * Author: Truong 10 | * 11 | * Created on June 12, 2021, 12:14 PM 12 | */ 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | class NodeIdent { 19 | 20 | public: 21 | NodeIdent() {}; 22 | std::vector & getIdNode(); 23 | NodeIdent* setIdNode(std::vector); 24 | 25 | private: 26 | std::vector idNode; 27 | }; 28 | 29 | 30 | -------------------------------------------------------------------------------- /NodeIdentMsh.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "NodeIdentMsh.h" 3 | 4 | /* 5 | * To change this license header, choose License Headers in Project Properties. 6 | * To change this template file, choose Tools | Templates 7 | * and open the template in the editor. 8 | */ 9 | 10 | NodeIdentMsh::NodeIdentMsh(unsigned ident, unsigned elemTyp, unsigned nbTags, unsigned tag1, unsigned tag2) { 11 | this->setIdent(ident); 12 | this->setElemTyp(elemTyp); 13 | this->setNbTags(nbTags); 14 | this->setTag1(tag1); 15 | this->setTag2(tag2); 16 | } 17 | 18 | unsigned NodeIdentMsh::getIdent() { 19 | return this->ident; 20 | } 21 | 22 | NodeIdentMsh* NodeIdentMsh::setIdent(unsigned ident) { 23 | this->ident = ident; 24 | return this; 25 | } 26 | 27 | unsigned NodeIdentMsh::getElemTyp() { 28 | return this->elemTyp; 29 | } 30 | 31 | NodeIdentMsh* NodeIdentMsh::setElemTyp(unsigned elemTyp) { 32 | this->elemTyp = elemTyp; 33 | return this; 34 | } 35 | 36 | unsigned NodeIdentMsh::getNbTags() { 37 | return this->nbTags; 38 | } 39 | 40 | NodeIdentMsh* NodeIdentMsh::setNbTags(unsigned nbTags) { 41 | this->nbTags = nbTags; 42 | return this; 43 | } 44 | 45 | unsigned NodeIdentMsh::getTag1() { 46 | return this->tag1; 47 | } 48 | 49 | NodeIdentMsh* NodeIdentMsh::setTag1(unsigned tag1) { 50 | this->tag1 = tag1; 51 | return this; 52 | } 53 | 54 | unsigned NodeIdentMsh::getTag2() { 55 | return this->tag2; 56 | } 57 | 58 | NodeIdentMsh* NodeIdentMsh::setTag2(unsigned tag2) { 59 | this->tag2 = tag2; 60 | return this; 61 | } -------------------------------------------------------------------------------- /NodeIdentMsh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | 7 | /* 8 | * File: NodeIdentMsh.h 9 | * Author: Truong 10 | * 11 | * Created on June 12, 2021, 1:02 PM 12 | */ 13 | #include "NodeIdent.h" 14 | 15 | class NodeIdentMsh : public NodeIdent { 16 | 17 | public: 18 | NodeIdentMsh() {}; 19 | NodeIdentMsh(unsigned, unsigned, unsigned, unsigned, unsigned); 20 | unsigned getIdent(); 21 | unsigned getElemTyp(); 22 | unsigned getNbTags(); 23 | unsigned getTag1(); 24 | unsigned getTag2(); 25 | NodeIdentMsh* setIdent(unsigned); 26 | NodeIdentMsh* setElemTyp(unsigned); 27 | NodeIdentMsh* setNbTags(unsigned); 28 | NodeIdentMsh* setTag1(unsigned); 29 | NodeIdentMsh* setTag2(unsigned); 30 | 31 | private: 32 | unsigned ident; 33 | unsigned elemTyp; 34 | unsigned nbTags; 35 | unsigned tag1; 36 | unsigned tag2; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /Point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Point.h" 5 | 6 | using namespace std; 7 | 8 | Point::Point(double x, double y, double z, unsigned ident) { 9 | this -> x = x; 10 | this -> y = y; 11 | this -> z = z; 12 | this -> ident = ident; 13 | } 14 | 15 | bool Point::operator==(Point rhs) { 16 | if (abs(this->x - rhs.x) <= 1.0e-9 && abs(this->y - rhs.y) <= 1.0e-9 && abs(this->z - rhs.z) <= 1.0e-9) { 17 | return true; 18 | } 19 | return false; 20 | } 21 | 22 | unsigned Point::getId() { 23 | return this->ident; 24 | } 25 | 26 | Point* Point::setId(unsigned id) { 27 | this->ident = id; 28 | return this; 29 | } 30 | 31 | double Point::getX() { 32 | return this->x; 33 | } 34 | 35 | Point* Point::setX(double x) { 36 | this->x = x; 37 | return this; 38 | } 39 | 40 | double Point::getY() { 41 | return this->y; 42 | } 43 | 44 | Point* Point::setY(double y) { 45 | this->y = y; 46 | return this; 47 | } 48 | 49 | double Point::getZ() { 50 | return this->z; 51 | } 52 | 53 | Point* Point::setZ(double z) { 54 | this->z = z; 55 | return this; 56 | } 57 | 58 | void Point::print() 59 | { 60 | cout << this -> x << " " << this -> y << " " << this -> z << "\n" << endl; 61 | } -------------------------------------------------------------------------------- /Point.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_H 2 | #define POINT_H 3 | class Point { 4 | 5 | public: 6 | Point(){}; 7 | Point(double, double, double, unsigned); 8 | bool operator==(Point); 9 | void print(); 10 | unsigned getId(); 11 | double getX(); 12 | double getY(); 13 | double getZ(); 14 | Point* setId(unsigned); 15 | Point* setX(double); 16 | Point* setY(double); 17 | Point* setZ(double); 18 | 19 | private: 20 | double x; 21 | double y; 22 | double z; 23 | unsigned ident; 24 | }; 25 | 26 | #endif /* POINT_H */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### gmsh-to-vtk-CPP11 2 | C++ 11 version of my Fortran code gmsh-to-vtk-and-tecplot 3 | 4 | Some features: 5 | 6 | - Convert .msh mesh file (Quadrilateral) of gmsh to .vtk file. 7 | - Written in modern C++ (C++11 standard, intensive use of C++ STL). 8 | 9 | **Remarks:** 10 | 11 | - You will need a mature C++11 compiler to compile and run my code, as described in **History** 12 | 13 | **History:** 14 | 15 | 06/2021 16 | 17 | - After a major refactoring, the code has been tested with MinGW g++ 9.20 (under NetBeans 8.2 IDE) and MinGW g++ 8.1 (under Code::Blocks 20.3 IDE). 18 | 19 | 2018 20 | 21 | - I have compiled and run my code successfully with g++ 5.1.0, Visual Studio 2015 Community Edition, Intel C++ 2018 for Linux. 22 | 23 | - The default C++ compiler of Ubuntu 14.04 LTS (g++ 4.8.4) failed to compile my code. This bug is fixed [here](https://github.com/truongd8593/Euler2dCpp11/commit/6350ba1ad3b54f72bd5d7fc752e6977979ff914f) 24 | 25 | [Description](https://github.com/truongd8593/gmsh-to-vtk-CPP11/wiki) 26 | 27 | ### Donations: 28 | If you think that any information you obtained here is worth of some money and are willing to pay for it, feel free to send any amount through paypal. 29 | 30 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://paypal.me/TruongDang85) 31 | -------------------------------------------------------------------------------- /input.dat: -------------------------------------------------------------------------------- 1 | naca_ref2 -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ExecutionTimer.h" 3 | #include "FvmMesh2D.h" 4 | 5 | int main() 6 | { 7 | ExecutionTimer timer; 8 | FvmMesh2D finiteVolumeMesh; 9 | 10 | finiteVolumeMesh.assignVertex(); 11 | finiteVolumeMesh.assignFaces(); 12 | // finiteVolumeMesh.assignBoundaryCondition(); 13 | finiteVolumeMesh.detectNearestNeighbor(); 14 | finiteVolumeMesh.writeTecplot(); 15 | finiteVolumeMesh.writeVtk(); 16 | timer.stop(); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /naca0012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CFD-Institute/CppMeshConverter/b91e1b0a7e47e3fc0fb5a591d26ebb1a9aa569c5/naca0012.png -------------------------------------------------------------------------------- /streamIO.h: -------------------------------------------------------------------------------- 1 | /// @file streamIO.h 2 | /// 3 | /// Functions for input/output operations on file streams. 4 | /// 5 | //***************************************************************************** 6 | // 7 | // (c) J. Blazek, CFD Consulting & Analysis, www.cfd-ca.de 8 | // Created February 15, 2014 9 | // Last modification: June 30, 2014 10 | // 11 | //============================================================================= 12 | // 13 | // This program is free software; you can redistribute it and/or 14 | // modify it under the terms of the GNU General Public License 15 | // as published by the Free Software Foundation; either version 2 16 | // of the License, or (at your option) any later version. 17 | // 18 | // This program is distributed in the hope that it will be useful, 19 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | // GNU General Public License for more details. 22 | // 23 | // You should have received a copy of the GNU General Public License 24 | // along with this program; if not, write to the Free Software 25 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 26 | // 27 | //***************************************************************************** 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | using std::ifstream; 36 | using std::ofstream; 37 | using std::runtime_error; 38 | using std::string; 39 | 40 | /// Reads a text line from file, strips any comment, leading and trailing spaces. 41 | /// It is assumed that a comment starts with the hash (#) sign. 42 | /// 43 | /// @param stream file stream 44 | /// @return processed line as a string (might be empty!) 45 | /// @exception std::runtime_error problem with the stream 46 | /// 47 | inline string ReadLine( ifstream &stream ) 48 | { 49 | string str; 50 | string::size_type ic; 51 | 52 | if (stream.good()) 53 | { 54 | getline( stream,str ); 55 | 56 | // get rid of comment 57 | ic = str.find_first_of( '#' ); 58 | if (ic != string::npos) str.erase( str.begin()+ic,str.end() ); 59 | 60 | // get rid of leading spaces 61 | ic = str.find_first_not_of( ' ' ); 62 | if ((int)ic > 0) str.erase( str.begin(),str.begin()+ic ); 63 | 64 | // get rid of trailing spaces 65 | ic = str.find_last_not_of( ' ' ); 66 | if (ic != string::npos) str.erase( str.begin()+ic+1,str.end() ); 67 | 68 | } 69 | else throw runtime_error( "could not read line from file." ); 70 | 71 | return str; 72 | } 73 | 74 | //***************************************************************************** 75 | 76 | /// Reads the next value from a binary file. 77 | /// 78 | /// @param stream file stream 79 | /// @param val value in the file 80 | /// @exception std::runtime_error problem with the stream 81 | /// 82 | template void ReadBinary( ifstream &stream, T &val ) 83 | { 84 | if (stream.good()) 85 | stream.read( (char*) &val,sizeof(T) ); 86 | else 87 | throw runtime_error( "could not read data from file." ); 88 | } 89 | 90 | //***************************************************************************** 91 | 92 | /// Writes given value to a binary file. 93 | /// 94 | /// @param stream file stream 95 | /// @param val value to be written 96 | /// 97 | template void WriteBinary( ofstream &stream, const T &val ) 98 | { 99 | stream.write( (char*) &val,sizeof(T) ); 100 | } --------------------------------------------------------------------------------