Commit 4f517c76b909f099e3f4a31b4256b3a782b4d9e6

Authored by David Mayerich
1 parent bbb519e6

added color-mapped networks, parallel viewing of two networks

Showing 1 changed file with 171 additions and 119 deletions   Show diff stats
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 8
9 //STIM includes 9 //STIM includes
10 #include <stim/visualization/gl_network.h> 10 #include <stim/visualization/gl_network.h>
11 -#include <stim/visualization/gl_aabb.h> 11 +#include <stim/visualization/gl_aaboundingbox.h>
12 #include <stim/parser/arguments.h> 12 #include <stim/parser/arguments.h>
13 #include <stim/visualization/camera.h> 13 #include <stim/visualization/camera.h>
14 14
@@ -18,62 +18,117 @@ @@ -18,62 +18,117 @@
18 //BOOST includes 18 //BOOST includes
19 #include <boost/tuple/tuple.hpp> 19 #include <boost/tuple/tuple.hpp>
20 20
21 -stim::gl_aabb<float> bb;  
22 -stim::camera cam; 21 +//visualization objects
  22 +stim::gl_aaboundingbox<float> bb; //axis-aligned bounding box object
  23 +stim::camera cam; //camera object
23 24
24 -stim::gl_network<float> GT;  
25 -stim::gl_network<float> T; 25 +unsigned num_nets = 0;
  26 +stim::gl_network<float> GT; //ground truth network
  27 +stim::gl_network<float> T; //test network
26 28
27 //hard-coded parameters 29 //hard-coded parameters
28 -float resample_rate = 0.5; 30 +float resample_rate = 0.5; //sample rate for the network (fraction of sigma used as the maximum sample rate)
  31 +float camera_factor = 1.2; //start point of the camera as a function of X and Y size
  32 +float orbit_factor = 0.01; //degrees per pixel used to orbit the camera
29 33
30 //mouse position tracking 34 //mouse position tracking
31 int mouse_x; 35 int mouse_x;
32 int mouse_y; 36 int mouse_y;
33 37
  38 +//OpenGL objects
  39 +GLuint cmap_tex = 0; //texture name for the color map
  40 +
  41 +//sets an OpenGL viewport taking up the entire window
  42 +void glut_render_single_projection(){
  43 +
  44 + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing
  45 + glLoadIdentity(); //start with the identity matrix
  46 + int X = glutGet(GLUT_WINDOW_WIDTH); //use the whole screen for rendering
  47 + int Y = glutGet(GLUT_WINDOW_HEIGHT);
  48 + glViewport(0, 0, X, Y); //specify a viewport for the entire window
  49 + float aspect = (float)X / (float)Y; //calculate the aspect ratio
  50 + gluPerspective(60, aspect, 0.1, 1000000); //set up a perspective projection
  51 +}
  52 +
  53 +//sets an OpenGL viewport taking up the left half of the window
  54 +void glut_render_left_projection(){
  55 +
  56 + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing
  57 + glLoadIdentity(); //start with the identity matrix
  58 + int X = glutGet(GLUT_WINDOW_WIDTH) / 2; //only use half of the screen for the viewport
  59 + int Y = glutGet(GLUT_WINDOW_HEIGHT);
  60 + glViewport(0, 0, X, Y); //specify the viewport on the left
  61 + float aspect = (float)X / (float)Y; //calculate the aspect ratio
  62 + gluPerspective(60, aspect, 0.1, 1000000); //set up a perspective projection
  63 +}
  64 +
  65 +//sets an OpenGL viewport taking up the right half of the window
  66 +void glut_render_right_projection(){
  67 +
  68 + glMatrixMode(GL_PROJECTION); //load the projection matrix for editing
  69 + glLoadIdentity(); //start with the identity matrix
  70 + int X = glutGet(GLUT_WINDOW_WIDTH) / 2; //only use half of the screen for the viewport
  71 + int Y = glutGet(GLUT_WINDOW_HEIGHT);
  72 + glViewport(X, 0, X, Y); //specify the viewport on the right
  73 + float aspect = (float)X / (float)Y; //calculate the aspect ratio
  74 + gluPerspective(60, aspect, 0.1, 1000000); //set up a perspective projection
  75 +}
  76 +
  77 +void glut_render_modelview(){
  78 +
  79 + glMatrixMode(GL_MODELVIEW); //load the modelview matrix for editing
  80 + glLoadIdentity(); //start with the identity matrix
  81 + stim::vec<float> eye = cam.getPosition(); //get the camera position (eye point)
  82 + stim::vec<float> focus = cam.getLookAt(); //get the camera focal point
  83 + stim::vec<float> up = cam.getUp(); //get the camera "up" orientation
  84 +
  85 + gluLookAt(eye[0], eye[1], eye[2], focus[0], focus[1], focus[2], up[0], up[1], up[2]); //set up the OpenGL camera
  86 +}
  87 +
  88 +//draws the network(s)
34 void glut_render(void) { 89 void glut_render(void) {
35 90
36 - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 91 + if(num_nets == 1){ //if a single network is loaded
  92 + glut_render_single_projection(); //fill the entire viewport
  93 + glut_render_modelview(); //set up the modelview matrix with camera details
  94 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear the screen
  95 + GT.glCenterline(GT.nmags() - 1); //render the GT network (the only one loaded)
  96 + }
37 97
38 - glMatrixMode(GL_MODELVIEW);  
39 - glLoadIdentity();  
40 - stim::vec<float> eye = cam.getPosition();  
41 - stim::vec<float> focus = cam.getLookAt();  
42 - stim::vec<float> up = cam.getUp(); 98 + if(num_nets == 2){ //if two networks are loaded
43 99
44 - gluLookAt(eye[0], eye[1], eye[2], focus[0], focus[1], focus[2], up[0], up[1], up[2]); 100 + glut_render_left_projection(); //set up a projection for the left half of the window
  101 + glut_render_modelview(); //set up the modelview matrix using camera details
  102 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear the screen
45 103
46 - 104 + glEnable(GL_TEXTURE_1D); //enable texture mapping
  105 + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //texture map will be used as the network color
  106 + glBindTexture(GL_TEXTURE_1D, cmap_tex); //bind the Brewer texture map
47 107
48 - // render the bounding box  
49 - glColor3f(0.0, 0.0, 1.0);  
50 - bb.glWire();  
51 - 108 + GT.glCenterline(GT.nmags() - 1); //render the GT network
52 109
53 - //render the GT network (red)  
54 - glColor3f(1.0, 0.0, 0.0);  
55 - GT.glCenterline(); 110 + glut_render_right_projection(); //set up a projection for the right half of the window
  111 + glut_render_modelview(); //set up the modelview matrix using camera details
  112 + T.glCenterline(T.nmags() - 1); //render the T network
56 113
57 - //render the T network (green)  
58 - glColor3f(0.0, 1.0, 0.0);  
59 - T.glCenterline(); 114 + }
60 115
61 glutSwapBuffers(); 116 glutSwapBuffers();
62 } 117 }
63 118
64 // defines camera motion based on mouse dragging 119 // defines camera motion based on mouse dragging
65 void glut_motion(int x, int y){ 120 void glut_motion(int x, int y){
66 - float factor = 0.01; 121 +
67 122
68 - float theta = factor * (mouse_x - x);  
69 - float phi = factor * (y - mouse_y); 123 + float theta = orbit_factor * (mouse_x - x); //determine the number of degrees along the x-axis to rotate
  124 + float phi = orbit_factor * (y - mouse_y); //number of degrees along the y-axis to rotate
70 125
71 - cam.OrbitFocus(theta, phi); 126 + cam.OrbitFocus(theta, phi); //rotate the camera around the focal point
72 127
73 - mouse_x = x; 128 + mouse_x = x; //update the mouse position
74 mouse_y = y; 129 mouse_y = y;
75 -  
76 - glutPostRedisplay(); 130 +
  131 + glutPostRedisplay(); //re-draw the visualization
77 } 132 }
78 133
79 // sets the mouse position when clicked 134 // sets the mouse position when clicked
@@ -82,19 +137,78 @@ void glut_mouse(int button, int state, int x, int y){ @@ -82,19 +137,78 @@ void glut_mouse(int button, int state, int x, int y){
82 mouse_y = y; 137 mouse_y = y;
83 } 138 }
84 139
85 -// re-calculates the projection matrix if the window is reshaped  
86 -void glut_reshape(int x, int y){ 140 +#define BREWER_CTRL_PTS 11 //number of control points in the Brewer map
  141 +void texture_initialize(){
  142 +
  143 + //define the colormap
  144 + static float brewer_map[BREWER_CTRL_PTS][3] = { //generate a Brewer color map (blue to red)
  145 + {0.192157f, 0.211765f, 0.584314f},
  146 + {0.270588f, 0.458824f, 0.705882f},
  147 + {0.454902f, 0.678431f, 0.819608f},
  148 + {0.670588f, 0.85098f, 0.913725f},
  149 + {0.878431f, 0.952941f, 0.972549f},
  150 + {1.0f, 1.0f, 0.74902f},
  151 + {0.996078f, 0.878431f, 0.564706f},
  152 + {0.992157f, 0.682353f, 0.380392f},
  153 + {0.956863f, 0.427451f, 0.262745f},
  154 + {0.843137f, 0.188235f, 0.152941f},
  155 + {0.647059f, 0.0f, 0.14902f}
  156 + };
  157 +
  158 + glGenTextures(1, &cmap_tex); //generate a texture map name
  159 + glBindTexture(GL_TEXTURE_1D, cmap_tex); //bind the texture map
  160 +
  161 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //enable linear interpolation
  162 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  163 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); //clamp the values at the minimum and maximum
  164 + glTexImage1D(GL_TEXTURE_1D, 0, 3, BREWER_CTRL_PTS, 0, GL_RGB, GL_FLOAT, //upload the texture map to the GPU
  165 + brewer_map);
  166 +}
  167 +
  168 +//Initialize the OpenGL (GLUT) window, including starting resolution, callbacks, texture maps, and camera
  169 +void glut_initialize(){
  170 +
  171 + int myargc = 1; //GLUT requires arguments, so create some bogus ones
  172 + char* myargv[1];
  173 + myargv [0]=strdup ("netmets");
  174 +
  175 + glutInit(&myargc, myargv); //pass bogus arguments to glutInit()
  176 + glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); //generate a color buffer, depth buffer, and enable double buffering
  177 + glutInitWindowPosition(100,100); //set the initial window position
  178 + glutInitWindowSize(320,320); //set the initial window size
  179 + glutCreateWindow("NetMets - STIM Lab, UH"); //set the dialog box title
87 180
88 - glMatrixMode(GL_PROJECTION);  
89 - glLoadIdentity();  
90 - glViewport(0, 0, x, y);  
91 - float aspect = (float)x / (float)y;  
92 - gluPerspective(60, aspect, 0.1, 1000000); 181 +
  182 + // register callback functions
  183 + glutDisplayFunc(glut_render); //function executed for rendering - renders networks
  184 + glutMouseFunc(glut_mouse); //executed on a mouse click - sets starting mouse positions for rotations
  185 + glutMotionFunc(glut_motion); //executed when the mouse is moved while a button is pressed
  186 +
  187 + texture_initialize(); //set up texture mapping (create texture maps, enable features)
  188 +
  189 + stim::vec<float> c = bb.center(); //get the center of the network bounding box
93 190
  191 + //place the camera along the z-axis at a distance determined by the network size along x and y
  192 + cam.setPosition(c + stim::vec<float>(0, 0, camera_factor * std::max(bb.size()[0], bb.size()[1])));
  193 + cam.LookAt(c[0], c[1], c[2]); //look at the center of the network
94 } 194 }
95 195
  196 +//compare both networks and fill the networks with error information
  197 +void compare(float sigma){
  198 +
  199 + GT = GT.compare(T, sigma); //compare the ground truth to the test case - store errors in GT
  200 + T = T.compare(GT, sigma); //compare the test case to the ground truth - store errors in T
  201 +
  202 + //calculate the metrics
  203 + float FPR = GT.average(1); //calculate the metrics
  204 + float FNR = T.average(1);
  205 +
  206 + std::cout << "FNR: " << FPR << std::endl; //print false alarms and misses
  207 + std::cout << "FPR: " << FNR << std::endl;
  208 +}
  209 +
  210 +// Output an advertisement for the lab, authors, and usage information
96 void advertise(){ 211 void advertise(){
97 - //output advertisement  
98 std::cout<<std::endl<<std::endl; 212 std::cout<<std::endl<<std::endl;
99 std::cout<<"========================================================================="<<std::endl; 213 std::cout<<"========================================================================="<<std::endl;
100 std::cout<<"Thank you for using the NetMets network comparison tool!"<<std::endl; 214 std::cout<<"Thank you for using the NetMets network comparison tool!"<<std::endl;
@@ -107,94 +221,32 @@ void advertise(){ @@ -107,94 +221,32 @@ void advertise(){
107 std::cout<<" compare two files with a tolerance of 10 (units defined by the network)"<<std::endl; 221 std::cout<<" compare two files with a tolerance of 10 (units defined by the network)"<<std::endl;
108 std::cout<<" netmets file1 --gui"<<std::endl<<std::endl; 222 std::cout<<" netmets file1 --gui"<<std::endl<<std::endl;
109 std::cout<<" load a file and display it using OpenGL"<<std::endl; 223 std::cout<<" load a file and display it using OpenGL"<<std::endl;
110 -  
111 -}  
112 -  
113 -void compare(float sigma){  
114 -  
115 - // compare ground truth with truth and viceversa  
116 - stim::network<float> cGT = GT.compare(T, sigma);  
117 - stim::network<float> cT = T.compare(GT, sigma);  
118 -  
119 - //calculate the metrics  
120 - float FPR = cGT.average(1);  
121 - float FNR = cT.average(1);  
122 - // print false alarms and misses  
123 - std::cout << "FNR: " << FPR << std::endl;  
124 - std::cout << "FPR: " << FNR << std::endl;  
125 -}  
126 -  
127 -void glut_initialize(){  
128 - float factor = 1.2;  
129 -  
130 - // init GLUT and create Window  
131 - int myargc = 1;  
132 - char* myargv[1];  
133 - myargv [0]=strdup ("netmets");  
134 -  
135 - glutInit(&myargc, myargv);  
136 - glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);  
137 - glutInitWindowPosition(100,100);  
138 - glutInitWindowSize(320,320);  
139 - glutCreateWindow("Lighthouse3D- GLUT Tutorial");  
140 -  
141 -  
142 - // register callbacks  
143 - glutDisplayFunc(glut_render);  
144 - glutMouseFunc(glut_mouse);  
145 - glutMotionFunc(glut_motion);  
146 - glutReshapeFunc(glut_reshape);  
147 -  
148 - //set up the camera  
149 - stim::vec<float> c = bb.center();  
150 - //place the camera along the z-axis at a distance determined by the network size along x and y  
151 - cam.setPosition(c + stim::vec<float>(0, 0, factor * std::max(bb.size()[0], bb.size()[1])));  
152 - cam.LookAt(c[0], c[1], c[2]); //look at the center  
153 -  
154 -}  
155 -  
156 -void display(){  
157 -  
158 -  
159 - //generate a bounding volume  
160 - bb = GT.boundingbox();  
161 -  
162 - //create the GLUT window and set callback functions  
163 - glut_initialize();  
164 -  
165 - glut_reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));  
166 -  
167 - // enter GLUT event processing cycle  
168 - glutMainLoop();  
169 } 224 }
170 225
171 int main(int argc, char* argv[]) 226 int main(int argc, char* argv[])
172 { 227 {
173 - //create an instance of arglist  
174 - stim::arglist args; 228 + stim::arglist args; //create an instance of arglist
175 229
176 //add arguments 230 //add arguments
177 args.add("help", "prints this help"); 231 args.add("help", "prints this help");
178 args.add("sigma", "force a sigma value to specify the tolerance of the network comparison", "10"); 232 args.add("sigma", "force a sigma value to specify the tolerance of the network comparison", "10");
179 args.add("gui", "display the network or network comparison using OpenGL"); 233 args.add("gui", "display the network or network comparison using OpenGL");
180 234
181 - //parse the user arguments  
182 - args.parse(argc, argv); 235 + args.parse(argc, argv); //parse the user arguments
183 236
184 - //test for help  
185 - if(args["help"].is_set() || args.nargs() == 0){  
186 - advertise();  
187 - std::cout<<args.str();  
188 - exit(1); 237 + if(args["help"].is_set() || args.nargs() == 0){ //test for help
  238 + advertise(); //output the advertisement
  239 + std::cout<<args.str(); //output arguments
  240 + exit(1); //exit
189 } 241 }
190 -  
191 - //if one file is specified, load it as the ground truth  
192 - if(args.nargs() >= 1){  
193 - GT.load_obj(args.arg(0)); 242 +
  243 + if(args.nargs() >= 1){ //if at least one network file is specified
  244 + num_nets = 1; //set the number of networks to one
  245 + GT.load_obj(args.arg(0)); //load the specified file as the ground truth
194 } 246 }
195 -  
196 - //if two files are provided, compare them  
197 - if(args.nargs() == 2){ 247 +
  248 + if(args.nargs() == 2){ //if two files are specified, they will be displayed in neighboring viewports and compared
  249 + num_nets = 2; //set the number of networks to two
198 float sigma = args["sigma"].as_float(); //get the sigma value from the user 250 float sigma = args["sigma"].as_float(); //get the sigma value from the user
199 T.load_obj(args.arg(1)); //load the second (test) network 251 T.load_obj(args.arg(1)); //load the second (test) network
200 252
@@ -205,9 +257,9 @@ int main(int argc, char* argv[]) @@ -205,9 +257,9 @@ int main(int argc, char* argv[])
205 } 257 }
206 258
207 //if a GUI is requested, display the network using OpenGL 259 //if a GUI is requested, display the network using OpenGL
208 - if(args["gui"].is_set())  
209 - display();  
210 -  
211 -  
212 - 260 + if(args["gui"].is_set()){
  261 + bb = GT.boundingbox(); //generate a bounding volume
  262 + glut_initialize(); //create the GLUT window and set callback functions
  263 + glutMainLoop(); // enter GLUT event processing cycle
  264 + }
213 } 265 }
214 \ No newline at end of file 266 \ No newline at end of file