/*---------------------------------------------------------------------------*\ ========= | \\ / 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 . Description cfMesh utility to convert a surface file to VTK multiblock dataset format, including the patches, feature edges and surface features. Author Ivor Clifford \*---------------------------------------------------------------------------*/ #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& 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& 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& points, const LongList& 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& points, const LongList& edges, const unallocLabelList& addr ) { // Remove unused points and create subaddressed edges DynamicList newPoints; labelList newPointAddr(points.size(), -1); LongList 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& points, const LongList& 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& facets, const unallocLabelList& addr ) { // Remove unused points and create subaddressed facets DynamicList newPoints; labelList newPointAddr(points.size(), -1); LongList newFacets(addr.size()); forAll(addr, addrI) { label faceI = addr[addrI]; const labelledTri& facet = facets[faceI]; const FixedList& pointIds = facet; FixedList 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& facets = origSurf.facets(); const LongList& 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 > 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