Commit 2282da383e7b7d10dc27a05ff2768bae1b9797b3
1 parent
6aca1767
added path selection and visualization of the paths. fixed the drawing of the in…
…visible objects interfearing with the drawing of the selected path.... STABLE
Showing
5 changed files
with
143 additions
and
15 deletions
Show diff stats
GraphCanvas.py
... | ... | @@ -9,7 +9,7 @@ Created on Mon Aug 5 15:43:59 2019 |
9 | 9 | """ |
10 | 10 | |
11 | 11 | from vispy import gloo, scene |
12 | -from vispy.gloo import set_viewport, set_state, clear, set_blend_color | |
12 | +from vispy.gloo import set_viewport, set_state, clear, set_blend_color, context | |
13 | 13 | from vispy.util.transforms import perspective, translate, rotate, scale |
14 | 14 | import vispy.gloo.gl as glcore |
15 | 15 | |
... | ... | @@ -208,6 +208,40 @@ class GraphCanvas(scene.SceneCanvas): |
208 | 208 | self.program.bind(self.vbo) |
209 | 209 | #self.program_e.bind(self.vbo) |
210 | 210 | self.update() |
211 | + | |
212 | + def update_color_buffers(self): | |
213 | + color = self.G.vertex_properties["RGBA"].get_2d_array(range(4)).T | |
214 | + self.data['a_bg_color'] = color | |
215 | + edges = self.G.get_edges() | |
216 | + for e in range(edges.shape[0]): | |
217 | + idx = int(4*edges[e][2]) | |
218 | + self.line_data['a_fg_color'][idx] = color[edges[e][0]] | |
219 | + self.line_data['a_fg_color'][idx+1] = color[edges[e][1]] | |
220 | + self.line_data['a_fg_color'][idx+2] = color[edges[e][0]] | |
221 | + self.line_data['a_fg_color'][idx+3] = color[edges[e][1]] | |
222 | + | |
223 | + | |
224 | + | |
225 | + self.vbo = gloo.VertexBuffer(self.data) | |
226 | + self.vbo_line = gloo.VertexBuffer(self.line_data) | |
227 | + self.program.bind(self.vbo) | |
228 | + self.program_e.bind(self.vbo_line) | |
229 | + | |
230 | + | |
231 | + """ | |
232 | + Function takes a graph and a state and sets all vertices and edges to | |
233 | + the transparency defined by state | |
234 | + """ | |
235 | + def make_all_transparent(self, state): | |
236 | + for v in self.G.vertices(): | |
237 | + temp = self.G.vertex_properties["RGBA"][v] | |
238 | + temp[3] = state | |
239 | + self.G.vertex_properties["RGBA"][v] = temp | |
240 | + for e in self.G.edges(): | |
241 | + temp = self.G.edge_properties["RGBA"][e] | |
242 | + temp[3] = state | |
243 | + self.G.edge_properties["RGBA"][e] = temp | |
244 | + self.update_color_buffers() | |
211 | 245 | |
212 | 246 | """ |
213 | 247 | Maps a statistic of the vertices based on the size of the canvas to size of |
... | ... | @@ -1121,19 +1155,33 @@ class GraphCanvas(scene.SceneCanvas): |
1121 | 1155 | else: |
1122 | 1156 | update_view() |
1123 | 1157 | |
1124 | - | |
1125 | 1158 | """ |
1126 | - Handles the double click event that it responsible for path selection. | |
1127 | - Generates paths our of consecutive paths out of the selected vertices. | |
1159 | + Gets the path and formats it in terms of vertex-to-vertex | |
1160 | + instead of source(obj)-to-source(obj) | |
1128 | 1161 | """ |
1129 | - def on_mouse_double_click(self, event): | |
1130 | - | |
1162 | + def get_path(self): | |
1163 | + p = [] | |
1164 | + for s in self.path: | |
1165 | + for e in s.e_path: | |
1166 | + temp = (int(e.source()), int(e.target())) | |
1167 | + if (temp not in p): | |
1168 | + p.append(temp) | |
1169 | + | |
1170 | + return p | |
1171 | + | |
1172 | + | |
1173 | + def update_path(self, event): | |
1131 | 1174 | #Method to update the vertex buffer of the nodes in the graph view |
1132 | 1175 | def update_vbo(self): |
1133 | 1176 | self.vbo = gloo.VertexBuffer(self.data) |
1134 | 1177 | self.program.bind(self.vbo) |
1135 | 1178 | self.update() |
1136 | 1179 | |
1180 | + def update_vertex_alpha(self, vertex, alpha): | |
1181 | + temp = self.G.vertex_properties["RGBA"][vertex] | |
1182 | + temp[3] = alpha | |
1183 | + self.G.vertex_properties["RGBA"][vertex] = temp | |
1184 | + | |
1137 | 1185 | #updates the path structure of the class |
1138 | 1186 | #source and target are of type "source" defined in this class. |
1139 | 1187 | def add_to_path(self, source, target): |
... | ... | @@ -1141,16 +1189,25 @@ class GraphCanvas(scene.SceneCanvas): |
1141 | 1189 | for v in range(1, len(vl)-1): |
1142 | 1190 | if (self.G.vertex_properties["selection"][vl[v]] != 1.0): |
1143 | 1191 | self.G.vertex_properties["selection"][vl[v]] = 2.0 |
1192 | + update_vertex_alpha(self, self.G.vertex(vl[v]), 1.0) | |
1144 | 1193 | self.data['a_selection'][int(vl[v])] = 2.0 |
1145 | 1194 | source.v_path.append(int(vl[v])) |
1146 | 1195 | for e in el: |
1147 | 1196 | source.e_path.append(e) |
1197 | + temp = self.G.edge_properties["RGBA"][e] | |
1198 | + temp[3] = 1.0 | |
1199 | + self.G.edge_properties["RGBA"][e] = temp | |
1148 | 1200 | |
1149 | 1201 | |
1150 | 1202 | def remove_from_path(self, source): |
1151 | 1203 | for v in source.v_path: |
1152 | 1204 | self.G.vertex_properties["selection"][self.G.vertex(v)] = 0.0 |
1205 | + update_vertex_alpha(self,self.G.vertex(v), 0.5) | |
1153 | 1206 | self.data['a_selection'][v] = 0.0 |
1207 | + for e in source.e_path: | |
1208 | + temp = self.G.edge_properties["RGBA"][e] | |
1209 | + temp[3] = 0.0 | |
1210 | + self.G.edge_properties["RGBA"][e] = temp | |
1154 | 1211 | source.clear_path() |
1155 | 1212 | |
1156 | 1213 | if (event.button == 1): |
... | ... | @@ -1164,12 +1221,15 @@ class GraphCanvas(scene.SceneCanvas): |
1164 | 1221 | self.pathing = True |
1165 | 1222 | self.path.append(path_point(c_id)) |
1166 | 1223 | self.data['a_selection'][c_id] = 1.0 |
1167 | - update_vbo(self) | |
1224 | + self.make_all_transparent(0.5) | |
1225 | + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) | |
1226 | + self.update_color_buffers() | |
1168 | 1227 | print("I turned on the first node") |
1169 | 1228 | else: |
1170 | 1229 | #If the node is selected already, unselect it and remove from path the last occurance in the path |
1171 | 1230 | if(self.G.vertex_properties["selection"][self.G.vertex(c_id)] == 1.0): |
1172 | 1231 | self.G.vertex_properties["selection"][self.G.vertex(c_id)] = 0.0 |
1232 | + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) | |
1173 | 1233 | self.data['a_selection'][c_id] = 0.0 |
1174 | 1234 | s_id = self.path.index(path_point(c_id)) |
1175 | 1235 | if(s_id == 0): |
... | ... | @@ -1187,21 +1247,24 @@ class GraphCanvas(scene.SceneCanvas): |
1187 | 1247 | if(path_point(c_id) not in self.path): |
1188 | 1248 | self.path.append(path_point(c_id)) |
1189 | 1249 | self.G.vertex_properties["selection"][self.G.vertex(c_id)] = 1.0 |
1250 | + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) | |
1190 | 1251 | self.data['a_selection'][c_id] = 1.0 |
1191 | 1252 | #if the source is not LAST in the path, add it. |
1192 | 1253 | elif(self.path[len(self.path)-1] != path_point(c_id)): |
1193 | 1254 | self.path.append(path_point(c_id)) |
1194 | 1255 | self.G.vertex_properties["selection"][self.G.vertex(c_id)] = 1.0 |
1256 | + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) | |
1195 | 1257 | self.data['a_selection'][c_id] = 1.0 |
1196 | 1258 | print("I turned on a node") |
1197 | 1259 | if(len(self.path) >= 1): |
1198 | 1260 | for i in range(len(self.path)-1): |
1199 | 1261 | add_to_path(self, self.path[i], self.path[i+1]) |
1200 | - update_vbo(self) | |
1262 | + self.update_color_buffers() | |
1201 | 1263 | #THIS IS WHERE I LEFT IT OFF. |
1202 | 1264 | if(np.sum(self.G.vertex_properties["selection"].get_array()) == 0): |
1203 | 1265 | self.pathing = False |
1204 | - update_vbo(self) | |
1266 | + self.make_all_transparent(1.0) | |
1267 | + self.update_color_buffers() | |
1205 | 1268 | |
1206 | 1269 | |
1207 | 1270 | |
... | ... | @@ -1209,6 +1272,14 @@ class GraphCanvas(scene.SceneCanvas): |
1209 | 1272 | # self.G.vertex_properties["selection"][self.G.vertex(c_id)] == False |
1210 | 1273 | print("clicked on: ", c_id, " ", self.path) |
1211 | 1274 | |
1275 | + | |
1276 | + """ | |
1277 | + Handles the double click event that it responsible for path selection. | |
1278 | + Generates paths our of consecutive paths out of the selected vertices. | |
1279 | + """ | |
1280 | + def on_mouse_double_click(self, event): | |
1281 | + n=1 | |
1282 | + | |
1212 | 1283 | """ |
1213 | 1284 | Resets the variables that are used during the pressdown and move events |
1214 | 1285 | """ | ... | ... |
GraphWidget.py
... | ... | @@ -142,7 +142,8 @@ class GraphWidget(QtGui.QWidget): |
142 | 142 | Pass-through function. |
143 | 143 | """ |
144 | 144 | def on_mouse_double_click(self, event): |
145 | - self.select.emit(self.canvas.path) | |
145 | + self.canvas.update_path(event) | |
146 | + self.select.emit(self.canvas.get_path()) | |
146 | 147 | |
147 | 148 | """ |
148 | 149 | Handles the mouse release event. | ... | ... |
TubeCanvas.py
... | ... | @@ -11,7 +11,8 @@ Created on Mon Aug 5 15:56:47 2019 |
11 | 11 | """ |
12 | 12 | |
13 | 13 | from vispy import gloo, scene |
14 | -from vispy.gloo import set_viewport, set_state, clear, set_blend_color | |
14 | +from vispy.gloo import set_viewport, set_state, clear, set_blend_color, context | |
15 | +from vispy.gloo import gl | |
15 | 16 | from vispy.util.transforms import perspective, translate, rotate, scale |
16 | 17 | import vispy.gloo.gl as glcore |
17 | 18 | from vispy.util.quaternion import Quaternion |
... | ... | @@ -40,6 +41,7 @@ class TubeDraw(scene.SceneCanvas): |
40 | 41 | #unfreeze the drawing area to allow for dynamic drawing and interaction |
41 | 42 | self.unfreeze() |
42 | 43 | self.edge_dict = {} |
44 | + self.select = False | |
43 | 45 | #generate dummy buffers for the meshes |
44 | 46 | self.program = gloo.Program(VERT_SHADER, FRAG_SHADER) |
45 | 47 | self.cylinder_data = np.zeros(5*5, dtype=[('a_position', np.float32, 3), |
... | ... | @@ -59,7 +61,7 @@ class TubeDraw(scene.SceneCanvas): |
59 | 61 | #set_state(clear_color='white', depth_test=True, blend=True, |
60 | 62 | # blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('less'), cull_face='back') |
61 | 63 | set_state(clear_color='white', depth_test=True, blend=True, |
62 | - blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal')) | |
64 | + blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal'), cull_face='back') | |
63 | 65 | #set_blend_color(color='black') |
64 | 66 | #set_state('translucent') |
65 | 67 | self.program['u_LightPos'] = [0., 0., -1000.] |
... | ... | @@ -72,6 +74,7 @@ class TubeDraw(scene.SceneCanvas): |
72 | 74 | |
73 | 75 | ##### prototype ##### |
74 | 76 | #Set the visualization matrices |
77 | + self.program['u_selection'] = 0.0 | |
75 | 78 | self.program['u_eye'] = self.camera |
76 | 79 | self.program['u_up'] = self.up |
77 | 80 | self.program['u_target'] = np.asarray([0., 0., 0.], dtype=np.float32) |
... | ... | @@ -143,6 +146,12 @@ class TubeDraw(scene.SceneCanvas): |
143 | 146 | def on_draw(self, event): |
144 | 147 | clear(color='white', depth=True) |
145 | 148 | gloo.set_clear_color('white') |
149 | + if self.select: | |
150 | + set_state(clear_color='white', depth_test=True, blend=True, | |
151 | + blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('always'), cull_face='back') | |
152 | + else: | |
153 | + set_state(clear_color='white', depth_test=True, blend=True, | |
154 | + blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal'), cull_face='back') | |
146 | 155 | self.program.draw('triangles', self.triangles) |
147 | 156 | self.projection = perspective(90.0, self.physical_size[0]/self.physical_size[1], 1.0, 1000.0) |
148 | 157 | self.program['u_projection'] = self.projection |
... | ... | @@ -158,7 +167,7 @@ class TubeDraw(scene.SceneCanvas): |
158 | 167 | self.cylinder_data = np.zeros(num_pts*num_sides, dtype=[('a_position', np.float32, 3), |
159 | 168 | ('a_normal', np.float32, 3), |
160 | 169 | ('a_fg_color', np.float32, 4), |
161 | - #('a_linewidth', np.float32, 1), | |
170 | + ('a_selection', np.float32, 1), | |
162 | 171 | ]) |
163 | 172 | self.triangle_data = np.random.randint(size=(num_tri, 3), low=0, |
164 | 173 | high=(G.num_edges()-1)).astype(np.uint32) |
... | ... | @@ -288,6 +297,7 @@ class TubeDraw(scene.SceneCanvas): |
288 | 297 | circle_pts_data = circle_pts.reshape((pts.shape[0]*num_sides, 3)) |
289 | 298 | self.cylinder_data['a_position'][index:(pts.shape[0]*num_sides+index)] = circle_pts_data |
290 | 299 | self.cylinder_data['a_fg_color'][index:(pts.shape[0]*num_sides+index)] = color |
300 | + self.cylinder_data['a_selection'][index:(pts.shape[0]*num_sides+index)] = 0.0 | |
291 | 301 | #generate the normals data structure |
292 | 302 | pts_normals = circle_pts.copy() |
293 | 303 | for p in range(pts.shape[0]): |
... | ... | @@ -299,7 +309,7 @@ class TubeDraw(scene.SceneCanvas): |
299 | 309 | pts_normals.reshape((pts.shape[0]*num_sides, 3)) |
300 | 310 | |
301 | 311 | index += pts.shape[0]*num_sides |
302 | - self.edge_dict[(e.source(), e.target())] = (index-pts.shape[0]*num_sides, index) | |
312 | + self.edge_dict[(int(e.source()), int(e.target()))] = (index-pts.shape[0]*num_sides, index) | |
303 | 313 | |
304 | 314 | #Add the caps for each of the endpoints. |
305 | 315 | |
... | ... | @@ -333,6 +343,37 @@ class TubeDraw(scene.SceneCanvas): |
333 | 343 | i+=1 |
334 | 344 | #create the data. |
335 | 345 | |
346 | + def select_edges(self, edges): | |
347 | + #gloo.context.set_current_canvas(gloo.context.get_current_canvas()) | |
348 | + if len(edges) > 0: | |
349 | + self.select = True | |
350 | + #gloo.set_depth_func('always') | |
351 | + #clear(color='white', depth=True) | |
352 | + #gl.GL_DEPTH_FUNC('always') | |
353 | + #print(gloo.wrappers.get_gl_configuration()) | |
354 | + self.program['u_selection'] = 1.0 | |
355 | + for e in edges: | |
356 | + if e in self.edge_dict: | |
357 | + idx = self.edge_dict[e] | |
358 | + #print(self.canvas.edge_dict[e]) | |
359 | + elif (e[1], e[0]) in self.edge_dict: | |
360 | + idx = self.edge_dict[(e[1],e[0])] | |
361 | + else: | |
362 | + print("WHAT THE FUCK HAPPENED") | |
363 | + self.cylinder_data["a_selection"][idx[0]:idx[1]] = 1.0 | |
364 | + self.vbo = gloo.VertexBuffer(self.cylinder_data) | |
365 | + self.program.bind(self.vbo) | |
366 | + #self.update() | |
367 | + else: | |
368 | + self.program['u_selection'] = 0.0 | |
369 | + self.select = False | |
370 | + #set_state(clear_color='white', depth_test=True, blend=True, | |
371 | + # blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal')) | |
372 | + #gloo.set_depth_func('lequal') | |
373 | + #clear(color='white', depth=True) | |
374 | + #print(gloo.wrappers.get_gl_configuration()) | |
375 | + self.update() | |
376 | + #print(self.canvas.edge_dict[(e[1], e[0])]) | |
336 | 377 | #Handles the mouse wheel event, i.e., zoom |
337 | 378 | def on_mouse_wheel(self, event): |
338 | 379 | # self.scale[0] = self.scale[0] + self.scale[0]*event.delta[1]*0.05 | ... | ... |
TubeWidget.py
... | ... | @@ -47,7 +47,7 @@ class TubeWidget(QtGui.QWidget): |
47 | 47 | if self.down: |
48 | 48 | self.sendCameraInfo() |
49 | 49 | |
50 | - #Handles the mouse press event | |
50 | + #Handles the mouse press events | |
51 | 51 | def on_mouse_press(self, event): |
52 | 52 | self.down = True |
53 | 53 | n = 3 |
... | ... | @@ -72,6 +72,12 @@ class TubeWidget(QtGui.QWidget): |
72 | 72 | """ |
73 | 73 | @QtCore.pyqtSlot(list) |
74 | 74 | def select(self, x): |
75 | + self.canvas.select_edges(x) | |
76 | +# for e in x: | |
77 | +# if e in self.canvas.edge_dict: | |
78 | +# print(self.canvas.edge_dict[e]) | |
79 | +# elif (e[1], e[0]) in self.canvas.edge_dict: | |
80 | +# print(self.canvas.edge_dict[(e[1], e[0])]) | |
75 | 81 | print("got signal", x) |
76 | 82 | |
77 | 83 | """ | ... | ... |
tube_shaders.py
... | ... | @@ -15,6 +15,7 @@ uniform vec3 u_LightPost; |
15 | 15 | uniform mat4 u_model; |
16 | 16 | //uniform mat4 u_view; |
17 | 17 | uniform mat4 u_projection; |
18 | +uniform float u_selection; | |
18 | 19 | |
19 | 20 | uniform vec3 u_eye; |
20 | 21 | uniform vec3 u_up; |
... | ... | @@ -25,6 +26,7 @@ uniform vec3 u_target; |
25 | 26 | attribute vec3 a_position; |
26 | 27 | attribute vec3 a_normal; |
27 | 28 | attribute vec4 a_fg_color; |
29 | +attribute float a_selection; | |
28 | 30 | |
29 | 31 | // Varyings |
30 | 32 | // ------------------------------------ |
... | ... | @@ -33,6 +35,7 @@ varying vec4 v_fg_color; |
33 | 35 | varying vec3 v_position; |
34 | 36 | varying mat4 u_view; |
35 | 37 | varying vec3 vt_position; |
38 | +varying float v_selection; | |
36 | 39 | |
37 | 40 | |
38 | 41 | // Functions |
... | ... | @@ -50,6 +53,7 @@ void main (void) { |
50 | 53 | v_position = vec3(MV*vec4(a_position, 1.0)); |
51 | 54 | vt_position = vec3(a_position); |
52 | 55 | v_fg_color = a_fg_color; |
56 | + v_selection = a_selection; | |
53 | 57 | gl_Position = MVP * vec4(a_position, 1.0); |
54 | 58 | } |
55 | 59 | |
... | ... | @@ -87,6 +91,7 @@ uniform vec3 u_LightPos; |
87 | 91 | uniform mat4 u_model; |
88 | 92 | //uniform mat4 u_view; |
89 | 93 | uniform mat4 u_projection; |
94 | +uniform float u_selection; | |
90 | 95 | |
91 | 96 | uniform vec3 u_eye; |
92 | 97 | uniform vec3 u_up; |
... | ... | @@ -99,6 +104,7 @@ varying vec4 v_fg_color; |
99 | 104 | varying vec3 v_position; |
100 | 105 | varying mat4 u_view; |
101 | 106 | varying vec3 vt_position; |
107 | +varying float v_selection; | |
102 | 108 | |
103 | 109 | float new_alpha(); |
104 | 110 | float set_view(); |
... | ... | @@ -128,6 +134,9 @@ void main() |
128 | 134 | |
129 | 135 | vec4 color = (ambient_color + diffuse)*v_fg_color; |
130 | 136 | float alpha = new_alpha(); |
137 | + if(u_selection > 0.0) | |
138 | + alpha = max(alpha*v_selection, 0.00); | |
139 | + //alpha = max(alpha * v_selection, 0.05); | |
131 | 140 | //if(alpha == 1.0) |
132 | 141 | // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); |
133 | 142 | // gl_FragColor = vec4(color.rgb, alpha); | ... | ... |