Changeset 8975:0a8877e6a08f in orange


Ignore:
Timestamp:
09/15/11 17:29:00 (3 years ago)
Author:
matejd <matejd@…>
Branch:
default
Convert:
e37a32c7206b78dd00781767c29d1cd34c2afa3c
Message:

More docs + internal cleanup

Location:
orange/OrangeWidgets
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • orange/OrangeWidgets/Visualize Qt/OWLinProj3DPlot.py

    r8969 r8975  
    7070        view = QMatrix4x4() 
    7171        view.lookAt( 
    72             QVector3D(self.camera[0]*self.camera_distance, 
    73                       self.camera[1]*self.camera_distance, 
    74                       self.camera[2]*self.camera_distance), 
     72            self.camera * self.camera_distance, 
    7573            QVector3D(0, 0, 0), 
    7674            QVector3D(0, 1, 0)) 
     
    127125            self._value_lines_shader.setUniformValue('modelview', self.view * self.model) 
    128126            self._value_lines_shader.setUniformValue('value_line_length', float(self.valueLineLength)) 
    129             self._value_lines_shader.setUniformValue('plot_scale', self.plot_scale[0], self.plot_scale[1], self.plot_scale[2]) 
     127            self._value_lines_shader.setUniformValue('plot_scale', self.plot_scale) 
    130128            self._value_lines_buffer.draw(GL_LINES) 
    131129            self._value_lines_shader.release() 
     
    193191        self.set_features(0, 1, 2, color_index, symbol_index, size_index, label_index, 
    194192                          colors, num_symbols_used, 
    195                           x_discrete, y_discrete, z_discrete, 
    196                           numpy.array([1., 1., 1.]), numpy.array([0., 0., 0.])) 
     193                          x_discrete, y_discrete, z_discrete) 
    197194 
    198195        def_color = QColor(150, 150, 150) 
     
    238235 
    239236            len_anchor_data = len(self.anchor_data) 
    240             x = array([x_positions[i]] * len_anchor_data) 
    241             y = array([y_positions[i]] * len_anchor_data) 
    242             z = array([z_positions[i]] * len_anchor_data) 
     237            x = numpy.array([x_positions[i]] * len_anchor_data) 
     238            y = numpy.array([y_positions[i]] * len_anchor_data) 
     239            z = numpy.array([z_positions[i]] * len_anchor_data) 
    243240            dists = numpy.sqrt((XAnchors - x)**2 + (YAnchors - y)**2 + (ZAnchors - z)**2) 
    244241            x_directions = 0.03 * (XAnchors - x) / dists 
  • orange/OrangeWidgets/Visualize Qt/OWScatterPlot3D.py

    r8970 r8975  
    2929Axis = enum('X', 'Y', 'Z') 
    3030 
    31 def plane_visible(plane, location): 
    32     normal = normal_from_points(*plane[:3]) 
    33     loc_plane = normalize(plane[0] - location) 
    34     if numpy.dot(normal, loc_plane) > 0: 
    35         return False 
    36     return True 
     31class Plane: 
     32    '''Internal convenience class.''' 
     33    def __init__(self, A, B, C, D): 
     34        self.A = A 
     35        self.B = B 
     36        self.C = C 
     37        self.D = D 
     38 
     39    def normal(self): 
     40        v1 = self.A - self.B 
     41        v2 = self.A - self.C 
     42        return QVector3D.crossProduct(v1, v2).normalized() 
     43 
     44    def visible_from(self, location): 
     45        normal = self.normal() 
     46        loc_plane = (self.A - location).normalized() 
     47        if QVector3D.dotProduct(normal, loc_plane) > 0: 
     48            return False 
     49        return True 
     50 
     51class Edge: 
     52    def __init__(self, v0, v1): 
     53        self.v0 = v0 
     54        self.v1 = v1 
     55 
     56    def __add__(self, vec): 
     57        return Edge(self.v0 + vec, self.v1 + vec) 
    3758 
    3859def nicenum(x, round): 
     
    166187            data_translation[2] = 1. 
    167188 
     189        self.data_scale = QVector3D(*data_scale) 
     190        self.data_translation = QVector3D(*data_translation) 
     191 
    168192        self._x_axis_labels = None 
    169193        self._y_axis_labels = None 
     
    188212            color_index, symbol_index, size_index, label_index, 
    189213            colors, num_symbols_used, 
    190             x_discrete, y_discrete, z_discrete, 
    191             data_scale, data_translation) 
     214            x_discrete, y_discrete, z_discrete) 
    192215 
    193216        ## Legend 
     
    273296        glBegin(GL_LINES) 
    274297        for edge in edges: 
    275             start, end = edge 
    276             glVertex3f(*start) 
    277             glVertex3f(*end) 
     298            start, end = edge.v0, edge.v1 
     299            glVertex3f(start.x(), start.y(), start.z()) 
     300            glVertex3f(end.x(), end.y(), end.z()) 
    278301        glEnd() 
    279302        glDisable(GL_LINE_STIPPLE) 
     
    281304        glDisable(GL_BLEND) 
    282305 
     306    def _map_to_original(self, point, coord_index): 
     307        v = vec_div(self.map_to_data(point), self.data_scale) + self.data_translation 
     308        if coord_index == 0: 
     309            return v.x() 
     310        elif coord_index == 1: 
     311            return v.y() 
     312        elif coord_index == 2: 
     313            return v.z() 
     314 
    283315    def _draw_grid(self): 
    284316        self.renderer.set_transform(self.model, self.view, self.projection) 
    285  
    286         cam_in_space = numpy.array([ 
    287           self.camera[0]*self.camera_distance, 
    288           self.camera[1]*self.camera_distance, 
    289           self.camera[2]*self.camera_distance 
    290         ]) 
     317        cam_in_space = self.camera * self.camera_distance 
    291318 
    292319        def _draw_grid_plane(axis0, axis1, normal0, normal1, i, j): 
    293320            for axis, normal, coord_index in zip([axis0, axis1], [normal0, normal1], [i, j]): 
    294                 start, end = axis.copy() 
    295                 start_value = self.map_to_data(start.copy())[coord_index] 
    296                 end_value = self.map_to_data(end.copy())[coord_index] 
     321                start, end = axis.v0, axis.v1 
     322                start_value = self._map_to_original(start, coord_index) 
     323                end_value = self._map_to_original(end, coord_index) 
    297324                values, _ = loose_label(start_value, end_value, 7) 
    298325                for value in values: 
     
    301328                    position = start + (end-start)*((value-start_value) / float(end_value-start_value)) 
    302329                    self.renderer.draw_line( 
    303                         QVector3D(*position), 
    304                         QVector3D(*(position-normal*1.)), 
     330                        position, 
     331                        position - normal*1, 
    305332                        color=self._theme.grid_color) 
    306333 
     
    315342                [self.x_axis+self.unit_z, self.y_axis+self.unit_z], 
    316343                [self.z_axis+self.unit_x, self.y_axis+self.unit_x]] 
    317         normals = [[numpy.array([0,-1, 0]), numpy.array([-1, 0, 0])], 
    318                    [numpy.array([0, 0,-1]), numpy.array([ 0,-1, 0])], 
    319                    [numpy.array([0,-1, 0]), numpy.array([-1, 0, 0])], 
    320                    [numpy.array([0,-1, 0]), numpy.array([ 0, 0,-1])]] 
     344        normals = [[QVector3D(0,-1, 0), QVector3D(-1, 0, 0)], 
     345                   [QVector3D(0, 0,-1), QVector3D( 0,-1, 0)], 
     346                   [QVector3D(0,-1, 0), QVector3D(-1, 0, 0)], 
     347                   [QVector3D(0,-1, 0), QVector3D( 0, 0,-1)]] 
    321348        coords = [[0, 1], 
    322349                  [1, 2], 
    323350                  [0, 1], 
    324351                  [2, 1]] 
    325         visible_planes = [plane_visible(plane, cam_in_space) for plane in planes] 
    326         xz_visible = not plane_visible(self.axis_plane_xz, cam_in_space) 
     352        visible_planes = [plane.visible_from(cam_in_space) for plane in planes] 
     353        xz_visible = not self.axis_plane_xz.visible_from(cam_in_space) 
    327354        if xz_visible: 
    328             _draw_grid_plane(self.x_axis, self.z_axis, numpy.array([0,0,-1]), numpy.array([-1,0,0]), 0, 2) 
     355            _draw_grid_plane(self.x_axis, self.z_axis, QVector3D(0, 0, -1), QVector3D(-1, 0, 0), 0, 2) 
    329356        for visible, (axis0, axis1), (normal0, normal1), (i, j) in\ 
    330357             zip(visible_planes, axes, normals, coords): 
     
    337364    def _build_axes(self): 
    338365        edge_half = 1. / 2. 
    339         x_axis = [[-edge_half, -edge_half, -edge_half], [edge_half, -edge_half, -edge_half]] 
    340         y_axis = [[-edge_half, -edge_half, -edge_half], [-edge_half, edge_half, -edge_half]] 
    341         z_axis = [[-edge_half, -edge_half, -edge_half], [-edge_half, -edge_half, edge_half]] 
    342  
    343         self.x_axis = x_axis = numpy.array(x_axis) 
    344         self.y_axis = y_axis = numpy.array(y_axis) 
    345         self.z_axis = z_axis = numpy.array(z_axis) 
    346  
    347         self.unit_x = unit_x = numpy.array([1., 0., 0.]) 
    348         self.unit_y = unit_y = numpy.array([0., 1., 0.]) 
    349         self.unit_z = unit_z = numpy.array([0., 0., 1.]) 
     366        self.x_axis = Edge(QVector3D(-edge_half, -edge_half, -edge_half), QVector3D( edge_half, -edge_half, -edge_half)) 
     367        self.y_axis = Edge(QVector3D(-edge_half, -edge_half, -edge_half), QVector3D(-edge_half,  edge_half, -edge_half)) 
     368        self.z_axis = Edge(QVector3D(-edge_half, -edge_half, -edge_half), QVector3D(-edge_half, -edge_half,  edge_half)) 
     369 
     370        self.unit_x = unit_x = QVector3D(1, 0, 0) 
     371        self.unit_y = unit_y = QVector3D(0, 1, 0) 
     372        self.unit_z = unit_z = QVector3D(0, 0, 1) 
    350373  
    351         A = y_axis[1] 
    352         B = y_axis[1] + unit_x 
    353         C = x_axis[1] 
    354         D = x_axis[0] 
     374        A = self.y_axis.v1 
     375        B = self.y_axis.v1 + unit_x 
     376        C = self.x_axis.v1 
     377        D = self.x_axis.v0 
    355378 
    356379        E = A + unit_z 
     
    359382        H = D + unit_z 
    360383 
    361         self.axis_plane_xy = [A, B, C, D] 
    362         self.axis_plane_yz = [A, D, H, E] 
    363         self.axis_plane_xz = [D, C, G, H] 
    364  
    365         self.axis_plane_xy_back = [H, G, F, E] 
    366         self.axis_plane_yz_right = [B, F, G, C] 
    367         self.axis_plane_xz_top = [E, F, B, A] 
     384        self.axis_plane_xy = Plane(A, B, C, D) 
     385        self.axis_plane_yz = Plane(A, D, H, E) 
     386        self.axis_plane_xz = Plane(D, C, G, H) 
     387 
     388        self.axis_plane_xy_back = Plane(H, G, F, E) 
     389        self.axis_plane_yz_right = Plane(B, F, G, C) 
     390        self.axis_plane_xz_top = Plane(E, F, B, A) 
    368391 
    369392    def _draw_axes(self): 
    370         glMatrixMode(GL_PROJECTION) 
    371         glLoadIdentity() 
    372         glMultMatrixd(numpy.array(self.projection.data(), dtype=float)) 
    373         glMatrixMode(GL_MODELVIEW) 
    374         glLoadIdentity() 
    375         glMultMatrixd(numpy.array(self.view.data(), dtype=float)) 
    376         glMultMatrixd(numpy.array(self.model.data(), dtype=float)) 
    377  
    378393        self.renderer.set_transform(self.model, self.view, self.projection) 
    379394 
    380         def _draw_axis(line): 
     395        def _draw_axis(axis): 
    381396            glLineWidth(2) 
    382             self.renderer.draw_line(QVector3D(*line[0]), 
    383                                     QVector3D(*line[1]), 
     397            self.renderer.draw_line(axis.v0, 
     398                                    axis.v1, 
    384399                                    color=self._theme.axis_color) 
    385400            glLineWidth(1) 
    386401 
    387402        def _draw_discrete_axis_values(axis, coord_index, normal, axis_labels): 
    388             start, end = axis.copy() 
    389             start_value = self.map_to_data(start.copy())[coord_index] 
    390             end_value = self.map_to_data(end.copy())[coord_index] 
     403            start, end = axis.v0, axis.v1 
     404            start_value = self._map_to_original(start, coord_index) 
     405            end_value = self._map_to_original(end, coord_index) 
    391406            length = end_value - start_value 
    392407            for i, label in enumerate(axis_labels): 
     
    395410                    position = start + (end-start)*((value-start_value) / length) 
    396411                    self.renderer.draw_line( 
    397                         QVector3D(*position), 
    398                         QVector3D(*(position + normal*0.03)), 
     412                        position, 
     413                        position + normal*0.03, 
    399414                        color=self._theme.axis_values_color) 
    400415                    position += normal * 0.1 
    401                     self.renderText(position[0], 
    402                                     position[1], 
    403                                     position[2], 
     416                    self.renderText(position.x(), 
     417                                    position.y(), 
     418                                    position.z(), 
    404419                                    label, font=self._theme.labels_font) 
    405420 
     
    409424                _draw_discrete_axis_values(axis, coord_index, normal, axis_labels) 
    410425                return 
    411             start, end = axis.copy() 
    412             start_value = self.map_to_data(start.copy())[coord_index] 
    413             end_value = self.map_to_data(end.copy())[coord_index] 
     426            start, end = axis.v0, axis.v1 
     427            start_value = self._map_to_original(start, coord_index) 
     428            end_value = self._map_to_original(end, coord_index) 
    414429            values, num_frac = loose_label(start_value, end_value, 7) 
    415430            for value in values: 
     
    419434                text = ('%%.%df' % num_frac) % value 
    420435                self.renderer.draw_line( 
    421                     QVector3D(*position), 
    422                     QVector3D(*(position+normal*0.03)), 
     436                    position, 
     437                    position+normal*0.03, 
    423438                    color=self._theme.axis_values_color) 
    424439                position += normal * 0.1 
    425                 self.renderText(position[0], 
    426                                 position[1], 
    427                                 position[2], 
     440                self.renderText(position.x(), 
     441                                position.y(), 
     442                                position.z(), 
    428443                                text, font=self._theme.axis_font) 
    429444 
    430445        def _draw_axis_title(axis, title, normal): 
    431             middle = (axis[0] + axis[1]) / 2. 
    432             middle += normal * 0.1 if axis[0][1] != axis[1][1] else normal * 0.2 
    433             self.renderText(middle[0], middle[1], middle[2], 
     446            middle = (axis.v0 + axis.v1) / 2. 
     447            middle += normal * 0.1 if axis.v0.y() != axis.v1.y() else normal * 0.2 
     448            self.renderText(middle.x(), middle.y(), middle.z(), 
    434449                            title, 
    435450                            font=self._theme.axis_title_font) 
     
    440455        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 
    441456 
    442         cam_in_space = numpy.array([ 
    443           self.camera[0]*self.camera_distance, 
    444           self.camera[1]*self.camera_distance, 
    445           self.camera[2]*self.camera_distance 
    446         ]) 
     457        cam_in_space = self.camera * self.camera_distance 
    447458 
    448459        # TODO: the code below is horrible and should be simplified 
    449460        planes = [self.axis_plane_xy, self.axis_plane_yz, 
    450461                  self.axis_plane_xy_back, self.axis_plane_yz_right] 
    451         normals = [[numpy.array([0,-1, 0]), numpy.array([-1, 0, 0])], 
    452                    [numpy.array([0, 0,-1]), numpy.array([ 0,-1, 0])], 
    453                    [numpy.array([0,-1, 0]), numpy.array([-1, 0, 0])], 
    454                    [numpy.array([0,-1, 0]), numpy.array([ 0, 0,-1])]] 
    455         visible_planes = [plane_visible(plane, cam_in_space) for plane in planes] 
    456         xz_visible = not plane_visible(self.axis_plane_xz, cam_in_space) 
     462        normals = [[QVector3D(0,-1, 0), QVector3D(-1, 0, 0)], 
     463                   [QVector3D(0, 0,-1), QVector3D( 0,-1, 0)], 
     464                   [QVector3D(0,-1, 0), QVector3D(-1, 0, 0)], 
     465                   [QVector3D(0,-1, 0), QVector3D( 0, 0,-1)]] 
     466        visible_planes = [plane.visible_from(cam_in_space) for plane in planes] 
     467        xz_visible = not self.axis_plane_xz.visible_from(cam_in_space) 
    457468 
    458469        if visible_planes[0 if xz_visible else 2]: 
    459470            _draw_axis(self.x_axis) 
    460             _draw_values(self.x_axis, 0, numpy.array([0, 0, -1]), self._x_axis_labels) 
     471            _draw_values(self.x_axis, 0, QVector3D(0, 0, -1), self._x_axis_labels) 
    461472            if self.show_x_axis_title: 
    462                 _draw_axis_title(self.x_axis, self._x_axis_title, numpy.array([0, 0, -1])) 
     473                _draw_axis_title(self.x_axis, self._x_axis_title, QVector3D(0, 0, -1)) 
    463474        elif visible_planes[2 if xz_visible else 0]: 
    464475            _draw_axis(self.x_axis + self.unit_z) 
    465             _draw_values(self.x_axis + self.unit_z, 0, numpy.array([0, 0, 1]), self._x_axis_labels) 
     476            _draw_values(self.x_axis + self.unit_z, 0, QVector3D(0, 0, 1), self._x_axis_labels) 
    466477            if self.show_x_axis_title: 
    467478                _draw_axis_title(self.x_axis + self.unit_z, 
    468                                 self._x_axis_title, numpy.array([0, 0, 1])) 
     479                                self._x_axis_title, QVector3D(0, 0, 1)) 
    469480 
    470481        if visible_planes[1 if xz_visible else 3]: 
    471482            _draw_axis(self.z_axis) 
    472             _draw_values(self.z_axis, 2, numpy.array([-1, 0, 0]), self._z_axis_labels) 
     483            _draw_values(self.z_axis, 2, QVector3D(-1, 0, 0), self._z_axis_labels) 
    473484            if self.show_z_axis_title: 
    474                 _draw_axis_title(self.z_axis, self._z_axis_title, numpy.array([-1, 0, 0])) 
     485                _draw_axis_title(self.z_axis, self._z_axis_title, QVector3D(-1, 0, 0)) 
    475486        elif visible_planes[3 if xz_visible else 1]: 
    476487            _draw_axis(self.z_axis + self.unit_x) 
    477             _draw_values(self.z_axis + self.unit_x, 2, numpy.array([1, 0, 0]), self._z_axis_labels) 
     488            _draw_values(self.z_axis + self.unit_x, 2, QVector3D(1, 0, 0), self._z_axis_labels) 
    478489            if self.show_z_axis_title: 
    479                 _draw_axis_title(self.z_axis + self.unit_x, self._z_axis_title, numpy.array([1, 0, 0])) 
     490                _draw_axis_title(self.z_axis + self.unit_x, self._z_axis_title, QVector3D(1, 0, 0)) 
    480491 
    481492        try: 
     
    489500                             self.y_axis+self.unit_z, 
    490501                             self.y_axis] 
    491         normals = [numpy.array([1, 0, 0]), 
    492                    numpy.array([0, 0, 1]), 
    493                    numpy.array([-1,0, 0]), 
    494                    numpy.array([0, 0,-1])] 
     502        normals = [QVector3D(1, 0, 0), 
     503                   QVector3D(0, 0, 1), 
     504                   QVector3D(-1,0, 0), 
     505                   QVector3D(0, 0,-1)] 
    495506        axis = y_axis_translated[rightmost_visible] 
    496507        normal = normals[rightmost_visible] 
  • orange/OrangeWidgets/Visualize Qt/OWSphereviz3D.py

    r8969 r8975  
    2929        lines = [] 
    3030        num_parts = 30 
    31         anchors = array([a[:3] for a in self.anchor_data]) 
     31        anchors = numpy.array([a[:3] for a in self.anchor_data]) 
    3232        for anchor in self.anchor_data: 
    33             a0 = array(anchor[:3]) 
     33            a0 = numpy.array(anchor[:3]) 
    3434            neighbours = anchors.copy() 
    3535            neighbours = [(((n-a0)**2).sum(), n)  for n in neighbours] 
     
    147147            view.lookAt( 
    148148                QVector3D(self._random_anchor[0], self._random_anchor[1], self._random_anchor[2]), 
    149                 QVector3D(self.camera[0], 
    150                           self.camera[1], 
    151                           self.camera[2]), 
     149                self.camera, 
    152150                QVector3D(0, 1, 0)) 
    153151            projection = QMatrix4x4() 
     
    158156            view.lookAt( 
    159157                QVector3D(0, 0, 0), 
    160                 QVector3D(self.camera[0]*self.camera_distance, 
    161                           self.camera[1]*self.camera_distance, 
    162                           self.camera[2]*self.camera_distance), 
     158                self.camera * self.camera_distance, 
    163159                QVector3D(0, 1, 0)) 
    164160            projection = QMatrix4x4() 
     
    168164        else: 
    169165            view.lookAt( 
    170                 QVector3D(self.camera[0]*self.camera_distance, 
    171                           self.camera[1]*self.camera_distance, 
    172                           self.camera[2]*self.camera_distance), 
     166                self.camera * self.camera_distance, 
    173167                QVector3D(0, 0, 0), 
    174168                QVector3D(0, 1, 0)) 
     
    238232        self._sphere_shader.setUniformValue('projection', self.projection) 
    239233        self._sphere_shader.setUniformValue('modelview', self.view * self.model) 
    240         self._sphere_shader.setUniformValue('cam_position', QVector3D(*self.camera)*self.camera_distance) 
     234        self._sphere_shader.setUniformValue('cam_position', self.camera * self.camera_distance) 
    241235        self._sphere_shader.setUniformValue('use_transparency', self.camera_type == 0) 
    242236        self._sphere_buffer.draw(GL_LINES) 
  • orange/OrangeWidgets/plot/owopenglrenderer.py

    r8967 r8975  
    55################# 
    66 
    7 .. autoclass:: OrangeWidgets.plot.OWOpenGLRenderer 
     7.. autoclass:: VertexBuffer 
     8 
     9.. autoclass:: OWOpenGLRenderer 
    810 
    911''' 
     
    98100            self._data_length = len(data) 
    99101            glBindBuffer(GL_ARRAY_BUFFER, 0) 
     102 
     103    def __del__(self): 
     104        # TODO 
     105        pass 
    100106 
    101107    def draw(self, primitives=GL_TRIANGLES, first=0, count=-1): 
  • orange/OrangeWidgets/plot/owplot3d.py

    r8973 r8975  
    4242 
    4343import numpy 
    44 from numpy import array, maximum 
    45 #numpy.seterr(all='raise') 
    4644 
    4745try: 
     
    5048except: 
    5149    pass 
     50 
     51def vec_div(v1, v2): 
     52    return QVector3D(v1.x() / v2.x(), 
     53                     v1.y() / v2.y(), 
     54                     v1.z() / v2.z()) 
     55 
     56def lower_bound(value, vec): 
     57    if vec.x() < value: 
     58        vec.setX(value) 
     59    if vec.y() < value: 
     60        vec.setY(value) 
     61    if vec.z() < value: 
     62        vec.setZ(value) 
     63    return vec 
    5264 
    5365def enum(*sequential): 
     
    6375              'DIAMOND', 'WEDGE', 'LWEDGE', 'CROSS', 'XCROSS') 
    6476 
    65 from plot.primitives import get_symbol_geometry, clamp, normalize, GeometryType 
    66  
    67 name_map = { 
    68     "saveToFileDirect": "save_to_file_direct", 
    69     "saveToFile" : "save_to_file", 
    70 } 
    71  
    72 @deprecated_members(name_map, wrap_methods=name_map.keys()) 
     77from plot.primitives import get_symbol_geometry, clamp, GeometryType 
     78 
    7379class OWLegend3D(OWLegend): 
    7480    def set_symbol_geometry(self, symbol, geometry): 
     
    149155                        QColor(0, 0, 0)) 
    150156 
     157name_map = { 
     158    "saveToFileDirect": "save_to_file_direct", 
     159    "saveToFile" : "save_to_file", 
     160} 
     161 
     162@deprecated_members(name_map, wrap_methods=name_map.keys()) 
    151163class OWPlot3D(orangeqt.Plot3D): 
    152164    ''' 
     
    165177    **Data** 
    166178        This is the most important part of the Plot3D API. :meth:`set_plot_data` is 
    167         used to (not surprisingly) set the data which will be drawn. 
     179        used to (not surprisingly) set the data to draw. 
    168180        :meth:`set_features` tells Plot3D how to interpret the data (this method must 
    169181        be called after :meth:`set_plot_data` and can be called multiple times). 
     
    171183        should not be drawn. It should be called after set_plot_data, but before set_features. 
    172184        This separation permits certain optimizations, e.g. ScatterPlot3D sets data once only (at 
    173         the beginning), later on it calls set_features and set_valid_data only. 
     185        the beginning), later on it calls solely set_features and set_valid_data. 
    174186 
    175187        .. automethod:: set_plot_data 
     
    211223 
    212224        Plot3D provides several callbacks which can be used to perform additional tasks ( 
    213         such as drawing geometry before/after the data is drawn). Callback provided: 
    214  
    215         auto_send_selection_callback 
    216         mouseover_callback 
    217         before_draw_callback 
    218         after_draw_callback 
     225        such as drawing custom geometry before/after the data is drawn). For example usage 
     226        see ``OWScatterPlot3D``. Callbacks provided: 
     227 
     228            ==============               ================================================== 
     229            Callback                     Event 
     230            --------------               -------------------------------------------------- 
     231            auto_send_selection_callback Selection changed. 
     232            mouseover_callback           Mouse cursor moved over a point. Also send example's index. 
     233            before_draw_callback         Right before drawing points (but after 
     234                                         current camera transformations have been computed, 
     235                                         so it's safe to use ``projection``, ``view`` and 
     236                                         ``model``). 
     237            after_draw_callback          Right after points have been drawn. 
     238            ==============               ================================================== 
    219239 
    220240    **Coordinate transformations** 
     241 
     242        Data set by ``set_plot_data`` is in what Plot3D calls 
     243        data coordinate system. Plot coordinate system takes into account plot translation 
     244        and scale (together effectively being zoom as well). 
    221245 
    222246        .. automethod:: map_to_plot 
     
    245269 
    246270        self.camera_distance = 6. 
    247  
    248271        self.scale_factor = 0.30 
    249272        self.rotation_factor = 0.3 
    250273        self.zoom_factor = 2000. 
    251  
    252274        self.yaw = self.pitch = -pi / 4. 
    253275        self.panning_factor = 0.8 
    254         self.update_camera() 
    255  
    256276        self.perspective_near = 0.5 
    257277        self.perspective_far = 10. 
    258278        self.camera_fov = 14. 
     279        self.update_camera() 
    259280 
    260281        self.show_legend = True 
     
    268289        self.symbol_scale = 1. 
    269290        self.alpha_value = 255 
    270         self._zoomed_size = [1., 1., 1.] 
    271291 
    272292        self._state = PlotState.IDLE 
    273  
    274293        self._selection = None 
    275294        self.selection_behavior = OWPlot.AddSelection 
     
    286305        self.mouse_sensitivity = 5 
    287306 
    288         self.additional_scale = array([0., 0., 0.]) 
    289         self.data_scale = array([1., 1., 1.]) 
    290         self.data_translation = array([0., 0., 0.]) 
    291         self.plot_scale = array([1., 1., 1.]) 
    292         self.plot_translation = -array([0.5, 0.5, 0.5]) 
    293  
    294         self._zoom_stack = [] 
     307        self.clear_plot_transformations() 
    295308 
    296309        self._theme = PlotTheme() 
    297  
    298310        self._tooltip_fbo_dirty = True 
    299311        self._tooltip_win_center = [0, 0] 
    300  
    301312        self._use_fbos = True 
    302313 
     
    304315        # if False, build VBO every time set_plot_data is called. 
    305316        self._use_opengl_3 = False 
    306  
    307317        self.hide_outside = False 
    308318        self.fade_outside = True 
    309319        self.label_index = -1 
    310320 
    311         self.data = None 
     321        self.data = self.data_array = None 
    312322 
    313323        self.continuous_palette = ColorPaletteGenerator(numberOfColors=-1) 
     
    318328            An :obj:`.OWPlotGUI` object associated with this plot 
    319329    ''' 
    320  
    321     def __del__(self): 
    322         pass 
    323         # TODO: never reached! 
    324         #glDeleteVertexArrays(1, self.dummy_vao) 
    325         #glDeleteVertexArrays(1, self.feedback_vao) 
    326         #glDeleteBuffers(1, self.symbol_buffer) 
    327         #if hasattr(self, 'data_buffer'): 
    328         #    glDeleteBuffers(1, self.data_buffer) 
    329330 
    330331    def legend(self): 
     
    497498    def update_camera(self): 
    498499        self.pitch = clamp(self.pitch, -3., -0.1) 
    499         self.camera = [ 
     500        self.camera = QVector3D( 
    500501            sin(self.pitch)*cos(self.yaw), 
    501502            cos(self.pitch), 
    502             sin(self.pitch)*sin(self.yaw)] 
     503            sin(self.pitch)*sin(self.yaw)) 
    503504 
    504505    def get_mvp(self): 
     
    513514        view = QMatrix4x4() 
    514515        view.lookAt( 
    515             QVector3D(self.camera[0]*self.camera_distance, 
    516                       self.camera[1]*self.camera_distance, 
    517                       self.camera[2]*self.camera_distance), 
     516            self.camera * self.camera_distance, 
    518517            QVector3D(0,-0.1, 0), 
    519518            QVector3D(0, 1, 0)) 
     
    536535            self.before_draw_callback() 
    537536 
    538         plot_scale = numpy.maximum([1e-5, 1e-5, 1e-5], self.plot_scale+self.additional_scale) 
     537        plot_scale = lower_bound(1e-5, self.plot_scale+self.additional_scale) 
    539538 
    540539        self.symbol_program.bind() 
     
    547546        self.symbol_program.setUniformValue(self.symbol_program_symbol_scale,   self.symbol_scale, self.symbol_scale) 
    548547        self.symbol_program.setUniformValue(self.symbol_program_alpha_value,    self.alpha_value / 255., self.alpha_value / 255.) 
    549         self.symbol_program.setUniformValue(self.symbol_program_scale,          *plot_scale) 
    550         self.symbol_program.setUniformValue(self.symbol_program_translation,    *self.plot_translation) 
     548        self.symbol_program.setUniformValue(self.symbol_program_scale,          plot_scale) 
     549        self.symbol_program.setUniformValue(self.symbol_program_translation,    self.plot_translation) 
    551550        self.symbol_program.setUniformValue(self.symbol_program_force_color,    0., 0., 0., 0.) 
    552551 
     
    568567        self.symbol_program.release() 
    569568 
    570         self.draw_labels() 
     569        self._draw_labels() 
    571570 
    572571        if self.after_draw_callback: 
     
    598597            glViewport(0, 0, self.width(), self.height()) 
    599598 
    600         self.draw_helpers() 
     599        self._draw_helpers() 
    601600 
    602601        if self.show_legend: 
     
    612611        self.swapBuffers() 
    613612 
    614     def draw_labels(self): 
     613    def _draw_labels(self): 
    615614        if self.label_index < 0: 
    616615            return 
     
    630629            z = example[self.z_index] 
    631630            label = example[self.label_index] 
    632             x, y, z = self.map_to_plot(array([x, y, z]), original=False) 
     631            x, y, z = self.map_to_plot(QVector3D(x, y, z)) 
    633632            # TODO 
    634633            #if isinstance(label, str): 
     
    638637                            font=self._theme.labels_font) 
    639638 
    640     def draw_helpers(self): 
     639    def _draw_helpers(self): 
    641640        glEnable(GL_BLEND) 
    642641        glDisable(GL_DEPTH_TEST) 
     
    708707            color_index, symbol_index, size_index, label_index, 
    709708            colors, num_symbols_used, 
    710             x_discrete, y_discrete, z_discrete, 
    711             data_scale=array([1., 1., 1.]), 
    712             data_translation=array([0., 0., 0.])): 
     709            x_discrete, y_discrete, z_discrete): 
    713710        ''' 
    714711        Explains to the plot how to interpret the data set by :meth:`set_plot_data`. Its arguments 
    715712        are indices (must be less than the size of an example) into the dataset (each one 
    716713        specifies a column). Additionally, it accepts a list of colors (when color is a discrete 
    717         attribute), a value specifying how many different symbols are needed to display the data, 
    718         information whether or not positional data is discrete, and transformations (scale and 
    719         translation) that were applied to the data. 
     714        attribute), a value specifying how many different symbols are needed to display the data and 
     715        information whether or not positional data is discrete. 
    720716 
    721717        .. note:: This function does not add items to the legend automatically.  
     
    760756        :param z_discrete: Specifies whether or not z coordinate is discrete. 
    761757        :type bool 
    762  
    763         :param data_scale: Specifies the scale that was applied to the data (set with set_plot_data). 
    764             Not required. 
    765         :type numpy.array 
    766  
    767         :param data_translation: Specifies the translation that was applied to the data (set with set_plot_data). 
    768             Not required. 
    769         :type numpy.array 
    770758        ''' 
    771759        if self.data == None: 
     
    774762        start = time.time() 
    775763        self.makeCurrent() 
    776         self.data_scale = data_scale 
    777         self.data_translation = data_translation 
    778764        self.x_index = x_index 
    779765        self.y_index = y_index 
     
    788774        self.z_discrete = z_discrete 
    789775        self.label_index = label_index 
    790  
    791         # If color is a discrete attribute, colors should be a list of QColor 
    792776 
    793777        if self._use_opengl_3: 
     
    856840    def set_plot_data(self, data, subset_data=None): 
    857841        ''' 
    858         Sets the data to be drawn. 
     842        Sets the data to be drawn. Data is expected to be scaled already (see ``OWScatterPlot3D`` for example). 
    859843 
    860844        :param data: Data 
     
    893877        orangeqt.Plot3D.set_valid_data(self, long(self.valid_data.ctypes.data)) 
    894878 
    895     def set_new_zoom(self, x_min, x_max, y_min, y_max, z_min, z_max, plot_coordinates=False): 
    896         '''Specifies new zoom in data or plot coordinates.''' 
     879    def set_new_zoom(self, min, max): 
     880        ''' 
     881        Specifies new zoom in data coordinates. Zoom is provided in form of plot translation 
     882        and scale, not camera transformation. This might not be what you want (``OWLinProj3D`` 
     883        disables this behavior for example). Plot3D remembers translation and scale. 
     884        ``zoom_out`` can be use to restore the previous zoom level. 
     885 
     886        :param min: Lower left corner of the new zoom volume. 
     887        :type QVector3D 
     888 
     889        :param max: Upper right corner of the new zoom volume. 
     890        :type QVector3D 
     891        ''' 
    897892        self._zoom_stack.append((self.plot_scale, self.plot_translation)) 
    898  
    899         max = array([x_max, y_max, z_max]).copy() 
    900         min = array([x_min, y_min, z_min]).copy() 
    901         if not plot_coordinates: 
    902             min -= self.data_translation 
    903             min *= self.data_scale 
    904             max -= self.data_translation 
    905             max *= self.data_scale 
    906893        center = (max + min) / 2. 
    907         new_translation = -array(center) 
    908         # Avoid division by zero by adding a small value (this happens when zooming in 
    909         # on elements with the same value of an attribute). 
    910         self._zoomed_size = array(map(lambda i: i+1e-5 if i == 0 else i, max-min)) 
    911         new_scale = 1. / self._zoomed_size 
     894        new_translation = -center 
     895        self._zoomed_size = max-min + QVector3D(1e-5, 1e-5, 1e-5) 
     896        new_scale = vec_div(QVector3D(1, 1, 1), self._zoomed_size) 
    912897        self._animate_new_scale_translation(new_scale, new_translation) 
     898 
     899    def zoom_out(self): 
     900        ''' 
     901        Restores previous zoom level. 
     902        ''' 
     903        if len(self._zoom_stack) < 1: 
     904            new_translation = QVector3D(-0.5, -0.5, -0.5) 
     905            new_scale = QVector3D(1, 1, 1) 
     906        else: 
     907            new_scale, new_translation = self._zoom_stack.pop() 
     908        self._animate_new_scale_translation(new_scale, new_translation) 
     909        self._zoomed_size = vec_div(QVector3D(1, 1, 1), new_scale) 
    913910 
    914911    def _animate_new_scale_translation(self, new_scale, new_translation, num_steps=10): 
     
    931928            self.repaint() 
    932929 
    933     def zoom_out(self): 
    934         if len(self._zoom_stack) < 1: 
    935             new_translation = -array([0.5, 0.5, 0.5]) 
    936             new_scale = array([1., 1., 1.]) 
    937         else: 
    938             new_scale, new_translation = self._zoom_stack.pop() 
    939         self._animate_new_scale_translation(new_scale, new_translation) 
    940         self._zoomed_size = 1. / new_scale 
    941  
    942930    def save_to_file(self, extraButtons=[]): 
     931        print('Save to file called!') 
    943932        sizeDlg = OWChooseImageSizeDlg(self, extraButtons, parent=self) 
    944933        sizeDlg.exec_() 
     
    948937        sizeDlg.saveImage(fileName, size) 
    949938 
    950     def map_to_plot(self, point, original=True): 
    951         if original: 
    952             point -= self.data_translation 
    953             point *= self.data_scale 
    954         point += self.plot_translation 
    955         plot_scale = maximum([1e-5, 1e-5, 1e-5], self.plot_scale+self.additional_scale) 
    956         point *= plot_scale 
     939    def map_to_plot(self, point): 
     940        ''' 
     941        Maps ``point`` to plot coordinates (applies current translation and scale). 
     942        ``point`` is assumed to be in data coordinates. 
     943 
     944        :param point: Location in space 
     945        :type QVector3D 
     946        ''' 
     947        plot_scale = lower_bound(1e-5, self.plot_scale+self.additional_scale) 
     948        point = (point + self.plot_translation) * plot_scale 
    957949        return point 
    958950 
    959     def map_to_data(self, point, original=True): 
    960         plot_scale = maximum([1e-5, 1e-5, 1e-5], self.plot_scale+self.additional_scale) 
    961         point /= plot_scale 
    962         point -= self.plot_translation 
    963         if original: 
    964             point /= self.data_scale 
    965             point += self.data_translation 
     951    def map_to_data(self, point): 
     952        ''' 
     953        Maps ``point`` to data coordinates (applies inverse of the current translation and scale). 
     954        ``point`` is assumed to be in plot coordinates. 
     955 
     956        :param point: Location in space 
     957        :type QVector3D 
     958        ''' 
     959        plot_scale = lower_bound(1e-5, self.plot_scale+self.additional_scale) 
     960        point = vec_div(point, plot_scale) - self.plot_translation 
    966961        return point 
    967962 
     
    976971        area = [min(area.left(), area.right()), min(area.top(), area.bottom()), abs(area.width()), abs(area.height())] 
    977972        min_max = orangeqt.Plot3D.get_min_max_selected(self, area, self.projection * self.view * self.model, 
    978                                                        viewport, 
    979                                                        QVector3D(*self.plot_scale), QVector3D(*self.plot_translation)) 
     973                                                       viewport, self.plot_scale, self.plot_translation) 
    980974        return min_max 
    981975 
     
    1000994        area = [min(area.left(), area.right()), min(area.top(), area.bottom()), abs(area.width()), abs(area.height())] 
    1001995        orangeqt.Plot3D.select_points(self, area, self.projection * self.view * self.model, 
    1002                                       viewport, 
    1003                                       QVector3D(*self.plot_scale), QVector3D(*self.plot_translation), 
     996                                      viewport, self.plot_scale, self.plot_translation, 
    1004997                                      behavior) 
    1005998        orangeqt.Plot3D.update_data(self, self.x_index, self.y_index, self.z_index, 
     
    10551048                self._state = PlotState.SCALING 
    10561049                self.scaling_init_pos = self._mouse_position 
    1057                 self.additional_scale = array([0., 0., 0.]) 
     1050                self.additional_scale = QVector3D(0, 0, 0) 
    10581051            else: 
    10591052                self.zoom_out() 
     
    11071100            self.update_camera() 
    11081101        elif self._state == PlotState.PANNING: 
    1109             right_vec = normalize(numpy.cross(self.camera, [0, 1, 0])) 
    1110             up_vec = normalize(numpy.cross(right_vec, self.camera)) 
    1111             right_vec[0] *= dx / (self.width() * self.plot_scale[0] * self.panning_factor) 
    1112             right_vec[2] *= dx / (self.width() * self.plot_scale[2] * self.panning_factor) 
    1113             right_vec[0] *= (self.mouse_sensitivity / 5.) 
    1114             right_vec[2] *= (self.mouse_sensitivity / 5.) 
    1115             up_scale = self.height() * self.plot_scale[1] * self.panning_factor 
     1102            right_vec = QVector3D.crossProduct(self.camera, QVector3D(0, 1, 0)).normalized() 
     1103            up_vec = QVector3D.crossProduct(right_vec, self.camera).normalized() 
     1104            right_vec.setX(right_vec.x() * dx / (self.width() * self.plot_scale.x() * self.panning_factor)) 
     1105            right_vec.setZ(right_vec.z() * dx / (self.width() * self.plot_scale.z() * self.panning_factor)) 
     1106            right_vec.setX(right_vec.x() * (self.mouse_sensitivity / 5.)) 
     1107            right_vec.setZ(right_vec.z() * (self.mouse_sensitivity / 5.)) 
     1108            up_scale = self.height() * self.plot_scale.y() * self.panning_factor 
    11161109            self.plot_translation -= right_vec + up_vec * (dy / up_scale) * (self.mouse_sensitivity / 5.) 
    11171110        elif self._state == PlotState.SCALING: 
     
    11201113            dx /= self.scale_factor * self.width() 
    11211114            dy /= self.scale_factor * self.height() 
    1122             dy /= float(self._zoomed_size[1]) 
     1115            dy /= float(self._zoomed_size.y()) 
    11231116            dx *= self.mouse_sensitivity / 5. 
    11241117            dy *= self.mouse_sensitivity / 5. 
    1125             right_vec = normalize(numpy.cross(self.camera, [0, 1, 0])) 
    1126             self.additional_scale = [-dx * abs(right_vec[0]) / float(self._zoomed_size[0]), 
    1127                                      dy, 
    1128                                      -dx * abs(right_vec[2]) / float(self._zoomed_size[2])] 
     1118            right_vec = QVector3D.crossProduct(self.camera, QVector3D(0, 1, 0)).normalized() 
     1119            self.additional_scale = QVector3D(-dx * abs(right_vec.x()) / float(self._zoomed_size.x()), 
     1120                                               dy, 
     1121                                              -dx * abs(right_vec.z()) / float(self._zoomed_size.z())) 
    11291122        elif self._state == PlotState.IDLE: 
    11301123            legend_pos = self._legend.pos() 
     
    11421135            self._legend.mouseReleaseEvent(event) 
    11431136        if self._state == PlotState.SCALING: 
    1144             self.plot_scale = numpy.maximum([1e-5, 1e-5, 1e-5], self.plot_scale+self.additional_scale) 
    1145             self.additional_scale = array([0., 0., 0.]) 
     1137            self.plot_scale = lower_bound(1e-5, self.plot_scale+self.additional_scale) 
     1138            self.additional_scale = QVector3D(0, 0, 0) 
    11461139            self._state = PlotState.IDLE 
    11471140        elif self._state == PlotState.SELECTING: 
     
    11491142            if self.state == ZOOMING: # self.state is actually set by OWPlotGUI (different from self._state!) 
    11501143                min_max = self.get_min_max_selected(self._selection) 
    1151                 self.set_new_zoom(*min_max, plot_coordinates=True) 
     1144                x_min, x_max, y_min, y_max, z_min, z_max = min_max 
     1145                min, max = QVector3D(x_min, y_min, z_min), QVector3D(x_max, y_max, z_max) 
     1146                self.set_new_zoom(min, max) 
    11521147            else: 
    11531148                self.select_points(self._selection, self.selection_behavior) 
    1154  
    11551149                if self.auto_send_selection_callback: 
    11561150                    self.auto_send_selection_callback() 
     
    12061200        ''' 
    12071201        self._legend.clear() 
    1208         self.data_scale = array([1., 1., 1.]) 
    1209         self.data_translation = array([0., 0., 0.]) 
    12101202        self._tooltip_fbo_dirty = True 
    12111203        self._feedback_generated = False 
     
    12161208        ''' 
    12171209        self._zoom_stack = [] 
    1218         self._zoomed_size = [1., 1., 1.] 
    1219         self.plot_translation = -array([0.5, 0.5, 0.5]) 
    1220         self.plot_scale = array([1., 1., 1.]) 
    1221         self.additional_scale = array([0., 0., 0.]) 
     1210        self._zoomed_size = QVector3D(1, 1, 1) 
     1211        self.plot_translation = QVector3D(-0.5, -0.5, -0.5) 
     1212        self.plot_scale = QVector3D(1, 1, 1) 
     1213        self.additional_scale = QVector3D(0, 0, 0) 
    12221214 
    12231215    contPalette = deprecated_attribute('contPalette', 'continuous_palette') 
Note: See TracChangeset for help on using the changeset viewer.