546 lines
15 KiB
C
546 lines
15 KiB
C
|
/*---------------------------------------------------------------------------*\
|
||
|
========= |
|
||
|
\\ / F ield | cfMesh: A library for mesh generation
|
||
|
\\ / O peration |
|
||
|
\\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
|
||
|
\\/ M anipulation | Copyright (C) Creative Fields, Ltd.
|
||
|
-------------------------------------------------------------------------------
|
||
|
License
|
||
|
This file is part of cfMesh.
|
||
|
|
||
|
cfMesh is free software; you can redistribute it and/or modify it
|
||
|
under the terms of the GNU General Public License as published by the
|
||
|
Free Software Foundation; either version 3 of the License, or (at your
|
||
|
option) any later version.
|
||
|
|
||
|
cfMesh is distributed in the hope that it will be useful, but WITHOUT
|
||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
|
for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
Description
|
||
|
cfMesh utility to convert a surface file to VTK multiblock dataset
|
||
|
format, including the patches, feature edges and surface features.
|
||
|
|
||
|
Author
|
||
|
Ivor Clifford <ivor.clifford@psi.ch>
|
||
|
|
||
|
\*---------------------------------------------------------------------------*/
|
||
|
|
||
|
#include "argList.H"
|
||
|
#include "autoPtr.H"
|
||
|
#include "OFstream.H"
|
||
|
#include "triSurf.H"
|
||
|
#include "triSurfModifier.H"
|
||
|
#include "xmlTag.H"
|
||
|
|
||
|
using namespace Foam;
|
||
|
|
||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||
|
|
||
|
//- Write the supplied pointList in serial vtkPolyData format
|
||
|
void writePointsToVTK
|
||
|
(
|
||
|
const fileName& fn,
|
||
|
const string& title,
|
||
|
const UList<point>& points
|
||
|
)
|
||
|
{
|
||
|
xmlTag xmlRoot("VTKFile");
|
||
|
xmlRoot.addAttribute("type", "PolyData");
|
||
|
|
||
|
xmlTag& xmlPolyData = xmlRoot.addChild("PolyData");
|
||
|
|
||
|
xmlTag& xmlPiece = xmlPolyData.addChild("Piece");
|
||
|
xmlPiece.addAttribute("NumberOfPoints", points.size());
|
||
|
|
||
|
xmlTag& xmlPoints = xmlPiece.addChild("Points");
|
||
|
|
||
|
xmlTag& xmlPointData = xmlPoints.addChild("DataArray");
|
||
|
xmlPointData.addAttribute("type", "Float32");
|
||
|
xmlPointData.addAttribute("NumberOfComponents", 3);
|
||
|
xmlPointData.addAttribute("format", "ascii");
|
||
|
xmlPointData << points;
|
||
|
|
||
|
OFstream os(fn);
|
||
|
os << xmlRoot << endl;
|
||
|
|
||
|
Info << "Created " << fn << endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
//- Write the supplied addressed pointList in serial vtkPolyData format
|
||
|
void writePointsToVTK
|
||
|
(
|
||
|
const fileName& fn,
|
||
|
const string& title,
|
||
|
const UList<point>& points,
|
||
|
unallocLabelList& addr
|
||
|
)
|
||
|
{
|
||
|
// Create subaddressed points
|
||
|
pointField newPoints(addr.size());
|
||
|
|
||
|
forAll(addr, i)
|
||
|
{
|
||
|
newPoints[i] = points[addr[i]];
|
||
|
}
|
||
|
|
||
|
writePointsToVTK
|
||
|
(
|
||
|
fn,
|
||
|
title,
|
||
|
newPoints
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
//- Write the supplied edgeList in serial vtkPolyData format
|
||
|
void writeEdgesToVTK
|
||
|
(
|
||
|
const fileName& fn,
|
||
|
const string& title,
|
||
|
const UList<point>& points,
|
||
|
const LongList<edge>& edges
|
||
|
)
|
||
|
{
|
||
|
labelList connectivity(edges.size());
|
||
|
|
||
|
forAll(edges, edgeI)
|
||
|
{
|
||
|
connectivity[edgeI] = 2*(edgeI+1);
|
||
|
}
|
||
|
|
||
|
xmlTag xmlRoot("VTKFile");
|
||
|
xmlRoot.addAttribute("type", "PolyData");
|
||
|
|
||
|
xmlTag& xmlPolyData = xmlRoot.addChild("PolyData");
|
||
|
|
||
|
xmlTag& xmlPiece = xmlPolyData.addChild("Piece");
|
||
|
xmlPiece.addAttribute("NumberOfPoints", points.size());
|
||
|
xmlPiece.addAttribute("NumberOfLines", edges.size());
|
||
|
|
||
|
xmlTag& xmlPoints = xmlPiece.addChild("Points");
|
||
|
|
||
|
xmlTag& xmlPointData = xmlPoints.addChild("DataArray");
|
||
|
xmlPointData.addAttribute("type", "Float32");
|
||
|
xmlPointData.addAttribute("NumberOfComponents", 3);
|
||
|
xmlPointData.addAttribute("format", "ascii");
|
||
|
xmlPointData << points;
|
||
|
|
||
|
xmlTag& xmlEdges = xmlPiece.addChild("Lines");
|
||
|
|
||
|
xmlTag& xmlEdgeData = xmlEdges.addChild("DataArray");
|
||
|
xmlEdgeData.addAttribute("type", "Int32");
|
||
|
xmlEdgeData.addAttribute("Name", "connectivity");
|
||
|
xmlEdgeData.addAttribute("format", "ascii");
|
||
|
xmlEdgeData << edges;
|
||
|
|
||
|
xmlTag& xmlConnectData = xmlEdges.addChild("DataArray");
|
||
|
xmlConnectData.addAttribute("type", "Int32");
|
||
|
xmlConnectData.addAttribute("Name", "offsets");
|
||
|
xmlConnectData.addAttribute("format", "ascii");
|
||
|
xmlConnectData << connectivity;
|
||
|
|
||
|
OFstream os(fn);
|
||
|
os << xmlRoot << endl;
|
||
|
|
||
|
Info << "Created " << fn << endl;
|
||
|
}
|
||
|
|
||
|
//- Write the supplied edgeList subset in serial vtkPolyData format
|
||
|
void writeEdgesToVTK
|
||
|
(
|
||
|
const fileName& fn,
|
||
|
const string& title,
|
||
|
const UList<point>& points,
|
||
|
const LongList<edge>& edges,
|
||
|
const unallocLabelList& addr
|
||
|
)
|
||
|
{
|
||
|
// Remove unused points and create subaddressed edges
|
||
|
DynamicList<point> newPoints;
|
||
|
labelList newPointAddr(points.size(), -1);
|
||
|
LongList<edge> newEdges(addr.size());
|
||
|
|
||
|
forAll(addr, addrI)
|
||
|
{
|
||
|
label edgeI = addr[addrI];
|
||
|
|
||
|
const edge& curEdge = edges[edgeI];
|
||
|
edge& newEdge = newEdges[addrI];
|
||
|
|
||
|
forAll(curEdge, i)
|
||
|
{
|
||
|
label pointId = curEdge[i];
|
||
|
|
||
|
if (newPointAddr[pointId] == -1)
|
||
|
{
|
||
|
newPoints.append(points[pointId]);
|
||
|
newPointAddr[pointId] = newPoints.size()-1;
|
||
|
}
|
||
|
|
||
|
newEdge[i] = newPointAddr[pointId];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
writeEdgesToVTK
|
||
|
(
|
||
|
fn,
|
||
|
title,
|
||
|
newPoints,
|
||
|
newEdges
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
//- Write the supplied facet list in serial vtkPolyData format
|
||
|
void writeFacetsToVTK
|
||
|
(
|
||
|
const fileName& fn,
|
||
|
const string& title,
|
||
|
const UList<point>& points,
|
||
|
const LongList<labelledTri>& facets
|
||
|
)
|
||
|
{
|
||
|
labelList connectivity(facets.size());
|
||
|
|
||
|
forAll(facets, faceI)
|
||
|
{
|
||
|
connectivity[faceI] = 3*(faceI+1);
|
||
|
}
|
||
|
|
||
|
labelList regionData(facets.size());
|
||
|
|
||
|
forAll(facets, faceI)
|
||
|
{
|
||
|
regionData[faceI] = facets[faceI].region();
|
||
|
}
|
||
|
|
||
|
xmlTag xmlRoot("VTKFile");
|
||
|
xmlRoot.addAttribute("type", "PolyData");
|
||
|
|
||
|
xmlTag& xmlPolyData = xmlRoot.addChild("PolyData");
|
||
|
|
||
|
xmlTag& xmlPiece = xmlPolyData.addChild("Piece");
|
||
|
xmlPiece.addAttribute("NumberOfPoints", points.size());
|
||
|
xmlPiece.addAttribute("NumberOfPolys", facets.size());
|
||
|
|
||
|
xmlTag& xmlPoints = xmlPiece.addChild("Points");
|
||
|
|
||
|
xmlTag& xmlPointData = xmlPoints.addChild("DataArray");
|
||
|
xmlPointData.addAttribute("type", "Float32");
|
||
|
xmlPointData.addAttribute("NumberOfComponents", 3);
|
||
|
xmlPointData.addAttribute("format", "ascii");
|
||
|
xmlPointData << points;
|
||
|
|
||
|
xmlTag& xmlPolys = xmlPiece.addChild("Polys");
|
||
|
|
||
|
xmlTag& xmlPolyDataArray = xmlPolys.addChild("DataArray");
|
||
|
xmlPolyDataArray.addAttribute("type", "Int32");
|
||
|
xmlPolyDataArray.addAttribute("Name", "connectivity");
|
||
|
xmlPolyDataArray.addAttribute("format", "ascii");
|
||
|
xmlPolyDataArray << facets;
|
||
|
|
||
|
xmlTag& xmlConnectData = xmlPolys.addChild("DataArray");
|
||
|
xmlConnectData.addAttribute("type", "Int32");
|
||
|
xmlConnectData.addAttribute("Name", "offsets");
|
||
|
xmlConnectData.addAttribute("format", "ascii");
|
||
|
xmlConnectData << connectivity;
|
||
|
|
||
|
xmlTag& xmlCellData = xmlPiece.addChild("CellData");
|
||
|
|
||
|
xmlTag& xmlCellDataArray = xmlCellData.addChild("DataArray");
|
||
|
xmlCellDataArray.addAttribute("type", "Int32");
|
||
|
xmlCellDataArray.addAttribute("Name", "region");
|
||
|
xmlCellDataArray.addAttribute("format", "ascii");
|
||
|
xmlCellDataArray << regionData;
|
||
|
|
||
|
OFstream os(fn);
|
||
|
os << xmlRoot << endl;
|
||
|
|
||
|
Info << "Created " << fn << endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
//- Write an addressed subset of the supplied facet list
|
||
|
//- in serial vtkPolyData format
|
||
|
void writeFacetsToVTK
|
||
|
(
|
||
|
const fileName& fn,
|
||
|
const string& title,
|
||
|
const pointField& points,
|
||
|
const LongList<labelledTri>& facets,
|
||
|
const unallocLabelList& addr
|
||
|
)
|
||
|
{
|
||
|
// Remove unused points and create subaddressed facets
|
||
|
DynamicList<point> newPoints;
|
||
|
labelList newPointAddr(points.size(), -1);
|
||
|
LongList<labelledTri> newFacets(addr.size());
|
||
|
|
||
|
forAll(addr, addrI)
|
||
|
{
|
||
|
label faceI = addr[addrI];
|
||
|
|
||
|
const labelledTri& facet = facets[faceI];
|
||
|
const FixedList<label, 3>& pointIds = facet;
|
||
|
FixedList<label, 3> newPointIds;
|
||
|
|
||
|
forAll(pointIds, i)
|
||
|
{
|
||
|
label pointId = pointIds[i];
|
||
|
|
||
|
if (newPointAddr[pointId] == -1)
|
||
|
{
|
||
|
newPoints.append(points[pointId]);
|
||
|
newPointAddr[pointId] = newPoints.size()-1;
|
||
|
}
|
||
|
|
||
|
newPointIds[i] = newPointAddr[pointId];
|
||
|
}
|
||
|
|
||
|
newFacets[addrI] = labelledTri
|
||
|
(
|
||
|
newPointIds[0],
|
||
|
newPointIds[1],
|
||
|
newPointIds[2],
|
||
|
facet.region()
|
||
|
);
|
||
|
}
|
||
|
|
||
|
writeFacetsToVTK
|
||
|
(
|
||
|
fn,
|
||
|
title,
|
||
|
newPoints,
|
||
|
newFacets
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
argList::noParallel();
|
||
|
argList::validArgs.clear();
|
||
|
|
||
|
argList::validArgs.append("input surface file");
|
||
|
argList::validArgs.append("output prefix");
|
||
|
argList args(argc, argv);
|
||
|
|
||
|
// Process commandline arguments
|
||
|
fileName inFileName(args.args()[1]);
|
||
|
fileName outPrefix(args.args()[2]);
|
||
|
|
||
|
// Read original surface
|
||
|
triSurf origSurf(inFileName);
|
||
|
|
||
|
const pointField& points = origSurf.points();
|
||
|
const LongList<labelledTri>& facets = origSurf.facets();
|
||
|
const LongList<edge>& edges = origSurf.featureEdges();
|
||
|
const geometricSurfacePatchList& patches = origSurf.patches();
|
||
|
|
||
|
label index = 0;
|
||
|
|
||
|
// Create file structure for multiblock dataset
|
||
|
mkDir(outPrefix);
|
||
|
mkDir(outPrefix + "/patches");
|
||
|
mkDir(outPrefix + "/pointSubsets");
|
||
|
mkDir(outPrefix + "/edgeSubsets");
|
||
|
mkDir(outPrefix + "/faceSubsets");
|
||
|
|
||
|
// Create VTK multiblock dataset file
|
||
|
xmlTag xmlRoot("VTKFile");
|
||
|
xmlRoot.addAttribute("type", "vtkMultiBlockDataSet");
|
||
|
xmlRoot.addAttribute("version", "1.0");
|
||
|
xmlRoot.addAttribute("byte_order", "LittleEndian");
|
||
|
|
||
|
xmlTag& xmlDataSet = xmlRoot.addChild("vtkMultiBlockDataSet");
|
||
|
|
||
|
// Write faces and feature edges
|
||
|
{
|
||
|
fileName fn = outPrefix / "facets.vtp";
|
||
|
|
||
|
writeFacetsToVTK
|
||
|
(
|
||
|
outPrefix / "facets.vtp",
|
||
|
outPrefix,
|
||
|
points,
|
||
|
facets
|
||
|
);
|
||
|
|
||
|
xmlTag& tag = xmlDataSet.addChild("DataSet");
|
||
|
tag.addAttribute("index", Foam::name(index++));
|
||
|
tag.addAttribute("name", "facets");
|
||
|
tag.addAttribute("file", fn);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
fileName fn = outPrefix / "featureEdges.vtp";
|
||
|
|
||
|
writeEdgesToVTK
|
||
|
(
|
||
|
outPrefix / "featureEdges.vtp",
|
||
|
"featureEdges",
|
||
|
points,
|
||
|
edges
|
||
|
);
|
||
|
|
||
|
xmlTag& tag = xmlDataSet.addChild("DataSet");
|
||
|
tag.addAttribute("index", Foam::name(index++));
|
||
|
tag.addAttribute("name", "featureEdges");
|
||
|
tag.addAttribute("file", fn);
|
||
|
}
|
||
|
|
||
|
// Write patches
|
||
|
// Create patch addressing
|
||
|
List<DynamicList<label> > patchAddr(patches.size());
|
||
|
|
||
|
forAll(facets, faceI)
|
||
|
{
|
||
|
patchAddr[facets[faceI].region()].append(faceI);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
xmlTag& xmlBlock = xmlDataSet.addChild("Block");
|
||
|
xmlBlock.addAttribute("index", Foam::name(index++));
|
||
|
xmlBlock.addAttribute("name", "patches");
|
||
|
|
||
|
forAll(patches, patchI)
|
||
|
{
|
||
|
word patchName = patches[patchI].name();
|
||
|
|
||
|
fileName fn = outPrefix / "patches" / patchName + ".vtp";
|
||
|
|
||
|
writeFacetsToVTK
|
||
|
(
|
||
|
fn,
|
||
|
patchName,
|
||
|
points,
|
||
|
facets,
|
||
|
patchAddr[patchI]
|
||
|
);
|
||
|
|
||
|
xmlTag& tag = xmlBlock.addChild("DataSet");
|
||
|
tag.addAttribute("index", Foam::name(patchI));
|
||
|
tag.addAttribute("name", patchName);
|
||
|
tag.addAttribute("file", fn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write point subsets
|
||
|
{
|
||
|
xmlTag& xmlBlock = xmlDataSet.addChild("Block");
|
||
|
xmlBlock.addAttribute("index", Foam::name(index++));
|
||
|
xmlBlock.addAttribute("name", "pointSubsets");
|
||
|
|
||
|
DynList<label> subsetIndices;
|
||
|
labelList subsetAddr;
|
||
|
|
||
|
origSurf.pointSubsetIndices(subsetIndices);
|
||
|
|
||
|
forAll(subsetIndices, id)
|
||
|
{
|
||
|
word subsetName = origSurf.pointSubsetName(id);
|
||
|
origSurf.pointsInSubset(id, subsetAddr);
|
||
|
|
||
|
fileName fn = outPrefix / "pointSubsets" / subsetName + ".vtp";
|
||
|
|
||
|
writePointsToVTK
|
||
|
(
|
||
|
fn,
|
||
|
subsetName,
|
||
|
points,
|
||
|
subsetAddr
|
||
|
);
|
||
|
|
||
|
xmlTag& tag = xmlBlock.addChild("DataSet");
|
||
|
tag.addAttribute("index", Foam::name(id));
|
||
|
tag.addAttribute("name", subsetName);
|
||
|
tag.addAttribute("file", fn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write edge subsets
|
||
|
{
|
||
|
xmlTag& xmlBlock = xmlDataSet.addChild("Block");
|
||
|
xmlBlock.addAttribute("index", Foam::name(index++));
|
||
|
xmlBlock.addAttribute("name", "edgeSubsets");
|
||
|
|
||
|
DynList<label> subsetIndices;
|
||
|
labelList subsetAddr;
|
||
|
|
||
|
origSurf.edgeSubsetIndices(subsetIndices);
|
||
|
|
||
|
forAll(subsetIndices, id)
|
||
|
{
|
||
|
word subsetName = origSurf.edgeSubsetName(id);
|
||
|
origSurf.edgesInSubset(id, subsetAddr);
|
||
|
|
||
|
fileName fn = outPrefix / "edgeSubsets" / subsetName + ".vtp";
|
||
|
|
||
|
writeEdgesToVTK
|
||
|
(
|
||
|
fn,
|
||
|
subsetName,
|
||
|
points,
|
||
|
edges,
|
||
|
subsetAddr
|
||
|
);
|
||
|
|
||
|
xmlTag& tag = xmlBlock.addChild("DataSet");
|
||
|
tag.addAttribute("index", Foam::name(id));
|
||
|
tag.addAttribute("name", subsetName);
|
||
|
tag.addAttribute("file", fn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write facet subsets
|
||
|
{
|
||
|
xmlTag& xmlBlock = xmlDataSet.addChild("Block");
|
||
|
xmlBlock.addAttribute("index", Foam::name(index++));
|
||
|
xmlBlock.addAttribute("name", "faceSubsets");
|
||
|
|
||
|
DynList<label> subsetIndices;
|
||
|
labelList subsetAddr;
|
||
|
|
||
|
origSurf.facetSubsetIndices(subsetIndices);
|
||
|
|
||
|
forAll(subsetIndices, id)
|
||
|
{
|
||
|
word subsetName = origSurf.facetSubsetName(id);
|
||
|
origSurf.facetsInSubset(id, subsetAddr);
|
||
|
|
||
|
fileName fn = outPrefix / "faceSubsets" / subsetName + ".vtp";
|
||
|
|
||
|
writeFacetsToVTK
|
||
|
(
|
||
|
fn,
|
||
|
subsetName,
|
||
|
points,
|
||
|
facets,
|
||
|
subsetAddr
|
||
|
);
|
||
|
|
||
|
xmlTag& tag = xmlBlock.addChild("DataSet");
|
||
|
tag.addAttribute("index", Foam::name(id));
|
||
|
tag.addAttribute("name", subsetName);
|
||
|
tag.addAttribute("file", fn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OFstream os(outPrefix + ".vtm");
|
||
|
os << xmlRoot << endl;
|
||
|
|
||
|
Info << "Created " << outPrefix + ".vtm" << endl;
|
||
|
|
||
|
Info << "End\n" << endl;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// ************************************************************************* //
|