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&centers 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 }