ctioga2 0.0 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/Changelog +25 -1
  2. data/lib/ctioga2/commands/commands.rb +13 -2
  3. data/lib/ctioga2/commands/doc/doc.rb +13 -17
  4. data/lib/ctioga2/commands/doc/documentation-commands.rb +14 -1
  5. data/lib/ctioga2/commands/doc/help.rb +136 -25
  6. data/lib/ctioga2/commands/doc/html.rb +56 -4
  7. data/lib/ctioga2/commands/doc/introspection.rb +45 -9
  8. data/lib/ctioga2/commands/doc/man.rb +7 -5
  9. data/lib/ctioga2/commands/doc/markup.rb +39 -12
  10. data/lib/ctioga2/commands/doc/wordwrap.rb +70 -0
  11. data/lib/ctioga2/commands/general-commands.rb +7 -4
  12. data/lib/ctioga2/commands/general-types.rb +27 -12
  13. data/lib/ctioga2/commands/interpreter.rb +2 -2
  14. data/lib/ctioga2/commands/parsers/command-line.rb +9 -5
  15. data/lib/ctioga2/commands/parsers/file.rb +5 -3
  16. data/lib/ctioga2/commands/type.rb +10 -3
  17. data/lib/ctioga2/commands/variables.rb +2 -2
  18. data/lib/ctioga2/data/backends/backend.rb +17 -15
  19. data/lib/ctioga2/data/backends/backends.rb +2 -2
  20. data/lib/ctioga2/data/backends/backends/gnuplot.rb +20 -5
  21. data/lib/ctioga2/data/backends/backends/math.rb +2 -2
  22. data/lib/ctioga2/data/backends/backends/text.rb +112 -17
  23. data/lib/ctioga2/data/backends/description.rb +10 -11
  24. data/lib/ctioga2/data/datacolumn.rb +73 -14
  25. data/lib/ctioga2/data/dataset.rb +305 -9
  26. data/lib/ctioga2/data/filters.rb +49 -1
  27. data/lib/ctioga2/data/indexed-dtable.rb +137 -0
  28. data/lib/ctioga2/data/point.rb +98 -7
  29. data/lib/ctioga2/data/stack.rb +98 -21
  30. data/lib/ctioga2/graphics/coordinates.rb +19 -2
  31. data/lib/ctioga2/graphics/elements.rb +12 -2
  32. data/lib/ctioga2/graphics/elements/containers.rb +14 -2
  33. data/lib/ctioga2/graphics/elements/contour.rb +67 -0
  34. data/lib/ctioga2/graphics/elements/curve2d.rb +103 -42
  35. data/lib/ctioga2/graphics/elements/element.rb +12 -2
  36. data/lib/ctioga2/graphics/elements/gradient-region.rb +94 -0
  37. data/lib/ctioga2/graphics/elements/parametric2d.rb +172 -0
  38. data/lib/ctioga2/graphics/elements/primitive.rb +37 -21
  39. data/lib/ctioga2/graphics/elements/region.rb +143 -0
  40. data/lib/ctioga2/graphics/elements/subplot.rb +92 -32
  41. data/lib/ctioga2/graphics/elements/tangent.rb +99 -0
  42. data/lib/ctioga2/graphics/elements/xyz-map.rb +126 -0
  43. data/lib/ctioga2/graphics/generator.rb +91 -6
  44. data/lib/ctioga2/graphics/legends.rb +26 -21
  45. data/lib/ctioga2/graphics/legends/area.rb +8 -8
  46. data/lib/ctioga2/graphics/legends/items.rb +5 -5
  47. data/lib/ctioga2/graphics/legends/storage.rb +4 -2
  48. data/lib/ctioga2/graphics/root.rb +24 -2
  49. data/lib/ctioga2/graphics/styles.rb +8 -0
  50. data/lib/ctioga2/graphics/styles/axes.rb +49 -23
  51. data/lib/ctioga2/graphics/styles/base.rb +2 -2
  52. data/lib/ctioga2/graphics/styles/carrays.rb +9 -2
  53. data/lib/ctioga2/graphics/styles/colormap.rb +272 -0
  54. data/lib/ctioga2/graphics/styles/curve.rb +64 -4
  55. data/lib/ctioga2/graphics/styles/drawable.rb +68 -9
  56. data/lib/ctioga2/graphics/styles/errorbar.rb +73 -0
  57. data/lib/ctioga2/graphics/styles/factory.rb +133 -17
  58. data/lib/ctioga2/graphics/styles/gradients.rb +60 -0
  59. data/lib/ctioga2/graphics/styles/location.rb +64 -0
  60. data/lib/ctioga2/graphics/styles/map-axes.rb +164 -0
  61. data/lib/ctioga2/graphics/styles/plot.rb +165 -62
  62. data/lib/ctioga2/graphics/styles/sets.rb +14 -1
  63. data/lib/ctioga2/graphics/styles/texts.rb +44 -34
  64. data/lib/ctioga2/graphics/subplot-commands.rb +94 -6
  65. data/lib/ctioga2/graphics/types.rb +113 -35
  66. data/lib/ctioga2/graphics/types/bijection.rb +3 -3
  67. data/lib/ctioga2/graphics/types/boundaries.rb +120 -1
  68. data/lib/ctioga2/graphics/types/dimensions.rb +8 -1
  69. data/lib/ctioga2/graphics/types/grid.rb +196 -0
  70. data/lib/ctioga2/graphics/types/location.rb +228 -0
  71. data/lib/ctioga2/graphics/types/point.rb +2 -2
  72. data/lib/ctioga2/log.rb +18 -18
  73. data/lib/ctioga2/metabuilder/type.rb +15 -3
  74. data/lib/ctioga2/metabuilder/types.rb +2 -2
  75. data/lib/ctioga2/metabuilder/types/coordinates.rb +13 -1
  76. data/lib/ctioga2/metabuilder/types/data.rb +50 -0
  77. data/lib/ctioga2/metabuilder/types/generic.rb +60 -0
  78. data/lib/ctioga2/metabuilder/types/lists.rb +53 -16
  79. data/lib/ctioga2/metabuilder/types/styles.rb +26 -45
  80. data/lib/ctioga2/plotmaker.rb +91 -20
  81. data/lib/ctioga2/postprocess.rb +8 -8
  82. data/lib/ctioga2/utils.rb +23 -4
  83. metadata +107 -75
  84. data/lib/ctioga2/data/merge.rb +0 -43
@@ -16,7 +16,7 @@ require 'ctioga2/log'
16
16
 
17
17
  module CTioga2
18
18
 
19
- Version::register_svn_info('$Revision: 67 $', '$Date: 2009-05-30 23:38:00 +0200 (Sat, 30 May 2009) $')
19
+ Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
20
20
 
21
21
  module Graphics
22
22
 
@@ -61,10 +61,10 @@ module CTioga2
61
61
  # separated by :: -- or only one block in the case of an
62
62
  # involution (very common, actually, all 1/x transforms).
63
63
  #
64
- # TODO: few things around here to change... in particular,
64
+ # \todo few things around here to change... in particular,
65
65
  # I should try to find a way to include Math...
66
66
  #
67
- # TODO: add very common cases ?
67
+ # \todo add very common cases ?
68
68
  def self.from_text(spec)
69
69
  blocks = spec.split(/::/).map do |code|
70
70
  eval("proc do |x|\n#{code}\nend")
@@ -16,7 +16,7 @@ require 'ctioga2/log'
16
16
 
17
17
  module CTioga2
18
18
 
19
- Version::register_svn_info('$Revision: 2 $', '$Date: 2009-04-25 14:03:30 +0200 (Sat, 25 Apr 2009) $')
19
+ Version::register_svn_info('$Revision: 125 $', '$Date: 2010-01-12 00:56:15 +0100 (Tue, 12 Jan 2010) $')
20
20
 
21
21
  # This module contains all graphical elements of CTioga2
22
22
  module Graphics
@@ -25,7 +25,108 @@ module CTioga2
25
25
  # with Tioga
26
26
  module Types
27
27
 
28
+ # A range of coordinates.
29
+ class SimpleRange
30
+
31
+ attr_accessor :first, :last
32
+
33
+ # Create a new SimpleRange object that runs from _first_ to
34
+ # _last_ (_last_ can be less than _first_). A _nil_,
35
+ # _false_ or NaN in one of those means *unspecified*.
36
+ #
37
+ # Alternatively, _first_ can be an object that responds to
38
+ # #first and #last.
39
+ def initialize(first, last = nil)
40
+ if first.respond_to?(:first)
41
+ @first = first.first
42
+ @last = first.last
43
+ else
44
+ @first = first
45
+ @last = last
46
+ end
47
+ end
48
+
49
+ # Minimum value
50
+ def min
51
+ @first < @last ? @first : @last
52
+ end
53
+
54
+ # Maximum value
55
+ def max
56
+ @first > @last ? @first : @last
57
+ end
58
+
59
+ # Algebraic distance
60
+ def distance
61
+ return @last - @first
62
+ end
63
+
64
+ # This function makes sures that the SimpleRange object is big
65
+ # enough to encompass what it currently does and the _range_
66
+ # SimpleRange object.
67
+ #
68
+ # \todo this does not work correctly in the case of reversed
69
+ # boundaries. I don't think it can anyway.
70
+ #
71
+ # Actually, it even works with normal Range elements !
72
+ def extend(range)
73
+ # Left/right
74
+ if (! @first.is_a? Float) or @first.nan? or
75
+ (@first > range.first)
76
+ @first = range.first
77
+ end
78
+
79
+ if (! @last.is_a? Float) or @last.nan? or
80
+ (@last < range.last)
81
+ @last = range.last
82
+ end
83
+
84
+ return self
85
+ end
86
+
87
+
88
+ # Override the Boundaries with the contents of _override_. All
89
+ # elements which are not _nil_ or NaN from _override_
90
+ # precisely override those in _self_.
91
+ def override(override)
92
+ for el in [ :first, :last]
93
+ val = override.send(el)
94
+ if val and (val == val) # Strip NaN on the property that NaN != NaN
95
+ self.send("#{el}=", val)
96
+ end
97
+ end
98
+ end
99
+
100
+ # Apply a fixed margin on the Boundaries.
101
+ def apply_margin!(margin)
102
+ d = self.distance
103
+ @first = @first - margin * d
104
+ @last = @last + margin * d
105
+ end
106
+
107
+ # Returns a SimpleRange object that is large enough to exactly
108
+ # contain all _values_
109
+ def self.bounds(values)
110
+ return SimpleRange.new(values.min, values.max)
111
+ end
112
+
113
+ # Takes an array of Boundaries and returns a Boundaries object
114
+ # that precisely encompasses them all. Invalid floats are simply
115
+ # ignored.
116
+ def self.overall_range(ranges)
117
+ retval = SimpleRange.new(nil, nil)
118
+ for r in ranges
119
+ retval.extend(b)
120
+ end
121
+ return retval
122
+ end
123
+ end
124
+
125
+
28
126
  # An object representing boundaries for a plot.
127
+ #
128
+ # \todo Should be converted to using two SimpleRange
129
+ # objects. Will be more clear anyway.
29
130
  class Boundaries
30
131
 
31
132
  # Boundaries
@@ -65,6 +166,18 @@ module CTioga2
65
166
  @bottom > @top ? @bottom : @top
66
167
  end
67
168
 
169
+ # Returns a SimpleRange object corresponding to the horizontal
170
+ # range
171
+ def horizontal
172
+ return SimpleRange.new(@left, @right)
173
+ end
174
+
175
+ # Returns a SimpleRange object corresponding to the vertical
176
+ # range
177
+ def vertical
178
+ return SimpleRange.new(@bottom, @top)
179
+ end
180
+
68
181
 
69
182
  # Converts to an [xmin, xmax, ymin, ymax] array
70
183
  def extrema
@@ -161,6 +274,12 @@ module CTioga2
161
274
  return retval
162
275
  end
163
276
 
277
+ # Creates a Boundaries object from two SimpleRange objects.
278
+ def self.from_ranges(horiz, vert)
279
+ return Boundaries.new(horiz.first, horiz.last,
280
+ vert.last, vert.first)
281
+ end
282
+
164
283
  end
165
284
 
166
285
  end
@@ -16,7 +16,7 @@ require 'ctioga2/log'
16
16
 
17
17
  module CTioga2
18
18
 
19
- Version::register_svn_info('$Revision: 92 $', '$Date: 2009-06-24 01:17:46 +0200 (Wed, 24 Jun 2009) $')
19
+ Version::register_svn_info('$Revision: 198 $', '$Date: 2010-11-30 00:48:23 +0100 (Tue, 30 Nov 2010) $')
20
20
 
21
21
  module Graphics
22
22
 
@@ -85,6 +85,13 @@ module CTioga2
85
85
  to_figure(t, orientation))
86
86
  end
87
87
 
88
+ # Express the Dimension in units of text height (dy)
89
+ def to_text_height(t, orientation = nil)
90
+ orientation ||= @orientation
91
+ return self.to_figure(t, orientation)/
92
+ t.send("default_text_height_d#{orientation}")
93
+ end
94
+
88
95
  # Replace this Dimension by _dimension_ if the latter is
89
96
  # bigger. Conserves the current orientation.
90
97
  def replace_if_bigger(t, dimension)
@@ -0,0 +1,196 @@
1
+ # grib.rb: setup and use of a "graph grid"
2
+ # copyright (c) 2009,2010 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
+ require 'ctioga2/graphics/types/dimensions'
18
+ require 'ctioga2/graphics/types/boxes'
19
+
20
+ module CTioga2
21
+
22
+ Version::register_svn_info('$Revision: 147 $', '$Date: 2010-04-06 21:13:28 +0200 (Tue, 06 Apr 2010) $')
23
+
24
+ module Graphics
25
+
26
+ module Types
27
+
28
+ # The position of a single element in a GridLayout
29
+ #
30
+ # \todo add the possibility to override one element of the
31
+ # final positions.
32
+ class GridBox < Box
33
+
34
+ OptionHashRE = /([\w-]+)\s*=\s*([^,]+),?\s*/
35
+
36
+ GridBoxRE = /^\s*grid:(\d+)\s*,\s*(\d+)(?:,(#{OptionHashRE}+))?\s*$/
37
+
38
+ # This hash helps to convert from a hash-based representation
39
+ # of frame coordinates to the array-based one.
40
+ #
41
+ # \todo I should either use existing code or refactor into
42
+ # something globally useful.
43
+ FrameCoordsOverride = { 'xl' => 0,
44
+ 'yt' => 1,
45
+ 'xr' => 2,
46
+ 'yb' => 3
47
+ }
48
+
49
+ def self.from_text(txt)
50
+ if txt =~ GridBoxRE
51
+ return GridBox.new(GridLayout.current_grid, $1.to_i, $2.to_i,
52
+ $3) # The latter being to remove
53
+ # the initial comma
54
+ else
55
+ raise "#{txt} is not a grid box."
56
+ end
57
+ end
58
+
59
+ def initialize(grid, x, y, options = {})
60
+ if options.is_a? String
61
+ str = options
62
+ options = {}
63
+ str.split(/\s*,\s*/).map { |s|
64
+ s =~ OptionHashRE
65
+ options[$1] =
66
+ BaseCoordinate.from_text($2,if FrameCoordsOverride[$1] % 2 == 0
67
+ :x
68
+ else
69
+ :y
70
+ end, :frame)
71
+ }
72
+ end
73
+ @x = x.to_i
74
+ @grid = grid
75
+ @y = y.to_i
76
+ @overrides = options || {}
77
+ end
78
+
79
+ def to_frame_coordinates(t)
80
+ a = @grid.frame_coordinates(t, @x, @y)
81
+ ## \todo write a framework for manipulating this !
82
+ for k,v in @overrides
83
+ next unless FrameCoordsOverride.key?(k)
84
+ a[FrameCoordsOverride[k]] = v.to_frame(t)
85
+ end
86
+ return a
87
+ end
88
+ end
89
+
90
+ # This class provides a grid-like layout through the use of a grid
91
+ # setup command and a grid box specification.
92
+ class GridLayout
93
+
94
+ # The margins (left, right, top, bottom) around the whole grid
95
+ attr_accessor :outer_margins
96
+
97
+ # The X offset to go from the right-hand side of one element to
98
+ # the left-hand-side of the next
99
+ attr_accessor :delta_x
100
+
101
+ # The Y offset to go from the bottom of one element to
102
+ # the top of the next.
103
+ attr_accessor :delta_y
104
+
105
+ # The nup: an array nb horizontal, nb vertical
106
+ attr_accessor :nup
107
+
108
+ # Horizontal scales
109
+ attr_accessor :hscales
110
+
111
+ # Vertical scales
112
+ attr_accessor :vscales
113
+
114
+ def initialize(nup = "2x2")
115
+ if nup.respond_to?(:split)
116
+ if nup =~ /,/
117
+ @hscales, @vscales = nup.split(/\s*x\s*/).map { |x|
118
+ x.split(/\s*,\s*/).map { |y| y.to_f }
119
+ }
120
+ @nup = [@hscales.size, @vscales.size]
121
+ else
122
+ @nup = nup.split(/\s*x\s*/).map { |s| s.to_i }
123
+ end
124
+ else
125
+ @nup = nup.dup
126
+ end
127
+
128
+ # Initialize with the given
129
+ @outer_margins = {
130
+ 'left' => Dimension.new(:dy, 2.5, :x),
131
+ 'right' => Dimension.new(:bp, 6, :x),
132
+ 'bottom' => Dimension.new(:dy, 2.5, :y),
133
+ 'top' => Dimension.new(:dy, 2.5, :y)
134
+ }
135
+ @delta_x = Dimension.new(:dy, 2.5, :x)
136
+ @delta_y = Dimension.new(:dy, 2.5, :y)
137
+
138
+ @hscales ||= [1] * @nup[0]
139
+ @vscales ||= [1] * @nup[1]
140
+ end
141
+
142
+ # The grid currently in use.
143
+ @current_grid = nil
144
+
145
+ def self.current_grid=(grid)
146
+ @current_grid = grid
147
+ end
148
+
149
+ def self.current_grid
150
+ return @current_grid
151
+ end
152
+
153
+ # Compute the frame coordinates fo the x,y element of the
154
+ # grid. They are numbered from the top,left element.
155
+ def frame_coordinates(t, x, y)
156
+ compute_lengths(t)
157
+ xo = if x > 0
158
+ @hscales[0..(x-1)].inject(0,:+) * @wbase
159
+ else
160
+ 0
161
+ end
162
+ xl = @outer_margins['left'].to_frame(t, :x) + xo +
163
+ x * @delta_x.to_frame(t, :x)
164
+ yo = if y > 0
165
+ @vscales[0..(y-1)].inject(0,:+) * @hbase
166
+ else
167
+ 0
168
+ end
169
+ yt = 1 - (@outer_margins['top'].to_frame(t, :y) + yo +
170
+ y * @delta_y.to_frame(t, :y))
171
+ return [xl, yt,
172
+ xl + @wbase * @hscales[x],
173
+ yt - @hbase * @vscales[y]]
174
+ end
175
+
176
+ protected
177
+
178
+ # Compute the necessary variables in frame coordinates
179
+ def compute_lengths(t)
180
+ return if (@wbase && @hbase)
181
+ @wbase = (1 -
182
+ (@outer_margins['left'].to_frame(t, :x) +
183
+ @outer_margins['right'].to_frame(t, :x) +
184
+ @delta_x.to_frame(t, :x) * (@nup[0]-1)))/@hscales.inject(0,:+)
185
+ @hbase = (1 -
186
+ (@outer_margins['top'].to_frame(t, :y) +
187
+ @outer_margins['bottom'].to_frame(t, :y) +
188
+ @delta_y.to_frame(t, :y) * (@nup[1]-1)))/@vscales.inject(0,:+)
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+ end
195
+
196
+ end
@@ -0,0 +1,228 @@
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
+