1 // sous mac
2 // g++ -I/usr/local/include/ -lglfw -lGLEW -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs main53.cpp -framework OpenGL -omain53
3 // ./main53
4
5 // sous linux
6 // g++ -I/usr/local/include/ -I/public/ig/glm/ -c main53.cpp -omain53.o
7 // g++ -I/usr/local main53.o -lglfw -lGLEW -lGL -omain53
8 // ./main53
9
10 // Inclut les en-têtes standards
11 #include <stdio.h>
12 #include <string>
13 #include <vector>
14 #include <iostream>
15 #include <fstream>
16 #include <algorithm>
17 #include <map>
18 using namespace std;
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <GL/glew.h>
24 #include <GLFW/glfw3.h>
25
26 // following the tutorial found here:
27 // https://www.learnopencv.com/delaunay-triangulation-and-voronoi-diagram-using-opencv-c-python/
28 // http://www.faadoosupport.com/learning-opencv-3-delaunay-triangulation-and-voronoi-diagram-explanation/
29 #include <opencv2/imgproc/imgproc.hpp>
30 #include <opencv2/highgui/highgui.hpp>
31
32 #ifdef __APPLE__
33 #include <OpenGL/gl.h>
34 #else
35 #include <GL/gl.h>
36 #endif
37
38 #define GLM_FORCE_RADIANS
39 #include <glm/glm.hpp>
40 #include <glm/gtc/matrix_transform.hpp>
41 #include <glm/gtc/type_ptr.hpp>
42
43
44 using namespace glm;
45 using namespace cv;
46
47 double dangle = M_PI/1024;
48
49 const int N = 17241;//17242;
50
51 vector<vector<Point2f> > facets;
52 vector<Point2f> centers;
53 Subdiv2D *subdiv;
54 Rect *rect;
55
56 std::map<Point2f,float> altitudes;
57
58 // stocke les variables uniformes qui seront communes a tous les vertex dessines dans une variable globale
59 GLint uniform_proj, uniform_view, uniform_model;
60 float w =800.0;
61
62
63 bool sitesOrdered(const Point2f& s1, const Point2f& s2) {
64 if (s1.y < s2.y)
65 return true;
66 if (s1.y == s2.y && s1.x < s2.x)
67 return true;
68
69 return false;
70 }
71
72
73
74 namespace cv {
75 bool operator<(Point2f const& lhs, Point2f const& rhs) {
76 return lhs.x == rhs.x ? lhs.y < rhs.y : lhs.x < rhs.x;
77 }
78 }
79
80
81
82 void readData(){
83 std::cout << "readData " <<endl;
84 unsigned int nPoints;
85 float dimension = 1.0;
86 rect = new Rect(0, 0, w, w);
87
88 // Create an instance of Subdiv2D
89 subdiv = new Subdiv2D(*rect);
90
91 ifstream file ( "villes.csv" ); // declare file stream: http://www.cplusplus.com/reference/iostream/ifstream/
92 string value;
93 getline ( file, value, '\n' );
94
95
96 float minlon = 10;
97 float maxlon = 0;
98 float minlat = 10;
99 float maxlat = 0;
100 int count = 0;
101
102 vector<Point2f> tmpSites;
103 vector<Point2f> sites;
104 Point2f s;
105
106
107 while ( file.good() ) {
108 getline ( file, value, ';' ); // read a string until next comma: http://www.cplusplus.com/reference/string/getline/
109 string sinsee = string( value, 0, value.length() );
110 getline ( file, value, ';' );
111 string sname = string( value, 0, value.length() );
112 getline ( file, value, ';' );
113 string saltitude = string( value, 0, value.length() );
114 float alt = stof(saltitude, NULL);
115 getline ( file, value, ';' );
116 string scp = string( value, 0, value.length() );
117 getline ( file, value, ';' );
118 string slon = string( value, 0, value.length() );
119 float lon = stof(slon, NULL);
120 getline ( file, value, ';' );
121 string slat = string( value, 0, value.length() );
122 float lat = stof(slat, NULL);
123 getline ( file, value, ';' );
124 string spop = string( value, 0, value.length() );
125 getline ( file, value, '\n' );
126 string ssur = string( value, 0, value.length() );
127
128 count++;
129 if (count<N && count !=17240){
130 minlon=glm::min(lon, minlon);
131 maxlon=glm::max(lon, maxlon);
132 minlat=glm::min(lat, minlat);
133 maxlat=glm::max(lat, maxlat);
134 s.x=lon;
135 s.y=lat;
136 altitudes[s] = alt/5000.0;
137
138 tmpSites.push_back(s);
139 } else if (count ==17240) {
140 cout <<"SKIP "<<count<<":"<<s.x<<","<<s.y<<endl;
141 }
142
143 }
144 cout << "City File read !" <<endl;
145 cout <<" lon:"<<minlon<<"..."<<maxlon<<" among "<<tmpSites.size()<<" / "<<N<<endl;
146
147 //remove any duplicates that may exist
148 Point2f s2;
149 std::sort(tmpSites.begin(), tmpSites.end(), sitesOrdered);
150 s2.x = (0.1+(tmpSites[0].x-minlon)/(maxlon-minlon))*0.8*w;
151 s2.y = (0.1+(tmpSites[0].y-minlat)/(maxlat-minlat))*0.8*w;
152
153 sites.push_back(s2);
154 for (vector<Point2f>::iterator it = tmpSites.begin(); it != tmpSites.end(); it++) {
155 Point2f& s =*it;
156 s2.x = (0.1+(s.x-minlon)/(maxlon-minlon)*0.8)*w;
157 s2.y = (0.1+(s.y-minlat)/(maxlat-minlat)*0.8)*w;
158
159 if (s != sites.back()) {
160 sites.push_back(s2);
161 altitudes[s2] = altitudes[s];
162 //cout <<"INSERT "<<s2<<"=>"<<altitudes[s]<<endl;
163 } else{
164 cout <<"WARNING: "<<s2.x<<","<<s2.y<<" is identical to "<<sites.back().x<<","<<sites.back().y<<endl;
165 }
166
167 }
168 cout << " point normalization and duplicate removal done. " <<endl;
169
170 for( vector<Point2f>::iterator it = sites.begin(); it != sites.end(); it++){
171 subdiv->insert(*it);
172 }
173 }
174
175
176
177 GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
178
179 // Create the shaders
180 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
181 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
182
183 // Read the Vertex Shader code from the file
184 std::string VertexShaderCode;
185 std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
186 if (VertexShaderStream.is_open()){
187 std::string Line = "";
188 while(getline(VertexShaderStream, Line))
189 VertexShaderCode += "\n" + Line;
190 VertexShaderStream.close();
191 } else {
192 printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
193 getchar();
194 return 0;
195 }
196
197 // Read the Fragment Shader code from the file
198 std::string FragmentShaderCode;
199 std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
200 if(FragmentShaderStream.is_open()){
201 std::string Line = "";
202 while(getline(FragmentShaderStream, Line))
203 FragmentShaderCode += "\n" + Line;
204 FragmentShaderStream.close();
205 }
206
207 GLint Result = GL_FALSE;
208 int InfoLogLength;
209
210
211 // Compile Vertex Shader
212 printf("Compiling shader : %s\n", vertex_file_path);
213 char const * VertexSourcePointer = VertexShaderCode.c_str();
214 glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
215 glCompileShader(VertexShaderID);
216
217 // Check Vertex Shader
218 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
219 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
220 if ( InfoLogLength > 0 ){
221 std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
222 glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
223 printf("%s\n", &VertexShaderErrorMessage[0]);
224 }
225
226
227 // Compile Fragment Shader
228 printf("Compiling shader : %s\n", fragment_file_path);
229 char const * FragmentSourcePointer = FragmentShaderCode.c_str();
230 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
231 glCompileShader(FragmentShaderID);
232
233 // Check Fragment Shader
234 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
235 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
236 if ( InfoLogLength > 0 ){
237 std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
238 glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
239 printf("%s\n", &FragmentShaderErrorMessage[0]);
240 }
241
242 // Link the program
243 printf("Linking program\n");
244 GLuint ProgramID = glCreateProgram();
245 glAttachShader(ProgramID, VertexShaderID);
246 glAttachShader(ProgramID, FragmentShaderID);
247 glLinkProgram(ProgramID);
248
249 // Check the program
250 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
251 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
252 if ( InfoLogLength > 0 ){
253 std::vector<char> ProgramErrorMessage(InfoLogLength+1);
254 glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
255 printf("%s\n", &ProgramErrorMessage[0]);
256 }
257
258 glDetachShader(ProgramID, VertexShaderID);
259 glDetachShader(ProgramID, FragmentShaderID);
260
261 glDeleteShader(VertexShaderID);
262 glDeleteShader(FragmentShaderID);
263
264 return ProgramID;
265 }
266
267
268 int main(){
269 // Initialise GLFW
270 if( !glfwInit() ) {
271 fprintf( stderr, "Failed to initialize GLFW\n" );
272 return -1;
273 }
274
275
276
277 readData();
278
279 vector<vector<Point2f> > facets;
280 vector<Point2f> centers;
281 vector<Vec6f> tl;
282 subdiv->getTriangleList(tl);
283 subdiv->getVoronoiFacetList(vector<int>(), facets, centers);
284 long sss=0;
285
286 cout << " facets¢ers list: " << facets.size() << " % " << centers.size()<<endl;
287
288 // a first pass on all voronoi edges to count them and for every point, add the
289 // altitude of the neighbor vononoi center (should happens 3 times per point then)
290 for( size_t i = 0; i < facets.size(); i++ ){
291 //cout <<" vor center "<<centers[i]<<" @ "<<altitudes[centers[i]]<<endl;
292 //ifacet.resize(facets[i].size());
293 for( size_t j = 0; j < facets[i].size(); j++ ){
294 //ifacet[j] = facets[i][j];
295 altitudes[facets[i][j]] = altitudes[facets[i][j]] + altitudes[centers[i]];
296 sss++;
297 }
298 }
299
300 // ii is now the number of needed triangles but we'll use it to allocate memory
301 sss = sss*sizeof(GLfloat)*9;
302
303 cout << "allocate arrays => "<<sss<<endl;
304
305 GLfloat *g_vertex_buffer_data = (GLfloat *)malloc(sss);
306 GLfloat *g_vertex_color_data = (GLfloat *)malloc(sss);
307 //GLfloat g_vertex_buffer_data[sss];
308 //GLfloat g_vertex_color_data[sss];
309
310 long ii=0;
311 for( size_t i = 0; i < facets.size(); i++ ){
312 Point2f p0 = centers[i];
313 srand(i);
314 float r = (rand()%256)/256.0;
315 float g = (rand()%256)/256.0;
316 float b = (rand()%256)/256.0;
317 for( size_t j = 0; j < facets[i].size(); j++ ){
318 //ifacet[j] = facets[i][j];
319 Point2f p1 = facets[i][j];
320 Point2f p2 = facets[i][(j+facets[i].size()-1)%facets[i].size()];
321
322 g_vertex_buffer_data[ 0+ii*9] = p0.x/w;
323 g_vertex_buffer_data[ 1+ii*9] = p0.y/w;
324 g_vertex_buffer_data[ 2+ii*9] = altitudes[p0];
325
326 g_vertex_buffer_data[ 3+ii*9] = p1.x/w;
327 g_vertex_buffer_data[ 4+ii*9] = p1.y/w;
328 g_vertex_buffer_data[ 5+ii*9] = altitudes[p1]/3.0;
329
330 g_vertex_buffer_data[ 6+ii*9] = p2.x/w;
331 g_vertex_buffer_data[ 7+ii*9] = p2.y/w;
332 g_vertex_buffer_data[ 8+ii*9] = altitudes[p2]/3.0;
333
334 g_vertex_color_data[ 0+ii*9] = altitudes[p0]*5;
335 g_vertex_color_data[ 1+ii*9] = altitudes[p0]*5;
336 g_vertex_color_data[ 2+ii*9] = altitudes[p0]*5;
337
338 g_vertex_color_data[ 3+ii*9] = 0.5+r/2.0;
339 g_vertex_color_data[ 4+ii*9] = 0.5+g/2.0;
340 g_vertex_color_data[ 5+ii*9] = 0.5+b/2.0;
341
342 g_vertex_color_data[ 6+ii*9] = 0.5+r/2.0;
343 g_vertex_color_data[ 7+ii*9] = 0.5+g/2.0;
344 g_vertex_color_data[ 8+ii*9] = 0.5+b/2.0;
345
346 //cout <<" vor border "<<centers[i]<<" @ "<<altitudes[p1]<<endl;
347 ii++;
348 }
349 }
350
351 /*int i=0;
352 for (Vec6f& t : tl){
353 //cout << t[0] << " " << t[1] << " "<< t[2] << " " << t[3] << " "<< t[4] << " " << t[5] << endl;
354 if ( rect->contains(Point(cvRound(t[0]), cvRound(t[1]))) &&
355 rect->contains(Point(cvRound(t[2]), cvRound(t[3]))) &&
356 rect->contains(Point(cvRound(t[4]), cvRound(t[5])))){
357 g_vertex_buffer_data[ 0+i*9] = t[0]/w;
358 g_vertex_buffer_data[ 1+i*9] = t[1]/w;
359 g_vertex_buffer_data[ 2+i*9] = 0;
360
361 g_vertex_buffer_data[ 3+i*9] = t[2]/w;
362 g_vertex_buffer_data[ 4+i*9] = t[3]/w;
363 g_vertex_buffer_data[ 5+i*9] = 0;
364
365 g_vertex_buffer_data[ 6+i*9] = t[4]/w;
366 g_vertex_buffer_data[ 7+i*9] = t[5]/w;
367 g_vertex_buffer_data[ 8+i*9] = 0;
368
369 srand(t[0]+t[1]);
370 float r = (rand()%256)/256.0;
371 float g = (rand()%256)/256.0;
372 float b = (rand()%256)/256.0;
373
374 g_vertex_color_data[ 0+i*9] = 0.5+r/2.0;
375 g_vertex_color_data[ 1+i*9] = 0.5+g/2.0;
376 g_vertex_color_data[ 2+i*9] = 0.5+b/2.0;
377
378 srand(t[2]+t[3]);
379 r = (rand()%256)/256.0;r=0.0;
380 g = (rand()%256)/256.0;g=0.0;
381 b = (rand()%256)/256.0;b=0.0;
382 g_vertex_color_data[ 3+i*9] = 0.5+r/2.0;
383 g_vertex_color_data[ 4+i*9] = 0.5+g/2.0;
384 g_vertex_color_data[ 5+i*9] = 0.5+b/2.0;
385
386
387 srand(t[4]+t[5]);
388 r = (rand()%256)/256.0;r=0.0;
389 g = (rand()%256)/256.0;g=0.0;
390 b = (rand()%256)/256.0;b=0.0;
391 g_vertex_color_data[ 6+i*9] = 0.5+r/2.0;
392 g_vertex_color_data[ 7+i*9] = 0.5+g/2.0;
393 g_vertex_color_data[ 8+i*9] = 0.5+b/2.0;
394 } else {
395 g_vertex_buffer_data[ 0+i*9] = 0.0f;
396 g_vertex_buffer_data[ 1+i*9] = 0.0f;
397 g_vertex_buffer_data[ 2+i*9] = 0.0f;
398
399 g_vertex_buffer_data[ 3+i*9] = 0.0f;
400 g_vertex_buffer_data[ 4+i*9] = 0.0f;
401 g_vertex_buffer_data[ 5+i*9] = 0.0f;
402
403 g_vertex_buffer_data[ 6+i*9] = 0.0f;
404 g_vertex_buffer_data[ 7+i*9] = 0.0f;
405 g_vertex_buffer_data[ 8+i*9] = 0.0f;
406
407 }
408 i++;
409 }*/
410
411 // cout << "array is full "<< (i*9*sizeof(GLfloat))<<endl;
412
413
414
415 glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
416 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // On veut OpenGL 3.3
417 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
418 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Pour rendre MacOS heureux ; ne devrait pas être nécessaire
419 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // On ne veut pas l'ancien OpenGL
420 glfwWindowHint(GLFW_DEPTH_BITS, 24);
421
422 // Ouvre une fenêtre et crée son contexte OpenGl
423 GLFWwindow* window; // (Dans le code source qui accompagne, cette variable est globale)
424 window = glfwCreateWindow( 1900, 1100, "Main 53", NULL, NULL);
425 if( window == NULL ){
426 fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
427 glfwTerminate();
428 return -1;
429 }
430
431 glfwMakeContextCurrent(window); // Initialise GLEW
432 glewExperimental=true; // Nécessaire dans le profil de base
433 if (glewInit() != GLEW_OK) {
434 fprintf(stderr, "Failed to initialize GLEW\n");
435 return -1;
436 }
437
438 // Enable depth test
439 glEnable(GL_DEPTH_TEST);
440 // Accept fragment if it closer to the camera than the former one
441 glDepthFunc(GL_LESS);
442 glDepthRange(-1, 1);
443
444 // Bon maintenant on cree le VAO et cette fois on va s'en servir !
445 GLuint VertexArrayID;
446 glGenVertexArrays(1, &VertexArrayID);
447 glBindVertexArray(VertexArrayID);
448
449 // This will identify our vertex buffer
450 GLuint vertexbuffer;
451 // Generate 1 buffer, put the resulting identifier in vertexbuffer
452 glGenBuffers(1, &vertexbuffer);
453
454 // The following commands will talk about our 'vertexbuffer' buffer
455 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
456 // Only allocqte memory. Do not send yet our vertices to OpenGL.
457 glBufferData(GL_ARRAY_BUFFER, sss+sss, 0, GL_STATIC_DRAW);
458
459 // send vertices in the first part of the buffer
460 glBufferSubData(GL_ARRAY_BUFFER, 0, sss, g_vertex_buffer_data);
461
462 // send vertices in the second part of the buffer
463 glBufferSubData(GL_ARRAY_BUFFER, sss, sss, g_vertex_color_data);
464
465 // ici les commandes stockees "une fois pour toute" dans le VAO
466 glVertexAttribPointer(
467 0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
468 3, // size
469 GL_FLOAT, // type
470 GL_FALSE, // normalized?
471 0, // stride
472 (void*)0 // array buffer offset
473 );
474 glEnableVertexAttribArray(0);
475
476 glVertexAttribPointer( // same thing for the colors
477 1,
478 3,
479 GL_FLOAT,
480 GL_FALSE,
481 0,
482 (void*)sss);
483 glEnableVertexAttribArray(1);
484
485
486 glBindBuffer(GL_ARRAY_BUFFER, 0);
487
488 // on desactive le VAO a la fin de l'initialisation
489 glBindVertexArray (0);
490
491
492 // Assure que l'on peut capturer la touche d'échappement enfoncée ci-dessous
493 glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
494
495 GLuint programID = LoadShaders( "SimpleVertexShader53.vertexshader", "SimpleFragmentShader53.fragmentshader" );
496 uniform_proj = glGetUniformLocation(programID, "projectionMatrix");
497 uniform_view = glGetUniformLocation(programID, "viewMatrix");
498 uniform_model = glGetUniformLocation(programID, "modelMatrix");
499
500 float angle = 0.0f;
501 float elev = M_PI/2;
502
503 do{
504 angle += dangle;
505 elev=M_PI/4+0.5*sin(angle)*sin(angle);
506
507 // clear before every draw 1
508 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
509
510 // Use our shader
511 glUseProgram(programID);
512
513 // onchange de matrice de projection : la projection orthogonale est plus propice a la visualization !
514 //glm::mat4 projectionMatrix = glm::perspective(glm::radians(66.0f), 1024.0f / 768.0f, 0.1f, 200.0f);
515 glm::mat4 projectionMatrix = glm::ortho( -1.0f, 1.0f, -1.0f, 1.0f, -3.f, 3.f );
516 glm::mat4 viewMatrix = glm::lookAt(
517 vec3(1.5*cos(angle)*cos(elev), 1.5*sin(angle)*cos(elev), 1.5*sin(elev)), // where is the camara
518 vec3(0,0,0), //where it looks
519 vec3(0,0,1) // head is up
520 );
521
522 mat4 modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(2.0f, 2.0f, 2.0f) );
523 modelMatrix = glm::translate(modelMatrix, glm::vec3(-0.5f, -0.5f, 0.0));
524
525 glUniformMatrix4fv(uniform_proj, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
526 glUniformMatrix4fv(uniform_view, 1, GL_FALSE, glm::value_ptr(viewMatrix));
527 glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(modelMatrix));
528
529 // on re-active le VAO avant d'envoyer les buffers
530 glBindVertexArray(VertexArrayID);
531
532 // dessine les triangle(s) !
533 glDrawArrays(GL_TRIANGLES, 0, sss/(3*sizeof(GLfloat))); // Starting from vertex 0;
534
535 // on desactive le VAO a la fin du dessin
536 glBindVertexArray (0);
537
538 // on desactive les shaders
539 glUseProgram(0);
540
541 // Swap buffers
542 glfwSwapBuffers(window);
543 glfwPollEvents();
544
545 } // Vérifie si on a appuyé sur la touche échap (ESC) ou si la fenêtre a été fermée
546 while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
547 glfwWindowShouldClose(window) == 0 );
548 }