|
|
|
|
#include "FITKOpenFOAMMeshReader.h"
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include "FITK_Interface/FITKInterfaceMesh/FITKUnstructuredMeshVTK.h"
|
|
|
|
|
#include "FITK_Interface/FITKInterfaceModel/FITKElementHex.h"
|
|
|
|
|
#include "FITK_Interface/FITKInterfaceModel/FITKElementPolygon.h"
|
|
|
|
|
#include "FITK_Interface/FITKInterfaceMesh/FITKUnstructuredFluidMeshVTK.h"
|
|
|
|
|
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
|
|
|
|
|
#include "FITK_Interface/FITKInterfaceModel/FITKElementQuad.h"
|
|
|
|
|
|
|
|
|
|
namespace IO {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FITKOpenFOAMMeshReader::FITKOpenFOAMMeshReader() = default;
|
|
|
|
|
|
|
|
|
|
FITKOpenFOAMMeshReader::~FITKOpenFOAMMeshReader() = default;
|
|
|
|
|
|
|
|
|
|
void FITKOpenFOAMMeshReader::run()
|
|
|
|
|
{
|
|
|
|
|
if (_fluidMesh == nullptr || _boundaryManager == nullptr) return;
|
|
|
|
|
read();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FITKOpenFOAMMeshReader::consoleMessage(int level, const QString & str)
|
|
|
|
|
{
|
|
|
|
|
//判断消息等级
|
|
|
|
|
switch (level)
|
|
|
|
|
{
|
|
|
|
|
case 1:AppFrame::FITKMessageNormal(str); break;
|
|
|
|
|
case 2: AppFrame::FITKMessageWarning(str); break;
|
|
|
|
|
case 3:AppFrame::FITKMessageError(str); break;
|
|
|
|
|
default: AppFrame::FITKMessageError(str); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FITKOpenFOAMMeshReader::setDataObject(Core::FITKAbstractDataObject * data)
|
|
|
|
|
{
|
|
|
|
|
auto mesh = dynamic_cast<Interface::FITKUnstructuredFluidMeshVTK*>(data);
|
|
|
|
|
if (mesh == nullptr) return;
|
|
|
|
|
_fluidMesh = mesh->getFieldMesh();
|
|
|
|
|
_boundaryManager = mesh->getBoundaryMeshManager();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::read()
|
|
|
|
|
{
|
|
|
|
|
if (_fluidMesh == nullptr) return false;
|
|
|
|
|
if (_fileName.isEmpty()) return false;
|
|
|
|
|
QFileInfo fileInfo(_fileName + QDir::separator());
|
|
|
|
|
if (!fileInfo.isDir()) return false;
|
|
|
|
|
|
|
|
|
|
auto dir = fileInfo.dir();
|
|
|
|
|
auto dirname = dir.absolutePath();
|
|
|
|
|
if (!dir.exists()) return false;
|
|
|
|
|
|
|
|
|
|
if (!dir.exists("points") || !dir.exists("faces") || !dir.exists("owner") || !dir.exists("neighbour") || !dir.exists("boundary")) return false;
|
|
|
|
|
|
|
|
|
|
printf("Reading points...\n");
|
|
|
|
|
if (!readPoints(dir.filePath("points"))) return false;
|
|
|
|
|
printf("Reading faces...\n");
|
|
|
|
|
if (!readFaces(dir.filePath("faces"))) return false;
|
|
|
|
|
printf("Reading owner...\n");
|
|
|
|
|
if (!readOwner(dir.filePath("owner"))) return false;
|
|
|
|
|
printf("Reading neighbour...\n");
|
|
|
|
|
if (!readNeighbour(dir.filePath("neighbour"))) return false;
|
|
|
|
|
printf("Reading boundary...\n");
|
|
|
|
|
if (!readBoundary(dir.filePath("boundary"))) return false;
|
|
|
|
|
//printf("Setup 2D cells...\n");
|
|
|
|
|
//if (!setup2DCells()) return false;
|
|
|
|
|
printf("Setup boundarys...\n");
|
|
|
|
|
if (!setupBoundarys()) return false;
|
|
|
|
|
|
|
|
|
|
printf("Finish reading. Node: %d, Element: %d\n", _fluidMesh->getNodeCount(), _fluidMesh->getElementCount());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::processLine(QString& line, bool inComment)
|
|
|
|
|
{
|
|
|
|
|
auto beginPos = line.indexOf("/*");
|
|
|
|
|
auto endPos = line.indexOf("*/");
|
|
|
|
|
auto singlePos = line.indexOf("//");
|
|
|
|
|
// 当前行为注释内容
|
|
|
|
|
if (inComment) {
|
|
|
|
|
// 注释尚未结束
|
|
|
|
|
if (endPos < 0) {
|
|
|
|
|
line.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// 注释结束
|
|
|
|
|
else {
|
|
|
|
|
line = line.mid(endPos + 2);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 当前行包含注释且在行内结束
|
|
|
|
|
if (beginPos >= 0 && endPos >= 0) {
|
|
|
|
|
line = line.mid(0, beginPos) + line.mid(endPos);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// 当前行包含注释尚未在行内结束
|
|
|
|
|
else if (beginPos >= 0) {
|
|
|
|
|
line = line.mid(0, beginPos);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// 当前行包含当行注释
|
|
|
|
|
else if (singlePos >= 0) {
|
|
|
|
|
line = line.mid(0, singlePos);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readFoamFileHeader(QFile& file, FoamFileHeader& header) {
|
|
|
|
|
QString line;
|
|
|
|
|
bool isInt{ false };
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
// 读到整数表示异常
|
|
|
|
|
line.toInt(&isInt);
|
|
|
|
|
if (isInt) return false;
|
|
|
|
|
auto strs = line.split(' ', Qt::SkipEmptyParts);
|
|
|
|
|
if (strs.size() != 2) continue;
|
|
|
|
|
if (strs.at(0) == "format") {
|
|
|
|
|
header.format = strs.at(1).chopped(1);
|
|
|
|
|
}
|
|
|
|
|
else if (strs.at(0) == "class") {
|
|
|
|
|
header.clazz = strs.at(1).chopped(1);
|
|
|
|
|
}
|
|
|
|
|
else if (strs.at(0) == "location") {
|
|
|
|
|
header.location = strs.at(1).chopped(1);
|
|
|
|
|
}
|
|
|
|
|
else if (strs.at(0) == "object") {
|
|
|
|
|
header.object = strs.at(1).chopped(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (!line.startsWith("}"));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readPointsData(QFile& file) {
|
|
|
|
|
if (_fluidMesh == nullptr) return false;
|
|
|
|
|
QString line;
|
|
|
|
|
bool ok1, ok2, ok3;
|
|
|
|
|
double x, y, z;
|
|
|
|
|
int index = -1;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
if (line == "(") continue;
|
|
|
|
|
if (line == ")") break;
|
|
|
|
|
// 移除括号
|
|
|
|
|
line = line.chopped(1).remove(0, 1);
|
|
|
|
|
auto strs = line.split(' ', Qt::SkipEmptyParts);
|
|
|
|
|
if (strs.size() != 3) continue;
|
|
|
|
|
x = strs.at(0).toDouble(&ok1);
|
|
|
|
|
y = strs.at(1).toDouble(&ok2);
|
|
|
|
|
z = strs.at(2).toDouble(&ok3);
|
|
|
|
|
if (ok1 && ok2 && ok3) {
|
|
|
|
|
_fluidMesh->addNode(++index, x, y, z);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} while (!file.atEnd());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readPoints(const QString &points)
|
|
|
|
|
{
|
|
|
|
|
if (_fluidMesh == nullptr) return false;
|
|
|
|
|
|
|
|
|
|
QFile pointsFile(points);
|
|
|
|
|
|
|
|
|
|
if (!pointsFile.exists()) return false;
|
|
|
|
|
|
|
|
|
|
if (!pointsFile.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
|
|
|
|
|
|
|
|
|
|
QString line;
|
|
|
|
|
bool inComment{ false };
|
|
|
|
|
bool isInt{ false };
|
|
|
|
|
while (!pointsFile.atEnd())
|
|
|
|
|
{
|
|
|
|
|
line = pointsFile.readLine();
|
|
|
|
|
inComment = processLine(line, inComment);
|
|
|
|
|
line = line.simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
// 读取文件头信息
|
|
|
|
|
if (line.startsWith("FoamFile")) {
|
|
|
|
|
FoamFileHeader header;
|
|
|
|
|
if (!readFoamFileHeader(pointsFile, header)) return false;
|
|
|
|
|
// 只支持文本格式
|
|
|
|
|
if (header.format != "ascii") return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取点数据
|
|
|
|
|
_pointsNum = line.toInt(&isInt);
|
|
|
|
|
if (isInt) {
|
|
|
|
|
if (!readPointsData(pointsFile)) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pointsFile.close();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readFacesData(QFile& file) {
|
|
|
|
|
QString line{}, multiLine{};
|
|
|
|
|
bool ok;
|
|
|
|
|
int i = -1;
|
|
|
|
|
bool atDataArea{ false };
|
|
|
|
|
bool inBracket{ false };
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
// 第一个括号
|
|
|
|
|
if (line == "(" && !atDataArea) {
|
|
|
|
|
atDataArea = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if (line == "(") {
|
|
|
|
|
inBracket = true;
|
|
|
|
|
}
|
|
|
|
|
else if (line == ")" && !inBracket) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 单行数据
|
|
|
|
|
if (!inBracket && line.endsWith(")")) {
|
|
|
|
|
multiLine = line.chopped(1);
|
|
|
|
|
}
|
|
|
|
|
// 跨行数据
|
|
|
|
|
else if (!line.endsWith(")")) {
|
|
|
|
|
multiLine.append(" " + line);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
multiLine.append(" " + line.chopped(1));
|
|
|
|
|
inBracket = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto strs = multiLine.split('(', Qt::SkipEmptyParts);
|
|
|
|
|
if (strs.size() != 2) continue;
|
|
|
|
|
|
|
|
|
|
QList<QString> indexStrs = strs.at(1).split(' ', Qt::SkipEmptyParts);
|
|
|
|
|
if (indexStrs.size() != strs.at(0).toInt()) return false;
|
|
|
|
|
QList<int> indexs{};
|
|
|
|
|
for (auto str : indexStrs)
|
|
|
|
|
{
|
|
|
|
|
auto val = str.toInt(&ok);
|
|
|
|
|
if (ok) indexs.append(val);
|
|
|
|
|
else return false;
|
|
|
|
|
}
|
|
|
|
|
multiLine.clear();
|
|
|
|
|
_faces[++i] = indexs;
|
|
|
|
|
} while (!file.atEnd());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readFaces(const QString &faces)
|
|
|
|
|
{
|
|
|
|
|
QFile facesFile(faces);
|
|
|
|
|
|
|
|
|
|
if (!facesFile.exists()) return false;
|
|
|
|
|
|
|
|
|
|
if (!facesFile.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
|
|
|
|
|
|
|
|
|
|
QString line;
|
|
|
|
|
bool inComment{ false };
|
|
|
|
|
bool isInt{ false };
|
|
|
|
|
while (!facesFile.atEnd())
|
|
|
|
|
{
|
|
|
|
|
line = facesFile.readLine();
|
|
|
|
|
inComment = processLine(line, inComment);
|
|
|
|
|
line = line.simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
// 读取文件头信息
|
|
|
|
|
if (line.startsWith("FoamFile")) {
|
|
|
|
|
FoamFileHeader header;
|
|
|
|
|
if (!readFoamFileHeader(facesFile, header)) return false;
|
|
|
|
|
// 只支持文本格式
|
|
|
|
|
if (header.format != "ascii") return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取面数据
|
|
|
|
|
_facesNum = line.toInt(&isInt);
|
|
|
|
|
if (isInt) {
|
|
|
|
|
_faces.resize(_facesNum);
|
|
|
|
|
if (!readFacesData(facesFile)) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
facesFile.close();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readOwnerData(QFile& file) {
|
|
|
|
|
QString line;
|
|
|
|
|
bool ok;
|
|
|
|
|
int faceIndex = -1;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
if (line == "(") continue;
|
|
|
|
|
if (line == ")") break;
|
|
|
|
|
|
|
|
|
|
auto ownerIndex = line.toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
_owner[ownerIndex].append(++faceIndex);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} while (!file.atEnd());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readOwner(const QString &owner)
|
|
|
|
|
{
|
|
|
|
|
QFile ownerFile(owner);
|
|
|
|
|
|
|
|
|
|
if (!ownerFile.exists()) return false;
|
|
|
|
|
|
|
|
|
|
if (!ownerFile.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
|
|
|
|
|
|
|
|
|
|
QString line;
|
|
|
|
|
bool inComment{ false };
|
|
|
|
|
bool isInt{ false };
|
|
|
|
|
int ownerNum{};
|
|
|
|
|
while (!ownerFile.atEnd())
|
|
|
|
|
{
|
|
|
|
|
line = ownerFile.readLine();
|
|
|
|
|
inComment = processLine(line, inComment);
|
|
|
|
|
line = line.simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
// 读取文件头信息
|
|
|
|
|
if (line.startsWith("FoamFile")) {
|
|
|
|
|
FoamFileHeader header;
|
|
|
|
|
if (!readFoamFileHeader(ownerFile, header)) return false;
|
|
|
|
|
// 只支持文本格式
|
|
|
|
|
if (header.format != "ascii") return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取Owner数据
|
|
|
|
|
ownerNum = line.toInt(&isInt);
|
|
|
|
|
if (isInt) {
|
|
|
|
|
if (!readOwnerData(ownerFile)) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ownerFile.close();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readNeighbourData(QFile& file)
|
|
|
|
|
{
|
|
|
|
|
QString line;
|
|
|
|
|
bool ok;
|
|
|
|
|
int faceIndex = -1;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
if (line == "(") continue;
|
|
|
|
|
if (line == ")") break;
|
|
|
|
|
|
|
|
|
|
auto neighbourIndex = line.toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
_neighbour[++faceIndex] = neighbourIndex;
|
|
|
|
|
_tempNeighbour[neighbourIndex].append(faceIndex);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} while (!file.atEnd());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readNeighbour(const QString &neighbour)
|
|
|
|
|
{
|
|
|
|
|
QFile neighbourFile(neighbour);
|
|
|
|
|
|
|
|
|
|
if (!neighbourFile.exists()) return false;
|
|
|
|
|
|
|
|
|
|
if (!neighbourFile.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
|
|
|
|
|
|
|
|
|
|
QString line;
|
|
|
|
|
bool inComment{ false };
|
|
|
|
|
bool isInt{ false };
|
|
|
|
|
int neighbourNum{};
|
|
|
|
|
while (!neighbourFile.atEnd())
|
|
|
|
|
{
|
|
|
|
|
line = neighbourFile.readLine();
|
|
|
|
|
inComment = processLine(line, inComment);
|
|
|
|
|
line = line.simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
// 读取文件头信息
|
|
|
|
|
if (line.startsWith("FoamFile")) {
|
|
|
|
|
FoamFileHeader header;
|
|
|
|
|
if (!readFoamFileHeader(neighbourFile, header)) return false;
|
|
|
|
|
// 只支持文本格式
|
|
|
|
|
if (header.format != "ascii") return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取Owner数据
|
|
|
|
|
neighbourNum = line.toInt(&isInt);
|
|
|
|
|
if (isInt) {
|
|
|
|
|
if (!readNeighbourData(neighbourFile)) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
neighbourFile.close();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readSingleBoundaryData(QFile & file, Boundary* boundary)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
QString line;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
if (line == "{") continue;
|
|
|
|
|
if (line == "}") break;
|
|
|
|
|
|
|
|
|
|
if (line.startsWith("type")) {
|
|
|
|
|
boundary->type = line.mid(4).simplified().chopped(1);
|
|
|
|
|
}
|
|
|
|
|
else if (line.startsWith("inGroups")) {
|
|
|
|
|
boundary->group = line.mid(8).simplified().chopped(1);
|
|
|
|
|
}
|
|
|
|
|
else if (line.startsWith("nFaces")) {
|
|
|
|
|
boundary->nFaces = line.mid(6).simplified().chopped(1).toInt();
|
|
|
|
|
}
|
|
|
|
|
else if (line.startsWith("startFace")) {
|
|
|
|
|
boundary->startFace = line.mid(9).simplified().chopped(1).toInt();
|
|
|
|
|
}
|
|
|
|
|
} while (!file.atEnd());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readBoundaryData(QFile & file)
|
|
|
|
|
{
|
|
|
|
|
QString line;
|
|
|
|
|
bool ok;
|
|
|
|
|
int faceIndex = -1;
|
|
|
|
|
Boundary boundary{};
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
line = file.readLine().simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
if (line == "(") continue;
|
|
|
|
|
if (line == ")") break;
|
|
|
|
|
|
|
|
|
|
auto boundary = new Boundary;
|
|
|
|
|
boundary->name = line;
|
|
|
|
|
readSingleBoundaryData(file, boundary);
|
|
|
|
|
if (!boundary->isValid()) {
|
|
|
|
|
delete boundary;
|
|
|
|
|
boundary = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
_Boundarys.append(boundary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (!file.atEnd());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::readBoundary(const QString & boundary)
|
|
|
|
|
{
|
|
|
|
|
QFile boundaryFile(boundary);
|
|
|
|
|
|
|
|
|
|
if (!boundaryFile.exists()) return false;
|
|
|
|
|
|
|
|
|
|
if (!boundaryFile.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
|
|
|
|
|
|
|
|
|
|
QString line;
|
|
|
|
|
bool inComment{ false };
|
|
|
|
|
bool isInt{ false };
|
|
|
|
|
int boundaryNum{};
|
|
|
|
|
while (!boundaryFile.atEnd())
|
|
|
|
|
{
|
|
|
|
|
line = boundaryFile.readLine();
|
|
|
|
|
inComment = processLine(line, inComment);
|
|
|
|
|
line = line.simplified();
|
|
|
|
|
if (line.isEmpty()) continue;
|
|
|
|
|
// 读取文件头信息
|
|
|
|
|
if (line.startsWith("FoamFile")) {
|
|
|
|
|
FoamFileHeader header;
|
|
|
|
|
if (!readFoamFileHeader(boundaryFile, header)) return false;
|
|
|
|
|
// 只支持文本格式
|
|
|
|
|
if (header.format != "ascii") return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取boundary数据
|
|
|
|
|
boundaryNum = line.toInt(&isInt);
|
|
|
|
|
if (isInt) {
|
|
|
|
|
if (!readBoundaryData(boundaryFile)) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
boundaryFile.close();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::getHex8IdsByFace(QList<int> face, int inIdPrev, int inIdNext, int& outIdPrev, int& outIdNext)
|
|
|
|
|
{
|
|
|
|
|
int idNextPos = face.indexOf(inIdNext);
|
|
|
|
|
int idPrevPos = face.indexOf(inIdPrev);
|
|
|
|
|
// id1必须在id2后面,且必须相邻
|
|
|
|
|
if (idPrevPos == 0 && idNextPos == 1) {
|
|
|
|
|
outIdNext = face.at(3);
|
|
|
|
|
outIdPrev = face.at(2);
|
|
|
|
|
}
|
|
|
|
|
else if (idPrevPos == 1 && idNextPos == 2) {
|
|
|
|
|
outIdNext = face.at(0);
|
|
|
|
|
outIdPrev = face.at(3);
|
|
|
|
|
}
|
|
|
|
|
else if (idPrevPos == 2 && idNextPos == 3) {
|
|
|
|
|
outIdNext = face.at(1);
|
|
|
|
|
outIdPrev = face.at(0);
|
|
|
|
|
}
|
|
|
|
|
else if (idPrevPos == 3 && idNextPos == 0) {
|
|
|
|
|
outIdNext = face.at(2);
|
|
|
|
|
outIdPrev = face.at(1);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Interface::FITKElementHex8* FITKOpenFOAMMeshReader::setupHex8Cell(int eleIndex, QVector<QList<int>> points) {
|
|
|
|
|
|
|
|
|
|
auto faceNum = points.size();
|
|
|
|
|
|
|
|
|
|
// 假定第一个面为底面
|
|
|
|
|
QList<int> bottomFace = points.at(0);
|
|
|
|
|
if (bottomFace.size() != 4) return nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int id0 = bottomFace.at(0);
|
|
|
|
|
int id1 = bottomFace.at(1);
|
|
|
|
|
int id2 = bottomFace.at(2);
|
|
|
|
|
int id3 = bottomFace.at(3);
|
|
|
|
|
|
|
|
|
|
int id4{ -1 }, id5{ -1 }, id6{ -1 }, id7{ -1 };
|
|
|
|
|
|
|
|
|
|
QList<int> leftFace{};
|
|
|
|
|
QList<int> rightFace{};
|
|
|
|
|
QList<int> frontFace{};
|
|
|
|
|
QList<int> backFace{};
|
|
|
|
|
|
|
|
|
|
// 只有三个面不足以确定所有顶点,需要添加邻面
|
|
|
|
|
if (faceNum < 5) {
|
|
|
|
|
auto faces = _tempNeighbour[eleIndex];
|
|
|
|
|
for (auto faceIndex : faces) {
|
|
|
|
|
auto face = _faces[faceIndex];
|
|
|
|
|
if (face.size() != 4) return nullptr;
|
|
|
|
|
points.append({ face.at(3), face.at(2), face.at(1), face.at(0) });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
faceNum = points.size();
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i < faceNum; ++i) {
|
|
|
|
|
auto face = points.at(i);
|
|
|
|
|
if (face.contains(id0) && face.contains(id1)) {
|
|
|
|
|
leftFace = std::move(face);
|
|
|
|
|
}
|
|
|
|
|
else if (face.contains(id1) && face.contains(id2)) {
|
|
|
|
|
backFace = std::move(face);
|
|
|
|
|
}
|
|
|
|
|
else if (face.contains(id2) && face.contains(id3)) {
|
|
|
|
|
rightFace = std::move(face);
|
|
|
|
|
}
|
|
|
|
|
else if (face.contains(id3) && face.contains(id0)) {
|
|
|
|
|
frontFace = std::move(face);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 分析面确定顶面的节点顺序
|
|
|
|
|
if (!leftFace.empty())
|
|
|
|
|
{
|
|
|
|
|
getHex8IdsByFace(leftFace, id1, id0, id4, id7);
|
|
|
|
|
}
|
|
|
|
|
if (!rightFace.empty())
|
|
|
|
|
{
|
|
|
|
|
getHex8IdsByFace(rightFace, id3, id2, id6, id5);
|
|
|
|
|
}
|
|
|
|
|
if ((id4 == -1 || id5 == -1) && !frontFace.empty())
|
|
|
|
|
{
|
|
|
|
|
getHex8IdsByFace(frontFace, id0, id3, id5, id4);
|
|
|
|
|
}
|
|
|
|
|
if ((id6 == -1 || id7 == -1) && !backFace.empty())
|
|
|
|
|
{
|
|
|
|
|
getHex8IdsByFace(backFace, id2, id1, id7, id6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 只有三个face的单元缺一个顶点,需要从neighbour中读取
|
|
|
|
|
if (id4 == -1 || id5 == -1 || id6 == -1 || id7 == -1)
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
// OpenFOAM的face节点是按右手螺旋定则排序的
|
|
|
|
|
auto hex8Cell = new Interface::FITKElementHex8;
|
|
|
|
|
hex8Cell->setEleID(eleIndex);
|
|
|
|
|
hex8Cell->setNodeID({ id0, id3, id2, id1, id4, id5, id6, id7 });
|
|
|
|
|
return hex8Cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Interface::FITKElementPolygon * FITKOpenFOAMMeshReader::setupPolygonCell(QList<int> face)
|
|
|
|
|
{
|
|
|
|
|
// OpenFOAM的face节点是按右手螺旋定则排序的
|
|
|
|
|
auto polygonCell = new Interface::FITKElementPolygon;
|
|
|
|
|
polygonCell->setNodeID(face);
|
|
|
|
|
return polygonCell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Interface::FITKAbstractElement* FITKOpenFOAMMeshReader::setupCell(int eleIndex, QList<int> faces) {
|
|
|
|
|
Interface::FITKAbstractElement* cell{};
|
|
|
|
|
|
|
|
|
|
// 单元包含面的个数
|
|
|
|
|
auto facesNum = faces.size();
|
|
|
|
|
|
|
|
|
|
// 包含每个面的点索引的面数组
|
|
|
|
|
QVector<QList<int>> points{};
|
|
|
|
|
|
|
|
|
|
// 包含每个面的点数的面数组
|
|
|
|
|
QVector<int> pointNumOfFace{};
|
|
|
|
|
|
|
|
|
|
// 遍历面
|
|
|
|
|
for (auto fIndex : faces) {
|
|
|
|
|
auto pointsInFace = _faces[fIndex];
|
|
|
|
|
points.append(pointsInFace);
|
|
|
|
|
|
|
|
|
|
pointNumOfFace.append(pointsInFace.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 面数组里面单个面中点数的最大值和最小值
|
|
|
|
|
int minPointNum = pointNumOfFace.at(0);
|
|
|
|
|
int maxPointNum = minPointNum;
|
|
|
|
|
|
|
|
|
|
for (int i = 1, n = 0; i < facesNum; ++i) {
|
|
|
|
|
n = pointNumOfFace.at(i);
|
|
|
|
|
if (minPointNum > n) minPointNum = n;
|
|
|
|
|
if (maxPointNum < n) maxPointNum = n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 六面体单元(最少有3个面,最多有6个面)
|
|
|
|
|
if (minPointNum == 4 && maxPointNum == 4) {
|
|
|
|
|
cell = setupHex8Cell(eleIndex, points);
|
|
|
|
|
}
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FITKOpenFOAMMeshReader::setup3DCells() {
|
|
|
|
|
if (_fluidMesh == nullptr) return false;
|
|
|
|
|
|
|
|
|
|
auto eleNum = _owner.size();
|
|
|
|
|
for (int i = 0; i < eleNum; ++i)
|
|
|
|
|
{
|
|
|
|
|
auto cell = setupCell(i, _owner[i]);
|
|
|
|
|
if (cell == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
_fluidMesh->appendElement(cell);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool FITKOpenFOAMMeshReader::setup2DCells()
|
|
|
|
|
{
|
|
|
|
|
if (_fluidMesh == nullptr) return false;
|
|
|
|
|
|
|
|
|
|
auto eleNum = _faces.size();
|
|
|
|
|
for (int i = 0; i < eleNum; ++i)
|
|
|
|
|
{
|
|
|
|
|
auto cell = setupPolygonCell(_faces.at(i));
|
|
|
|
|
if (cell == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
_fluidMesh->appendElement(cell);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool FITKOpenFOAMMeshReader::setupBoundarys()
|
|
|
|
|
{
|
|
|
|
|
if (_boundaryManager == nullptr) return false;
|
|
|
|
|
|
|
|
|
|
for (auto boundary : _Boundarys) {
|
|
|
|
|
auto b = new Interface::FITKBoundaryMeshVTK(_fluidMesh);
|
|
|
|
|
//记录边界网格信息 libaojun@20240906
|
|
|
|
|
b->setUserData(Core::FITKUserData::FITKUserRole, boundary->startFace);
|
|
|
|
|
b->setUserData(Core::FITKUserData::FITKUserRole + 1, boundary->nFaces);
|
|
|
|
|
//********************
|
|
|
|
|
for (int i = 0; i < boundary->nFaces; ++i)
|
|
|
|
|
{
|
|
|
|
|
const QList<int>& face = _faces[boundary->startFace + i];
|
|
|
|
|
auto ele = new Interface::FITKElementPolygon;
|
|
|
|
|
ele->setNodeCount(face.size());
|
|
|
|
|
ele->setNodeID(face);
|
|
|
|
|
b->appendElement(ele);
|
|
|
|
|
}
|
|
|
|
|
b->setDataObjectName(boundary->name);
|
|
|
|
|
_boundaryManager->appendDataObj(b);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|