ViennaLS
Loading...
Searching...
No Matches
lsVTKRenderWindow.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifdef VIENNALS_VTK_RENDERING
4
5#include <lsMaterialMap.hpp>
6#include <lsMesh.hpp>
7
8#include <vtkActor.h>
9#include <vtkAutoInit.h>
10#include <vtkCamera.h>
11#include <vtkCellArray.h>
12#include <vtkCellData.h>
13#include <vtkDataSetMapper.h>
14#include <vtkInteractorStyleImage.h>
15#include <vtkLookupTable.h>
16#include <vtkPoints.h>
17#include <vtkPolyData.h>
18#include <vtkPolyDataMapper.h>
19#include <vtkProperty.h>
20#include <vtkRenderWindow.h>
21#include <vtkRenderWindowInteractor.h>
22#include <vtkRenderer.h>
23#include <vtkUnstructuredGrid.h>
24
25#ifndef VIENNALS_VTK_MODULE_INIT
26VTK_MODULE_INIT(vtkRenderingOpenGL2);
27VTK_MODULE_INIT(vtkInteractionStyle);
28VTK_MODULE_INIT(vtkRenderingFreeType);
29VTK_MODULE_INIT(vtkRenderingUI);
30#endif
31
32class ImagePanInteractorStyle : public vtkInteractorStyleImage {
33public:
34 static ImagePanInteractorStyle *New();
35 vtkTypeMacro(ImagePanInteractorStyle, vtkInteractorStyleImage);
36
37 void OnLeftButtonDown() override { this->StartPan(); }
38
39 void OnLeftButtonUp() override { this->EndPan(); }
40};
41
42vtkStandardNewMacro(ImagePanInteractorStyle);
43
44namespace viennals {
45
46template <typename T> class VTKRenderWindow {
47public:
48 VTKRenderWindow() { initialize(); }
49 VTKRenderWindow(SmartPointer<Mesh<T>> passedMesh) {
50 initialize();
51 setMesh(passedMesh);
52 }
53
54 ~VTKRenderWindow() {
55 if (interactor) {
56 interactor->SetRenderWindow(nullptr);
57 }
58 if (renderWindow) {
59 renderWindow->RemoveRenderer(renderer);
60 }
61 }
62
63 void setMesh(SmartPointer<Mesh<T>> passedMesh) {
64 mesh = passedMesh;
65 auto matIds = mesh->getCellData().getScalarData("MaterialIds", false);
66 if (matIds) {
67 materialIds = *matIds;
68 }
69 updatePolyData();
70 }
71
72 void setVolumeMesh(vtkSmartPointer<vtkUnstructuredGrid> volumeVTK) {
73 volumeMesh = volumeVTK;
74 updateVolumeMesh();
75 }
76
77 void setMaterialIds(const std::vector<T> &ids) { materialIds = ids; }
78
79 auto setBackgroundColor(const std::array<double, 3> &color) {
80 backgroundColor = color;
81 if (renderer) {
82 renderer->SetBackground(backgroundColor.data());
83 }
84
85 return *this;
86 }
87
88 void render() {
89 if (mesh == nullptr && volumeMesh == nullptr) {
90 VIENNACORE_LOG_WARNING("No mesh set for rendering.");
91 return;
92 }
93
94 // Re-attach renderer to the style right before starting, in case the style
95 // was changed in the meantime
96 if (auto style = interactor->GetInteractorStyle()) {
97 style->SetDefaultRenderer(renderer);
98 style->SetCurrentRenderer(renderer);
99 }
100 interactor->SetRenderWindow(renderWindow);
101 renderWindow->AddRenderer(renderer);
102
103 renderWindow->Render();
104 interactor->Initialize();
105 interactor->Start();
106 }
107
108 vtkSmartPointer<vtkRenderWindow> getRenderWindow() { return renderWindow; }
109
110 auto enable2DMode() {
111 assert(renderer && "Renderer not initialized");
112 vtkCamera *cam = renderer->GetActiveCamera();
113 cam->ParallelProjectionOn();
114
115 auto style = vtkSmartPointer<ImagePanInteractorStyle>::New();
116 // Make sure both the interactor and the style know which renderer to use
117 style->SetDefaultRenderer(renderer);
118 style->SetCurrentRenderer(renderer);
119 interactor->SetInteractorStyle(style);
120 return *this;
121 }
122
123private:
124 void initialize() {
125 renderer = vtkSmartPointer<vtkRenderer>::New();
126 renderer->SetBackground(backgroundColor.data());
127
128 renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
129 renderWindow->SetWindowName("ViennaLS Render Window");
130 renderWindow->SetSize(windowSize.data());
131
132 // Initialize interactor
133 interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
134 interactor->SetRenderWindow(renderWindow);
135
136 // Set interactor style
137 auto style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
138 interactor->SetInteractorStyle(style);
139
140 renderWindow->SetInteractor(interactor);
141 }
142
143 void updatePolyData() {
144 if (mesh == nullptr) {
145 return;
146 }
147
148 polyData = vtkSmartPointer<vtkPolyData>::New();
149
150 // Points
151 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
152 for (const auto &node : mesh->getNodes()) {
153 points->InsertNextPoint(node[0], node[1], node[2]);
154 }
155 polyData->SetPoints(points);
156
157 // Debug: print bounds
158 double bounds[6];
159 polyData->GetBounds(bounds);
160
161 // Vertices
162 if (!mesh->vertices.empty()) {
163 vtkSmartPointer<vtkCellArray> verts =
164 vtkSmartPointer<vtkCellArray>::New();
165 for (const auto &vertex : mesh->vertices) {
166 verts->InsertNextCell(1);
167 verts->InsertCellPoint(vertex[0]);
168 }
169 polyData->SetVerts(verts);
170 }
171
172 // Lines
173 if (!mesh->lines.empty()) {
174 vtkSmartPointer<vtkCellArray> lines =
175 vtkSmartPointer<vtkCellArray>::New();
176 for (const auto &line : mesh->lines) {
177 lines->InsertNextCell(2);
178 lines->InsertCellPoint(line[0]);
179 lines->InsertCellPoint(line[1]);
180 }
181 polyData->SetLines(lines);
182
183 enable2DMode();
184 }
185
186 // Triangles
187 if (!mesh->triangles.empty()) {
188 vtkSmartPointer<vtkCellArray> polys =
189 vtkSmartPointer<vtkCellArray>::New();
190 for (const auto &triangle : mesh->triangles) {
191 polys->InsertNextCell(3);
192 polys->InsertCellPoint(triangle[0]);
193 polys->InsertCellPoint(triangle[1]);
194 polys->InsertCellPoint(triangle[2]);
195 }
196 polyData->SetPolys(polys);
197 }
198
199 // Material IDs as cell data
200 bool useMaterialIds =
201 !materialIds.empty() &&
202 (materialIds.size() == mesh->lines.size() + mesh->triangles.size());
203 int minId = std::numeric_limits<int>::max();
204 int maxId = std::numeric_limits<int>::min();
205 if (useMaterialIds) {
206 vtkSmartPointer<vtkIntArray> matIdArray =
207 vtkSmartPointer<vtkIntArray>::New();
208 matIdArray->SetName("MaterialIds");
209 for (const auto &id : materialIds) {
210 int mId = static_cast<int>(id);
211 matIdArray->InsertNextValue(mId);
212 minId = std::min(minId, mId);
213 maxId = std::max(maxId, mId);
214 }
215 polyData->GetCellData()->AddArray(matIdArray);
216 polyData->GetCellData()->SetActiveScalars("MaterialIds");
217 VIENNACORE_LOG_DEBUG("Added MaterialIds array to cell data.");
218 }
219
220 auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
221 mapper->SetInputData(polyData);
222
223 if (useMaterialIds) {
224 mapper->SetScalarModeToUseCellData();
225 mapper->ScalarVisibilityOn();
226 mapper->SelectColorArray("MaterialIds");
227
228 vtkSmartPointer<vtkLookupTable> lut =
229 vtkSmartPointer<vtkLookupTable>::New();
230
231 lut->SetNumberOfTableValues(256);
232 lut->SetHueRange(0.667, 0.0); // blue → red
233 lut->SetSaturationRange(1.0, 1.0);
234 lut->SetValueRange(1.0, 1.0);
235 lut->Build();
236
237 mapper->SetLookupTable(lut);
238 mapper->SetScalarRange(minId, maxId);
239 }
240
241 auto actor = vtkSmartPointer<vtkActor>::New();
242 actor->SetMapper(mapper);
243 actor->GetProperty()->SetLineWidth(3.0); // Thicker lines
244
245 renderer->AddActor(actor);
246 renderer->ResetCamera();
247 }
248
249 void updateVolumeMesh() {
250 auto mapper = vtkSmartPointer<vtkDataSetMapper>::New();
251 mapper->SetInputData(volumeMesh);
252
253 auto actor = vtkSmartPointer<vtkActor>::New();
254 actor->SetMapper(mapper);
255
256 renderer->AddActor(actor);
257 renderer->ResetCamera();
258 }
259
260private:
261 SmartPointer<Mesh<T>> mesh = nullptr;
262 std::vector<T> materialIds;
263
264 vtkSmartPointer<vtkUnstructuredGrid> volumeMesh = nullptr;
265
266 vtkSmartPointer<vtkRenderer> renderer;
267 vtkSmartPointer<vtkRenderWindow> renderWindow;
268 vtkSmartPointer<vtkRenderWindowInteractor> interactor;
269 vtkSmartPointer<vtkPolyData> polyData;
270
271 std::array<double, 3> backgroundColor = {84.0 / 255, 89.0 / 255, 109.0 / 255};
272 std::array<int, 2> windowSize = {800, 600};
273};
274
275} // namespace viennals
276
277#endif // VIENNALS_VTK_RENDERING
tuple bounds
Definition AirGapDeposition.py:23
mesh
Definition AirGapDeposition.py:36
Definition lsAdvect.hpp:37