1.3.49
 
Loading...
Searching...
No Matches
VisualizerGeometry.cpp
Go to the documentation of this file.
1
16// Freetype Libraries (rendering fonts)
17extern "C" {
18#include <ft2build.h>
19#include FT_FREETYPE_H
20}
21
22#include "Visualizer.h"
23
24using namespace helios;
25
27 geometry_handler.clearAllGeometry();
28
29 contextUUIDs_build.clear();
30 colorPrimitives_UUIDs.clear();
31 colorPrimitives_objIDs.clear();
32 contextUUIDs_build.clear();
33 depth_buffer_data.clear();
34 colorbar_min = 0;
35 colorbar_max = 0;
36}
37
38size_t Visualizer::addRectangleByCenter(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const RGBcolor &color, CoordinateSystem coordFlag) {
39 return addRectangleByCenter(center, size, rotation, make_RGBAcolor(color.r, color.g, color.b, 1), coordFlag);
40}
41
42size_t Visualizer::addRectangleByCenter(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const RGBAcolor &color, CoordinateSystem coordFlag) {
43 std::vector<vec3> vertices;
44 vertices.resize(4);
45
46 vec3 v0 = make_vec3(-0.5f * size.x, -0.5f * size.y, 0.f);
47 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
48 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
49 vertices.at(0) = center + v0;
50
51 vec3 v1 = make_vec3(+0.5f * size.x, -0.5f * size.y, 0.f);
52 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
53 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
54 vertices.at(1) = center + v1;
55
56 vec3 v2 = make_vec3(+0.5f * size.x, +0.5f * size.y, 0.f);
57 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
58 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
59 vertices.at(2) = center + v2;
60
61 vec3 v3 = make_vec3(-0.5f * size.x, +0.5f * size.y, 0.f);
62 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
63 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
64 vertices.at(3) = center + v3;
65
66 return addRectangleByVertices(vertices, color, coordFlag);
67}
68
69size_t Visualizer::addRectangleByCenter(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const char *texture_file, CoordinateSystem coordFlag) {
70 std::vector<vec3> vertices;
71 vertices.resize(4);
72
73 vec3 v0 = make_vec3(-0.5f * size.x, -0.5f * size.y, 0.f);
74 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
75 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
76 vertices.at(0) = center + v0;
77
78 vec3 v1 = make_vec3(+0.5f * size.x, -0.5f * size.y, 0.f);
79 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
80 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
81 vertices.at(1) = center + v1;
82
83 vec3 v2 = make_vec3(+0.5f * size.x, +0.5f * size.y, 0.f);
84 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
85 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
86 vertices.at(2) = center + v2;
87
88 vec3 v3 = make_vec3(-0.5f * size.x, +0.5f * size.y, 0.f);
89 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
90 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
91 vertices.at(3) = center + v3;
92
93 return addRectangleByVertices(vertices, texture_file, coordFlag);
94}
95
96size_t Visualizer::addRectangleByCenter(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const RGBcolor &color, const char *texture_file, CoordinateSystem coordFlag) {
97 std::vector<vec3> vertices;
98 vertices.resize(4);
99
100 vec3 v0 = make_vec3(-0.5f * size.x, -0.5f * size.y, 0.f);
101 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
102 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
103 vertices.at(0) = center + v0;
104
105 vec3 v1 = make_vec3(+0.5f * size.x, -0.5f * size.y, 0.f);
106 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
107 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
108 vertices.at(1) = center + v1;
109
110 vec3 v2 = make_vec3(+0.5f * size.x, +0.5f * size.y, 0.f);
111 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
112 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
113 vertices.at(2) = center + v2;
114
115 vec3 v3 = make_vec3(-0.5f * size.x, +0.5f * size.y, 0.f);
116 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
117 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
118 vertices.at(3) = center + v3;
119
120 return addRectangleByVertices(vertices, color, texture_file, coordFlag);
121}
122
123size_t Visualizer::addRectangleByCenter(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const RGBcolor &color, const Glyph *glyph, CoordinateSystem coordFlag) {
124 std::vector<vec3> vertices;
125 vertices.resize(4);
126
127 vec3 v0 = make_vec3(-0.5f * size.x, -0.5f * size.y, 0.f);
128 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
129 v0 = rotatePointAboutLine(v0, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
130 vertices.at(0) = center + v0;
131
132 vec3 v1 = make_vec3(+0.5f * size.x, -0.5f * size.y, 0.f);
133 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
134 v1 = rotatePointAboutLine(v1, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
135 vertices.at(1) = center + v1;
136
137 vec3 v2 = make_vec3(+0.5f * size.x, +0.5f * size.y, 0.f);
138 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
139 v2 = rotatePointAboutLine(v2, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
140 vertices.at(2) = center + v2;
141
142 vec3 v3 = make_vec3(-0.5f * size.x, +0.5f * size.y, 0.f);
143 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(1, 0, 0), -rotation.elevation);
144 v3 = rotatePointAboutLine(v3, make_vec3(0, 0, 0), make_vec3(0, 0, 1), -rotation.azimuth);
145 vertices.at(3) = center + v3;
146
147 return addRectangleByVertices(vertices, color, glyph, coordFlag);
148}
149
150size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const RGBcolor &color, CoordinateSystem coordFlag) {
151 return addRectangleByVertices(vertices, make_RGBAcolor(color.r, color.g, color.b, 1), coordFlag);
152}
153
154size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const RGBAcolor &color, CoordinateSystem coordFlag) {
155 if (coordFlag == COORDINATES_WINDOW_NORMALIZED) { // No vertex transformation (i.e., identity matrix)
156
157 // Check that coordinates are inside drawable area
158 for (auto vertex: vertices) {
159 if (vertex.x < 0.f || vertex.x > 1.f) {
160 if (message_flag) {
161 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x << " ) is outside of drawable area." << std::endl;
162 }
163 } else if (vertex.y < 0.f || vertex.y > 1.f) {
164 if (message_flag) {
165 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y << " ) is outside of drawable area." << std::endl;
166 }
167 } else if (vertex.z < -1.f || vertex.z > 1.f) {
168 if (message_flag) {
169 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z << " ) is outside of drawable area." << std::endl;
170 }
171 }
172 }
173 }
174
175 size_t UUID = geometry_handler.sampleUUID();
176 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, color, {}, -1, false, false, coordFlag, true, false);
177 return UUID;
178}
179
180size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const char *texture_file, CoordinateSystem coordFlag) {
181 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
182 return addRectangleByVertices(vertices, texture_file, uvs, coordFlag);
183}
184
185size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const char *texture_file, const std::vector<vec2> &uvs, CoordinateSystem coordFlag) {
186 if (coordFlag == COORDINATES_WINDOW_NORMALIZED) { // No vertex transformation (i.e., identity matrix)
187
188 // Check that coordinates are inside drawable area
189 for (auto vertex: vertices) {
190 if (vertex.x < 0.f || vertex.x > 1.f) {
191 if (message_flag) {
192 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x << " ) is outside of drawable area." << std::endl;
193 }
194 } else if (vertex.y < 0.f || vertex.y > 1.f) {
195 if (message_flag) {
196 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y << " ) is outside of drawable area." << std::endl;
197 }
198 } else if (vertex.z < -1.f || vertex.z > 1.f) {
199 if (message_flag) {
200 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z << " ) is outside of drawable area." << std::endl;
201 }
202 }
203 }
204 }
205
206 uint textureID = registerTextureImage(texture_file);
207
208 size_t UUID = geometry_handler.sampleUUID();
209 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, RGBA::black, uvs, textureID, false, false, coordFlag, true, false);
210 return UUID;
211}
212
213size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const RGBcolor &color, const char *texture_file, CoordinateSystem coordFlag) {
214 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
215 return addRectangleByVertices(vertices, color, texture_file, uvs, coordFlag);
216}
217
218size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const helios::RGBcolor &color, const char *texture_file, const std::vector<vec2> &uvs, CoordinateSystem coordFlag) {
219 if (coordFlag == COORDINATES_WINDOW_NORMALIZED) { // No vertex transformation (i.e., identity matrix)
220
221 // Check that coordinates are inside drawable area
222 for (auto vertex: vertices) {
223 if (vertex.x < 0.f || vertex.x > 1.f) {
224 if (message_flag) {
225 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x << " ) is outside of drawable area." << std::endl;
226 }
227 } else if (vertex.y < 0.f || vertex.y > 1.f) {
228 if (message_flag) {
229 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y << " ) is outside of drawable area." << std::endl;
230 }
231 } else if (vertex.z < -1.f || vertex.z > 1.f) {
232 if (message_flag) {
233 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z << " ) is outside of drawable area." << std::endl;
234 }
235 }
236 }
237 }
238
239 uint textureID = registerTextureImage(texture_file);
240
241 size_t UUID = geometry_handler.sampleUUID();
242 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, make_RGBAcolor(color, 1.f), uvs, textureID, false, false, coordFlag, true, false);
243 return UUID;
244}
245
246size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const RGBcolor &color, const Glyph *glyph, CoordinateSystem coordFlag) {
247 return addRectangleByVertices(vertices, make_RGBAcolor(color, 1), glyph, coordFlag);
248}
249
250size_t Visualizer::addRectangleByVertices(const std::vector<vec3> &vertices, const RGBAcolor &color, const Glyph *glyph, CoordinateSystem coordFlag) {
251 if (coordFlag == COORDINATES_WINDOW_NORMALIZED) { // No vertex transformation (i.e., identity matrix)
252
253 // Check that coordinates are inside drawable area
254 for (auto vertex: vertices) {
255 if (vertex.x < 0.f || vertex.x > 1.f) {
256 if (message_flag) {
257 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x << " ) is outside of drawable area." << std::endl;
258 }
259 } else if (vertex.y < 0.f || vertex.y > 1.f) {
260 if (message_flag) {
261 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y << " ) is outside of drawable area." << std::endl;
262 }
263 } else if (vertex.z < -1.f || vertex.z > 1.f) {
264 if (message_flag) {
265 std::cerr << "WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z << " ) is outside of drawable area." << std::endl;
266 }
267 }
268 }
269 }
270
271 uint textureID = registerTextureGlyph(glyph);
272
273 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
274
275 // Disable shadows for glyphs
276 CoordinateSystem coordFlag2 = coordFlag;
277 if (coordFlag == COORDINATES_CARTESIAN) {
278 coordFlag2 = scast<CoordinateSystem>(2);
279 }
280
281 size_t UUID = geometry_handler.sampleUUID();
282 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, color, uvs, textureID, true, true, coordFlag2, true, false);
283 return UUID;
284}
285
286size_t Visualizer::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2, const RGBcolor &color, CoordinateSystem coordFlag) {
287 return addTriangle(vertex0, vertex1, vertex2, make_RGBAcolor(color.r, color.g, color.b, 1), coordFlag);
288}
289
290size_t Visualizer::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2, const RGBAcolor &color, CoordinateSystem coordFlag) {
291 const std::vector<vec3> vertices{vertex0, vertex1, vertex2};
292
293 if (coordFlag == 0) { // No vertex transformation (i.e., identity matrix)
294
295 // Check that coordinates are inside drawable area
296 for (const auto &vertex: vertices) {
297 if (vertex.x < 0.f || vertex.x > 1.f) {
298 if (message_flag) {
299 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `x' position ( " << vertex.x << " ) is outside of drawable area." << std::endl;
300 }
301 } else if (vertex.y < 0.f || vertex.y > 1.f) {
302 if (message_flag) {
303 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `y' position ( " << vertex.y << " ) is outside of drawable area." << std::endl;
304 }
305 } else if (vertex.z < -1.f || vertex.z > 1.f) {
306 if (message_flag) {
307 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `z' position ( " << vertex.z << " ) is outside of drawable area." << std::endl;
308 }
309 }
310 }
311 }
312
313 size_t UUID = geometry_handler.sampleUUID();
314 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_TRIANGLE, vertices, color, {}, -1, false, false, coordFlag, true, false);
315 return UUID;
316}
317
318size_t Visualizer::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2, const char *texture_file, const helios::vec2 &uv0, const helios::vec2 &uv1, const helios::vec2 &uv2, CoordinateSystem coordFlag) {
319 const std::vector<vec3> vertices{vertex0, vertex1, vertex2};
320 const std::vector<vec2> uvs{uv0, uv1, uv2};
321
322 if (coordFlag == 0) { // No vertex transformation (i.e., identity matrix)
323
324 // Check that coordinates are inside drawable area
325 for (auto &vertex: vertices) {
326 if (vertex.x < 0.f || vertex.x > 1.f) {
327 if (message_flag) {
328 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `x' position ( " << vertex.x << " ) is outside of drawable area." << std::endl;
329 }
330 } else if (vertex.y < 0.f || vertex.y > 1.f) {
331 if (message_flag) {
332 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `y' position ( " << vertex.y << " ) is outside of drawable area." << std::endl;
333 }
334 } else if (vertex.z < -1.f || vertex.z > 1.f) {
335 if (message_flag) {
336 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `z' position ( " << vertex.z << " ) is outside of drawable area." << std::endl;
337 }
338 }
339 }
340 }
341
342 uint textureID = registerTextureImage(texture_file);
343
344 size_t UUID = geometry_handler.sampleUUID();
345 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_TRIANGLE, vertices, RGBA::black, uvs, textureID, false, false, coordFlag, true, false);
346 return UUID;
347}
348
349size_t Visualizer::addTriangle(const vec3 &vertex0, const vec3 &vertex1, const vec3 &vertex2, const char *texture_file, const helios::vec2 &uv0, const helios::vec2 &uv1, const helios::vec2 &uv2, const RGBAcolor &color, CoordinateSystem coordFlag) {
350 const std::vector<vec3> vertices{vertex0, vertex1, vertex2};
351 const std::vector<vec2> uvs{uv0, uv1, uv2};
352
353 if (coordFlag == 0) { // No vertex transformation (i.e., identity matrix)
354
355 // Check that coordinates are inside drawable area
356 for (const auto &tri_vertex: vertices) {
357 if (tri_vertex.x < 0.f || tri_vertex.x > 1.f) {
358 if (message_flag) {
359 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `x' position ( " << tri_vertex.x << " ) is outside of drawable area." << std::endl;
360 }
361 } else if (tri_vertex.y < 0.f || tri_vertex.y > 1.f) {
362 if (message_flag) {
363 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `y' position ( " << tri_vertex.y << " ) is outside of drawable area." << std::endl;
364 }
365 } else if (tri_vertex.z < -1.f || tri_vertex.z > 1.f) {
366 if (message_flag) {
367 std::cerr << "WARNING (Visualizer::addTriangle): Triangle `z' position ( " << tri_vertex.z << " ) is outside of drawable area." << std::endl;
368 }
369 }
370 }
371 }
372
373 uint textureID = registerTextureImage(texture_file);
374
375 size_t UUID = geometry_handler.sampleUUID();
376 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_TRIANGLE, vertices, color, uvs, textureID, true, false, coordFlag, true, false);
377 return UUID;
378}
379
380std::vector<size_t> Visualizer::addVoxelByCenter(const vec3 &center, const vec3 &size, const SphericalCoord &rotation, const RGBcolor &color, CoordinateSystem coordFlag) {
381 return addVoxelByCenter(center, size, rotation, make_RGBAcolor(color.r, color.g, color.b, 1), coordFlag);
382}
383
384std::vector<size_t> Visualizer::addVoxelByCenter(const vec3 &center, const vec3 &size, const SphericalCoord &rotation, const RGBAcolor &color, CoordinateSystem coordFlag) {
385 float eps = 1e-4; // Avoid z-fighting
386
387 float az = rotation.azimuth;
388
389 std::vector<size_t> UUIDs(6);
390
391 const vec3 c0 = center + rotatePoint(make_vec3(0, -0.5f * size.y, 0.f), 0, az) + eps;
392 UUIDs.at(0) = addRectangleByCenter(c0, make_vec2(size.x, size.z), make_SphericalCoord(-0.5 * PI_F, az), color, coordFlag);
393
394 const vec3 c1 = center + rotatePoint(make_vec3(0, 0.5f * size.y, 0.f), 0, az) + eps;
395 UUIDs.at(1) = addRectangleByCenter(c1, make_vec2(size.x, size.z), make_SphericalCoord(0.5 * PI_F, az), color, coordFlag);
396
397 const vec3 c2 = center + rotatePoint(make_vec3(0.5f * size.x, 0.f, 0.f), 0, az) + eps;
398 UUIDs.at(2) = addRectangleByCenter(c2, make_vec2(size.y, size.z), make_SphericalCoord(0.5 * PI_F, 0.5 * PI_F + az), color, coordFlag);
399
400 const vec3 c3 = center + rotatePoint(make_vec3(-0.5f * size.x, 0.f, 0.f), 0, az) + eps;
401 UUIDs.at(3) = addRectangleByCenter(c3, make_vec2(size.y, size.z), make_SphericalCoord(0.5 * PI_F, 0.5 * PI_F + az), color, coordFlag);
402
403 const vec3 c4 = center + make_vec3(0.f, 0.f, -0.5f * size.z) + eps;
404 UUIDs.at(4) = addRectangleByCenter(c4, make_vec2(size.x, size.y), make_SphericalCoord(PI_F, az), color, coordFlag);
405
406 const vec3 c5 = center + make_vec3(0.f, 0.f, 0.5f * size.z) + eps;
407 UUIDs.at(5) = addRectangleByCenter(c5, make_vec2(size.x, size.y), make_SphericalCoord(0, az), color, coordFlag);
408
409 return UUIDs;
410}
411
412size_t Visualizer::addLine(const vec3 &start, const vec3 &end, const RGBcolor &color, CoordinateSystem coordinate_system) {
413 return addLine(start, end, make_RGBAcolor(color, 1), coordinate_system);
414}
415
416size_t Visualizer::addLine(const vec3 &start, const vec3 &end, const RGBAcolor &color, CoordinateSystem coordFlag) {
417 const std::vector<vec3> vertices{start, end};
418
419 size_t UUID = geometry_handler.sampleUUID();
420 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_LINE, vertices, color, {}, -1, false, false, coordFlag, true, false);
421 return UUID;
422}
423
424size_t Visualizer::addLine(const vec3 &start, const vec3 &end, const RGBcolor &color, float line_width, CoordinateSystem coordinate_system) {
425 return addLine(start, end, make_RGBAcolor(color, 1), line_width, coordinate_system);
426}
427
428size_t Visualizer::addLine(const vec3 &start, const vec3 &end, const RGBAcolor &color, float line_width, CoordinateSystem coordFlag) {
429 // Basic validation - ensure positive line width
430 if (line_width <= 0.0f) {
431 std::cerr << "WARNING (Visualizer::addLine): Line width must be positive. Setting to 1.0." << std::endl;
432 line_width = 1.0f;
433 }
434
435 const std::vector<vec3> vertices{start, end};
436
437 size_t UUID = geometry_handler.sampleUUID();
438 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_LINE, vertices, color, {}, -1, false, false, coordFlag, true, false, static_cast<int>(line_width));
439 return UUID;
440}
441
442size_t Visualizer::addPoint(const vec3 &position, const RGBcolor &color, float pointsize, CoordinateSystem coordinate_system) {
443 return addPoint(position, make_RGBAcolor(color, 1), pointsize, coordinate_system);
444}
445
446size_t Visualizer::addPoint(const vec3 &position, const RGBAcolor &color, float pointsize, CoordinateSystem coordinate_system) {
447 // Only perform OpenGL validation if we have a valid context (not in headless mode during initialization)
448 if (!headless && window != nullptr) {
449 // Use conservative OpenGL 3.3 Core Profile point size limits
450 // Most implementations support at least 1.0 to 64.0 for point sizes
451 const float MIN_POINT_SIZE = 1.0f;
452 const float MAX_POINT_SIZE = 64.0f;
453
454 if (pointsize < MIN_POINT_SIZE || pointsize > MAX_POINT_SIZE) {
455 std::cerr << "WARNING (Visualizer::addPoint): Point size ( " << pointsize << " ) is outside of supported range ( " << MIN_POINT_SIZE << ", " << MAX_POINT_SIZE << " ). Clamping value.." << std::endl;
456 if (pointsize < MIN_POINT_SIZE) {
457 pointsize = MIN_POINT_SIZE;
458 } else {
459 pointsize = MAX_POINT_SIZE;
460 }
461 }
462 }
463 this->point_width = pointsize;
464
465 size_t UUID = geometry_handler.sampleUUID();
466 geometry_handler.addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_POINT, {position}, color, {}, -1, false, false, coordinate_system, true, false, pointsize);
467 return UUID;
468}
469
470std::vector<size_t> Visualizer::addSphereByCenter(float radius, const vec3 &center, uint Ndivisions, const RGBcolor &color, CoordinateSystem coordinate_system) {
471 return addSphereByCenter(radius, center, Ndivisions, make_RGBAcolor(color.r, color.g, color.b, 1), coordinate_system);
472}
473
474std::vector<size_t> Visualizer::addSphereByCenter(float radius, const vec3 &center, uint Ndivisions, const RGBAcolor &color, CoordinateSystem coordinate_system) {
475 float dtheta = PI_F / scast<float>(Ndivisions);
476 float dphi = 2.f * PI_F / scast<float>(Ndivisions);
477
478 std::vector<size_t> UUIDs;
479 UUIDs.reserve(2 * Ndivisions + 2 * (Ndivisions - 2) * (Ndivisions - 1));
480
481 // bottom cap
482 for (int j = 0; j < Ndivisions; j++) {
483 float phi = scast<float>(j) * dphi;
484 float phi_plus = scast<float>(j + 1) * dphi;
485
486 vec3 v0 = center + sphere2cart(make_SphericalCoord(radius, -0.5f * PI_F, 0));
487 vec3 v1 = center + sphere2cart(make_SphericalCoord(radius, -0.5f * PI_F + dtheta, phi));
488 vec3 v2 = center + sphere2cart(make_SphericalCoord(radius, -0.5f * PI_F + dtheta, phi_plus));
489
490 UUIDs.push_back(addTriangle(v0, v1, v2, color, coordinate_system));
491 }
492
493 // top cap
494 for (int j = 0; j < Ndivisions; j++) {
495 float phi = scast<float>(j) * dphi;
496 float phi_plus = scast<float>(j + 1) * dphi;
497
498 vec3 v0 = center + sphere2cart(make_SphericalCoord(radius, 0.5f * PI_F, 0));
499 vec3 v1 = center + sphere2cart(make_SphericalCoord(radius, 0.5f * PI_F - dtheta, phi));
500 vec3 v2 = center + sphere2cart(make_SphericalCoord(radius, 0.5f * PI_F - dtheta, phi_plus));
501
502 UUIDs.push_back(addTriangle(v2, v1, v0, color, coordinate_system));
503 }
504
505 // middle
506 for (int j = 0; j < Ndivisions; j++) {
507 float phi = scast<float>(j) * dphi;
508 float phi_plus = scast<float>(j + 1) * dphi;
509 for (int i = 1; i < Ndivisions - 1; i++) {
510 float theta = -0.5f * PI_F + scast<float>(i) * dtheta;
511 float theta_plus = -0.5f * PI_F + scast<float>(i + 1) * dtheta;
512
513 vec3 v0 = center + sphere2cart(make_SphericalCoord(radius, theta, phi));
514 vec3 v1 = center + sphere2cart(make_SphericalCoord(radius, theta_plus, phi));
515 vec3 v2 = center + sphere2cart(make_SphericalCoord(radius, theta_plus, phi_plus));
516 vec3 v3 = center + sphere2cart(make_SphericalCoord(radius, theta, phi_plus));
517
518 UUIDs.push_back(addTriangle(v0, v1, v2, color, coordinate_system));
519 UUIDs.push_back(addTriangle(v0, v2, v3, color, coordinate_system));
520 }
521 }
522
523 return UUIDs;
524}
525
526void Visualizer::addSkyDomeByCenter(float radius, const vec3 &center, uint Ndivisions, const char *texture_file, int layer) {
527 addSkyDomeByCenter(radius, center, Ndivisions, texture_file);
528}
529
530std::vector<size_t> Visualizer::addSkyDomeByCenter(float radius, const vec3 &center, uint Ndivisions, const char *texture_file) {
531 float thetaStart = -0.1f * PI_F;
532
533 float dtheta = (0.5f * PI_F - thetaStart) / float(Ndivisions - 1);
534 float dphi = 2.f * PI_F / float(Ndivisions - 1);
535
536 std::vector<size_t> UUIDs;
537 UUIDs.reserve(2u * Ndivisions * Ndivisions);
538
539 vec3 cart;
540
541 // top cap
542 for (int j = 0; j < scast<int>(Ndivisions - 1); j++) {
543 cart = sphere2cart(make_SphericalCoord(1.f, 0.5f * PI_F, 0));
544 vec3 v0 = center + radius * cart;
545 cart = sphere2cart(make_SphericalCoord(1.f, 0.5f * PI_F - dtheta, float(j + 1) * dphi));
546 vec3 v1 = center + radius * cart;
547 cart = sphere2cart(make_SphericalCoord(1.f, 0.5f * PI_F - dtheta, float(j) * dphi));
548 vec3 v2 = center + radius * cart;
549
550 vec3 n0 = v0 - center;
551 n0.normalize();
552 vec3 n1 = v1 - center;
553 n1.normalize();
554 vec3 n2 = v2 - center;
555 n2.normalize();
556
557 vec2 uv0 = make_vec2(1.f - atan2f(sinf((float(j) + 0.5f) * dphi), -cosf((float(j) + 0.5f) * dphi)) / (2.f * PI_F) - 0.5f, 1.f - n0.z * 0.5f - 0.5f);
558 vec2 uv1 = make_vec2(1.f - atan2f(n1.x, -n1.y) / (2.f * PI_F) - 0.5f, 1.f - n1.z * 0.5f - 0.5f);
559 vec2 uv2 = make_vec2(1.f - atan2f(n2.x, -n2.y) / (2.f * PI_F) - 0.5f, 1.f - n2.z * 0.5f - 0.5f);
560
561 if (j == scast<int>(Ndivisions - 2)) {
562 uv2.x = 1;
563 }
564
565 UUIDs.push_back(addTriangle(v0, v1, v2, texture_file, uv0, uv1, uv2, scast<CoordinateSystem>(2)));
566 }
567
568 // middle
569 for (int j = 0; j < scast<int>(Ndivisions - 1); j++) {
570 for (int i = 0; i < scast<int>(Ndivisions - 1); i++) {
571 cart = sphere2cart(make_SphericalCoord(1.f, float(i) * dtheta, float(j) * dphi));
572 vec3 v0 = center + radius * cart;
573 cart = sphere2cart(make_SphericalCoord(1.f, float(i + 1) * dtheta, float(j) * dphi));
574 vec3 v1 = center + radius * cart;
575 cart = sphere2cart(make_SphericalCoord(1.f, float(i + 1) * dtheta, float(j + 1) * dphi));
576 vec3 v2 = center + radius * cart;
577 cart = sphere2cart(make_SphericalCoord(1.f, float(i) * dtheta, float(j + 1) * dphi));
578 vec3 v3 = center + radius * cart;
579
580 vec3 n0 = v0 - center;
581 n0.normalize();
582 vec3 n1 = v1 - center;
583 n1.normalize();
584 vec3 n2 = v2 - center;
585 n2.normalize();
586 vec3 n3 = v3 - center;
587 n3.normalize();
588
589 vec2 uv0 = make_vec2(1.f - atan2f(n0.x, -n0.y) / (2.f * PI_F) - 0.5f, 1.f - n0.z * 0.5f - 0.5f);
590 vec2 uv1 = make_vec2(1.f - atan2f(n1.x, -n1.y) / (2.f * PI_F) - 0.5f, 1.f - n1.z * 0.5f - 0.5f);
591 vec2 uv2 = make_vec2(1.f - atan2f(n2.x, -n2.y) / (2.f * PI_F) - 0.5f, 1.f - n2.z * 0.5f - 0.5f);
592 vec2 uv3 = make_vec2(1.f - atan2f(n3.x, -n3.y) / (2.f * PI_F) - 0.5f, 1.f - n3.z * 0.5f - 0.5f);
593
594 if (j == scast<int>(Ndivisions - 2)) {
595 uv2.x = 1;
596 uv3.x = 1;
597 }
598
599 UUIDs.push_back(addTriangle(v0, v1, v2, texture_file, uv0, uv1, uv2, scast<CoordinateSystem>(2)));
600 UUIDs.push_back(addTriangle(v0, v2, v3, texture_file, uv0, uv2, uv3, scast<CoordinateSystem>(2)));
601 }
602 }
603
604 return UUIDs;
605}
606
607std::vector<size_t> Visualizer::addTextboxByCenter(const char *textstring, const vec3 &center, const SphericalCoord &rotation, const RGBcolor &fontcolor, uint fontsize, const char *fontname, CoordinateSystem coordinate_system) {
608 FT_Library ft; // FreeType objects
609 FT_Face face;
610
611 // initialize the freetype library
612 if (FT_Init_FreeType(&ft) != 0) {
613 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Could not init freetype library");
614 }
615
616 std::vector<std::vector<unsigned char>> maskData; // This will hold the letter mask data
617
618 // Load the font
619 std::string font;
620 // std::snprintf(font,100,"plugins/visualizer/fonts/%s.ttf",fontname);
621 font = helios::resolvePluginAsset("visualizer", "fonts/" + (std::string) fontname + ".ttf").string();
622 auto error = FT_New_Face(ft, font.c_str(), 0, &face);
623 if (error != 0) {
624 switch (error) {
625 case FT_Err_Ok:; // do nothing
626 case FT_Err_Cannot_Open_Resource:
627 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Cannot open resource.");
628 case FT_Err_Unknown_File_Format:
629 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Unknown file format.");
630 case FT_Err_Invalid_File_Format:
631 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid file format.");
632 case FT_Err_Invalid_Version:
633 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid FreeType version.");
634 case FT_Err_Lower_Module_Version:
635 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Lower module version.");
636 case FT_Err_Invalid_Argument:
637 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid argument.");
638 case FT_Err_Unimplemented_Feature:
639 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Unimplemented feature.");
640 case FT_Err_Invalid_Table:
641 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid table.");
642 case FT_Err_Invalid_Offset:
643 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid offset.");
644 case FT_Err_Array_Too_Large:
645 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Array too large.");
646 case FT_Err_Missing_Module:
647 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Missing module.");
648 case FT_Err_Out_Of_Memory:
649 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Out of memory.");
650 case FT_Err_Invalid_Face_Handle:
651 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid face handle.");
652 case FT_Err_Invalid_Size_Handle:
653 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid size handle.");
654 case FT_Err_Invalid_Slot_Handle:
655 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid slot handle.");
656 case FT_Err_Invalid_CharMap_Handle:
657 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid charmap handle.");
658 case FT_Err_Invalid_Glyph_Index:
659 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid glyph index.");
660 case FT_Err_Invalid_Character_Code:
661 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid character code.");
662 case FT_Err_Invalid_Glyph_Format:
663 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid glyph format.");
664 case FT_Err_Cannot_Render_Glyph:
665 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Cannot render glyph.");
666 case FT_Err_Invalid_Outline:
667 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid outline.");
668 case FT_Err_Invalid_Composite:
669 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid composite glyph.");
670 case FT_Err_Too_Many_Hints:
671 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Too many hints.");
672 case FT_Err_Invalid_Pixel_Size:
673 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid pixel size.");
674 case FT_Err_Invalid_Library_Handle:
675 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid library handle.");
676 case FT_Err_Invalid_Stream_Handle:
677 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid stream handle.");
678 case FT_Err_Invalid_Frame_Operation:
679 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid frame operation.");
680 case FT_Err_Nested_Frame_Access:
681 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Nested frame access.");
682 case FT_Err_Invalid_Frame_Read:
683 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid frame read.");
684 case FT_Err_Raster_Uninitialized:
685 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Raster uninitialized.");
686 case FT_Err_Raster_Corrupted:
687 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Raster corrupted.");
688 case FT_Err_Raster_Overflow:
689 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Raster overflow.");
690 case FT_Err_Raster_Negative_Height:
691 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Raster negative height.");
692 case FT_Err_Too_Many_Caches:
693 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Too many caches.");
694 case FT_Err_Invalid_Opcode:
695 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Invalid opcode.");
696 case FT_Err_Too_Few_Arguments:
697 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Too few arguments.");
698 case FT_Err_Stack_Overflow:
699 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Stack overflow.");
700 case FT_Err_Stack_Underflow:
701 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Stack underflow.");
702 case FT_Err_Ignore:
703 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Ignore.");
704 case FT_Err_No_Unicode_Glyph_Name:
705 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): No Unicode glyph name.");
706 case FT_Err_Missing_Property:
707 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Missing property.");
708 default:
709 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Unknown FreeType error.");
710 }
711 }
712 if (error != 0) {
713 helios_runtime_error("ERROR (Visualizer::addTextboxByCenter): Could not open font '" + std::string(fontname) + "'");
714 }
715
716 // Load the font size
717 FT_Set_Pixel_Sizes(face, 0, fontsize);
718
719 // x- and y- size of a pixel in [0,1] normalized coordinates
720 float sx = 1.f / float(Wdisplay);
721 float sy = 1.f / float(Hdisplay);
722
723 FT_GlyphSlot gg = face->glyph; // FreeType glyph for font `fontname' and size `fontsize'
724
725 // first, find out how wide the text is going to be
726 // This is because we need to know the width beforehand if we want to center the text
727 float wtext = 0;
728 float htext = 0;
729 const char *textt = textstring;
730 for (const char *p = textt; *p; p++) { // looping over each letter in `textstring'
731 if (FT_Load_Char(face, *p, FT_LOAD_RENDER)) // load the letter
732 continue;
733 float scale = 1;
734 if (strncmp(p, "_", 1) == 0) { // subscript
735 scale = 0.5;
736 continue;
737 } else if (strncmp(p, "^", 1) == 0) { // superscript
738 scale = 0.5;
739 continue;
740 }
741 wtext += gg->bitmap.width * sx * scale;
742 htext = std::max(gg->bitmap.rows * sy, htext);
743 }
744
745 // location of the center of our textbox
746 float xt = center.x - 0.5f * wtext;
747 float yt = center.y - 0.5f * htext;
748
749 if (message_flag) {
750 if (coordinate_system == COORDINATES_WINDOW_NORMALIZED) {
751 if (xt < 0 || xt > 1) {
752 if (message_flag) {
753 std::cerr << "WARNING (Visualizer::addTextboxByCenter): text x-coordinate is outside of window area" << std::endl;
754 }
755 }
756 if (yt < 0 || yt > 1) {
757 if (message_flag) {
758 std::cerr << "WARNING (Visualizer::addTextboxByCenter): text y-coordinate is outside of window area" << std::endl;
759 }
760 }
761 }
762 }
763
764 FT_GlyphSlot g = face->glyph; // Another FreeType glyph for font `fontname' and size `fontsize'
765
766 std::vector<size_t> UUIDs;
767 UUIDs.reserve(std::strlen(textstring));
768
769 const char *text = textstring;
770
771 float offset = 0; // baseline offset for subscript/superscript
772 float scale = 1; // scaling factor for subscript/superscript
773 for (const char *p = text; *p; p++) { // looping over each letter in `textstring'
774
775 if (FT_Load_Char(face, *p, FT_LOAD_RENDER)) // load the letter
776 continue;
777
778 if (strncmp(p, "_", 1) == 0) { // subscript
779 offset = -0.3f * sy;
780 scale = 0.5f;
781 continue;
782 } else if (strncmp(p, "^", 1) == 0) { // superscript
783 offset = 0.3f * sy;
784 scale = 0.5f;
785 continue;
786 }
787
788 // Copy the letter's mask into 2D `maskData' structure
789 uint2 tsize(g->bitmap.width, g->bitmap.rows);
790 maskData.resize(tsize.y);
791 for (int j = 0; j < tsize.y; j++) {
792 maskData.at(j).resize(tsize.x);
793 for (int i = 0; i < tsize.x; i++) {
794 maskData.at(j).at(i) = g->bitmap.buffer[i + j * tsize.x];
795 }
796 }
797
798 // size of this letter (i.e., the size of the rectangle we're going to make
799 vec2 lettersize = make_vec2(g->bitmap.width * scale * sx, g->bitmap.rows * scale * sy);
800
801 // position of this letter (i.e., the center of the rectangle we're going to make
802 vec3 letterposition = make_vec3(xt + g->bitmap_left * sx + 0.5 * lettersize.x, yt + g->bitmap_top * (sy + offset) - 0.5 * lettersize.y, center.z);
803
804 // advance the x- and y- letter position
805 xt += (g->advance.x >> 6) * sx * scale;
806 yt += (g->advance.y >> 6) * sy * scale;
807
808 // reset the offset and scale
809 offset = 0;
810 scale = 1;
811
812 if (lettersize.x == 0 || lettersize.y == 0) { // if the size of the letter is 0, don't add a rectangle
813 continue;
814 }
815
816 Glyph glyph(tsize, maskData);
817
818 //\todo Currently, this adds a separate rectangle for each letter. Would be better to bake the whole string into a single rectangle/texture.
819 UUIDs.push_back(addRectangleByCenter(letterposition, lettersize, rotation, make_RGBcolor(fontcolor.r, fontcolor.g, fontcolor.b), &glyph, coordinate_system));
820 }
821
822 FT_Done_Face(face);
823 FT_Done_FreeType(ft);
824
825 return UUIDs;
826}
827
828void Visualizer::deleteGeometry(size_t geometry_id) {
829 if (geometry_handler.doesGeometryExist(geometry_id)) {
830 geometry_handler.deleteGeometry(geometry_id);
831 }
832}
833
834std::vector<size_t> Visualizer::addColorbarByCenter(const char *title, const helios::vec2 &size, const helios::vec3 &center, const helios::RGBcolor &font_color, const Colormap &colormap) {
835 uint Ndivs = 50;
836
837 uint Nticks = 4;
838
839 std::vector<size_t> UUIDs;
840 UUIDs.reserve(Ndivs + 2 * Nticks + 20);
841
842 if (!colorbar_ticks.empty()) {
843 Nticks = colorbar_ticks.size();
844 }
845
846 float dx = size.x / float(Ndivs);
847
848 float cmin = clamp(colormap.getLowerLimit(), -1e7f, 1e7f);
849 float cmax = clamp(colormap.getUpperLimit(), -1e7f, 1e7f);
850
851 for (uint i = 0; i < Ndivs; i++) {
852 float x = center.x - 0.5f * size.x + (float(i) + 0.5f) * dx;
853
854 RGBcolor color = colormap.query(cmin + float(i) / float(Ndivs) * (cmax - cmin));
855
856 UUIDs.push_back(addRectangleByCenter(make_vec3(x, center.y, center.z), make_vec2(dx, 0.5f * size.y), make_SphericalCoord(0, 0), color, COORDINATES_WINDOW_NORMALIZED));
857 }
858
859 std::vector<vec3> border;
860 border.reserve(5);
861 border.push_back(make_vec3(center.x - 0.5f * size.x, center.y + 0.25f * size.y, center.z - 0.001f));
862 border.push_back(make_vec3(center.x + 0.5f * size.x, center.y + 0.25f * size.y, center.z - 0.001f));
863 border.push_back(make_vec3(center.x + 0.5f * size.x, center.y - 0.25f * size.y, center.z - 0.001f));
864 border.push_back(make_vec3(center.x - 0.5f * size.x, center.y - 0.25f * size.y, center.z - 0.001f));
865 border.push_back(make_vec3(center.x - 0.5f * size.x, center.y + 0.25f * size.y, center.z - 0.001f));
866
867 for (uint i = 0; i < border.size() - 1; i++) {
868 UUIDs.push_back(addLine(border.at(i), border.at(i + 1), font_color, COORDINATES_WINDOW_NORMALIZED));
869 }
870
871 dx = size.x / float(Nticks - 1);
872
873 std::vector<vec3> ticks;
874 ticks.resize(2);
875 for (uint i = 0; i < Nticks; i++) {
877 char textstr[10], precision[10];
878
879 float x;
880 float value;
881 if (colorbar_ticks.empty()) {
882 x = center.x - 0.5f * size.x + float(i) * dx;
883 value = cmin + float(i) / float(Nticks - 1) * (cmax - cmin);
884 } else {
885 value = colorbar_ticks.at(i);
886 x = center.x - 0.5f * size.x + (value - cmin) / (cmax - cmin) * size.x;
887 }
888
889 if (std::fabs(floor(value) - value) < 1e-4) { // value is an integer
890 std::snprintf(precision, 10, "%%d");
891 std::snprintf(textstr, 10, precision, int(floor(value)));
892 } else if (value != 0.f) {
893 // value needs decimal formatting
894 int d1 = floor(log10(std::fabs(value)));
895 int d2 = -d1 + 1;
896 if (d2 < 1) {
897 d2 = 1;
898 }
899 std::snprintf(precision, 10, "%%%u.%uf", (char) abs(d1) + 1, (char) d2);
900 std::snprintf(textstr, 10, precision, value);
901 }
902
903 // tick labels
904 std::vector<size_t> UUIDs_text = addTextboxByCenter(textstr, make_vec3(x, center.y - 0.4f * size.y, center.z), make_SphericalCoord(0, 0), font_color, colorbar_fontsize, "OpenSans-Regular", COORDINATES_WINDOW_NORMALIZED);
905 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
906
907 if (i > 0 && i < Nticks - 1) {
908 ticks[0] = make_vec3(x, center.y - 0.25f * size.y, center.z - 0.001f);
909 ticks[1] = make_vec3(x, center.y - 0.25f * size.y + 0.05f * size.y, center.z - 0.001f);
910 addLine(ticks[0], ticks[1], make_RGBcolor(0.25, 0.25, 0.25), COORDINATES_WINDOW_NORMALIZED);
911 ticks[0] = make_vec3(x, center.y + 0.25f * size.y, center.z - 0.001f);
912 ticks[1] = make_vec3(x, center.y + 0.25f * size.y - 0.05f * size.y, center.z - 0.001f);
913 UUIDs.push_back(addLine(ticks[0], ticks[1], make_RGBcolor(0.25, 0.25, 0.25), COORDINATES_WINDOW_NORMALIZED));
914 }
915 }
916
917 // title
918 std::vector<size_t> UUIDs_text = addTextboxByCenter(title, make_vec3(center.x, center.y + 0.4f * size.y, center.z), make_SphericalCoord(0, 0), font_color, colorbar_fontsize, "CantoraOne-Regular", COORDINATES_WINDOW_NORMALIZED);
919 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
920
921 return UUIDs;
922}
923
927
928void Visualizer::addCoordinateAxes(const helios::vec3 &origin, const helios::vec3 &length, const std::string &sign) {
929 float mult;
930 if (sign == "both") {
931 mult = 1.0;
932 } else {
933 mult = 0.0;
934 }
935
936 float Lmag = length.magnitude();
937
938 std::vector<size_t> UUIDs, UUIDs_text;
939 UUIDs.reserve(12);
940
941 // x axis
942 UUIDs.push_back(addLine(make_vec3(mult * -1.0f * length.x + origin.x, origin.y, origin.z), make_vec3(length.x + origin.x, origin.y, origin.z), RGB::black, Visualizer::COORDINATES_CARTESIAN));
943
944 if (length.x > 0) {
945 UUIDs_text = addTextboxByCenter("+ X", helios::make_vec3(1.2f * length.x + origin.x, origin.y, origin.z), nullrotation, helios::RGB::black, uint(200 * Lmag), "OpenSans-Regular", Visualizer::COORDINATES_CARTESIAN);
946 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
947 }
948
949 // y axis
950 UUIDs.push_back(addLine(make_vec3(origin.x, mult * -1.0f * length.y + origin.y, origin.z), make_vec3(origin.x, length.y + origin.y, origin.z), RGB::black, Visualizer::COORDINATES_CARTESIAN));
951
952 if (length.y > 0) {
953 UUIDs_text = addTextboxByCenter("+ Y", helios::make_vec3(origin.x, 1.1f * length.y + origin.y, origin.z), nullrotation, RGB::black, uint(200 * Lmag), "OpenSans-Regular", Visualizer::COORDINATES_CARTESIAN);
954 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
955 }
956
957 // z axis
958 UUIDs.push_back(addLine(make_vec3(origin.x, origin.y, mult * -1.f * length.z + origin.z), make_vec3(origin.x, origin.y, length.z + origin.z), RGB::black, Visualizer::COORDINATES_CARTESIAN));
959
960 if (length.z > 0) {
961 UUIDs_text = addTextboxByCenter("+ Z", helios::make_vec3(origin.x, origin.y, length.z + origin.z), nullrotation, RGB::black, uint(200 * Lmag), "OpenSans-Regular", Visualizer::COORDINATES_CARTESIAN);
962 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
963 }
964
965 this->coordinate_axes_IDs = UUIDs;
966}
967
969 if (!coordinate_axes_IDs.empty()) {
970 geometry_handler.deleteGeometry(coordinate_axes_IDs);
971 }
972}
973
974void Visualizer::addGridWireFrame(const helios::vec3 &center, const helios::vec3 &size, const helios::int3 &subdiv) {
975 const helios::vec3 boxmin = make_vec3(center.x - 0.5f * size.x, center.y - 0.5f * size.y, center.z - 0.5f * size.z);
976 const helios::vec3 boxmax = make_vec3(center.x + 0.5f * size.x, center.y + 0.5f * size.y, center.z + 0.5f * size.z);
977
978 float spacing_x = size.x / scast<float>(subdiv.x);
979 float spacing_y = size.y / scast<float>(subdiv.y);
980 float spacing_z = size.z / scast<float>(subdiv.z);
981
982 std::vector<size_t> UUIDs;
983 UUIDs.reserve(subdiv.x * subdiv.y + subdiv.y * subdiv.z + subdiv.x * subdiv.z);
984
985 for (int i = 0; i <= subdiv.x; i++) {
986 for (int j = 0; j <= subdiv.y; j++) {
987 UUIDs.push_back(addLine(make_vec3(boxmin.x + i * spacing_x, boxmin.y + j * spacing_y, boxmin.z), make_vec3(boxmin.x + i * spacing_x, boxmin.y + j * spacing_y, boxmax.z), RGB::black, Visualizer::COORDINATES_CARTESIAN));
988 }
989 }
990
991 for (int i = 0; i <= subdiv.z; i++) {
992 for (int j = 0; j <= subdiv.y; j++) {
993 UUIDs.push_back(addLine(make_vec3(boxmin.x, boxmin.y + j * spacing_y, boxmin.z + i * spacing_z), make_vec3(boxmax.x, boxmin.y + j * spacing_y, boxmin.z + i * spacing_z), RGB::black, Visualizer::COORDINATES_CARTESIAN));
994 }
995 }
996
997 for (int i = 0; i <= subdiv.x; i++) {
998 for (int j = 0; j <= subdiv.z; j++) {
999 UUIDs.push_back(addLine(make_vec3(boxmin.x + i * spacing_x, boxmin.y, boxmin.z + j * spacing_z), make_vec3(boxmin.x + i * spacing_x, boxmax.y, boxmin.z + j * spacing_z), RGB::black, Visualizer::COORDINATES_CARTESIAN));
1000 }
1001 }
1002
1003 if (primitiveColorsNeedUpdate) {
1005 }
1006}