def _build_anchor_grid(self): lines = [] num_parts = 30 anchors = numpy.array([a[:3] for a in self.anchor_data]) for anchor in self.anchor_data: a0 = numpy.array(anchor[:3]) neighbours = anchors.copy() neighbours = [(((n - a0)**2).sum(), n) for n in neighbours] neighbours.sort(key=lambda e: e[0]) for i in range(1, min(len(anchors), 4)): difference = neighbours[i][1] - a0 for j in range(num_parts): lines.extend( normalize(a0 + difference * j / float(num_parts))) lines.extend( normalize(a0 + difference * (j + 1) / float(num_parts))) self._grid_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)])
def _build_anchor_grid(self): lines = [] num_parts = 30 anchors = numpy.array([a[:3] for a in self.anchor_data]) for anchor in self.anchor_data: a0 = numpy.array(anchor[:3]) neighbours = anchors.copy() neighbours = [(((n-a0)**2).sum(), n) for n in neighbours] neighbours.sort(key=lambda e: e[0]) for i in range(1, min(len(anchors), 4)): difference = neighbours[i][1]-a0 for j in range(num_parts): lines.extend(normalize(a0 + difference*j/float(num_parts))) lines.extend(normalize(a0 + difference*(j+1)/float(num_parts))) self._grid_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)])
def setData(self, data, subset_data=None, **args): OWLinProj3DPlot.set_data(self, data, subset_data, **args) # No need to generate backgroud grid sphere geometry more than once if hasattr(self, '_sphere_buffer'): return self.makeCurrent() lines = [] num_parts = 30 num_horizontal_rings = 20 num_vertical_rings = 24 r = 1. for i in range(num_horizontal_rings): z_offset = float(i) * 2 / num_horizontal_rings - 1. r = (1. - z_offset**2)**0.5 for j in range(num_parts): angle_z_0 = float(j) * 2 * pi / num_parts angle_z_1 = float(j+1) * 2 * pi / num_parts lines.extend([sin(angle_z_0)*r, z_offset, cos(angle_z_0)*r, sin(angle_z_1)*r, z_offset, cos(angle_z_1)*r]) for i in range(num_vertical_rings): r = 1. phi = 2 * i * pi / num_vertical_rings for j in range(num_parts): theta_0 = (j) * pi / num_parts theta_1 = (j+1) * pi / num_parts lines.extend([sin(theta_0)*cos(phi)*r, cos(theta_0)*r, sin(theta_0)*sin(phi)*r, sin(theta_1)*cos(phi)*r, cos(theta_1)*r, sin(theta_1)*sin(phi)*r]) self._sphere_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)]) self._sphere_shader = QtOpenGL.QGLShaderProgram() self._sphere_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'sphere.vs')) self._sphere_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'sphere.fs')) self._sphere_shader.bindAttributeLocation('position', 0) if not self._sphere_shader.link(): print('Failed to link sphere shader!') ## Cones cone_data = parse_obj('cone_hq.obj') vertices = [] for v0, v1, v2, n0, n1, n2 in cone_data: vertices.extend([v0[0],v0[1],v0[2], n0[0],n0[1],n0[2], v1[0],v1[1],v1[2], n1[0],n1[1],n1[2], v2[0],v2[1],v2[2], n2[0],n2[1],n2[2]]) self._cone_buffer = VertexBuffer(numpy.array(vertices, numpy.float32), [(3, GL_FLOAT), (3, GL_FLOAT)]) self._cone_shader = QtOpenGL.QGLShaderProgram() self._cone_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'cone.vs')) self._cone_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'cone.fs')) self._cone_shader.bindAttributeLocation('position', 0) self._cone_shader.bindAttributeLocation('normal', 1) if not self._cone_shader.link(): print('Failed to link cone shader!') ## Another dummy shader (anchor grid) self._grid_shader = QtOpenGL.QGLShaderProgram() self._grid_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'grid.vs')) self._grid_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'grid.fs')) self._grid_shader.bindAttributeLocation('position', 0) if not self._grid_shader.link(): print('Failed to link grid shader!') self.before_draw_callback = self.before_draw
class OWSphereviz3DPlot(OWLinProj3DPlot): def __init__(self, widget, parent=None, name='SpherevizPlot'): OWLinProj3DPlot.__init__(self, widget, parent, name) self.camera_angle = 90 self.camera_type = 0 # Default, center, attribute self.show_anchor_grid = False def _build_anchor_grid(self): lines = [] num_parts = 30 anchors = numpy.array([a[:3] for a in self.anchor_data]) for anchor in self.anchor_data: a0 = numpy.array(anchor[:3]) neighbours = anchors.copy() neighbours = [(((n-a0)**2).sum(), n) for n in neighbours] neighbours.sort(key=lambda e: e[0]) for i in range(1, min(len(anchors), 4)): difference = neighbours[i][1]-a0 for j in range(num_parts): lines.extend(normalize(a0 + difference*j/float(num_parts))) lines.extend(normalize(a0 + difference*(j+1)/float(num_parts))) self._grid_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)]) def update_data(self, labels=None, setAnchors=0, **args): OWLinProj3DPlot.updateData(self, labels, setAnchors, **args) if self.anchor_data: self._build_anchor_grid() self.updateGL() updateData = update_data def setData(self, data, subset_data=None, **args): OWLinProj3DPlot.set_data(self, data, subset_data, **args) # No need to generate backgroud grid sphere geometry more than once if hasattr(self, '_sphere_buffer'): return self.makeCurrent() lines = [] num_parts = 30 num_horizontal_rings = 20 num_vertical_rings = 24 r = 1. for i in range(num_horizontal_rings): z_offset = float(i) * 2 / num_horizontal_rings - 1. r = (1. - z_offset**2)**0.5 for j in range(num_parts): angle_z_0 = float(j) * 2 * pi / num_parts angle_z_1 = float(j+1) * 2 * pi / num_parts lines.extend([sin(angle_z_0)*r, z_offset, cos(angle_z_0)*r, sin(angle_z_1)*r, z_offset, cos(angle_z_1)*r]) for i in range(num_vertical_rings): r = 1. phi = 2 * i * pi / num_vertical_rings for j in range(num_parts): theta_0 = (j) * pi / num_parts theta_1 = (j+1) * pi / num_parts lines.extend([sin(theta_0)*cos(phi)*r, cos(theta_0)*r, sin(theta_0)*sin(phi)*r, sin(theta_1)*cos(phi)*r, cos(theta_1)*r, sin(theta_1)*sin(phi)*r]) self._sphere_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)]) self._sphere_shader = QtOpenGL.QGLShaderProgram() self._sphere_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'sphere.vs')) self._sphere_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'sphere.fs')) self._sphere_shader.bindAttributeLocation('position', 0) if not self._sphere_shader.link(): print('Failed to link sphere shader!') ## Cones cone_data = parse_obj('cone_hq.obj') vertices = [] for v0, v1, v2, n0, n1, n2 in cone_data: vertices.extend([v0[0],v0[1],v0[2], n0[0],n0[1],n0[2], v1[0],v1[1],v1[2], n1[0],n1[1],n1[2], v2[0],v2[1],v2[2], n2[0],n2[1],n2[2]]) self._cone_buffer = VertexBuffer(numpy.array(vertices, numpy.float32), [(3, GL_FLOAT), (3, GL_FLOAT)]) self._cone_shader = QtOpenGL.QGLShaderProgram() self._cone_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'cone.vs')) self._cone_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'cone.fs')) self._cone_shader.bindAttributeLocation('position', 0) self._cone_shader.bindAttributeLocation('normal', 1) if not self._cone_shader.link(): print('Failed to link cone shader!') ## Another dummy shader (anchor grid) self._grid_shader = QtOpenGL.QGLShaderProgram() self._grid_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'grid.vs')) self._grid_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'grid.fs')) self._grid_shader.bindAttributeLocation('position', 0) if not self._grid_shader.link(): print('Failed to link grid shader!') self.before_draw_callback = self.before_draw def update_camera_type(self): if self.camera_type == 2: self._random_anchor = choice(self.anchor_data) self.update() def before_draw(self): view = QMatrix4x4() if self.camera_type == 2: view.lookAt( QVector3D(self._random_anchor[0], self._random_anchor[1], self._random_anchor[2]), self.camera, QVector3D(0, 1, 0)) projection = QMatrix4x4() projection.perspective(self.camera_angle, float(self.width()) / self.height(), 0.01, 5.) self.projection = projection elif self.camera_type == 1: view.lookAt( QVector3D(0, 0, 0), self.camera * self.camera_distance, QVector3D(0, 1, 0)) projection = QMatrix4x4() projection.perspective(self.camera_angle, float(self.width()) / self.height(), 0.01, 5.) self.projection = projection else: view.lookAt( self.camera * self.camera_distance, QVector3D(0, 0, 0), QVector3D(0, 1, 0)) self.view = view self._draw_sphere() # Qt text rendering classes still use deprecated OpenGL functionality glEnable(GL_DEPTH_TEST) glDisable(GL_BLEND) glMatrixMode(GL_PROJECTION) glLoadIdentity() glMultMatrixd(numpy.array(self.projection.data(), dtype=float)) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glMultMatrixd(numpy.array(self.view.data(), dtype=float)) glMultMatrixd(numpy.array(self.model.data(), dtype=float)) if self.showAnchors: for anchor in self.anchor_data: x, y, z, label = anchor direction = QVector3D(x, y, z) up = QVector3D(0, 1, 0) right = QVector3D.crossProduct(direction, up).normalized() up = QVector3D.crossProduct(right, direction) rotation = QMatrix4x4() rotation.setColumn(0, QVector4D(right, 0)) rotation.setColumn(1, QVector4D(up, 0)) rotation.setColumn(2, QVector4D(direction, 0)) model = QMatrix4x4() model.translate(x, y, z) model = model * rotation model.rotate(-90, 1, 0, 0) model.translate(0, -0.05, 0) model.scale(0.02, 0.02, 0.02) self._cone_shader.bind() self._cone_shader.setUniformValue('projection', self.projection) self._cone_shader.setUniformValue('modelview', self.view * model) self._cone_buffer.draw() self._cone_shader.release() self.qglColor(self._theme.axis_values_color) self.renderText(x*1.2, y*1.2, z*1.2, label) if self.anchor_data and not hasattr(self, '_grid_buffer'): self._build_anchor_grid() # Draw grid between anchors if self.show_anchor_grid: self._grid_shader.bind() self._grid_shader.setUniformValue('projection', self.projection) self._grid_shader.setUniformValue('modelview', self.view * self.model) self._grid_shader.setUniformValue('color', self._theme.axis_color) self._grid_buffer.draw(GL_LINES) self._grid_shader.release() self._draw_value_lines() def _draw_sphere(self): glDisable(GL_DEPTH_TEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) self._sphere_shader.bind() self._sphere_shader.setUniformValue('projection', self.projection) self._sphere_shader.setUniformValue('modelview', self.view * self.model) self._sphere_shader.setUniformValue('cam_position', self.camera * self.camera_distance) self._sphere_shader.setUniformValue('use_transparency', self.camera_type == 0) self._sphere_buffer.draw(GL_LINES) self._sphere_shader.release() def mouseMoveEvent(self, event): self.invert_mouse_x = self.camera_type != 0 OWLinProj3DPlot.mouseMoveEvent(self, event)
def updateData(self, labels=None, setAnchors=0, **args): self.clear() self.clear_plot_transformations() if labels == None: labels = [anchor[3] for anchor in self.anchor_data] if not self.have_data or len(labels) < 3: self.anchor_data = [] self.update() return if setAnchors or (args.has_key('XAnchors') and args.has_key('YAnchors') and args.has_key('ZAnchors')): self.setAnchors(args.get('XAnchors'), args.get('YAnchors'), args.get('ZAnchors'), labels) indices = [ self.attribute_name_index[anchor[3]] for anchor in self.anchor_data ] valid_data = self.getValidList(indices) trans_proj_data = self.create_projection_as_numeric_array( indices, validData=valid_data, scaleFactor=1.0, normalize=self.normalize_examples, jitterSize=-1, useAnchorData=1, removeMissingData=0) if trans_proj_data == None: return proj_data = trans_proj_data.T proj_data[0:3] += 0.5 if self.data_has_discrete_class: proj_data[3] = self.no_jittering_scaled_data[ self.attribute_name_index[self.data_domain.classVar.name]] self.set_plot_data(proj_data, None) self.proj_data = proj_data self.symbol_scale = self.point_width * self._point_width_to_symbol_scale self.hide_outside = False self.fade_outside = False color_index = symbol_index = size_index = label_index = -1 color_discrete = False x_discrete = self.data_domain[self.anchor_data[0] [3]].varType == Discrete y_discrete = self.data_domain[self.anchor_data[1] [3]].varType == Discrete z_discrete = self.data_domain[self.anchor_data[2] [3]].varType == Discrete if self.data_has_discrete_class: self.discrete_palette.setNumberOfColors( len(self.data_domain.classVar.values)) use_different_symbols = self.useDifferentSymbols and self.data_has_discrete_class and\ len(self.data_domain.classVar.values) <= len(Symbol) if use_different_symbols: symbol_index = 3 num_symbols_used = len(self.data_domain.classVar.values) else: num_symbols_used = -1 if self.useDifferentColors and self.data_has_discrete_class: color_discrete = True color_index = 3 colors = [] if color_discrete: for i in range(len(self.data_domain.classVar.values)): c = self.discrete_palette[i] colors.append(c) self.set_features(0, 1, 2, color_index, symbol_index, size_index, label_index, colors, num_symbols_used, x_discrete, y_discrete, z_discrete) def_color = QColor(150, 150, 150) def_symbol = 0 def_size = 10 if color_discrete: num = len(self.data_domain.classVar.values) values = get_variable_values_sorted(self.data_domain.classVar) for ind in range(num): symbol = ind if use_different_symbols else def_symbol self.legend().add_item( self.data_domain.classVar.name, values[ind], OWPoint(symbol, self.discrete_palette[ind], def_size)) if use_different_symbols and not color_discrete: num = len(self.data_domain.classVar.values) values = get_variable_values_sorted(self.data_domain.classVar) for ind in range(num): self.legend().add_item(self.data_domain.classVar.name, values[ind], OWPoint(ind, def_color, def_size)) self.legend().set_orientation(Qt.Vertical) self.legend().max_size = QSize(400, 400) if self.legend().pos().x() == 0: self.legend().setPos(QPointF(100, 100)) self.legend().update_items() self.legend().setVisible(self.show_legend) x_positions = proj_data[0] - 0.5 y_positions = proj_data[1] - 0.5 z_positions = proj_data[2] - 0.5 XAnchors = [anchor[0] for anchor in self.anchor_data] YAnchors = [anchor[1] for anchor in self.anchor_data] ZAnchors = [anchor[2] for anchor in self.anchor_data] data_size = len(self.raw_data) value_lines = [] for i in range(data_size): if not valid_data[i]: continue if self.useDifferentColors and self.data_has_discrete_class: color = self.discrete_palette.getRGB( self.original_data[self.data_class_index][i]) else: color = (0, 0, 0) len_anchor_data = len(self.anchor_data) x = numpy.array([x_positions[i]] * len_anchor_data) y = numpy.array([y_positions[i]] * len_anchor_data) z = numpy.array([z_positions[i]] * len_anchor_data) dists = numpy.sqrt((XAnchors - x)**2 + (YAnchors - y)**2 + (ZAnchors - z)**2) x_directions = 0.03 * (XAnchors - x) / dists y_directions = 0.03 * (YAnchors - y) / dists z_directions = 0.03 * (ZAnchors - z) / dists example_values = [ self.no_jittering_scaled_data[attr_ind, i] for attr_ind in indices ] for j in range(len_anchor_data): value_lines.extend([ x_positions[i], y_positions[i], z_positions[i], color[0] / 255., color[1] / 255., color[2] / 255., 0., 0., 0., x_positions[i], y_positions[i], z_positions[i], color[0] / 255., color[1] / 255., color[2] / 255., x_directions[j] * example_values[j], y_directions[j] * example_values[j], z_directions[j] * example_values[j] ]) self._value_lines_buffer = VertexBuffer( numpy.array(value_lines, numpy.float32), [(3, GL_FLOAT), (3, GL_FLOAT), (3, GL_FLOAT)]) self.update()
def setData(self, data, subset_data=None, **args): OWLinProj3DPlot.set_data(self, data, subset_data, **args) # No need to generate backgroud grid sphere geometry more than once if hasattr(self, '_sphere_buffer'): return self.makeCurrent() lines = [] num_parts = 30 num_horizontal_rings = 20 num_vertical_rings = 24 r = 1. for i in range(num_horizontal_rings): z_offset = float(i) * 2 / num_horizontal_rings - 1. r = (1. - z_offset**2)**0.5 for j in range(num_parts): angle_z_0 = float(j) * 2 * pi / num_parts angle_z_1 = float(j + 1) * 2 * pi / num_parts lines.extend([ sin(angle_z_0) * r, z_offset, cos(angle_z_0) * r, sin(angle_z_1) * r, z_offset, cos(angle_z_1) * r ]) for i in range(num_vertical_rings): r = 1. phi = 2 * i * pi / num_vertical_rings for j in range(num_parts): theta_0 = (j) * pi / num_parts theta_1 = (j + 1) * pi / num_parts lines.extend([ sin(theta_0) * cos(phi) * r, cos(theta_0) * r, sin(theta_0) * sin(phi) * r, sin(theta_1) * cos(phi) * r, cos(theta_1) * r, sin(theta_1) * sin(phi) * r ]) self._sphere_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)]) self._sphere_shader = QtOpenGL.QGLShaderProgram() self._sphere_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'sphere.vs')) self._sphere_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'sphere.fs')) self._sphere_shader.bindAttributeLocation('position', 0) if not self._sphere_shader.link(): print('Failed to link sphere shader!') ## Cones cone_data = parse_obj('cone_hq.obj') vertices = [] for v0, v1, v2, n0, n1, n2 in cone_data: vertices.extend([ v0[0], v0[1], v0[2], n0[0], n0[1], n0[2], v1[0], v1[1], v1[2], n1[0], n1[1], n1[2], v2[0], v2[1], v2[2], n2[0], n2[1], n2[2] ]) self._cone_buffer = VertexBuffer(numpy.array(vertices, numpy.float32), [(3, GL_FLOAT), (3, GL_FLOAT)]) self._cone_shader = QtOpenGL.QGLShaderProgram() self._cone_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'cone.vs')) self._cone_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'cone.fs')) self._cone_shader.bindAttributeLocation('position', 0) self._cone_shader.bindAttributeLocation('normal', 1) if not self._cone_shader.link(): print('Failed to link cone shader!') ## Another dummy shader (anchor grid) self._grid_shader = QtOpenGL.QGLShaderProgram() self._grid_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'grid.vs')) self._grid_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'grid.fs')) self._grid_shader.bindAttributeLocation('position', 0) if not self._grid_shader.link(): print('Failed to link grid shader!') self.before_draw_callback = self.before_draw
class OWSphereviz3DPlot(OWLinProj3DPlot): def __init__(self, widget, parent=None, name='SpherevizPlot'): OWLinProj3DPlot.__init__(self, widget, parent, name) self.camera_angle = 90 self.camera_type = 0 # Default, center, attribute self.show_anchor_grid = False def _build_anchor_grid(self): lines = [] num_parts = 30 anchors = numpy.array([a[:3] for a in self.anchor_data]) for anchor in self.anchor_data: a0 = numpy.array(anchor[:3]) neighbours = anchors.copy() neighbours = [(((n - a0)**2).sum(), n) for n in neighbours] neighbours.sort(key=lambda e: e[0]) for i in range(1, min(len(anchors), 4)): difference = neighbours[i][1] - a0 for j in range(num_parts): lines.extend( normalize(a0 + difference * j / float(num_parts))) lines.extend( normalize(a0 + difference * (j + 1) / float(num_parts))) self._grid_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)]) def update_data(self, labels=None, setAnchors=0, **args): OWLinProj3DPlot.updateData(self, labels, setAnchors, **args) if self.anchor_data: self._build_anchor_grid() self.updateGL() updateData = update_data def setData(self, data, subset_data=None, **args): OWLinProj3DPlot.set_data(self, data, subset_data, **args) # No need to generate backgroud grid sphere geometry more than once if hasattr(self, '_sphere_buffer'): return self.makeCurrent() lines = [] num_parts = 30 num_horizontal_rings = 20 num_vertical_rings = 24 r = 1. for i in range(num_horizontal_rings): z_offset = float(i) * 2 / num_horizontal_rings - 1. r = (1. - z_offset**2)**0.5 for j in range(num_parts): angle_z_0 = float(j) * 2 * pi / num_parts angle_z_1 = float(j + 1) * 2 * pi / num_parts lines.extend([ sin(angle_z_0) * r, z_offset, cos(angle_z_0) * r, sin(angle_z_1) * r, z_offset, cos(angle_z_1) * r ]) for i in range(num_vertical_rings): r = 1. phi = 2 * i * pi / num_vertical_rings for j in range(num_parts): theta_0 = (j) * pi / num_parts theta_1 = (j + 1) * pi / num_parts lines.extend([ sin(theta_0) * cos(phi) * r, cos(theta_0) * r, sin(theta_0) * sin(phi) * r, sin(theta_1) * cos(phi) * r, cos(theta_1) * r, sin(theta_1) * sin(phi) * r ]) self._sphere_buffer = VertexBuffer(numpy.array(lines, numpy.float32), [(3, GL_FLOAT)]) self._sphere_shader = QtOpenGL.QGLShaderProgram() self._sphere_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'sphere.vs')) self._sphere_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'sphere.fs')) self._sphere_shader.bindAttributeLocation('position', 0) if not self._sphere_shader.link(): print('Failed to link sphere shader!') ## Cones cone_data = parse_obj('cone_hq.obj') vertices = [] for v0, v1, v2, n0, n1, n2 in cone_data: vertices.extend([ v0[0], v0[1], v0[2], n0[0], n0[1], n0[2], v1[0], v1[1], v1[2], n1[0], n1[1], n1[2], v2[0], v2[1], v2[2], n2[0], n2[1], n2[2] ]) self._cone_buffer = VertexBuffer(numpy.array(vertices, numpy.float32), [(3, GL_FLOAT), (3, GL_FLOAT)]) self._cone_shader = QtOpenGL.QGLShaderProgram() self._cone_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'cone.vs')) self._cone_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'cone.fs')) self._cone_shader.bindAttributeLocation('position', 0) self._cone_shader.bindAttributeLocation('normal', 1) if not self._cone_shader.link(): print('Failed to link cone shader!') ## Another dummy shader (anchor grid) self._grid_shader = QtOpenGL.QGLShaderProgram() self._grid_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Vertex, os.path.join(os.path.dirname(__file__), 'grid.vs')) self._grid_shader.addShaderFromSourceFile( QtOpenGL.QGLShader.Fragment, os.path.join(os.path.dirname(__file__), 'grid.fs')) self._grid_shader.bindAttributeLocation('position', 0) if not self._grid_shader.link(): print('Failed to link grid shader!') self.before_draw_callback = self.before_draw def update_camera_type(self): if self.camera_type == 2: self._random_anchor = choice(self.anchor_data) self.update() def before_draw(self): view = QMatrix4x4() if self.camera_type == 2: view.lookAt( QVector3D(self._random_anchor[0], self._random_anchor[1], self._random_anchor[2]), self.camera, QVector3D(0, 1, 0)) projection = QMatrix4x4() projection.perspective(self.camera_angle, float(self.width()) / self.height(), 0.01, 5.) self.projection = projection elif self.camera_type == 1: view.lookAt(QVector3D(0, 0, 0), self.camera * self.camera_distance, QVector3D(0, 1, 0)) projection = QMatrix4x4() projection.perspective(self.camera_angle, float(self.width()) / self.height(), 0.01, 5.) self.projection = projection else: view.lookAt(self.camera * self.camera_distance, QVector3D(0, 0, 0), QVector3D(0, 1, 0)) self.view = view self._draw_sphere() # Qt text rendering classes still use deprecated OpenGL functionality glEnable(GL_DEPTH_TEST) glDisable(GL_BLEND) glMatrixMode(GL_PROJECTION) glLoadIdentity() glMultMatrixd(numpy.array(self.projection.data(), dtype=float)) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glMultMatrixd(numpy.array(self.view.data(), dtype=float)) glMultMatrixd(numpy.array(self.model.data(), dtype=float)) if self.showAnchors: for anchor in self.anchor_data: x, y, z, label = anchor direction = QVector3D(x, y, z) up = QVector3D(0, 1, 0) right = QVector3D.crossProduct(direction, up).normalized() up = QVector3D.crossProduct(right, direction) rotation = QMatrix4x4() rotation.setColumn(0, QVector4D(right, 0)) rotation.setColumn(1, QVector4D(up, 0)) rotation.setColumn(2, QVector4D(direction, 0)) model = QMatrix4x4() model.translate(x, y, z) model = model * rotation model.rotate(-90, 1, 0, 0) model.translate(0, -0.05, 0) model.scale(0.02, 0.02, 0.02) self._cone_shader.bind() self._cone_shader.setUniformValue('projection', self.projection) self._cone_shader.setUniformValue('modelview', self.view * model) self._cone_buffer.draw() self._cone_shader.release() self.qglColor(self._theme.axis_values_color) self.renderText(x * 1.2, y * 1.2, z * 1.2, label) if self.anchor_data and not hasattr(self, '_grid_buffer'): self._build_anchor_grid() # Draw grid between anchors if self.show_anchor_grid: self._grid_shader.bind() self._grid_shader.setUniformValue('projection', self.projection) self._grid_shader.setUniformValue('modelview', self.view * self.model) self._grid_shader.setUniformValue('color', self._theme.axis_color) self._grid_buffer.draw(GL_LINES) self._grid_shader.release() self._draw_value_lines() def _draw_sphere(self): glDisable(GL_DEPTH_TEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) self._sphere_shader.bind() self._sphere_shader.setUniformValue('projection', self.projection) self._sphere_shader.setUniformValue('modelview', self.view * self.model) self._sphere_shader.setUniformValue('cam_position', self.camera * self.camera_distance) self._sphere_shader.setUniformValue('use_transparency', self.camera_type == 0) self._sphere_buffer.draw(GL_LINES) self._sphere_shader.release() def mouseMoveEvent(self, event): self.invert_mouse_x = self.camera_type != 0 OWLinProj3DPlot.mouseMoveEvent(self, event)