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

« back to all changes in this revision

Viewing changes to lib/ctioga2/graphics/types/location.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
# location.rb: handling the concept of "location" (for an axis especially)
 
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, but
 
10
# WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
# General Public License for more details (in the COPYING file).
 
13
 
 
14
require 'ctioga2/utils'
 
15
require 'ctioga2/log'
 
16
 
 
17
module CTioga2
 
18
 
 
19
  Version::register_svn_info('$Revision: 223 $', '$Date: 2011-01-11 01:07:48 +0100 (Tue, 11 Jan 2011) $')
 
20
 
 
21
  module Graphics
 
22
 
 
23
    module Types
 
24
 
 
25
 
 
26
      # Location of an object (especially axes) in a plot, in terms of
 
27
      # the side of the plot or the X and Y axis.
 
28
      class PlotLocation
 
29
 
 
30
        # Conversion between the #base_location attribute and the real
 
31
        # constant used for Tioga
 
32
        LocationToTiogaLocation = {
 
33
          :left => Tioga::FigureConstants::LEFT,
 
34
          :right => Tioga::FigureConstants::RIGHT,
 
35
          :bottom => Tioga::FigureConstants::BOTTOM,
 
36
          :top => Tioga::FigureConstants::TOP,
 
37
          :at_x_origin => Tioga::FigureConstants::AT_X_ORIGIN,
 
38
          :at_y_origin => Tioga::FigureConstants::AT_Y_ORIGIN
 
39
        }
 
40
 
 
41
        # Horizontal or vertical
 
42
        LocationVertical = {
 
43
          :left => true,
 
44
          :right => true,
 
45
          :bottom => false,
 
46
          :top => false,
 
47
          :at_x_origin => true,
 
48
          :at_y_origin => false
 
49
        }
 
50
 
 
51
        # A few helper hashes to convert from sides to margins
 
52
        # @todo won't work for origins.
 
53
        LocationBaseMargins = {
 
54
          :left => [0,1,0,0],
 
55
          :right => [1,0,0,0],
 
56
          :bottom => [0,0,1,0],
 
57
          :top => [0,0,0,1]
 
58
        }
 
59
 
 
60
        # Multiply this by the frame dimension in the correct
 
61
        # direction to get the frame margins.
 
62
        LocationMarginMultiplier = {
 
63
          :left => [-1,0,0,0],
 
64
          :right => [0,-1,0,0],
 
65
          :bottom => [0,0,0,-1],
 
66
          :top => [0,0,-1,0]
 
67
        }
 
68
 
 
69
        LocationsReorientMargins = {
 
70
          :left => [1,0,3,2],
 
71
          :right => [0,1,2,3],
 
72
          :top => [2,3,1,0],
 
73
          :bottom => [3,2,0,1]
 
74
        }
 
75
 
 
76
        # The position of the object, one of :left, :right, :top,
 
77
        # :bottom, :at_y_origin or :at_x_origin.
 
78
        #
 
79
        # @todo This will have to be extended to allow possibly
 
80
        # arbitrary frame/figure placement.
 
81
        attr_accessor :base_location
 
82
 
 
83
        # The shift away from the position given by #base_location.
 
84
        #
 
85
        # This will be a Dimension object.
 
86
        #
 
87
        # @todo This is not currently implemented
 
88
        attr_accessor :shift
 
89
        
 
90
 
 
91
        # Creates a new PlotLocation object, either copying the one
 
92
        # given as argument or from scratch specifying at least the
 
93
        # base location.
 
94
        def initialize(location, shift = nil)
 
95
          if location.respond_to? :shift
 
96
            @base_location = location.base_location
 
97
            @shift = shift || location.shift
 
98
          else
 
99
            @base_location = location
 
100
            @shift = shift
 
101
          end
 
102
        end
 
103
 
 
104
        # Returns the tioga location (ie that suitable for sending to
 
105
        # show_axis for instance)
 
106
        def tioga_location
 
107
          return LocationToTiogaLocation[@base_location]
 
108
        end
 
109
 
 
110
        # Whether the given location is vertical or horizontal
 
111
        def vertical?
 
112
          return LocationVertical[@base_location]
 
113
        end
 
114
 
 
115
        # Returns the orientation away from the graph
 
116
        def orientation
 
117
          if vertical?
 
118
            return :x
 
119
          else
 
120
            return :y
 
121
          end
 
122
        end
 
123
 
 
124
        # Extra extension that should be reserved for a label on the
 
125
        # given side based on simple heuristics. Value is returned in
 
126
        # text height units.
 
127
        def label_extra_space(t)
 
128
          case @base_location
 
129
          when :bottom, :right
 
130
            extra = 0.5       # To account for baseline ?
 
131
          when :top, :left
 
132
            extra = 1
 
133
          else                # We take the safe side !
 
134
            extra = 1
 
135
          end
 
136
          if @shift
 
137
            ## @todo Here add the shift
 
138
          end
 
139
          return extra
 
140
        end
 
141
 
 
142
        # Returns whether the location is on the given side.
 
143
        def is_side?(which)
 
144
          return @base_location == which
 
145
        end
 
146
 
 
147
        # Takes a set of margins, expressed in relative terms, ie
 
148
        # * _close_ (the margins on the side next to the graph),
 
149
        # * _away_ (on the other side),
 
150
        # * _aleft_ (on the left going away from the graph) and
 
151
        # * _aright_ (on the right going away from the graph)
 
152
        # into a left,right,top,bottom suitable for standards margins calls.
 
153
        def reorient_margins(close, away, aleft, aright)
 
154
          a = [close, away, aleft, aright]
 
155
          return LocationsReorientMargins[@base_location].map do |i|
 
156
            a[i]
 
157
          end
 
158
        end
 
159
 
 
160
        # Returns the margins argument suitable for sending to
 
161
        # set_subframe to paint within the region defined by the given
 
162
        # size at the given position.
 
163
        # 
 
164
        # _size_ is a Dimension object.
 
165
        def frame_margins_for_size(t, size)
 
166
          margins = Dobjects::Dvector[*LocationBaseMargins[@base_location]]
 
167
          ## @todo handle the case of at Y and at X
 
168
          dim = size.to_frame(t, orientation)
 
169
 
 
170
          add = Dobjects::Dvector[*LocationMarginMultiplier[@base_location]]
 
171
          add.mul!(dim)
 
172
          margins += add
 
173
          return margins
 
174
        end
 
175
 
 
176
        def do_sub_frame(t, size) 
 
177
          margins = frame_margins_for_size(t, size)
 
178
 
 
179
          ## @todo This is should integrate some common class.
 
180
          left = t.convert_frame_to_page_x(margins[0])
 
181
          right = t.convert_frame_to_page_x(1 - margins[1])
 
182
          top = t.convert_frame_to_page_y(1 - margins[2])
 
183
          bottom = t.convert_frame_to_page_y(margins[3])
 
184
 
 
185
          # Ensure that we don't have coords outside of the page range
 
186
          # because of rounding problems:
 
187
          left = 0.0 if left < 0
 
188
          bottom = 0.0 if bottom < 0
 
189
          right = 1.0 if right > 1
 
190
          top = 1.0 if top > 1
 
191
 
 
192
          t.context do 
 
193
            t.set_frame_sides(left, right, top, bottom)
 
194
            yield
 
195
          end
 
196
        end
 
197
 
 
198
        # Creates a location from the given text
 
199
        #
 
200
        # So far, no real parsing
 
201
        def self.from_text(str)
 
202
          str.gsub!(/-/,"_")
 
203
          return PlotLocation.new(str.to_sym)
 
204
        end
 
205
 
 
206
        
 
207
      end
 
208
 
 
209
      # Something meant to be fed to PlotStyle#get_axis_style
 
210
      LocationType = CmdType.new('location', { :type => :function_based,
 
211
                                 :class => Graphics::Types::PlotLocation
 
212
                                 }, <<EOD)
 
213
A position on the plot, referenced with respect to the sides. Can be:
 
214
 * @left@
 
215
 * @right@
 
216
 * @top@
 
217
 * @bottom@
 
218
 
 
219
In addition, there will one day be the possibility to specify an 
 
220
offset from these locations. But that is still something to do.
 
221
EOD
 
222
 
 
223
 
 
224
      
 
225
    end
 
226
  end
 
227
end
 
228