From 2282da383e7b7d10dc27a05ff2768bae1b9797b3 Mon Sep 17 00:00:00 2001 From: Pavel Govyadinov Date: Fri, 16 Aug 2019 17:45:39 -0500 Subject: [PATCH] added path selection and visualization of the paths. fixed the drawing of the invisible objects interfearing with the drawing of the selected path.... STABLE --- GraphCanvas.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- GraphWidget.py | 3 ++- TubeCanvas.py | 49 +++++++++++++++++++++++++++++++++++++++++++++---- TubeWidget.py | 8 +++++++- tube_shaders.py | 9 +++++++++ 5 files changed, 143 insertions(+), 15 deletions(-) diff --git a/GraphCanvas.py b/GraphCanvas.py index f832d10..15ca17b 100644 --- a/GraphCanvas.py +++ b/GraphCanvas.py @@ -9,7 +9,7 @@ Created on Mon Aug 5 15:43:59 2019 """ from vispy import gloo, scene -from vispy.gloo import set_viewport, set_state, clear, set_blend_color +from vispy.gloo import set_viewport, set_state, clear, set_blend_color, context from vispy.util.transforms import perspective, translate, rotate, scale import vispy.gloo.gl as glcore @@ -208,6 +208,40 @@ class GraphCanvas(scene.SceneCanvas): self.program.bind(self.vbo) #self.program_e.bind(self.vbo) self.update() + + def update_color_buffers(self): + color = self.G.vertex_properties["RGBA"].get_2d_array(range(4)).T + self.data['a_bg_color'] = color + edges = self.G.get_edges() + for e in range(edges.shape[0]): + idx = int(4*edges[e][2]) + self.line_data['a_fg_color'][idx] = color[edges[e][0]] + self.line_data['a_fg_color'][idx+1] = color[edges[e][1]] + self.line_data['a_fg_color'][idx+2] = color[edges[e][0]] + self.line_data['a_fg_color'][idx+3] = color[edges[e][1]] + + + + self.vbo = gloo.VertexBuffer(self.data) + self.vbo_line = gloo.VertexBuffer(self.line_data) + self.program.bind(self.vbo) + self.program_e.bind(self.vbo_line) + + + """ + Function takes a graph and a state and sets all vertices and edges to + the transparency defined by state + """ + def make_all_transparent(self, state): + for v in self.G.vertices(): + temp = self.G.vertex_properties["RGBA"][v] + temp[3] = state + self.G.vertex_properties["RGBA"][v] = temp + for e in self.G.edges(): + temp = self.G.edge_properties["RGBA"][e] + temp[3] = state + self.G.edge_properties["RGBA"][e] = temp + self.update_color_buffers() """ Maps a statistic of the vertices based on the size of the canvas to size of @@ -1121,19 +1155,33 @@ class GraphCanvas(scene.SceneCanvas): else: update_view() - """ - Handles the double click event that it responsible for path selection. - Generates paths our of consecutive paths out of the selected vertices. + Gets the path and formats it in terms of vertex-to-vertex + instead of source(obj)-to-source(obj) """ - def on_mouse_double_click(self, event): - + def get_path(self): + p = [] + for s in self.path: + for e in s.e_path: + temp = (int(e.source()), int(e.target())) + if (temp not in p): + p.append(temp) + + return p + + + def update_path(self, event): #Method to update the vertex buffer of the nodes in the graph view def update_vbo(self): self.vbo = gloo.VertexBuffer(self.data) self.program.bind(self.vbo) self.update() + def update_vertex_alpha(self, vertex, alpha): + temp = self.G.vertex_properties["RGBA"][vertex] + temp[3] = alpha + self.G.vertex_properties["RGBA"][vertex] = temp + #updates the path structure of the class #source and target are of type "source" defined in this class. def add_to_path(self, source, target): @@ -1141,16 +1189,25 @@ class GraphCanvas(scene.SceneCanvas): for v in range(1, len(vl)-1): if (self.G.vertex_properties["selection"][vl[v]] != 1.0): self.G.vertex_properties["selection"][vl[v]] = 2.0 + update_vertex_alpha(self, self.G.vertex(vl[v]), 1.0) self.data['a_selection'][int(vl[v])] = 2.0 source.v_path.append(int(vl[v])) for e in el: source.e_path.append(e) + temp = self.G.edge_properties["RGBA"][e] + temp[3] = 1.0 + self.G.edge_properties["RGBA"][e] = temp def remove_from_path(self, source): for v in source.v_path: self.G.vertex_properties["selection"][self.G.vertex(v)] = 0.0 + update_vertex_alpha(self,self.G.vertex(v), 0.5) self.data['a_selection'][v] = 0.0 + for e in source.e_path: + temp = self.G.edge_properties["RGBA"][e] + temp[3] = 0.0 + self.G.edge_properties["RGBA"][e] = temp source.clear_path() if (event.button == 1): @@ -1164,12 +1221,15 @@ class GraphCanvas(scene.SceneCanvas): self.pathing = True self.path.append(path_point(c_id)) self.data['a_selection'][c_id] = 1.0 - update_vbo(self) + self.make_all_transparent(0.5) + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) + self.update_color_buffers() print("I turned on the first node") else: #If the node is selected already, unselect it and remove from path the last occurance in the path if(self.G.vertex_properties["selection"][self.G.vertex(c_id)] == 1.0): self.G.vertex_properties["selection"][self.G.vertex(c_id)] = 0.0 + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) self.data['a_selection'][c_id] = 0.0 s_id = self.path.index(path_point(c_id)) if(s_id == 0): @@ -1187,21 +1247,24 @@ class GraphCanvas(scene.SceneCanvas): if(path_point(c_id) not in self.path): self.path.append(path_point(c_id)) self.G.vertex_properties["selection"][self.G.vertex(c_id)] = 1.0 + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) self.data['a_selection'][c_id] = 1.0 #if the source is not LAST in the path, add it. elif(self.path[len(self.path)-1] != path_point(c_id)): self.path.append(path_point(c_id)) self.G.vertex_properties["selection"][self.G.vertex(c_id)] = 1.0 + update_vertex_alpha(self, self.G.vertex(c_id), 1.0) self.data['a_selection'][c_id] = 1.0 print("I turned on a node") if(len(self.path) >= 1): for i in range(len(self.path)-1): add_to_path(self, self.path[i], self.path[i+1]) - update_vbo(self) + self.update_color_buffers() #THIS IS WHERE I LEFT IT OFF. if(np.sum(self.G.vertex_properties["selection"].get_array()) == 0): self.pathing = False - update_vbo(self) + self.make_all_transparent(1.0) + self.update_color_buffers() @@ -1209,6 +1272,14 @@ class GraphCanvas(scene.SceneCanvas): # self.G.vertex_properties["selection"][self.G.vertex(c_id)] == False print("clicked on: ", c_id, " ", self.path) + + """ + Handles the double click event that it responsible for path selection. + Generates paths our of consecutive paths out of the selected vertices. + """ + def on_mouse_double_click(self, event): + n=1 + """ Resets the variables that are used during the pressdown and move events """ diff --git a/GraphWidget.py b/GraphWidget.py index 2026f84..c9dacdb 100644 --- a/GraphWidget.py +++ b/GraphWidget.py @@ -142,7 +142,8 @@ class GraphWidget(QtGui.QWidget): Pass-through function. """ def on_mouse_double_click(self, event): - self.select.emit(self.canvas.path) + self.canvas.update_path(event) + self.select.emit(self.canvas.get_path()) """ Handles the mouse release event. diff --git a/TubeCanvas.py b/TubeCanvas.py index 2058740..60ffac1 100644 --- a/TubeCanvas.py +++ b/TubeCanvas.py @@ -11,7 +11,8 @@ Created on Mon Aug 5 15:56:47 2019 """ from vispy import gloo, scene -from vispy.gloo import set_viewport, set_state, clear, set_blend_color +from vispy.gloo import set_viewport, set_state, clear, set_blend_color, context +from vispy.gloo import gl from vispy.util.transforms import perspective, translate, rotate, scale import vispy.gloo.gl as glcore from vispy.util.quaternion import Quaternion @@ -40,6 +41,7 @@ class TubeDraw(scene.SceneCanvas): #unfreeze the drawing area to allow for dynamic drawing and interaction self.unfreeze() self.edge_dict = {} + self.select = False #generate dummy buffers for the meshes self.program = gloo.Program(VERT_SHADER, FRAG_SHADER) self.cylinder_data = np.zeros(5*5, dtype=[('a_position', np.float32, 3), @@ -59,7 +61,7 @@ class TubeDraw(scene.SceneCanvas): #set_state(clear_color='white', depth_test=True, blend=True, # blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('less'), cull_face='back') set_state(clear_color='white', depth_test=True, blend=True, - blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal')) + blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal'), cull_face='back') #set_blend_color(color='black') #set_state('translucent') self.program['u_LightPos'] = [0., 0., -1000.] @@ -72,6 +74,7 @@ class TubeDraw(scene.SceneCanvas): ##### prototype ##### #Set the visualization matrices + self.program['u_selection'] = 0.0 self.program['u_eye'] = self.camera self.program['u_up'] = self.up self.program['u_target'] = np.asarray([0., 0., 0.], dtype=np.float32) @@ -143,6 +146,12 @@ class TubeDraw(scene.SceneCanvas): def on_draw(self, event): clear(color='white', depth=True) gloo.set_clear_color('white') + if self.select: + set_state(clear_color='white', depth_test=True, blend=True, + blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('always'), cull_face='back') + else: + set_state(clear_color='white', depth_test=True, blend=True, + blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal'), cull_face='back') self.program.draw('triangles', self.triangles) self.projection = perspective(90.0, self.physical_size[0]/self.physical_size[1], 1.0, 1000.0) self.program['u_projection'] = self.projection @@ -158,7 +167,7 @@ class TubeDraw(scene.SceneCanvas): self.cylinder_data = np.zeros(num_pts*num_sides, dtype=[('a_position', np.float32, 3), ('a_normal', np.float32, 3), ('a_fg_color', np.float32, 4), - #('a_linewidth', np.float32, 1), + ('a_selection', np.float32, 1), ]) self.triangle_data = np.random.randint(size=(num_tri, 3), low=0, high=(G.num_edges()-1)).astype(np.uint32) @@ -288,6 +297,7 @@ class TubeDraw(scene.SceneCanvas): circle_pts_data = circle_pts.reshape((pts.shape[0]*num_sides, 3)) self.cylinder_data['a_position'][index:(pts.shape[0]*num_sides+index)] = circle_pts_data self.cylinder_data['a_fg_color'][index:(pts.shape[0]*num_sides+index)] = color + self.cylinder_data['a_selection'][index:(pts.shape[0]*num_sides+index)] = 0.0 #generate the normals data structure pts_normals = circle_pts.copy() for p in range(pts.shape[0]): @@ -299,7 +309,7 @@ class TubeDraw(scene.SceneCanvas): pts_normals.reshape((pts.shape[0]*num_sides, 3)) index += pts.shape[0]*num_sides - self.edge_dict[(e.source(), e.target())] = (index-pts.shape[0]*num_sides, index) + self.edge_dict[(int(e.source()), int(e.target()))] = (index-pts.shape[0]*num_sides, index) #Add the caps for each of the endpoints. @@ -333,6 +343,37 @@ class TubeDraw(scene.SceneCanvas): i+=1 #create the data. + def select_edges(self, edges): + #gloo.context.set_current_canvas(gloo.context.get_current_canvas()) + if len(edges) > 0: + self.select = True + #gloo.set_depth_func('always') + #clear(color='white', depth=True) + #gl.GL_DEPTH_FUNC('always') + #print(gloo.wrappers.get_gl_configuration()) + self.program['u_selection'] = 1.0 + for e in edges: + if e in self.edge_dict: + idx = self.edge_dict[e] + #print(self.canvas.edge_dict[e]) + elif (e[1], e[0]) in self.edge_dict: + idx = self.edge_dict[(e[1],e[0])] + else: + print("WHAT THE FUCK HAPPENED") + self.cylinder_data["a_selection"][idx[0]:idx[1]] = 1.0 + self.vbo = gloo.VertexBuffer(self.cylinder_data) + self.program.bind(self.vbo) + #self.update() + else: + self.program['u_selection'] = 0.0 + self.select = False + #set_state(clear_color='white', depth_test=True, blend=True, + # blend_func=('src_alpha', 'one_minus_src_alpha'), depth_func = ('lequal')) + #gloo.set_depth_func('lequal') + #clear(color='white', depth=True) + #print(gloo.wrappers.get_gl_configuration()) + self.update() + #print(self.canvas.edge_dict[(e[1], e[0])]) #Handles the mouse wheel event, i.e., zoom def on_mouse_wheel(self, event): # self.scale[0] = self.scale[0] + self.scale[0]*event.delta[1]*0.05 diff --git a/TubeWidget.py b/TubeWidget.py index a0ee55b..b1df505 100644 --- a/TubeWidget.py +++ b/TubeWidget.py @@ -47,7 +47,7 @@ class TubeWidget(QtGui.QWidget): if self.down: self.sendCameraInfo() - #Handles the mouse press event + #Handles the mouse press events def on_mouse_press(self, event): self.down = True n = 3 @@ -72,6 +72,12 @@ class TubeWidget(QtGui.QWidget): """ @QtCore.pyqtSlot(list) def select(self, x): + self.canvas.select_edges(x) +# for e in x: +# if e in self.canvas.edge_dict: +# print(self.canvas.edge_dict[e]) +# elif (e[1], e[0]) in self.canvas.edge_dict: +# print(self.canvas.edge_dict[(e[1], e[0])]) print("got signal", x) """ diff --git a/tube_shaders.py b/tube_shaders.py index 642eee3..85bf562 100644 --- a/tube_shaders.py +++ b/tube_shaders.py @@ -15,6 +15,7 @@ uniform vec3 u_LightPost; uniform mat4 u_model; //uniform mat4 u_view; uniform mat4 u_projection; +uniform float u_selection; uniform vec3 u_eye; uniform vec3 u_up; @@ -25,6 +26,7 @@ uniform vec3 u_target; attribute vec3 a_position; attribute vec3 a_normal; attribute vec4 a_fg_color; +attribute float a_selection; // Varyings // ------------------------------------ @@ -33,6 +35,7 @@ varying vec4 v_fg_color; varying vec3 v_position; varying mat4 u_view; varying vec3 vt_position; +varying float v_selection; // Functions @@ -50,6 +53,7 @@ void main (void) { v_position = vec3(MV*vec4(a_position, 1.0)); vt_position = vec3(a_position); v_fg_color = a_fg_color; + v_selection = a_selection; gl_Position = MVP * vec4(a_position, 1.0); } @@ -87,6 +91,7 @@ uniform vec3 u_LightPos; uniform mat4 u_model; //uniform mat4 u_view; uniform mat4 u_projection; +uniform float u_selection; uniform vec3 u_eye; uniform vec3 u_up; @@ -99,6 +104,7 @@ varying vec4 v_fg_color; varying vec3 v_position; varying mat4 u_view; varying vec3 vt_position; +varying float v_selection; float new_alpha(); float set_view(); @@ -128,6 +134,9 @@ void main() vec4 color = (ambient_color + diffuse)*v_fg_color; float alpha = new_alpha(); + if(u_selection > 0.0) + alpha = max(alpha*v_selection, 0.00); + //alpha = max(alpha * v_selection, 0.05); //if(alpha == 1.0) // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // gl_FragColor = vec4(color.rgb, alpha); -- libgit2 0.21.4