Changeset 8344:3176a3c6e1df in orange
 Timestamp:
 07/01/11 00:17:13 (3 years ago)
 Branch:
 default
 Convert:
 87186325aa999dcda66ebd99d779cab1d8395ec3
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

orange/OrangeWidgets/OWGraph3D.py
r8342 r8344 1 """ 2 """ 3 1 4 from PyQt4.QtCore import * 2 5 from PyQt4.QtGui import * … … 7 10 from OpenGL.GL import * 8 11 from OpenGL.GLU import * 12 from ctypes import byref, c_char_p, c_int, create_string_buffer 9 13 import sys 10 14 import numpy 11 15 from math import sin, cos 12 16 17 # Import undefined functions. 18 try: 19 from OpenGL import platform 20 gl = platform.OpenGL 21 except ImportError: 22 try: 23 gl = cdll.LoadLibrary('libGL.so') 24 except OSError: 25 from ctypes.util import find_library 26 path = find_library('OpenGL') 27 gl = cdll.LoadLibrary(path) 28 29 glCreateProgram = gl.glCreateProgram 30 glCreateShader = gl.glCreateShader 31 glShaderSource = gl.glShaderSource 32 glCompileShader = gl.glCompileShader 33 glGetShaderiv = gl.glGetShaderiv 34 glDeleteShader = gl.glDeleteShader 35 36 13 37 def normalize(vec): 14 38 return vec / numpy.sqrt(numpy.sum(vec** 2)) 39 15 40 16 41 class OWGraph3D(QtOpenGL.QGLWidget): … … 20 45 self.minx = self.miny = self.minz = 0 21 46 self.maxx = self.maxy = self.maxz = 0 22 self.b_box = [numpy.array([0, 0, 0]), numpy.array([0, 0, 0])] 23 self.camera = numpy.array([0.6, 0.8, 0]) # Spherical unit vector around the center. This is where camera is looking from. 24 self.center = numpy.array([0, 0, 0]) # Camera is looking into this point. 25 26 # Try to use displays lists for performance. 27 self.sphere_dl = glGenLists(1) # TODO: why does this fail? 28 if self.sphere_dl != 0: 29 gluQuadric = gluNewQuadric() 30 glNewList(self.sphere_dl, GL_COMPILE) 31 gluSphere(gluQuadric, 1, 10, 10) 32 glEndList() 33 gluDeleteQuadric(gluQuadric) 34 35 # TODO: other shapes 47 self.b_box = [numpy.array([0, 0, 0]), numpy.array([0, 0, 0])] 48 self.camera = numpy.array([0.6, 0.8, 0]) # Location on a unit sphere around the center. This is where camera is looking from. 49 self.center = numpy.array([0, 0, 0]) 50 36 51 # TODO: move to center shortcut (maybe a GUI element?) 37 52 38 self.yaw = self.pitch = 0 53 self.yaw = self.pitch = 0. 39 54 self.rotation_factor = 100. 40 55 self.zoom_factor = 100. 41 self.zoom = 10 56 self.zoom = 10. 42 57 self.move_factor = 100. 43 self.mouse_pos = [100,100] # TODO: get real mouse position, calculate camera, fix the initial jump 44 self.updateAxes() 45 46 self.axisTitleFont = QFont('Helvetica', 10, QFont.Bold) 47 self.ticksFont = QFont('Helvetica', 9) 48 self.XaxisTitle = '' 49 self.YaxisTitle = '' 50 self.ZaxisTitle = '' 58 self.mouse_pos = [100, 100] # TODO: get real mouse position, calculate camera, fix the initial jump 59 self.update_axes() 60 61 self.axis_title_font = QFont('Helvetica', 10, QFont.Bold) 62 self.ticks_font = QFont('Helvetica', 9) 63 self.x_axis_title = '' 64 self.y_axis_title = '' 65 self.z_axis_title = '' 66 67 self.color_shader = glCreateProgram() 68 vertex_shader = glCreateShader(GL_VERTEX_SHADER) 69 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER) 70 71 vertex_shader_source = ''' 72 attribute vec4 position; 73 attribute vec4 color; 74 75 uniform mat4 projection; 76 uniform mat4 modelview; 77 78 varying vec4 var_color; 79 80 void main(void) { 81 gl_Position = projection * modelview * position; 82 var_color = color; 83 } 84 ''' 85 86 fragment_shader_source = ''' 87 varying vec4 var_color; 88 89 void main(void) { 90 gl_FragColor = var_color; 91 } 92 ''' 93 94 vertex_shader_source = c_char_p(vertex_shader_source) 95 fragment_shader_source = c_char_p(fragment_shader_source) 96 97 def print_log(shader): 98 length = c_int() 99 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, byref(length)) 100 101 if length.value > 0: 102 log = create_string_buffer(length.value) 103 glGetShaderInfoLog(shader, length, byref(length), log) 104 print(log.value) 105 106 length = c_int(1) 107 for shader, source in zip([vertex_shader, fragment_shader], [vertex_shader_source, fragment_shader_source]): 108 glShaderSource(shader, 1, byref(source), byref(length)); 109 glCompileShader(shader) 110 status = c_int() 111 glGetShaderiv(shader, GL_COMPILE_STATUS, byref(status)) 112 if not status.value: 113 print('Failed to compile shader:') 114 print_log(shader) 115 glDeleteShader(shader) 116 117 print('Shaders compiled!') 118 51 119 52 120 def initializeGL(self): … … 63 131 glLoadIdentity() 64 132 65 def resizeGL(self, w, h): 66 glViewport(0, 0, w, h) 133 134 def resizeGL(self, width, height): 135 glViewport(0, 0, width, height) 67 136 glMatrixMode(GL_PROJECTION) 68 137 glLoadIdentity() 69 if h == 0:138 if height == 0: 70 139 aspect = 1 71 140 else: 72 aspect = float(w )/float(h)141 aspect = float(width) / height 73 142 gluPerspective(30.0, aspect, 0.1, 100) 74 143 glMatrixMode(GL_MODELVIEW) 75 144 glLoadIdentity() 145 76 146 77 147 def paintGL(self): … … 87 157 self.center[2], 88 158 0, 1, 0) 89 self.paint Axes()159 self.paint_axes() 90 160 91 161 glEnable(GL_CULL_FACE) 92 162 glCullFace(GL_BACK) 93 94 if self.sphere_dl == 0: 95 gluQuadric = gluNewQuadric() 96 for cmd, (array, colors, sizes) in self.commands: 97 for (x,y,z), (r, g, b, a), size in zip(array, colors, sizes): 98 glPushMatrix() 99 glTranslatef(x, y, z) 100 glColor4f(r, g, b, a) 101 scale = self.normalSize * size 102 glScalef(scale, scale, scale) 103 if self.sphere_dl == 0: 104 gluSphere(gluQuadric, 1, 10, 10) 105 else: 106 glCallList(self.sphere_dl) 107 glPopMatrix() 108 if self.sphere_dl == 0: 109 gluDeleteQuadric(gluQuadric) 163 164 for cmd, vertex_buffer in self.commands: 165 self.color_shader.bind() 166 self.color_shader.setAttributeBuffer(0, GL_FLOAT, 0, 4, 8*4) 167 self.color_shader.setAttributeBuffer(1, GL_FLOAT, 4*4, 4, 8*4) 168 self.color_shader.enableAttributeArray(0) 169 self.color_shader.enableAttributeArray(1) 170 171 glDrawArrays(GL_TRIANGLES, 0, vertex_buffer.num_vertices); 172 173 self.color_shader.disableAttributeArray(0) 174 self.color_shader.disableAttributeArray(1) 175 glUseProgram(0) 110 176 111 177 glDisable(GL_CULL_FACE) 112 178 113 def set XaxisTitle(self, title):114 self. XaxisTitle = title179 def set_x_axis_title(self, title): 180 self.x_axis_title = title 115 181 self.updateGL() 116 182 117 def set YaxisTitle(self, title):118 self. YaxisTitle = title183 def set_y_axis_title(self, title): 184 self.y_axis_title = title 119 185 self.updateGL() 120 186 121 def set ZaxisTitle(self, title):122 self. ZaxisTitle = title187 def set_z_axis_title(self, title): 188 self.z_axis_title = title 123 189 self.updateGL() 124 190 125 def paint Axes(self):191 def paint_axes(self): 126 192 glDisable(GL_CULL_FACE) 127 193 glColor4f(1,1,1,1) … … 138 204 139 205 ac = (self.x_axis[0] + self.x_axis[1]) / 2. 140 self.renderText(ac[0], ac[1]0.2, ac[2]0.2, self.XaxisTitle, font=self.axisTitleFont) 206 self.renderText(ac[0], ac[1]0.2, ac[2]0.2, self.x_axis_title, font=self.axis_title_font) 207 208 glPushMatrix(); 141 209 ac = (self.y_axis[0] + self.y_axis[1]) / 2. 142 self.renderText(ac[0], ac[1]0.2, ac[2]0.2, self.YaxisTitle, font=self.axisTitleFont) 210 glTranslatef(ac[0], ac[1]0.2, ac[2]0.2) 211 glRotatef(90, 1,0,0); 212 #self.renderText(ac[0], ac[1]0.2, ac[2]0.2, self.YaxisTitle, font=self.axisTitleFont) 213 self.renderText(0,0,0, self.y_axis_title, font=self.axis_title_font) 214 glPopMatrix(); 215 143 216 ac = (self.z_axis[0] + self.z_axis[1]) / 2. 144 self.renderText(ac[0], ac[1]0.2, ac[2]0.2, self. ZaxisTitle, font=self.axisTitleFont)217 self.renderText(ac[0], ac[1]0.2, ac[2]0.2, self.z_axis_title, font=self.axis_title_font) 145 218 146 219 outwards = normalize(self.x_axis[0]  bb_center) … … 150 223 glColor4f(1,1,1,1) 151 224 152 def paint Grid(planeQuad, sub=20):153 P11, P12, P22, P21 = numpy.asarray(plane Quad)225 def paint_grid(plane_quad, sub=20): 226 P11, P12, P22, P21 = numpy.asarray(plane_quad) 154 227 Dx = numpy.linspace(0.0, 1.0, num=sub) 155 228 P1vecH = P12  P11 … … 170 243 glEnd() 171 244 172 def paint Quad(planeQuad):173 P11, P12, P21, P22 = numpy.asarray(plane Quad)245 def paint_quad(plane_quad): 246 P11, P12, P21, P22 = numpy.asarray(plane_quad) 174 247 glBegin(GL_QUADS) 175 248 glVertex3f(*P11) … … 179 252 glEnd() 180 253 181 color Plane = [0.5, 0.5, 0.5, 0.5]182 color Grid = [0.3, 0.3, 0.3, 1.0]183 184 def paint Plain(planeQuad):254 color_plane = [0.5, 0.5, 0.5, 0.5] 255 color_grid = [0.3, 0.3, 0.3, 1.0] 256 257 def paint_plane(plane_quad): 185 258 #glColor4f(*colorPlane) 186 259 #paintQuad(planeQuad) 187 glColor4f(*color Grid)188 paint Grid(planeQuad)189 190 def normal FromPoints(P1, P2, P3):260 glColor4f(*color_grid) 261 paint_grid(plane_quad) 262 263 def normal_from_points(P1, P2, P3): 191 264 V1 = P2  P1 192 265 V2 = P3  P1 193 266 return normalize(numpy.cross(V1, V2)) 194 267 195 def draw GridVisible(planeQuad, ccw=False):196 normal = normal FromPoints(*planeQuad[:3])197 cam InSpace = numpy.array([268 def draw_grid_visible(plane_quad, ccw=False): 269 normal = normal_from_points(*plane_quad[:3]) 270 cam_in_space = numpy.array([ 198 271 self.center[0] + self.camera[0]*self.zoom, 199 272 self.center[1] + self.camera[1]*self.zoom, 200 273 self.center[2] + self.camera[2]*self.zoom 201 274 ]) 202 camera Vector = normalize(planeQuad[0]  camInSpace)203 cos = numpy.dot(normal, camera Vector) * (1 if ccw else 1)275 camera_vector = normalize(plane_quad[0]  cam_in_space) 276 cos = numpy.dot(normal, camera_vector) * (1 if ccw else 1) 204 277 if cos > 0: 205 paint Plain(planeQuad)206 207 draw GridVisible(self.axisPlaneXY)208 draw GridVisible(self.axisPlaneYZ)209 draw GridVisible(self.axisPlaneXZ)210 draw GridVisible(self.axisPlaneXYBack)211 draw GridVisible(self.axisPlaneYZRight)212 draw GridVisible(self.axisPLaneXZTop)278 paint_plane(plane_quad) 279 280 draw_grid_visible(self.axis_plane_xy) 281 draw_grid_visible(self.axis_plane_yz) 282 draw_grid_visible(self.axis_plane_xz) 283 draw_grid_visible(self.axis_plane_xy_back) 284 draw_grid_visible(self.axis_plane_yz_right) 285 draw_grid_visible(self.axis_plane_xz_top) 213 286 214 287 glEnable(GL_CULL_FACE) 215 288 216 def update Axes(self):289 def update_axes(self): 217 290 x_axis = [[self.minx, self.miny, self.minz], 218 291 [self.maxx, self.miny, self.minz]] … … 239 312 H = D + unit_z 240 313 241 self.axis PlaneXY= [A, B, C, D]242 self.axis PlaneYZ= [A, D, H, E]243 self.axis PlaneXZ= [D, C, G, H]244 245 self.axis PlaneXYBack = [H, G, F, E]246 self.axis PlaneYZRight = [B, F, G, C]247 self.axis PLaneXZTop = [E, F, B, A]248 249 def scatter(self, X, Y, Z =0, c="b", s=20, **kwargs):314 self.axis_plane_xy = [A, B, C, D] 315 self.axis_plane_yz = [A, D, H, E] 316 self.axis_plane_xz = [D, C, G, H] 317 318 self.axis_plane_xy_back = [H, G, F, E] 319 self.axis_plane_yz_right = [B, F, G, C] 320 self.axis_plane_xz_top = [E, F, B, A] 321 322 def scatter(self, X, Y, Z, c="b", s=20, **kwargs): 250 323 array = [[x, y, z] for x,y,z in zip(X, Y, Z)] 251 324 if isinstance(c, str): 252 color Dict ={"r": [1.0, 0.0, 0.0, 1.0],253 "g": [0.0, 1.0, 0.0, 1.0],254 "b": [0.0, 0.0, 1.0, 1.0]}325 color_map = {"r": [1.0, 0.0, 0.0, 1.0], 326 "g": [0.0, 1.0, 0.0, 1.0], 327 "b": [0.0, 0.0, 1.0, 1.0]} 255 328 default = [0.0, 0.0, 1.0, 1.0] 256 colors = [color Dict.get(c, default) for iin array]329 colors = [color_map.get(c, default) for _ in array] 257 330 else: 258 331 colors = c … … 261 334 s = [s for _ in array] 262 335 263 self.commands.append(("scatter", (array, colors, s)))264 336 max, min = numpy.max(array, axis=0), numpy.min(array, axis=0) 265 337 self.b_box = [max, min] … … 267 339 self.maxx, self.maxy, self.maxz = max 268 340 self.center = (min + max) / 2 269 self.normalSize = numpy.max(self.center  self.b_box[1]) / 100. 270 self.updateAxes() 341 self.normal_size = numpy.max(self.center  self.b_box[1]) / 100. 342 343 vertex_buffer = QtOpenGL.QGLBuffer(QtOpenGL.QGLBuffer.VertexBuffer) 344 if vertex_buffer.create() == False: 345 print('Warning: vertex buffers not supported') 346 return 347 348 vertex_buffer.bind() 349 vertex_buffer.setUsagePattern(QtOpenGL.QGLBuffer.StaticDraw) 350 351 vertices = [] 352 for (x,y,z), (r,g,b,a), size in zip(array, colors, s): 353 vertices.extend([xsize*self.normal_size,y,z, r,g,b,a]) 354 vertices.extend([x+size*self.normal_size,y,z, r,g,b,a]) 355 vertices.extend([x,y+size*self.normal_size,z, r,g,b,a]) 356 357 vertex_buffer.allocate((GLfloat * len(vertices))(vertices), len(vertices)*4) 358 359 self.commands.append(("scatter", (vertex_buffer))) 360 self.update_axes() 271 361 self.updateGL() 272 362 … … 296 386 def wheelEvent(self, event): 297 387 if event.orientation() == Qt.Vertical: 298 self.zoom += event.delta() / self.zoom_factor388 self.zoom = event.delta() / self.zoom_factor 299 389 if self.zoom < 2: 300 390 self.zoom = 2 … … 310 400 311 401 from random import random 312 rand = lambda :random()  0.5402 rand = lambda: random()  0.5 313 403 N = 100 314 404 data = orange.ExampleTable("../doc/datasets/iris.tab")
Note: See TracChangeset
for help on using the changeset viewer.