~ubuntu-branches/ubuntu/precise/python-chaco/precise

« back to all changes in this revision

Viewing changes to enthought/chaco/tools/base_zoom_tool.py

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2008-12-29 02:34:05 UTC
  • Revision ID: james.westby@ubuntu.com-20081229023405-x7i4kp9mdxzmdnvu
Tags: upstream-3.0.1
ImportĀ upstreamĀ versionĀ 3.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
""" Defines the base class for various types of zoom tools.
 
2
"""
 
3
 
 
4
from numpy import allclose, inf
 
5
 
 
6
# Enthought library imports
 
7
from enthought.traits.api import Enum, Float, HasTraits
 
8
 
 
9
class BaseZoomTool(HasTraits):
 
10
    """ Defines traits and methods to actually perform the logic of zooming
 
11
    onto a plot.
 
12
    """
 
13
    
 
14
    # If the tool only applies to a particular axis, this attribute is used to
 
15
    # determine which mapper and range to use.
 
16
    axis = Enum("index", "value")
 
17
 
 
18
    # The maximum ratio between the original data space bounds and the zoomed-in
 
19
    # data space bounds.  If None, then there is no limit (not advisable!).
 
20
    max_zoom_in_factor = Float(1e5, allow_none=True)
 
21
 
 
22
    # The maximum ratio between the zoomed-out data space bounds and the original
 
23
    # bounds.  If None, then there is no limit.
 
24
    max_zoom_out_factor = Float(1e5, allow_none=True)
 
25
    
 
26
    def _zoom_limit_reached(self, orig_low, orig_high, new_low, new_high):
 
27
        """ Returns True if the new low and high exceed the maximum zoom
 
28
        limits
 
29
        """
 
30
        orig_bounds = orig_high - orig_low
 
31
 
 
32
        if orig_bounds == inf:
 
33
            # There isn't really a good way to handle the case when the
 
34
            # original bounds were infinite, since any finite zoom
 
35
            # range will certainly exceed whatever zoom factor is set.
 
36
            # In this case, we just allow unbounded levels of zoom.
 
37
            return False
 
38
        
 
39
        new_bounds = new_high - new_low
 
40
        if allclose(orig_bounds, 0.0):
 
41
            return True
 
42
        if allclose(new_bounds, 0.0):
 
43
            return True
 
44
        if (new_bounds / orig_bounds) > self.max_zoom_out_factor or \
 
45
           (orig_bounds / new_bounds) > self.max_zoom_in_factor:
 
46
            return True
 
47
        return False
 
48
 
 
49
    #------------------------------------------------------------------------
 
50
    # Utility methods for computing axes, coordinates, etc.
 
51
    #------------------------------------------------------------------------
 
52
 
 
53
    def _get_mapper(self):
 
54
        """ Returns the mapper for the component associated with this tool.
 
55
        
 
56
        The zoom tool really only cares about this, so subclasses can easily
 
57
        customize SimpleZoom to work with all sorts of components just by
 
58
        overriding this method.
 
59
        """
 
60
        if self.component is not None:
 
61
            return getattr(self.component, self.axis + "_mapper")
 
62
        else:
 
63
            return None
 
64
        
 
65
 
 
66
    def _get_axis_coord(self, event, axis="index"):
 
67
        """ Returns the coordinate of the event along the axis of interest
 
68
        to the tool (or along the orthogonal axis, if axis="value").
 
69
        """
 
70
        event_pos = (event.x, event.y)
 
71
        if axis == "index":
 
72
            return event_pos[ self._determine_axis() ]
 
73
        else:
 
74
            return event_pos[ 1 - self._determine_axis() ]
 
75
 
 
76
    def _determine_axis(self):
 
77
        """ Determines whether the index of the coordinate along the axis of
 
78
        interest is the first or second element of an (x,y) coordinate tuple.
 
79
        """
 
80
        if self.axis == "index":
 
81
            if self.component.orientation == "h":
 
82
                return 0
 
83
            else:
 
84
                return 1
 
85
        else:   # self.axis == "value"
 
86
            if self.component.orientation == "h":
 
87
                return 1
 
88
            else:
 
89
                return 0
 
90
 
 
91
    def _map_coordinate_box(self, start, end):
 
92
        """ Given start and end points in screen space, returns corresponding
 
93
        low and high points in data space.
 
94
        """
 
95
        low = [0,0]
 
96
        high = [0,0]
 
97
        for axis_index, mapper in [(0, self.component.x_mapper), \
 
98
                                   (1, self.component.y_mapper)]:
 
99
            low_val = mapper.map_data(start[axis_index])
 
100
            high_val = mapper.map_data(end[axis_index])
 
101
            
 
102
            if low_val > high_val:
 
103
                low_val, high_val = high_val, low_val
 
104
            low[axis_index] = low_val
 
105
            high[axis_index] = high_val
 
106
        return low, high
 
107