Changeset 8569:2dec71626e92 in orange


Ignore:
Timestamp:
08/02/11 12:08:49 (3 years ago)
Author:
Noughmad <Noughmad@…>
Branch:
default
Convert:
f01da3dce520d3bc7c321dd3a6141bb14762a0d0
Message:

Rework zoom, pan and selection to be work as expected.

Files:
9 edited

Legend:

Unmodified
Added
Removed
  • orange/OrangeWidgets/plot/owplot.py

    r8549 r8569  
    8989            The plot title, usually show on top of the plot 
    9090             
    91         .. attribute:: zoom_transform 
    92              
    93             Contains the current zoom transformation  
    94              
    9591        .. automethod:: set_main_title 
    9692         
     
    9995    **Coordinate transformation** 
    10096     
    101         .. attribute zoom_transform 
    102          
    103             A QTransform that contains the current zoom transformation 
    10497         
    10598        .. automethod:: map_to_graph 
     
    218211        self._marker_items = [] 
    219212         
    220         self._zoom_factor = 1.0 
    221         self._zoom_point = None 
    222         self.zoom_transform = QTransform() 
     213        self._zoom_rect = None 
     214        self._zoom_transform = QTransform() 
    223215        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 
    224216        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 
     
    279271            point = point * self.map_transform 
    280272        if zoom: 
    281             point = point * self.zoom_transform 
     273            point = point * self._zoom_transform 
    282274        return (point.x(), point.y()) 
    283275         
     
    293285            point = QPointF(x,y) 
    294286        if zoom: 
    295             t, ok = self.zoom_transform.inverted() 
     287            t, ok = self._zoom_transform.inverted() 
    296288            point = point * t 
    297289        if axes: 
     
    386378    def setData(self, data): 
    387379        self.clear() 
    388         self.zoomStack = [] 
    389380        self.replot() 
    390381         
     
    483474        ''' 
    484475        c = OWCurve(xData, yData, x_axis_key, y_axis_key, tooltip=name, parent=self.graph_item) 
    485         c.set_zoom_factor(self._zoom_factor) 
     476        c.set_zoom_transform(self._zoom_transform) 
    486477        c.name = name 
    487478        c.set_style(style) 
     
    566557            Axes are not removed 
    567558        ''' 
     559        qDebug('  ## Clearing the plot ##  ') 
    568560        for i in self.plot_items(): 
    569561            self.remove_item(i) 
     
    669661            c.update_properties() 
    670662             
    671     def update_zoom(self, recalculate_transform = True): 
     663    def update_zoom(self): 
    672664        ''' 
    673665            Updates the zoom transformation of the plot items.  
    674666        ''' 
    675         if recalculate_transform: 
    676             self.zoom_transform = self.transform_for_zoom(self._zoom_factor, self._zoom_point, self.graph_area) 
    677         self.zoom_rect = self.zoom_transform.mapRect(self.graph_area) 
     667        zt = self.zoom_transform 
     668        self._zoom_transform = zt 
    678669        for c in self.plot_items(): 
    679             if hasattr(c, 'set_zoom_factor'): 
    680                 c.set_zoom_factor(self._zoom_factor) 
     670            if hasattr(c, 'set_zoom_transform'): 
     671                c.set_zoom_transform(zt) 
    681672                c.update_properties() 
    682         self.graph_item.setTransform(self.zoom_transform) 
    683          
    684         for item, region in self.selection_items: 
    685             item.setTransform(self.zoom_transform) 
    686          
    687         """ 
    688         NOTE: I'm not sure if this is necessary 
    689         for item,x,y,x_axis,y_axis in self._marker_items: 
    690             p = QPointF(x,y) * self.transform_for_axes(x_axis, y_axis) * self.zoom_transform + QPointF(4,4) 
    691             r = item.boundingRect() 
    692             item.setPos(p - r.center() + r.topLeft()) 
    693         """ 
     673                 
     674        self.graph_item.setTransform(zt) 
     675         
    694676        self.update_axes(zoom_only=True) 
    695677        self.viewport().update() 
     
    726708                graph_line = t.map(item.data_line) 
    727709                if item.zoomable: 
    728                     item.graph_line = self.zoom_transform.map(graph_line) 
     710                    item.graph_line = self._zoom_transform.map(graph_line) 
    729711                else: 
    730712                    item.graph_line = graph_line 
    731713                item.graph_line.translate(self.graph_item.pos()) 
    732             item.zoom_transform = self.zoom_transform 
     714            item.zoom_transform = self._zoom_transform 
    733715            item.update(zoom_only) 
    734716         
     
    770752         
    771753    def legend_rect(self): 
    772         return self._legend.mapRectToScene(self._legend.boundingRect()) 
     754        if self.show_legend: 
     755            return self._legend.mapRectToScene(self._legend.boundingRect()) 
     756        else: 
     757            return QRectF() 
    773758         
    774759    def isLegendEvent(self, event, function): 
    775         if self.legend_rect().contains(self.mapToScene(event.pos())): 
     760        if self.show_legend and self.legend_rect().contains(self.mapToScene(event.pos())): 
    776761            function(self, event) 
    777762            return True 
     
    797782        if event.button() == Qt.LeftButton and self.state == PANNING: 
    798783            self._last_pan_pos = point 
     784        event.accept() 
    799785             
    800786    def mouseMoveEvent(self, event): 
     
    817803         
    818804        if self._pressed_mouse_button == Qt.LeftButton: 
    819             if self.state == SELECT_RECTANGLE and self.graph_area.contains(point): 
     805            if self.state in [ZOOMING, SELECT] and self.graph_area.contains(point): 
    820806                if not self._current_rs_item: 
    821807                    self._selection_start_point = self.mapToScene(event.pos()) 
     
    824810                    self._current_rs_item.setBrush(SelectionBrush) 
    825811                    self._current_rs_item.setZValue(SelectionZValue) 
    826                 if self._current_rs_item: 
    827                     self._current_rs_item.setRect(QRectF(self._selection_start_point, point).normalized()) 
     812                self._current_rs_item.setRect(QRectF(self._selection_start_point, point).normalized()) 
    828813            elif self.state == PANNING: 
    829                 self._zoom_point = self._zoom_point - (point - self._last_pan_pos) * (self._zoom_factor - 1.0) 
     814                if self._last_pan_pos: 
     815                    self.pan(point - self._last_pan_pos) 
    830816                self._last_pan_pos = point 
    831                 self.update_zoom() 
    832817        elif not self._pressed_mouse_button and self.state == SELECT_POLYGON and self._current_ps_item: 
    833818            self._current_ps_polygon[-1] = point 
     
    846831                text = self.buildTooltip(text) 
    847832            if text and x is not None and y is not None: 
    848                 tp = self.mapFromScene(QPointF(x,y) * self.map_transform * self.zoom_transform) 
     833                tp = self.mapFromScene(QPointF(x,y) * self.map_transform * self._zoom_transform) 
    849834                self.showTip(tp.x(), tp.y(), text) 
    850835         
     
    862847            return 
    863848         
    864         if event.button() == Qt.LeftButton and self.state == SELECT_RECTANGLE and self._current_rs_item: 
    865             self.add_selection(self._current_rs_item.rect()) 
     849        if event.button() == Qt.LeftButton and self.state in [ZOOMING, SELECT] and self._current_rs_item: 
     850            rect = self._current_rs_item.rect() 
     851            if self.state == ZOOMING: 
     852                self.zoom_to_rect(rect) 
     853            else: 
     854                self.add_selection(rect) 
    866855            self.scene().removeItem(self._current_rs_item) 
    867856            self._current_rs_item = None 
    868857     
    869858    def mouseStaticClick(self, event): 
    870              
    871859        point = self.mapToScene(event.pos()) 
     860        if point not in self.graph_area: 
     861            return False 
    872862        if self.state == ZOOMING: 
    873             t, ok = self.zoom_transform.inverted() 
    874             if not ok: 
    875                 return False 
    876             p = point * t 
    877863            if event.button() == Qt.LeftButton: 
    878                 end_zoom_factor = self._zoom_factor * 2 
    879                 self._zoom_point = p 
     864                self.zoom_in(point) 
    880865            elif event.button() == Qt.RightButton: 
    881                 end_zoom_factor = max(self._zoom_factor/2, 1) 
     866                self.zoom_out(point) 
    882867            else: 
    883868                return False 
    884             self.animate(self, 'zoom_factor', float(end_zoom_factor)) 
    885869            return True 
    886870             
     
    916900            self.selection_items.reverse() 
    917901        elif self.state == SELECT: 
    918             dr = self.data_rect_for_axes() 
    919             gr = self.graph_area 
    920             d = 10 * max(dr.width(), dr.height()) / max(gr.width(), gr.height()) 
    921             point_item = self.nearest_point(self.map_from_graph(point), d) 
     902            point_item = self.nearest_point(point) 
    922903            b = self.selection_behavior 
    923904            if b == self.ReplaceSelection: 
     
    938919    @staticmethod 
    939920    def transform_from_rects(r1, r2): 
     921        if r1 is None or r2 is None: 
     922            return QTransform() 
    940923        if r1.width() == 0 or r1.height() == 0 or r2.width() == 0 or r2.height() == 0: 
    941924            return QTransform() 
     
    956939        t.translate(-dp.x(), -dp.y()) 
    957940        return t 
    958  
    959     @pyqtProperty(QRectF) 
    960     def zoom_area(self): 
    961         return self._zoom_area 
    962          
    963     @zoom_area.setter 
    964     def zoom_area(self, value): 
    965         self._zoom_area = value 
    966         self.zoom_transform = self.transform_from_rects(self._zoom_area, self.graph_area) 
    967         self.zoom_rect = self.zoom_transform.mapRect(self.graph_area) 
    968         self.replot() 
    969          
    970     @pyqtProperty(float) 
    971     def zoom_factor(self): 
    972         return self._zoom_factor 
    973          
    974     @zoom_factor.setter 
    975     def zoom_factor(self, value): 
    976         self._zoom_factor = value 
    977         self.update_zoom() 
    978          
    979     @pyqtProperty(QPointF) 
    980     def zoom_point(self): 
    981         return self._zoom_point 
    982          
    983     @zoom_point.setter 
    984     def zoom_point(self, value): 
    985         self._zoom_point = value 
    986         self.update_zoom() 
     941         
     942    def rect_for_zoom(self, point, old_rect, scale = 2): 
     943        r = QRectF() 
     944        r.setWidth(old_rect.width() / scale) 
     945        r.setHeight(old_rect.height() / scale) 
     946        r.moveCenter(point) 
     947         
     948        self.ensure_inside(r, old_rect) 
     949         
     950        return r 
    987951         
    988952    def set_state(self, state): 
     
    12331197        if self.auto_send_selection_callback: 
    12341198            self.auto_send_selection_callback() 
     1199             
     1200    def pan(self, delta): 
     1201        if type(delta) == tuple: 
     1202            x, y = delta 
     1203        else: 
     1204            x, y = delta.x(), delta.y() 
     1205        t = self.zoom_transform 
     1206        x = x / t.m11() 
     1207        y = y / t.m22() 
     1208        r = QRectF(self.zoom_rect) 
     1209        r.translate(-QPointF(x,y)) 
     1210        self.ensure_inside(r, self.graph_area) 
     1211        self.zoom_rect = r 
     1212 
     1213    def zoom_to_rect(self, rect): 
     1214        self.ensure_inside(rect, self.graph_area) 
     1215        self.animate(self, 'zoom_rect', rect) 
     1216 
     1217    def reset_zoom(self): 
     1218        self._zoom_rect = None 
     1219        self.update_zoom() 
     1220         
     1221    @pyqtProperty(QTransform) 
     1222    def zoom_transform(self): 
     1223        return self.transform_from_rects(self.zoom_rect, self.graph_area) 
     1224         
     1225    def zoom_in(self, point): 
     1226        self.zoom(point, scale = 2) 
     1227         
     1228    def zoom_out(self, point): 
     1229        self.zoom(point, scale = 0.5) 
     1230         
     1231    def zoom(self, point, scale): 
     1232        r = QRectF(self.zoom_rect) 
     1233        i = 1.0/scale 
     1234        r.setTopLeft(point*(1-i) + r.topLeft()*i) 
     1235        r.setBottomRight(point*(1-i) + r.bottomRight()*i) 
     1236         
     1237        self.ensure_inside(r, self.graph_area) 
     1238        self.zoom_to_rect(r) 
     1239         
     1240    @pyqtProperty(QRectF) 
     1241    def zoom_rect(self): 
     1242        return self._zoom_rect if self._zoom_rect else self.graph_area 
     1243         
     1244    @zoom_rect.setter 
     1245    def zoom_rect(self, rect): 
     1246        self._zoom_rect = rect 
     1247        self._zoom_transform = self.transform_from_rects(rect, self.graph_area) 
     1248        self.update_zoom() 
     1249         
     1250    @staticmethod 
     1251    def ensure_inside(small_rect, big_rect): 
     1252        if small_rect.width() > big_rect.width(): 
     1253            small_rect.setWidth(big_rect.width()) 
     1254        if small_rect.height() > big_rect.height(): 
     1255            small_rect.setHeight(big_rect.height()) 
     1256         
     1257        if small_rect.right() > big_rect.right(): 
     1258            small_rect.moveRight(big_rect.right()) 
     1259        elif small_rect.left() < big_rect.left(): 
     1260            small_rect.moveLeft(big_rect.left()) 
     1261             
     1262        if small_rect.bottom() > big_rect.bottom(): 
     1263            small_rect.moveBottom(big_rect.bottom()) 
     1264        elif small_rect.top() < big_rect.top(): 
     1265            small_rect.moveTop(big_rect.top()) 
  • source/orangeplot/curve.cpp

    r8501 r8569  
    6868  { 
    6969    QPen p = m_pen; 
    70     p.setWidthF(m_pen.widthF()/m_zoom_factor); 
     70    p.setWidthF(m_pen.widthF()/m_zoom_transform.determinant()); 
    7171    m_lineItem->setPen(p); 
    7272    m_line = QPainterPath(); 
     
    109109  if (m_needsUpdate & (UpdateZoom | UpdateBrush | UpdatePen | UpdateSize | UpdateSymbol) ) 
    110110  { 
    111     update_items(m_pointItems, PointUpdater(m_symbol, m_color, m_pointSize, Point::DisplayPath, 1.0/m_zoom_factor), UpdateSymbol); 
     111    update_items(m_pointItems, PointUpdater(m_symbol, m_color, m_pointSize, Point::DisplayPath, point_transform()), UpdateSymbol); 
    112112  } 
    113113  m_needsUpdate = 0; 
     
    314314} 
    315315 
    316 double Curve::zoom_factor() 
    317 { 
    318     return m_zoom_factor; 
    319 } 
    320  
    321 void Curve::set_zoom_factor(double factor) 
    322 { 
    323     m_zoom_factor = factor; 
     316void Curve::set_zoom_transform(const QTransform& transform) 
     317{ 
     318    m_zoom_transform = transform; 
    324319    m_needsUpdate |= UpdateZoom; 
    325320    checkForUpdate(); 
     321} 
     322 
     323QTransform Curve::zoom_transform() 
     324{ 
     325    return m_zoom_transform; 
    326326} 
    327327 
     
    349349} 
    350350 
     351QTransform Curve::point_transform() 
     352{ 
     353    const QTransform i = m_zoom_transform.inverted(); 
     354    return QTransform(i.m11(), 0, 0, 0, i.m22(), 0, 0, 0, 1.0); 
     355} 
     356 
  • source/orangeplot/curve.h

    r8501 r8569  
    1616}; 
    1717 
    18 struct ScaleUpdater 
    19 { 
    20     ScaleUpdater(double scale) {m_scale = scale;} 
    21     void operator()(QGraphicsItem* item) {item->setScale(m_scale);} 
     18struct ZoomUpdater 
     19{ 
     20    ZoomUpdater(const QTransform& inv_zoom) : transform(inv_zoom) {} 
     21    void operator()(QGraphicsItem* item) 
     22    { 
     23        item->setTransform(transform); 
     24    } 
    2225     
    2326private: 
    24     double m_scale; 
     27    QTransform transform; 
    2528}; 
    2629 
    2730struct PointUpdater 
    2831{ 
    29     PointUpdater(int symbol, QColor color, int size, Point::DisplayMode mode, double scale) 
     32    PointUpdater(int symbol, QColor color, int size, Point::DisplayMode mode, const QTransform& scale) 
    3033    { 
    3134        m_symbol = symbol; 
     
    4245        point->set_size(m_size); 
    4346        point->set_display_mode(m_mode); 
    44         point->setScale(m_scale); 
     47        point->setTransform(m_scale); 
    4548    } 
    4649     
     
    5053     int m_size; 
    5154     Point::DisplayMode m_mode; 
    52      double m_scale; 
     55     QTransform m_scale; 
    5356}; 
    5457 
     
    155158  void set_auto_update(bool auto_update); 
    156159   
    157   double zoom_factor(); 
    158   void set_zoom_factor(double factor); 
     160  QTransform zoom_transform(); 
     161  void set_zoom_transform(const QTransform& transform); 
    159162   
    160163  double max_x_value() const; 
     
    183186  void update_items(Sequence& sequence, Updater updater, Curve::UpdateFlag flag); 
    184187   
     188protected: 
     189  QTransform point_transform(); 
     190   
    185191private: 
    186192  void checkForUpdate(); 
     
    204210  QPen m_pen; 
    205211  QBrush m_brush; 
    206   double m_zoom_factor; 
     212  QTransform m_zoom_transform; 
    207213  QMap<UpdateFlag, QFuture<void> > m_currentUpdate; 
    208214}; 
  • source/orangeplot/curve.sip

    r8444 r8569  
    9999  void set_style(int style); 
    100100  
    101   double zoom_factor(); 
    102   void set_zoom_factor(double factor); 
     101  QTransform zoom_transform(); 
     102  void set_zoom_transform(const QTransform& transform); 
    103103 
    104104  bool auto_update() const; 
     
    121121  void set_dirty(Curve::UpdateFlags flags = Curve::UpdateAll); 
    122122   
     123protected: 
     124  QTransform point_transform(); 
     125   
    123126}; 
  • source/orangeplot/networkcurve.cpp

    r8556 r8569  
    277277{ 
    278278    const QTransform t = graph_transform(); 
    279     const double scale = 1.0/zoom_factor(); 
    280     update_items(m_nodes, NodeUpdater(t, scale), UpdatePosition); 
     279    update_items(m_nodes, NodeUpdater(t, point_transform()), UpdatePosition); 
    281280    update_items(m_edges, EdgeUpdater(t), UpdatePen); 
    282281} 
  • source/orangeplot/networkcurve.h

    r8556 r8569  
    112112{ 
    113113public: 
    114     NodeUpdater(const QTransform& t, double scale) : m_t(t), m_scale(scale) {} 
     114    NodeUpdater(const QTransform& t, const QTransform& zoom) : m_t(t), m_zoom(zoom) {} 
    115115    void operator()(NodeItem* item)  
    116116    {  
    117117        item->set_graph_transform(m_t);  
    118         item->setScale(m_scale); 
     118        item->setTransform(m_zoom); 
    119119    } 
    120120private: 
    121121    QTransform m_t; 
    122     double m_scale; 
     122    QTransform m_zoom; 
    123123}; 
    124124 
     
    126126{ 
    127127public: 
    128     EdgeUpdater(const QTransform& t) : m_t(t){} 
     128    EdgeUpdater(const QTransform& t) : m_t(t) {} 
    129129    void operator()(EdgeItem* item) 
    130130    { 
     
    139139private: 
    140140    QTransform m_t; 
    141     double m_scale; 
    142141}; 
    143142 
  • source/orangeplot/plot.cpp

    r8540 r8569  
    1313} 
    1414 
    15 inline double distance(const DataPoint& one, const DataPoint& other) 
     15inline double distance(const QPointF& one, const QPointF& other) 
    1616{ 
    1717    // For speed, we use the slightly wrong method, also known as Manhattan distance 
    18     return fabs(one.x - other.x) + fabs(one.y - other.y);  
     18    return (one - other).manhattanLength(); 
    1919} 
    2020 
     
    240240} 
    241241 
    242 Point* Plot::nearest_point(const DataPoint& pos, double max_distance) 
     242Point* Plot::nearest_point(const QPointF& pos) 
    243243{ 
    244244    QPair<double, DataPoint> closest_point = qMakePair( std::numeric_limits<double>::max(), DataPoint() ); 
     
    253253        for (it; it != end; ++it) 
    254254        { 
    255             const double d = distance(*it, pos); 
     255            const double d = distance(m_point_hash[item][*it]->pos(), pos); 
    256256            if (d < closest_point.first) 
    257257            { 
     
    261261        } 
    262262    } 
    263     if (closest_point.first < max_distance) 
    264     { 
    265         return point_at(closest_point.second); 
    266     } 
    267     return 0; 
     263    Point* point = point_at(closest_point.second); 
     264    if(distance(point->pos(), pos) <= point->size()) 
     265    { 
     266        return point; 
     267    } 
     268    else 
     269    { 
     270        return 0; 
     271    } 
    268272} 
    269273 
  • source/orangeplot/plot.h

    r8540 r8569  
    5858    QList< int > selected_points(const QList< double > x_data, const QList< double > y_data, const QTransform& transform); 
    5959     
    60     /** 
    61      * This function uses a fuzzy equality check, so it will return any function that is near enough.  
    62      *  
    63      * The equality check is specified in compare_data() 
    64      *  
    65      **/ 
    66     Point* nearest_point(const DataPoint& pos, double max_distance); 
     60    Point* nearest_point(const QPointF& pos); 
    6761     
    6862    Point* point_at(const DataPoint& pos); 
  • source/orangeplot/plot.sip

    r8540 r8569  
    6767     
    6868    QList< int > selected_points(const QList< double > x_data, const QList< double > y_data, const QTransform& transform); 
    69     Point* nearest_point(const DataPoint& pos, double max_distance); 
     69    Point* nearest_point(const QPointF& pos); 
    7070    Point* point_at(const DataPoint& pos); 
    7171     
Note: See TracChangeset for help on using the changeset viewer.