1 #include "MarkerGraph.h" 2 #include "DGM/IGraphPairwise.h" 3 #include "ColorSpaces.h" 8 #include "GLFW/glfw3.h" 10 #include "glm/gtc/matrix_transform.hpp" 12 #include "CameraControl.h" 22 void drawLine(Mat &img, Point pt1, Point pt2, Scalar color1, Scalar color2,
int thikness = 1,
int lineType = LINE_8,
int shift = 0)
24 const int nSegments = 8;
26 Point2f Pt1 =
static_cast<Point2f
>(pt1);
27 Point2f inc =
static_cast<Point2f
>(pt2 - pt1) / nSegments;
28 for (
int i = 0; i < nSegments; i++) {
29 Point2f Pt2 = Pt1 + inc;
30 double a =
static_cast<double>(i) / nSegments;
31 Scalar color = (1 - a) * color1 + a * color2;
32 line(img, Pt1, Pt2, color, thikness, lineType, shift);
38 void drawTriangle(Mat &img, Point pt1, Point pt2, Point pt3, Scalar color,
int lineType = LINE_8,
int shift = 0)
40 Point triangle[1][3] = {{ pt1, pt2, pt3 }};
41 const Point * pts[1] = { triangle[0] };
43 fillPoly(img, pts, &npts, 1, color, lineType, shift);
47 void drawArrow(Mat &img, Point pt1, Point pt2, Scalar color,
int lineType = LINE_8,
int shift = 0,
double tipLength = 15)
49 Point2f dir =
static_cast<Point2f
>(pt1 - pt2);
50 float len = sqrtf(dir.dot(dir));
51 dir *= tipLength / len;
53 float alpha = 15 *
static_cast<float>(Pi) / 180;
54 float cs = cosf(alpha);
55 float sn = sinf(alpha);
57 Point2f left( dir.dot(Point2f(cs, -sn)) + 0.5f, dir.dot(Point2f( sn, cs)) + 0.5f);
58 Point2f right(dir.dot(Point2f(cs, sn)) + 0.5f, dir.dot(Point2f(-sn, cs)) + 0.5f);
60 drawTriangle(img, pt2, pt2 + static_cast<Point>(left), pt2 + static_cast<Point>(right), color, lineType, shift);
69 void drawArrowedLine(Mat &img, Point pt1, Point pt2, Scalar color1, Scalar color2,
int thikness = 1,
int lineType = LINE_8,
int shift = 0,
double tipLength = 15)
71 drawLine(img, pt1, pt2, color1, color2, thikness, lineType, shift);
72 drawArrow(img, pt1, pt2, color2, lineType, shift, tipLength);
76 Mat
drawGraph(
int size,
IGraphPairwise &graph, std::function<Point2f(
size_t)> posFunc, std::function<cv::Scalar(
size_t)> colorFunc,
const vec_scalar_t &groupsColor)
79 Scalar color1, color2;
83 Mat res(size, size, CV_8UC3);
84 Mat alpha(size, size, CV_8UC3);
88 for (
size_t n = 0; n < nNodes; n++) {
93 pt1.x = 0.5f * (1 + pt1.x) * size;
94 pt1.y = 0.5f * (1 + pt1.y) * size;
96 color1 = colorFunc ? colorFunc(n) :
colorspaces::hsv2rgb(DGM_HSV(360.0 * n / nNodes, 255.0, 192.0));
98 for (
size_t c : childs) {
99 if (graph.
isEdgeArc(n, c) && n < c)
continue;
102 pt2.x = 0.5f * (1 + pt2.x) * size;
103 pt2.y = 0.5f * (1 + pt2.y) * size;
104 color2 = colorFunc ? colorFunc(c) :
colorspaces::hsv2rgb(DGM_HSV(360.0 * c / nNodes, 255.0, 192.0));
107 if (groupsColor.size() > 0)
108 color1 = color2 = groupsColor[graph.
getEdgeGroup(n, c) % groupsColor.size()];
111 if (graph.
isEdgeArc(n, c)) drawLine(alpha, pt1, pt2, color1, color2, 1, cv::LineTypes::LINE_AA);
112 else drawArrowedLine(alpha, pt1, pt2, color1, color2, 1, cv::LineTypes::LINE_AA);
113 add(res, alpha, res);
118 for (
size_t n = 0; n < nNodes; n++) {
119 color1 = colorFunc ? colorFunc(n) :
colorspaces::hsv2rgb(DGM_HSV(360.0 * n / nNodes, 255.0, 255.0));
121 pt1.x = 0.5f * (1 + pt1.x) * size;
122 pt1.y = 0.5f * (1 + pt1.y) * size;
123 circle(res, pt1, 3, color1, -1, cv::LineTypes::LINE_AA);
134 void LoadShaders(GLuint &NodeProgramID, GLuint &EdgeProgramID)
137 GLint Result = GL_FALSE;
138 int InfoLogLength = 0;
141 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
143 const std::string sourceCode =
144 #include "VertexShader.glsl" 146 #ifdef DEBUG_PRINT_INFO 147 printf(
"Compiling vertex shader... ");
149 char const * VertexSourcePointer = sourceCode.c_str();
150 glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
151 glCompileShader(VertexShaderID);
153 #ifdef DEBUG_MODE // Check Vertex Shader 154 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
155 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
156 if (InfoLogLength > 1) {
157 std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
158 glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
159 printf(
"\n%s\n", &VertexShaderErrorMessage[0]);
162 #ifdef DEBUG_PRINT_INFO 168 GLuint NodeFragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
170 const std::string sourceCode =
171 #include "NodeFragmentShader.glsl" 173 #ifdef DEBUG_PRINT_INFO 174 printf(
"Compiling node fragment Shader... ");
176 char const * FragmentSourcePointer = sourceCode.c_str();
177 glShaderSource(NodeFragmentShaderID, 1, &FragmentSourcePointer, NULL);
178 glCompileShader(NodeFragmentShaderID);
180 #ifdef DEBUG_MODE // Check Fragment Shader 181 glGetShaderiv(NodeFragmentShaderID, GL_COMPILE_STATUS, &Result);
182 glGetShaderiv(NodeFragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
183 if (InfoLogLength > 1) {
184 std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
185 glGetShaderInfoLog(NodeFragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
186 printf(
"\n%s\n", &FragmentShaderErrorMessage[0]);
189 #ifdef DEBUG_PRINT_INFO 195 GLuint EdgeFragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
197 const std::string sourceCode =
198 #include "EdgeFragmentShader.glsl" 200 #ifdef DEBUG_PRINT_INFO 201 printf(
"Compiling edge fragment shader... ");
203 char const * FragmentSourcePointer = sourceCode.c_str();
204 glShaderSource(EdgeFragmentShaderID, 1, &FragmentSourcePointer, NULL);
205 glCompileShader(EdgeFragmentShaderID);
207 #ifdef DEBUG_MODE // Check Fragment Shader 208 glGetShaderiv(EdgeFragmentShaderID, GL_COMPILE_STATUS, &Result);
209 glGetShaderiv(EdgeFragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
210 if (InfoLogLength > 1) {
211 std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
212 glGetShaderInfoLog(EdgeFragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
213 printf(
"\n%s\n", &FragmentShaderErrorMessage[0]);
216 #ifdef DEBUG_PRINT_INFO 224 #ifdef DEBUG_PRINT_INFO 225 printf(
"Linking node program... ");
227 NodeProgramID = glCreateProgram();
228 glAttachShader(NodeProgramID, VertexShaderID);
229 glAttachShader(NodeProgramID, NodeFragmentShaderID);
230 glLinkProgram(NodeProgramID);
232 #ifdef DEBUG_MODE // Check the program 233 glGetProgramiv(NodeProgramID, GL_LINK_STATUS, &Result);
234 glGetProgramiv(NodeProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
235 if (InfoLogLength > 1) {
236 std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
237 glGetProgramInfoLog(NodeProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
238 printf(
"%s\n", &ProgramErrorMessage[0]);
241 #ifdef DEBUG_PRINT_INFO 244 glDetachShader(NodeProgramID, VertexShaderID);
245 glDetachShader(NodeProgramID, NodeFragmentShaderID);
250 #ifdef DEBUG_PRINT_INFO 251 printf(
"Linking edge program... ");
253 EdgeProgramID = glCreateProgram();
254 glAttachShader(EdgeProgramID, VertexShaderID);
255 glAttachShader(EdgeProgramID, EdgeFragmentShaderID);
256 glLinkProgram(EdgeProgramID);
258 #ifdef DEBUG_MODE // Check the program 259 glGetProgramiv(EdgeProgramID, GL_LINK_STATUS, &Result);
260 glGetProgramiv(EdgeProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
261 if (InfoLogLength > 1) {
262 std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
263 glGetProgramInfoLog(EdgeProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
264 printf(
"%s\n", &ProgramErrorMessage[0]);
267 #ifdef DEBUG_PRINT_INFO 270 glDetachShader(NodeProgramID, VertexShaderID);
271 glDetachShader(NodeProgramID, NodeFragmentShaderID);
274 glDeleteShader(VertexShaderID);
275 glDeleteShader(NodeFragmentShaderID);
276 glDeleteShader(EdgeFragmentShaderID);
279 void addCone(
vec_vec3_t &vVertices,
vec_vec3_t &vColors, vec_word_t &vIndices, glm::vec3 pt1, glm::vec3 pt2, glm::vec3 color,
float length)
281 const int nSectors = 32;
283 word v0 =
static_cast<word
>(vVertices.size());
285 glm::vec3 dir = glm::normalize(pt1 - pt2);
286 glm::vec3 normal = glm::cross(dir, glm::vec3(0, 0, 1));
287 if (glm::length(normal) < FLT_EPSILON) normal = glm::cross(dir, glm::vec3(0, 1, 0));
288 normal = glm::normalize(normal);
290 glm::vec3 mid = pt2 + dir * length;
292 glm::mat4 rmat = glm::rotate(glm::mat4(1), glm::radians(360.0f / nSectors), dir);
294 glm::vec3 point1 = normal * length * glm::tan(glm::radians(15.0f));
295 for (
unsigned short i = 0; i < nSectors; i++) {
296 glm::vec3 point2 = rmat * glm::vec4(point1, 1.0f);
297 vVertices.push_back(mid + point1);
298 vColors.push_back(color);
302 vVertices.push_back(top);
303 vColors.push_back(color);
305 vVertices.push_back(mid);
306 vColors.push_back(color);
308 for (word i = 1; i <= nSectors; i++) {
310 vIndices.push_back(v0 + i - 1);
311 vIndices.push_back(v0 + i % nSectors);
312 vIndices.push_back(v0 + nSectors);
315 vIndices.push_back(v0 + i % nSectors);
316 vIndices.push_back(v0 + i - 1);
317 vIndices.push_back(v0 + nSectors + 1);
322 void showGraph3D(
int size,
IGraphPairwise &graph, std::function<Point3f(
size_t)> posFunc, std::function<cv::Scalar(
size_t)> colorFunc,
const vec_scalar_t &groupsColor)
326 const bool isGroupsColor = groupsColor.size() > 0;
329 DGM_ASSERT_MSG(glfwInit(),
"Failed to initialize GLFW");
332 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
333 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
334 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
335 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
336 glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
337 glfwWindowHint(GLFW_SAMPLES, 16);
340 GLFWwindow *window = glfwCreateWindow(size, size,
"3D Graph Viewer", NULL, NULL);
342 DGM_WARNING(
"Unable to create GLFW window");
347 glfwMakeContextCurrent(window);
348 glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
351 DGM_ASSERT_MSG(glewInit() == GLEW_OK,
"Failed to initialize GLEW");
353 #ifdef DEBUG_PRINT_INFO 354 printf(
"OpenGL Ver: %s\n", glGetString(GL_VERSION));
358 glShadeModel(GL_SMOOTH);
361 glEnable(GL_PROGRAM_POINT_SIZE);
365 glEnable(GL_CULL_FACE);
368 GLuint vertex_array_id;
369 glGenVertexArrays(1, &vertex_array_id);
370 glBindVertexArray(vertex_array_id);
373 GLuint NodeProgramID, EdgeProgramID;
374 LoadShaders(NodeProgramID, EdgeProgramID);
377 GLuint NodeMatrixID = glGetUniformLocation(NodeProgramID,
"MVP");
378 GLuint EdgeMatrixID = glGetUniformLocation(EdgeProgramID,
"MVP");
384 vec_word_t vIndices, vConeIndices;
388 for (
size_t n = 0; n < nNodes; n++) {
389 Point3f pt = posFunc(n);
390 vVertices.push_back(glm::vec3(pt.x, pt.y, pt.z));
392 color =
static_cast<Scalar
>(color) / 255;
393 vColors.push_back(glm::vec3(color.val[0], color.val[1], color.val[2]));
397 for (
size_t n = 0; n < nNodes; n++) {
401 for (
size_t c : childs) {
402 if (graph.
isEdgeArc(n, c) && n < c)
continue;
403 vIndices.push_back(static_cast<word>(n));
404 vIndices.push_back(static_cast<word>(c));
408 cv::Scalar color = groupsColor[group % groupsColor.size()];
409 color =
static_cast<Scalar
>(color) / 255;
410 vGroupColors.push_back(glm::vec3(color.val[0], color.val[1], color.val[2]));
414 addCone(vVertices, vColors, vConeIndices, vVertices[n], vVertices[c], vColors[c], 30.0f / size);
417 const size_t nEdgesIdx = vIndices.size();
418 vIndices.insert(vIndices.end(), vConeIndices.begin(), vConeIndices.end());
419 vConeIndices.clear();
423 glGenBuffers(1, &vertexBuffer);
424 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
425 glBufferData(GL_ARRAY_BUFFER, vVertices.size() *
sizeof(glm::vec3), &vVertices[0], GL_STATIC_DRAW);
428 glGenBuffers(1, &colorBuffer);
429 glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
430 glBufferData(GL_ARRAY_BUFFER, vColors.size() *
sizeof(glm::vec3), &vColors[0], GL_STATIC_DRAW);
432 GLuint groupColorBuffer;
434 glGenBuffers(1, &groupColorBuffer);
435 glBindBuffer(GL_ARRAY_BUFFER, groupColorBuffer);
436 glBufferData(GL_ARRAY_BUFFER, vGroupColors.size() *
sizeof(glm::vec3), &vGroupColors[0], GL_STATIC_DRAW);
440 glGenBuffers(1, &indexBuffer);
441 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
442 glBufferData(GL_ELEMENT_ARRAY_BUFFER, vIndices.size() *
sizeof(word), &vIndices[0], GL_STATIC_DRAW);
446 const float _bkgIntencity =
static_cast<float>(
bkgIntencity) / 255;
447 glClearColor(_bkgIntencity, _bkgIntencity, _bkgIntencity, 0.0f);
449 glm::mat4 ModelMatrix = glm::mat4(1.0f);
451 glm::mat4 ProjectionMatrix = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f);
454 while (!glfwWindowShouldClose(window) && glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS ) {
455 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
458 if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) camera.
reset();
459 glm::mat4 MVP = ProjectionMatrix * camera.
getViewMatrix() * ModelMatrix;
462 glEnableVertexAttribArray(0);
463 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
464 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (
void *)0);
467 glEnableVertexAttribArray(1);
468 glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
469 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (
void *)0);
473 glEnableVertexAttribArray(1);
474 glBindBuffer(GL_ARRAY_BUFFER, groupColorBuffer);
475 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (
void *)0);
479 glUseProgram(NodeProgramID);
482 glUniformMatrix4fv(NodeMatrixID, 1, GL_FALSE, &MVP[0][0]);
484 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(nNodes));
488 glUseProgram(EdgeProgramID);
490 glUniformMatrix4fv(EdgeMatrixID, 1, GL_FALSE, &MVP[0][0]);
492 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
494 glDrawElements(GL_LINES, static_cast<GLsizei>(nEdgesIdx), GL_UNSIGNED_SHORT, (
void *) 0);
495 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(vIndices.size() - nEdgesIdx), GL_UNSIGNED_SHORT, (
void *) (nEdgesIdx *
sizeof(word)));
498 glDisableVertexAttribArray(0);
499 glDisableVertexAttribArray(1);
501 glfwSwapBuffers(window);
506 glDeleteBuffers(1, &vertexBuffer);
507 glDeleteBuffers(1, &colorBuffer);
508 if (isGroupsColor) glDeleteBuffers(1, &groupColorBuffer);
509 glDeleteBuffers(1, &indexBuffer);
511 glDeleteProgram(NodeProgramID);
512 glDeleteProgram(EdgeProgramID);
513 glDeleteVertexArrays(1, &vertex_array_id);
std::vector< glm::vec3 > vec_vec3_t
virtual void getChildNodes(size_t node, vec_size_t &vNodes) const =0
Returns the set of IDs of the child nodes of the argument node.
Trackball camera control class.
virtual size_t getNumNodes(void) const =0
Returns the number of nodes in the graph.
cv::Scalar bgr2rgb(cv::Scalar bgr)
Transforms color from RGB to BGR.
Mat drawGraph(int size, IGraphPairwise &graph, std::function< Point2f(size_t)> posFunc, std::function< cv::Scalar(size_t)> colorFunc, const vec_scalar_t &groupsColor)
Visualizes the graph structure.
glm::mat4 getViewMatrix(void)
Returns the view matrix within the camera coordinate.
virtual byte getEdgeGroup(size_t srcNode, size_t dstNode) const =0
Returns the group of the edge.
cv::Scalar hsv2rgb(cv::Scalar hsv)
Transforms color from HSV to RGB space.
void reset(void)
Resets the camera position.
Interface class for graphical models.
void showGraph3D(int size, IGraphPairwise &graph, std::function< Point3f(size_t)> posFunc, std::function< cv::Scalar(size_t)> colorFunc, const vec_scalar_t &groupsColor)
Visualizes the graph structure in 3D.
cv::Scalar hsv2bgr(cv::Scalar hsv)
Transforms color from HSV to BGR space.
virtual bool isEdgeArc(size_t srcNode, size_t dstNode) const
Checks whether the edge is a part of an arc.