#include <open3d/Open3D.h> #include <Eigen/Dense> #include <vector> #include <cmath> #include <memory> #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "glew32s.lib") using namespace open3d;
std::shared_ptr<geometry::LineSet> MakePolyline() { const double x0 = -2.0 * 3.14159; const double x1 = 2.0 * 3.14159; const double amplitude = 1.0; // 振幅 const double frequency = 1.0; // 周波数 const double phase = 1.0; // 位相 const int samples = 400; ///////////////////////////////////////////////////////// auto lineset = std::make_shared<geometry::LineSet>(); // 頂点作成 const double step = (x1 - x0) / (samples - 1); for (int i = 0; i < samples; ++i) { double x = x0 + step * i; double y = amplitude * std::sin(frequency * x + phase); lineset->points_.emplace_back(Eigen::Vector3d(x, y, 0.0)); } ///////////////////////////////////////////////////////// // 頂点インデックスの組み合わせで線分を作成 for (size_t i = 0; i < samples-1; ++i){ lineset->lines_.emplace_back( (int)i, (int)(i + 1) ); // 線分に対する色を設定 lineset->colors_.emplace_back(Eigen::Vector3d(1.0, i/float(samples), 0.0)); } return lineset; }
int main() { auto sine_ls = MakePolyline(); visualization::Visualizer vis; vis.CreateVisualizerWindow("LineSet", 800, 600); vis.AddGeometry(sine_ls); auto& opt = vis.GetRenderOption(); opt.line_width_ = 2.0; opt.background_color_ = { 0, 0, 0 }; vis.Run(); vis.DestroyVisualizerWindow(); return 0; }
#pragma once #include <vtkCellArray.h> #include <vtkPoints.h> #include <vtkPolyData.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkDoubleArray.h> #include <vtkSmartPointer.h> #include <vtkPointData.h> #include <vtkProperty.h> #include <open3d/Open3D.h> #include <open3d/geometry/PointCloud.h> #include <Eigen/Core> #include "vtkFromO3dCommon.hpp" namespace vtko3d {
vtkSmartPointer<vtkPolyData> toCloudPolyData(const open3d::geometry::PointCloud& cloud, USEVALUE usedata=POINT_RGB) { // 頂点配列 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); // 色情報の配列 vtkSmartPointer<vtkDoubleArray> colors = vtkSmartPointer<vtkDoubleArray>::New(); colors->SetNumberOfComponents(3); colors->SetName("Colors"); auto normals = vtkSmartPointer<vtkDoubleArray>::New(); normals->SetNumberOfComponents(3); // x, y, z normals->SetName("Normals"); // 頂点インデクスの配列 vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New(); for (size_t i = 0; i < cloud.points_.size(); i++) { double x = cloud.points_[i].x(); double y = cloud.points_[i].y(); double z = cloud.points_[i].z(); points->InsertNextPoint(x, y, z); // 座標追加 if (usedata & POINT_RGB) { double r = cloud.colors_[i].x(); double g = cloud.colors_[i].y(); double b = cloud.colors_[i].z(); colors->InsertNextTuple3(r, g, b); // 色情報追加 } if (usedata & POINT_NORMAL) { double nx = cloud.normals_[i].x(); double ny = cloud.normals_[i].y(); double nz = cloud.normals_[i].z(); normals->InsertNextTuple3(nx, ny, nz); // 法線ベクトル追加 } cells->InsertNextCell(1); // 要素数 cells->InsertCellPoint(i); // 頂点インデックスを追加 } // --- vtkPolyData作成 --- auto polydata = vtkSmartPointer<vtkPolyData>::New(); polydata->SetPoints(points); polydata->SetVerts(cells); if (usedata & POINT_RGB) { polydata->GetPointData()->SetScalars(colors); } if (usedata & POINT_NORMAL) { polydata->GetPointData()->SetNormals(normals); } return polydata; }
vtkSmartPointer<vtkActor> toCloudActor(vtkSmartPointer<vtkPolyDataMapper> mapper, int point_size = 1,std::optional< std::array<double, 3> > single_color = std::nullopt) { auto actor = vtkSmartPointer<vtkActor>::New(); if (single_color.has_value()) { mapper->SetScalarVisibility(false); // 頂点ごとの色情報を無視 } actor->SetMapper(mapper); if (mapper->GetScalarVisibility() == false) { if (single_color.has_value()) { actor->GetProperty()->SetColor(single_color.value()[0], single_color.value()[1], single_color.value()[2]); // 単色(R, G, B)を指定 } } actor->GetProperty()->SetPointSize(point_size); // 頂点サイズを5に設定(ピクセル単位) actor->GetProperty()->SetLighting(false); return actor; }
std::shared_ptr<open3d::geometry::PointCloud> createSampleCloud() { auto pointcloud = std::make_shared<open3d::geometry::PointCloud>(); for (size_t i = 0; i < 100000; i++) { double x = (double)rand() / (double)RAND_MAX; double y = (double)rand() / (double)RAND_MAX; double z = (double)rand() / (double)RAND_MAX; pointcloud->points_.emplace_back(x, y, z); // 座標追加 pointcloud->colors_.emplace_back(x, y, z); // 色情報追加 pointcloud->normals_.emplace_back(x, y, z); // 法線ベクトル追加 } return pointcloud; }
}
auto cloud = vtko3d::createSampleCloud(); auto polyData = vtko3d::toCloudPolyData(*cloud, vtko3d::POINT_RGB); auto mapper = vtko3d::toMapper(polyData); auto actor = vtko3d::toCloudActor(mapper,3);
open3dのメッシュを可視化するためのコードを纏めておく。
#pragma once #include <vtkTriangle.h> #include <vtkProperty.h> #include <vtkActor.h> #include <open3d/Open3D.h> #include <open3d/geometry/PointCloud.h> #include <Eigen/Core> #include "vtkFromO3dCommon.hpp" namespace vtko3d {
vtkSmartPointer<vtkPolyData> toMeshPolyData(const open3d::geometry::TriangleMesh& mesh, USEVALUE usedata, bool withpoints = false) { vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New(); // 色情報の配列 vtkSmartPointer<vtkDoubleArray> colors = vtkSmartPointer<vtkDoubleArray>::New(); colors->SetNumberOfComponents(3); colors->SetName("Colors"); vtkSmartPointer<vtkDoubleArray> normals = vtkSmartPointer<vtkDoubleArray>::New(); normals->SetNumberOfComponents(3); normals->SetName("Normals"); for (size_t i = 0; i < mesh.vertices_.size(); ++i) { double x = mesh.vertices_[i].x(); double y = mesh.vertices_[i].y(); double z = mesh.vertices_[i].z(); vtkIdType pid = points->InsertNextPoint(x, y, z); if (withpoints) { vertices->InsertNextCell(1, &pid); } if (usedata & POINT_RGB) { double r = mesh.vertex_colors_[i].x(); double g = mesh.vertex_colors_[i].y(); double b = mesh.vertex_colors_[i].z(); colors->InsertNextTuple3(r, g, b); // 色情報追加 } if (usedata & POINT_NORMAL) { double nx = mesh.vertex_normals_[i].x(); double ny = mesh.vertex_normals_[i].y(); double nz = mesh.vertex_normals_[i].z(); normals->InsertNextTuple3(nx, ny, nz); } } ////////////////////////////////////////////////////////////////////// for (size_t i = 0; i < mesh.triangles_.size(); ++i) { size_t p1 = mesh.triangles_[i](0); size_t p2 = mesh.triangles_[i](1); size_t p3 = mesh.triangles_[i](2); // 三角形1 (p1, p2, p3) vtkSmartPointer<vtkTriangle> tri = vtkSmartPointer<vtkTriangle>::New(); tri->GetPointIds()->SetId(0, p1); tri->GetPointIds()->SetId(1, p2); tri->GetPointIds()->SetId(2, p3); triangles->InsertNextCell(tri); } // vtkPolyData の作成 vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); if (withpoints) { polyData->SetVerts(vertices); } polyData->SetPolys(triangles); // 三角形セルを設定 if(usedata & POINT_RGB) { polyData->GetPointData()->SetScalars(colors); } if (usedata & POINT_NORMAL) { polyData->GetPointData()->SetNormals(normals); } return polyData; }
struct wireframe_option { bool show_faces = false; float line_width = 1.2f; std::array<double, 3> line_color = { 1.0, 1.0, 1.0 }; };
vtkSmartPointer<vtkActor> toMeshActor( vtkSmartPointer<vtkPolyDataMapper> mapper, bool usephong=false, std::optional<wireframe_option> wireopt = std::nullopt, std::optional< std::array<double, 3> > single_color = std::nullopt, int point_size = 5 ) { vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); if (single_color.has_value()) { actor->GetProperty()->SetColor(single_color.value()[0], single_color.value()[1], single_color.value()[2]); } else { actor->GetProperty()->SetColor(1.0, 1.0, 1.0); // デフォルトは白色 } vtkPolyData* poly = mapper->GetInput(); if (poly->GetVerts()->GetNumberOfCells() > 0) { actor->GetProperty()->SetPointSize(point_size); // 点のサイズを設定 } if (usephong) { actor->GetProperty()->SetInterpolationToPhong(); // またはSetInterpolationToGouraud() } if (wireopt.has_value()) { if (wireopt->show_faces) { actor->GetProperty()->SetRepresentationToSurface(); actor->GetProperty()->EdgeVisibilityOn(); actor->GetProperty()->SetEdgeColor( wireopt->line_color.data() ); // エッジ色 actor->GetProperty()->SetLineWidth(wireopt->line_width); } else { actor->GetProperty()->SetRepresentationToWireframe(); actor->GetProperty()->SetLineWidth(wireopt->line_width); actor->GetProperty()->SetLighting(false); actor->GetProperty()->BackfaceCullingOff(); actor->GetProperty()->FrontfaceCullingOff(); } } return actor; }
// テスト用のメッシュを作成 std::shared_ptr<open3d::geometry::TriangleMesh> createSampleMesh() { std::shared_ptr<open3d::geometry::TriangleMesh> mesh = std::make_shared<open3d::geometry::TriangleMesh>(); int xcount = 20; int ycount = 20; float width = 1.0f; float height = 1.0f; float depth = 0.1f; float density = 10.0f; // 頂点の登録 for (int i = 0; i < xcount; ++i) { for (int j = 0; j < ycount; ++j) { double x = -0.5 + 1.0 * i / (xcount - 1); double y = -0.5 + 1.0 * j / (ycount - 1); double z = sin(x * density) * depth + sin(y * density) * depth; mesh->vertices_.emplace_back(x, y, z); mesh->vertex_colors_.emplace_back(x + 0.5, y + 0.5, z + 0.5); } } // メッシュ(三角形)の作成 for (int i = 0; i < xcount - 1; ++i) { for (int j = 0; j < ycount - 1; ++j) { // 四角形を2つの三角形に分割 int p1 = i * ycount + j; // 左下 int p2 = (i + 1) * ycount + j; // 右下 int p3 = i * ycount + (j + 1); // 左上 int p4 = (i + 1) * ycount + (j + 1); // 右上 mesh->triangles_.emplace_back(Eigen::Vector3i(p1, p2, p3)); mesh->triangles_.emplace_back(Eigen::Vector3i(p2, p4, p3)); } } return mesh; } }
#pragma once #include <vtkSmartPointer.h> #include <vtkPolyData.h> #include <vtkPolyDataMapper.h> namespace vtko3d { enum USEVALUE { POINT_XYZ = 0b0001, POINT_RGB = 0b0010, POINT_NORMAL = 0b0100, POINT_RGBNORMAL = POINT_RGB | POINT_NORMAL, }; vtkSmartPointer<vtkPolyDataMapper> toMapper(vtkSmartPointer<vtkPolyData> polydata) { auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(polydata); return mapper; } }
auto mesh = vtko3d::createSampleMesh(); mesh->ComputeVertexNormals(); // 法線ベクトルを計算 auto polyData = vtko3d::toMeshPolyData(*mesh, vtko3d::POINT_RGBNORMAL,false); auto mapper = vtko3d::toMapper(polyData); auto actor = vtko3d::toMeshActor(mapper, true, vtko3d::wireframe_option{ false }); auto renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor);
動作を中断して状況を見たいが、ブレークポイントなどでプログラムそのものを中断すると出力コードも動かなくて困る。デバッグしたい処理をスレッドで動かし、セマフォを使うことで任意の場所で中断・再開できるらしい。
#include <iostream> #include <semaphore> #include <atomic> #include <thread>
class MyBreakPoint { std::binary_semaphore gate{ 0 }; // 許可は最大1に飽和 std::atomic<bool> run_free{ false }; // trueで連続実行 public: // 停止点: run_free=false のときだけ待つ void BreakPoint() { if (run_free.load(std::memory_order_acquire)) return; gate.acquire(); } // 次のBreakPointまで進める void ContinueToNextBreak() { gate.release(); } // 以後ブレーク無視 void RunFree() { run_free.store(true, std::memory_order_release); gate.release(); // 既に待っていれば抜ける } // 以後BreakPointで停止 void PauseAtBreak() { run_free.store(false, std::memory_order_release); // 残っている許可を掃き出し、次回は必ず止まる while (gate.try_acquire()) { /* drain */ } } };
void worker(MyBreakPoint& pauser) { for (int i = 0; i < 100; ++i) { // 処理本体 std::cout << i << std::endl; if (i % 5 == 0) { std::cout << "i % 5 == 0" << std::endl; pauser.BreakPoint(); // ブレークポイント } // 動作を見るための速度調節 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::cout << "done" << std::endl; }
int main() { MyBreakPoint poser; std::thread th(worker, std::ref(poser)); // ユーザー入力でデバッグ操作 for (char c; std::cin >> c; ) { if (c == 'c') poser.ContinueToNextBreak();// 次にBreakPointが呼ばれるまで実行 else if (c == 'r') poser.RunFree();// 以後BreakPointを無視 else if (c == 'p') poser.PauseAtBreak();// 以後BreakPointが呼ばれたら止まる } th.join(); }
MFCを使う機会が増えそうになってきた。CStringで正規表現する方法を調べたがATL,MFCには(今はもう)無いらしく、C++標準のstd::regexを使うのが一番いいらしい。
// AfxMessageBox #include <afxwin.h> // CString #include <atlstr.h> #include <string> #include <regex> #ifdef _UNICODE using tregex = std::wregex; using tmatch = std::wcmatch; #else using tregex = std::regex; using tmatch = std::cmatch; #endif int main() { CString text = _T("Hello, 123 こんにちは"); #ifdef _UNICODE CString cset= _T(" (UNICODE)"); #else CString cset= _T(" (MULTIBYTE)"); #endif tregex re(_T("こん.*")); tmatch match; if (std::regex_search( LPCTSTR(text), match, re)) { int length = (int)(match[0].second - match[0].first); CString result(match[0].first, length); AfxMessageBox(result + cset); } }
自分で導入したvcpkg installをコマンドプロンプトから実行して以下のエラーに遭遇
error: Could not locate a manifest (vcpkg.json) above the current working directory.
This vcpkg distribution does not have a classic mode instance.
これは自分で導入したvcpkgを実行したつもりで、実はVisual Studioが管理しているvcpkgが実行された場合に起こるらしい。具体的には
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
などでVisual Studioの環境を設定した場合、且つ、環境変数などで自前のvcpkgのパスを通していた場合に起こる可能性がある。
つまり、vcvars64.batが環境を整備しているときに、Visual Studio以外で導入したvcpkgの存在が確認できた時、これを有効にしてしまうとVisual Studioのvcpkgを使っているつもりなのに異なるvcpkgを操作してしまったということが起こり得てしまいまずいので、強制的にVS用のvcpkgに上書きされる。
この上書きはdoskeyというコマンドで行われるらしい。以下の確認用コマンドで、もし
の結果が
などであれば、vcpkgのパスが上書きされているので、以下を実行してこの設定を消す。
描画した頂点の番号や座標値などを表示したいとき用。
#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <Eigen/Dense> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkActor.h> #include <vtkPolyDataMapper.h> #include <vtkPolyData.h> #include <vtkPoints.h> #include <vtkCellArray.h> #include <vtkUnsignedCharArray.h> #include <vtkProperty.h> #include <vtkPointData.h> //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle);
// 座標群生製
std::vector<Eigen::Vector3d> make_cloud(int count) { std::vector<Eigen::Vector3d> cloud; for (size_t i = 0; i < count; i++) { double x = (double)rand() / (double)RAND_MAX; double y = (double)rand() / (double)RAND_MAX; double z = (double)rand() / (double)RAND_MAX; cloud.push_back(Eigen::Vector3d(x, y, z)); } return cloud; }
//////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// #include <vtkStringArray.h> #include <vtkLabeledDataMapper.h> #include <vtkActor2D.h> #include <vtkTextProperty.h>
// ラベルを表すPolyDataを作成 vtkSmartPointer<vtkPolyData> toLabel(const std::vector<Eigen::Vector3d>& data) { ////////////////////////// // auto points = vtkSmartPointer<vtkPoints>::New(); // インデックス文字列を作成 auto labels = vtkSmartPointer<vtkStringArray>::New(); labels->SetName("labels"); for (vtkIdType i = 0; i < data.size(); ++i) { std::string text = std::to_string(i); points->InsertNextPoint(data[i].data()); // 位置 labels->InsertNextValue(text.c_str()); // ラベル } auto polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); polyData->GetPointData()->AddArray(labels); return polyData; }
// ラベル表示用のActorを作成 vtkSmartPointer<vtkActor2D> toLabelActor( vtkSmartPointer<vtkPolyData> poly, int fontSize = 20 ) { double color[3] = { 1.0, 1.0, 1.0 }; auto labelMapper = vtkSmartPointer<vtkLabeledDataMapper>::New(); labelMapper->SetInputData(poly); labelMapper->SetLabelModeToLabelFieldData(); labelMapper->SetFieldDataName("labels"); auto textProperty = labelMapper->GetLabelTextProperty(); textProperty->SetFontSize(fontSize); // フォントサイズ textProperty->SetColor(color); // 色 //textProperty->SetShadow(1); auto labelActor = vtkSmartPointer<vtkActor2D>::New(); labelActor->SetMapper(labelMapper); return labelActor; }
//////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// int main(int /*argc*/, char** /*argv*/) { auto renderer = vtkSmartPointer<vtkRenderer>::New(); auto cloud = make_cloud(10);// 座標群を作成 ////////////////////////////////////// // 座標にデータ番号を表示 auto textpoly = toLabel(cloud); vtkSmartPointer<vtkActor2D> textactor = toLabelActor(textpoly); renderer->AddActor(textactor);// ラベル表示 ////////////////////////////////////// renderer->ResetCamera(); auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); ////////////////////////////////////// auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); renderWindow->SetInteractor(interactor); renderWindow->Render(); interactor->Start(); //イベントループへ入る return 0; }
VTK の MFC 対応 vtkMFCWindow は、文字セットがUnicodeの場合、Debugモードで実行中に以下で実行時エラーが発生する。
m_vtkMFCWindow = new vtkMFCWindow(this);
VTKのCMakeLists.txtを編集してこれを回避できるらしい。
VTKのソースコードをダウンロードしたら、以下のファイルを開く
VTK-9.5.1\GUISupport\MFC\CMakeLists.txt
CMakeLists.txt内、ファイル中央付近に以下のように追加をする。
# C runtime lib linkage and MFC lib linkage *MUST* match.
# If linking to C runtime static lib, link to MFC static lib.
# If linking to C runtime dll, link to MFC dll.
if (vtk_mfc_static)
set(CMAKE_MFC_FLAG 1)
else ()
set(CMAKE_MFC_FLAG 2)
endif ()
set(classes
vtkMFCWindow
)
vtk_module_add_module(VTK::GUISupportMFC
CLASSES ${classes})
vtk_add_test_mangling(VTK::GUISupportMFC)
### 追加 ###
vtk_module_definitions(VTK::GUISupportMFC PRIVATE _UNICODE UNICODE)
#############
if (vtk_mfc_static)
vtk_module_link(VTK::GUISupportMFC
PRIVATE
"debug;nafxcwd;optimized;nafxcw"
"debug;LIBCMTD;optimized;LIBCMT"
Uxtheme
windowscodecs)
else ()
vtk_module_definitions(VTK::GUISupportMFC
PRIVATE
_AFXDLL)
endif ()
別に詰まったわけではないし、公式からダウンロードしたもので事足りるのだけれど、一応成功事例を残しておく。
Window 11, Visual C++ 2022 x64
以下を設定
BUILD_SHARED_LIBS=ON
これをすると、WEBRTCが使えなくなるのでOFFにする
BUILD_WEBRTC=OFF
BUILD_WEBRTC_FROM_SOURCE=OFF
あと、/MDにしたいので
STATIC_WINDOWS_RUNTIME=OFF
ビルド結果は、以下+resources。DLLが少ないのは良いこと。
Release:
lib/Open3D.lib
lib/tbb12.lib
bin/Open3D.dll
bin/tbb12.dll
Debug:
lib/Open3D.lib
lib/tbb12_debug.lib
bin/Open3D.dll
bin/tbb12_debug.dll
#include <iostream> #include <vector> #include <filesystem> #include <regex> #include <unordered_map> struct PathList { std::vector<std::filesystem::path> directories; std::vector<std::filesystem::path> files; };
// 指定したパス内のファイル一覧を取得
PathList GetFileList(const std::filesystem::path& _path) { PathList result; if (!std::filesystem::exists(_path) || !std::filesystem::is_directory(_path)) { return result; // 存在しない場合は空を返す } for (const auto& entry : std::filesystem::directory_iterator(_path)) { if (entry.is_directory()) { result.directories.push_back(entry.path()); } else if (entry.is_regular_file()) { result.files.push_back(entry.path()); } } return result; }
// パスのファイル名からIDを取り出し、pair<size_t, path> の配列で返す std::vector<std::pair<size_t, std::filesystem::path>> GetFileIncdies(const std::vector<std::filesystem::path>& pathlist, const std::regex& pattern, std::vector<std::filesystem::path>* excep) { std::vector<std::pair<size_t, std::filesystem::path>> result; for (const auto& p : pathlist) { const std::string name = p.filename().string(); std::smatch m; if (std::regex_search(name, m, pattern)) { // パターンにマッチしたかどうか bool ok = false; size_t idx = 0; for (size_t i = 1; i < m.size(); ++i) { const std::string s = m[i].str(); if (s.empty()) continue; // すべて数字かを判定 const bool all_digits = std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c) != 0; }); if (!all_digits) continue; try { idx = static_cast<size_t>(std::stoull(s)); ok = true; break; } catch (...) { // stoull 失敗時は次のキャプチャを試す } } if (ok) { result.emplace_back(idx, p); } else if (excep) { excep->push_back(p); } } else { if (excep) excep->push_back(p); } } // インデックス昇順、同値ならパスの辞書順 std::sort(result.begin(), result.end(), [](const auto& a, const auto& b) { if (a.first != b.first) return a.first < b.first; return a.second < b.second; }); return result; }
template<typename Tuple,typename Pair,int Index> std::unordered_map<size_t, Tuple> CreateDataSetList(std::unordered_map<size_t, Tuple>& datamap,std::vector<Tuple>& datasets, std::vector<Pair>& pairs) { for (const auto& p : pairs) { size_t idx = p.first; const auto& path = p.second; auto& tupleitem = datamap[idx]; std::get<Index>(tupleitem) = path; // Index番目にパスをセット } return datamap; }
// マップをIDでソートしたものを返す template<typename Tuple> std::vector<std::pair<size_t, Tuple>> SortByID(const std::unordered_map<size_t, Tuple>& byidmap) { std::vector<std::pair<size_t, Tuple>> sorted; sorted.reserve(byidmap.size()); for (const auto& kv : byidmap) { sorted.emplace_back(kv.first, kv.second); } std::sort(sorted.begin(), sorted.end(), [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; // size_tキーで昇順 }); return sorted; }
using Tuple = std::tuple<std::filesystem::path, std::filesystem::path, std::filesystem::path>; using Pair = std::pair<size_t, std::filesystem::path>;
// パスとパターンからファイル一覧を作成し、インデックスとパスのペアを返す関数 std::vector<std::pair<size_t, std::filesystem::path> > GetFiles(const std::filesystem::path& path,std::regex pattern){ PathList fileList = GetFileList(path); std::vector<std::pair<size_t, std::filesystem::path> > flist; flist = GetFileIncdies(fileList.files, pattern, nullptr); return flist; }
int main() { std::vector< Tuple > dataSetList; std::vector<Pair > list_1 = GetFiles("C:\\test\\tmp\\txt", std::regex(R"(新規 テキスト000_(\d+)\.txt)") ); std::vector<Pair > list_2 = GetFiles("C:\\test\\tmp\\doc", std::regex(R"(doc_000_(\d+)\.doc)") ); std::unordered_map<size_t, Tuple> byidmap; CreateDataSetList<Tuple, Pair, 0>(byidmap, dataSetList, list_1); CreateDataSetList<Tuple, Pair, 1>(byidmap, dataSetList, list_2); std::vector<std::pair<size_t, Tuple>> sorted = SortByID(byidmap); for(const auto& b : sorted) { std::cout << "ID: " << b.first << " " << std::get<0>(b.second).filename() << " " << std::get<1>(b.second).filename() << " " << std::get<2>(b.second) << "\n"; } }