1
# location.rb: handling the concept of "location" (for an axis especially)
2
# copyright (c) 2009 by Vincent Fourmond
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.
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).
14
require 'ctioga2/utils'
19
Version::register_svn_info('$Revision: 223 $', '$Date: 2011-01-11 01:07:48 +0100 (Tue, 11 Jan 2011) $')
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.
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
41
# Horizontal or vertical
51
# A few helper hashes to convert from sides to margins
52
# @todo won't work for origins.
53
LocationBaseMargins = {
60
# Multiply this by the frame dimension in the correct
61
# direction to get the frame margins.
62
LocationMarginMultiplier = {
65
:bottom => [0,0,0,-1],
69
LocationsReorientMargins = {
76
# The position of the object, one of :left, :right, :top,
77
# :bottom, :at_y_origin or :at_x_origin.
79
# @todo This will have to be extended to allow possibly
80
# arbitrary frame/figure placement.
81
attr_accessor :base_location
83
# The shift away from the position given by #base_location.
85
# This will be a Dimension object.
87
# @todo This is not currently implemented
91
# Creates a new PlotLocation object, either copying the one
92
# given as argument or from scratch specifying at least the
94
def initialize(location, shift = nil)
95
if location.respond_to? :shift
96
@base_location = location.base_location
97
@shift = shift || location.shift
99
@base_location = location
104
# Returns the tioga location (ie that suitable for sending to
105
# show_axis for instance)
107
return LocationToTiogaLocation[@base_location]
110
# Whether the given location is vertical or horizontal
112
return LocationVertical[@base_location]
115
# Returns the orientation away from the graph
124
# Extra extension that should be reserved for a label on the
125
# given side based on simple heuristics. Value is returned in
127
def label_extra_space(t)
130
extra = 0.5 # To account for baseline ?
133
else # We take the safe side !
137
## @todo Here add the shift
142
# Returns whether the location is on the given side.
144
return @base_location == which
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|
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.
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)
170
add = Dobjects::Dvector[*LocationMarginMultiplier[@base_location]]
176
def do_sub_frame(t, size)
177
margins = frame_margins_for_size(t, size)
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])
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
193
t.set_frame_sides(left, right, top, bottom)
198
# Creates a location from the given text
200
# So far, no real parsing
201
def self.from_text(str)
203
return PlotLocation.new(str.to_sym)
209
# Something meant to be fed to PlotStyle#get_axis_style
210
LocationType = CmdType.new('location', { :type => :function_based,
211
:class => Graphics::Types::PlotLocation
213
A position on the plot, referenced with respect to the sides. Can be:
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.