~ubuntu-branches/ubuntu/oneiric/ctioga2/oneiric

« back to all changes in this revision

Viewing changes to lib/ctioga2/graphics/styles/axes.rb

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Fourmond
  • Date: 2011-01-24 21:36:06 UTC
  • Revision ID: james.westby@ubuntu.com-20110124213606-9ettx0ugl83z0bzp
Tags: upstream-0.1
ImportĀ upstreamĀ versionĀ 0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# axes.rb: the style of one axis or edge 
 
2
# copyright (c) 2009 by Vincent Fourmond
 
3
  
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
  
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details (in the COPYING file).
 
13
 
 
14
require 'ctioga2/utils'
 
15
require 'ctioga2/log'
 
16
 
 
17
# This module contains all the classes used by ctioga
 
18
module CTioga2
 
19
 
 
20
  Version::register_svn_info('$Revision: 202 $', '$Date: 2010-11-30 22:21:17 +0100 (Tue, 30 Nov 2010) $')
 
21
 
 
22
  module Graphics
 
23
 
 
24
    module Styles
 
25
 
 
26
      # The style of an axis or an egde of the plot. Unlike tioga,
 
27
      # ctioga2 does not make any difference.
 
28
      class AxisStyle < BasicStyle
 
29
        include Tioga::FigureConstants
 
30
        
 
31
        # The type of the edge/axis. Any of the Tioga constants:
 
32
        # AXIS_HIDDEN, AXIS_LINE_ONLY, AXIS_WITH_MAJOR_TICKS_ONLY,
 
33
        # AXIS_WITH_TICKS_ONLY,
 
34
        # AXIS_WITH_MAJOR_TICKS_AND_NUMERIC_LABELS, and
 
35
        # AXIS_WITH_TICKS_AND_NUMERIC_LABELS.
 
36
        attr_accessor :decoration
 
37
        
 
38
        # The position of the axis. Can be one of :left, :right, :top,
 
39
        # :bottom, :at_y_origin or :at_x_origin.
 
40
        attr_accessor :location
 
41
 
 
42
        # Offset of the axis with respect to its normal position. It
 
43
        # is counted *away* from the graph. It is either a
 
44
        # Types::Dimension object or _nil_.
 
45
        attr_accessor :offset
 
46
 
 
47
        # The background lines for the given axis. _nil_ for nothing,
 
48
        # or a StrokeStyle object if we want to draw something.
 
49
        attr_accessor :background_lines
 
50
 
 
51
        # The style of the tick labels
 
52
        attr_accessor :tick_label_style
 
53
 
 
54
        # The label of the axis, if there is one
 
55
        attr_accessor :axis_label
 
56
 
 
57
        # Whether the axis should be log scale or not
 
58
        attr_accessor :log
 
59
 
 
60
        # Transform: a Types::Bijection object specifying a coordinate
 
61
        # transformation for the axis.
 
62
        attr_accessor :transform
 
63
 
 
64
        # The color of the stroke for the lines of the axis
 
65
        attr_accessor :stroke_color
 
66
 
 
67
 
 
68
        # Creates a new AxisStyle object at the given location with
 
69
        # the given style.
 
70
        def initialize(location = nil, decoration = nil, label = nil)
 
71
          @location = Types::PlotLocation.new(location)
 
72
          @decoration = decoration
 
73
 
 
74
          @tick_label_style = FullTextStyle.new
 
75
          @axis_label = TextLabel.new(label)
 
76
          @log = false
 
77
        end
 
78
 
 
79
        # Draws the axis within the current plot. Boundaries are the
 
80
        # current plot boundaries. Also draw the #axis_label, if there
 
81
        # is one.
 
82
        #
 
83
        # \todo
 
84
        # * the offset mechanism, to place the axis away from the place
 
85
        #   where it should be...
 
86
        # * non-linear axes (or linear, for that matter, but with
 
87
        #   a transformation)
 
88
        def draw_axis(t)
 
89
          spec = get_axis_specification(t)
 
90
          # Add tick label style:
 
91
          spec.merge!(@tick_label_style.to_hash)
 
92
          if @stroke_color
 
93
            spec['stroke_color'] = @stroke_color
 
94
          end
 
95
          t.show_axis(spec)
 
96
          @axis_label.loc = @location
 
97
          default = vertical? ? 'ylabel' : 'xlabel'
 
98
          @axis_label.draw(t, default)
 
99
        end
 
100
 
 
101
        # Sets the current boundaries of the _t_ object to the _range_
 
102
        # SimpleRange object for the direction handled by the
 
103
        # AxisStyle, without touching the rest.
 
104
        def set_bounds_for_axis(t, range = nil)
 
105
          if ! range
 
106
            return
 
107
          end
 
108
          l,r,top,b = t.bounds_left, t.bounds_right, 
 
109
          t.bounds_top, t.bounds_bottom
 
110
 
 
111
          if self.vertical?
 
112
            b = range.first
 
113
            top = range.last
 
114
          else
 
115
            l = range.first
 
116
            r = range.last
 
117
          end
 
118
          t.set_bounds([l,r,top,b])
 
119
        end
 
120
 
 
121
        # Draw the axis background lines:
 
122
        def draw_background_lines(t)
 
123
          if @background_lines
 
124
            # First, getting major ticks location from tioga
 
125
            info = t.axis_information(get_axis_specification(t))
 
126
 
 
127
            if info['vertical']
 
128
              x0 = t.bounds_left
 
129
              x1 = t.bounds_right
 
130
            else
 
131
              y0 = t.bounds_bottom
 
132
              y1 = t.bounds_top
 
133
            end
 
134
            t.context do
 
135
              @background_lines.set_stroke_style(t)
 
136
              values = info['major_ticks'] || info['major']
 
137
              for val in values
 
138
                if info['vertical']
 
139
                  t.stroke_line(x0, val, x1, val)
 
140
                else
 
141
                  t.stroke_line(val, y0, val, y1)
 
142
                end
 
143
              end
 
144
            end
 
145
          end
 
146
        end
 
147
 
 
148
        # Returns the AxisStyle object corresponding to the named axis
 
149
        # in the current plot.
 
150
        def self.current_axis_style(plotmaker, spec)
 
151
          return PlotStyle.current_plot_style(plotmaker).
 
152
            get_axis_style(spec)
 
153
        end
 
154
 
 
155
        # Returns the part of the #extension only due to the labels
 
156
        # (ticks and standard label).
 
157
        #
 
158
        # For now, it returns the same value as #extension, but that
 
159
        # might change
 
160
        def labels_only_extension(t, style = nil)
 
161
          ticks_shift, ticks_scale = *get_ticks_parameters(t)
 
162
          default =  vertical? ? 'ylabel' : 'xlabel'
 
163
          le = @axis_label.label_extension(t, default, @location)
 
164
 
 
165
          case @decoration
 
166
          when AXIS_WITH_MAJOR_TICKS_AND_NUMERIC_LABELS,
 
167
            AXIS_WITH_TICKS_AND_NUMERIC_LABELS
 
168
            te = ticks_shift * ticks_scale
 
169
          else
 
170
            te = 0
 
171
          end
 
172
          return Dobjects::Dvector[le,te].max * 
 
173
            (style ? style.text_scale || 1 : 1)
 
174
        end
 
175
 
 
176
        # Returns the extension of the axis (including tick labels and
 
177
        # labels if applicable) perpendicular to itself, in units of
 
178
        # text height (at scale = current text scale when drawing
 
179
        # axes).
 
180
        #
 
181
        # _style_ is a PlotStyle object containing the style
 
182
        # information for the target plot.
 
183
        #
 
184
        # \todo handle offset axes when that is implemented.
 
185
        def extension(t, style = nil)
 
186
          return labels_only_extension(t, style)
 
187
        end
 
188
 
 
189
        protected
 
190
 
 
191
        # Whether the axis is vertical or not
 
192
        def vertical?
 
193
          return @location.vertical?
 
194
        end
 
195
 
 
196
        # Returns: _ticks_shift_, _ticks_scale_ for the axis.
 
197
        #
 
198
        # \todo try something clever with the angles ?
 
199
        def get_ticks_parameters(t)
 
200
          i = t.axis_information({'location' => @location.tioga_location})
 
201
          retval = []
 
202
          retval << (@tick_label_style.shift || i['shift'])
 
203
          retval << (@tick_label_style.scale || i['scale'])
 
204
 
 
205
          retval[0] += 1
 
206
          return retval
 
207
        end
 
208
        
 
209
        # Returns an argument suitable for use for
 
210
        # FigureMaker#show_axis or FigureMaker#axis_information.
 
211
        #
 
212
        # For the log axis scale to work, tioga revision 543 is
 
213
        # absolutely necessary. It won't fail, though, without it.
 
214
        def get_axis_specification(t)
 
215
          if @transform
 
216
            retval = compute_coordinate_transforms(t)
 
217
          else
 
218
            retval = {}
 
219
          end
 
220
          if @offset 
 
221
            raise YetUnimplemented, "This has not been implemented yet"
 
222
          else
 
223
            retval.
 
224
              update({'location' => @location.tioga_location,
 
225
                       'type' => @decoration, 'log' => @log})
 
226
            return retval
 
227
          end
 
228
        end
 
229
 
 
230
        # Setup coordinate transformations
 
231
        def compute_coordinate_transforms(t)
 
232
          return unless @transform
 
233
          # We'll proceed by steps...
 
234
          i = t.axis_information({'location' => @location.tioga_location})
 
235
          t.context do 
 
236
            if i['vertical']
 
237
              top,b = @transform.convert_to([t.bounds_top, t.bounds_bottom])
 
238
              l,r = t.bounds_left, t.bounds_right
 
239
            else
 
240
              top,b = t.bounds_top, t.bounds_bottom
 
241
              l,r = @transform.convert_to([t.bounds_left, t.bounds_right])
 
242
            end
 
243
            t.set_bounds([l,r,top,b])
 
244
            i = t.axis_information({'location' => @location.tioga_location})
 
245
            # Now, we have the location of everything we need.
 
246
          end
 
247
          # In the following, the || are because of a fix in Tioga
 
248
          # r545
 
249
          return { 'labels' => i['labels'], 
 
250
            'major_ticks' => @transform.
 
251
            convert_from(i['major_ticks'] || i['major']),
 
252
            'minor_ticks' => @transform.
 
253
            convert_from(i['minor_ticks'] || i['minor'] )
 
254
          }
 
255
        end
 
256
 
 
257
 
 
258
       
 
259
      end
 
260
 
 
261
      PartialAxisStyle = {
 
262
        'transform' => CmdArg.new('bijection'),
 
263
        'location' => CmdArg.new('location'),
 
264
        'stroke_color' => CmdArg.new('color')
 
265
      }
 
266
 
 
267
      FullAxisStyle = PartialAxisStyle.dup
 
268
      FullAxisStyle['decoration'] = CmdArg.new('axis-decoration')
 
269
                       
 
270
 
 
271
    end
 
272
  end
 
273
end