スポンサーリンク
VTM、VTPはXML形式なので、VTKを使わなくても出力できる。自分で作ったデータをvtm,vtpで出力するとparaview等で可視化できる。
XMLなのでpugixmlを使用。
save_vtm_vtkfreeで.vtmファイルを保存する。
#pragma once #include <Eigen/Dense> #include <filesystem> #include <vector> #include <string> #include "pugixml.hpp" struct Data3D { std::vector< Eigen::Vector3d > points; std::vector< Eigen::Vector3i > triangles; // 頂点ID三つで構成される三角形 std::vector< int > polyline;// N個の頂点を格納した頂点リストで表現される折れ線 };
void save_vtp_vtkfree(const std::string& filename, const Data3D& data) { pugi::xml_document doc; auto vtkFile = doc.append_child("VTKFile"); vtkFile.append_attribute("type") = "PolyData"; vtkFile.append_attribute("version") = "1.0"; vtkFile.append_attribute("byte_order") = "LittleEndian"; auto polyData = vtkFile.append_child("PolyData"); polyData.append_attribute("WholeExtent") = "0 0 0 0 0 0"; auto piece = polyData.append_child("Piece"); piece.append_attribute("NumberOfPoints") = data.points.size(); piece.append_attribute("NumberOfLines") = data.polyline.empty() ? 0 : 1; piece.append_attribute("NumberOfPolys") = data.triangles.size(); ////////////////////////////////////////////////////////////////// // Points auto pointsNode = piece.append_child("Points"); auto pointsArray = pointsNode.append_child("DataArray"); pointsArray.append_attribute("type") = "Float64"; pointsArray.append_attribute("NumberOfComponents") = 3; pointsArray.append_attribute("format") = "ascii"; std::ostringstream pointsStream; for (const auto& p : data.points) { pointsStream << p.x() << " " << p.y() << " " << p.z() << " "; } pointsArray.text().set(pointsStream.str().c_str()); ////////////////////////////////////////////////////////////////// // PolyLine if (!data.polyline.empty()) { auto linesNode = piece.append_child("Lines"); auto connArray = linesNode.append_child("DataArray"); connArray.append_attribute("type") = "Int32"; connArray.append_attribute("Name") = "connectivity"; connArray.append_attribute("format") = "ascii"; std::ostringstream connStream; for (const auto& pointIndex : data.polyline) { connStream << pointIndex << " "; } connArray.text().set(connStream.str().c_str()); auto offsetArray = linesNode.append_child("DataArray"); offsetArray.append_attribute("type") = "Int32"; offsetArray.append_attribute("Name") = "offsets"; offsetArray.append_attribute("format") = "ascii"; std::ostringstream offsetStream; offsetStream << data.polyline.size(); offsetArray.text().set(offsetStream.str().c_str()); } ////////////////////////////////////////////////////////////////// // Triangles if (!data.triangles.empty()) { auto polysNode = piece.append_child("Polys"); auto polyConnArray = polysNode.append_child("DataArray"); polyConnArray.append_attribute("type") = "Int32"; polyConnArray.append_attribute("Name") = "connectivity"; polyConnArray.append_attribute("format") = "ascii"; std::ostringstream polyConnStream; for (const auto& tri : data.triangles) { polyConnStream << tri[0] << " " << tri[1] << " " << tri[2] << " "; } polyConnArray.text().set(polyConnStream.str().c_str()); auto polyOffsetArray = polysNode.append_child("DataArray"); polyOffsetArray.append_attribute("type") = "Int32"; polyOffsetArray.append_attribute("Name") = "offsets"; polyOffsetArray.append_attribute("format") = "ascii"; std::ostringstream polyOffsetStream; for (size_t i = 0; i < data.triangles.size(); ++i) { polyOffsetStream << (i + 1) * 3 << " "; } polyOffsetArray.text().set(polyOffsetStream.str().c_str()); } ////////////////////////////////////////////////////////////////// doc.save_file(filename.c_str()); }
// VTKの形式であるVTMファイルを保存する関数 // ただしVTKライブラリを使用しない void save_vtm_vtkfree(const std::string& filename, const std::vector<Data3D>& dataList) { // filenameからディレクトリ名を取得 std::filesystem::path path(filename); std::string directory = path.parent_path().string(); std::string filenameWithoutExtension = path.stem().string(); if( directory.empty() ) { directory = "."; } std::string vtpdirectory = directory + "/" + filenameWithoutExtension; // ディレクトリが存在しない場合は作成存在する場合は中を空にする if (std::filesystem::exists(vtpdirectory)) { for (const auto& entry : std::filesystem::directory_iterator(vtpdirectory)) { std::filesystem::remove_all(entry.path()); } } std::filesystem::create_directories(vtpdirectory); pugi::xml_document doc; auto vtkFile = doc.append_child("VTKFile"); vtkFile.append_attribute("type") = "vtkMultiBlockDataSet"; vtkFile.append_attribute("version") = "1.0"; vtkFile.append_attribute("byte_order") = "LittleEndian"; auto mbNode = vtkFile.append_child("vtkMultiBlockDataSet"); for (size_t i = 0; i < dataList.size(); ++i) { std::string vtpFilename = filenameWithoutExtension + "_" + std::to_string(i) + ".vtp"; save_vtp_vtkfree(vtpdirectory + "/" + vtpFilename, dataList[i]); auto dataSetNode = mbNode.append_child("DataSet"); dataSetNode.append_attribute("index") = static_cast<int>(i); dataSetNode.append_attribute("file") = (filenameWithoutExtension + "/" + vtpFilename).c_str(); } doc.save_file(filename.c_str()); }
#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkActor.h> #include <vtkPolyData.h> #include <vtkPolyDataMapper.h> #include <vtkCellArray.h> #include <vtkPoints.h> #include <vtkLine.h> #include <vtkTriangle.h> #include <vtkProperty.h> #include <vtkXMLPolyDataReader.h> #include <vtkXMLMultiBlockDataReader.h> #include <vtkMultiBlockDataSet.h> //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); #include "save_vtm_vtkfree.hpp" // メッシュデータの生成関数 Data3D createSampleData(); void displayVTP(const std::string& filename, bool showLines, bool showPolys, double lineWidth, double lineColor[3], double polyColor[3]); int main(int /*argc*/, char** /*argv*/) { Data3D data = createSampleData(); Data3D data2 = createSampleData(); for(auto& p : data2.points){ p.x() += 1.0; p.y() += 1.0; p.z() += 1.0; } //データをVTK形式で保存 std::vector<Data3D> dataList; dataList.push_back(data); dataList.push_back(data2); save_vtm_vtkfree("C:\\test\\test2.vtm", dataList); double c[3] = { 1.0, 0.0, 0.0 }, d[3] = { 0.0, 1.0, 0.0 }; displayVTP("C:\\test\\test2.vtm", true, true, 5.0, c,d); return 0; } Data3D createSampleData() { Data3D data; // 点群の生成 data.points.push_back(Eigen::Vector3d(0.0, 0.0, 0.0)); data.points.push_back(Eigen::Vector3d(1.0, 0.0, 0.0)); data.points.push_back(Eigen::Vector3d(1.0, 1.0, 0.0)); data.points.push_back(Eigen::Vector3d(0.0, 1.0, 0.0)); data.points.push_back(Eigen::Vector3d(0.5, 0.5, 1.0)); // 三角形の生成 (底面と頂点を結ぶ三角形) data.triangles.push_back(Eigen::Vector3i(0, 1, 4)); data.triangles.push_back(Eigen::Vector3i(1, 2, 4)); data.triangles.push_back(Eigen::Vector3i(2, 3, 4)); data.triangles.push_back(Eigen::Vector3i(3, 0, 4)); data.triangles.push_back(Eigen::Vector3i(0, 1, 2)); data.triangles.push_back(Eigen::Vector3i(0, 2, 3)); // 折れ線の生成 data.polyline = { 0, 1, 2, 3, 0, }; return data; } void displayVTP(const std::string& filename, bool showLines, bool showPolys, double lineWidth, double lineColor[3], double polyColor[3]) { vtkSmartPointer<vtkXMLMultiBlockDataReader> reader = vtkSmartPointer<vtkXMLMultiBlockDataReader>::New(); reader->SetFileName(filename.c_str()); reader->Update(); vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->SetBackground(0.1, 0.1, 0.1); vtkMultiBlockDataSet* multiBlockData = vtkMultiBlockDataSet::SafeDownCast(reader->GetOutput()); if (!multiBlockData) return; for (unsigned int i = 0; i < multiBlockData->GetNumberOfBlocks(); ++i) { vtkSmartPointer<vtkPolyData> polyData = vtkPolyData::SafeDownCast(multiBlockData->GetBlock(i)); if (!polyData) continue; if (showLines && polyData->GetLines()->GetNumberOfCells() > 0) { vtkSmartPointer<vtkPolyDataMapper> lineMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); lineMapper->SetInputData(polyData); vtkSmartPointer<vtkActor> lineActor = vtkSmartPointer<vtkActor>::New(); lineActor->SetMapper(lineMapper); lineActor->GetProperty()->SetColor(lineColor); lineActor->GetProperty()->SetLineWidth(lineWidth); renderer->AddActor(lineActor); } if (showPolys && polyData->GetPolys()->GetNumberOfCells() > 0) { vtkSmartPointer<vtkPolyDataMapper> polyMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); polyMapper->SetInputData(polyData); vtkSmartPointer<vtkActor> polyActor = vtkSmartPointer<vtkActor>::New(); polyActor->SetMapper(polyMapper); polyActor->GetProperty()->SetColor(polyColor); polyActor->GetProperty()->SetEdgeVisibility(false); renderer->AddActor(polyActor); } } vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); renderWindow->Render(); interactor->Start(); }
test2.vtm
<?xml version="1.0"?> <VTKFile type="vtkMultiBlockDataSet" version="1.0" byte_order="LittleEndian"> <vtkMultiBlockDataSet> <DataSet index="0" file="test2/test2_0.vtp" /> <DataSet index="1" file="test2/test2_1.vtp" /> </vtkMultiBlockDataSet> </VTKFile>
test2/test2_0.vtp
<?xml version="1.0"?> <VTKFile type="PolyData" version="1.0" byte_order="LittleEndian"> <PolyData WholeExtent="0 0 0 0 0 0"> <Piece NumberOfPoints="5" NumberOfLines="1" NumberOfPolys="6"> <Points> <DataArray type="Float64" NumberOfComponents="3" format="ascii">0 0 0 1 0 0 1 1 0 0 1 0 0.5 0.5 1 </DataArray> </Points> <Lines> <DataArray type="Int32" Name="connectivity" format="ascii">0 1 2 3 0 </DataArray> <DataArray type="Int32" Name="offsets" format="ascii">5</DataArray> </Lines> <Polys> <DataArray type="Int32" Name="connectivity" format="ascii">0 1 4 1 2 4 2 3 4 3 0 4 0 1 2 0 2 3 </DataArray> <DataArray type="Int32" Name="offsets" format="ascii">3 6 9 12 15 18 </DataArray> </Polys> </Piece> </PolyData> </VTKFile>