ctioga2 0.11 → 0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -40,6 +40,9 @@ module CTioga2
40
40
  # parameter. It is a hash.
41
41
  attr_accessor :sets
42
42
 
43
+ # The name of the default set, when it isn't 'default'
44
+ attr_accessor :default_set
45
+
43
46
  # The description of the parameter.
44
47
  attr_accessor :description
45
48
 
@@ -60,8 +63,16 @@ module CTioga2
60
63
  def initialize(name, type, sets, description,
61
64
  short_option = nil, disable_cmds = false)
62
65
  @name = name
63
- @type = type
64
- @sets = sets
66
+ @type = type
67
+ if sets
68
+ # If the sets is an array, it is of the form [sets, 'default set']
69
+ if sets.is_a? Array
70
+ @sets = sets[0]
71
+ @default_set = sets[1]
72
+ else
73
+ @sets = sets
74
+ end
75
+ end
65
76
  @description = description
66
77
  @short_option = short_option
67
78
  @disable_commands = disable_cmds
@@ -81,7 +92,9 @@ module CTioga2
81
92
  # Returns a suitable default set for the given object.
82
93
  def default_set
83
94
  return nil unless @sets
84
- if @sets.key? 'default'
95
+ if @default_set
96
+ return @sets[@default_set]
97
+ elsif @sets.key? 'default'
85
98
  return @sets['default']
86
99
  else
87
100
  @sets.each do |k,v|
@@ -249,22 +262,36 @@ module CTioga2
249
262
  }
250
263
  @parameters_carrays = {}
251
264
  for target, param in self.class.parameters
265
+ # There should be a way to do that !
252
266
  set = param.default_set
253
267
  if set
254
268
  @parameters_carrays[target] = CircularArray.new(set)
255
269
  end
256
270
  end
271
+
272
+ @next_style = nil
273
+ end
274
+
275
+ # Sets the style to be returned from the next call to #next
276
+ # (not counting the effect of the options passed)
277
+ def set_next_style(stl)
278
+ @next_style = stl
257
279
  end
258
280
 
259
281
  # Gets the style for the next curve. The _one_time_ hash
260
282
  # contains values 'parameter name' (name, and not target) =>
261
283
  # value that are used for this time only.
262
284
  def next(one_time = {})
263
- base = {}
264
- for target, array in @parameters_carrays
265
- base[target] = array.next
285
+ if @next_style
286
+ base = @next_style
287
+ @next_style = nil
288
+ else
289
+ base = {}
290
+ for target, array in @parameters_carrays
291
+ base[target] = array.next
292
+ end
293
+ base.merge!(@override_parameters)
266
294
  end
267
- base.merge!(@override_parameters)
268
295
  base.merge!(hash_name_to_target(one_time))
269
296
  return CurveStyle.from_hash(resolve_links(base))
270
297
  end
@@ -327,18 +354,29 @@ module CTioga2
327
354
  simple_parameter 'line_style', 'line style', Sets::LineStyleSets
328
355
 
329
356
  # Markers
330
- simple_parameter 'marker', 'marker', Sets::MarkerSets, '-m'
357
+ simple_parameter 'marker', 'marker', Sets::MarkerSets, '-m'
331
358
 
332
359
  simple_parameter 'marker_color', "marker color", Sets::ColorSets
333
360
 
361
+ simple_parameter 'marker_fill_color', "marker fill color", [Sets::ColorSets, 'nil']
362
+
363
+ simple_parameter 'marker_line_color', "marker stroke color", [Sets::ColorSets, 'nil']
364
+
334
365
  simple_parameter 'marker_scale', "marker scale", Sets::LineWidthSets
335
366
 
367
+ simple_parameter 'marker_angle', "marker angle", nil
368
+
369
+ simple_parameter 'marker_line_width', "marker line width", nil
370
+
336
371
  simple_parameter 'marker_min_scale', "marker scale", nil
337
372
 
338
373
  # Error bars:
339
374
  simple_parameter 'error_bar_color', "error bar color",
340
375
  Sets::ColorSets
341
376
 
377
+ simple_parameter 'error_bar_line_width', "error bar line width",
378
+ Sets::LineWidthSets
379
+
342
380
  # Location:
343
381
  define_parameter 'location_xaxis', 'xaxis',
344
382
  nil, "X axis", nil, true
@@ -470,7 +508,40 @@ module CTioga2
470
508
  return tv
471
509
  end
472
510
  end
473
- end
511
+
512
+ SkipCommand =
513
+ Cmd.new("skip",nil,"--skip",
514
+ [], {'number' => CmdArg.new("integer")}
515
+ ) do |plotmaker, opts|
516
+ number = opts['number'] || 1
517
+ fct = plotmaker.curve_generator.style_factory
518
+ while number > 0
519
+ number -= 1
520
+ fct.next
521
+ end
522
+ end
523
+
524
+ SkipCommand.describe('Skips next curve style',
525
+ <<EOH, CurveStyleFactory::CurveStyleGroup)
526
+ This command acts as if one (or @number@) dataset had been drawn with
527
+ respect to the style of the next dataset to be drawn.
528
+ EOH
529
+
530
+ ReuseCommand =
531
+ Cmd.new("reuse-style",nil,"--reuse-style",
532
+ [CmdArg.new('object')], {}
533
+ ) do |plotmaker, obj, opts|
534
+ stl = obj.curve_style.to_hash
535
+ plotmaker.curve_generator.style_factory.set_next_style(stl)
536
+ end
537
+
538
+ ReuseCommand.describe('Reuse the style of a previous curve',
539
+ <<EOH, CurveStyleFactory::CurveStyleGroup)
540
+ After using this command, the next curve will have the same style as the
541
+ curve whose name was given as the first argument (it is the name given to
542
+ the `/id=` option to plot.
543
+ EOH
544
+ end
474
545
 
475
546
  # Now, we document some aspects of the above created commands
476
547
  c = Commands::Command
@@ -439,7 +439,7 @@ EOH
439
439
  style = AxisStyle.current_axis_style(plotmaker, w)
440
440
  style.set_from_hash(opts)
441
441
  rescue Exception => e
442
- error {"Error while setting style of axis: #{w} -- #{e}"}
442
+ Log::error {"Error while setting style of axis: #{w} -- #{e}"}
443
443
  end
444
444
  end
445
445
  end
@@ -0,0 +1,72 @@
1
+ # scope.rb: containers that provide translation and scaling capacities
2
+ # copyright (c) 2015 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
+ module Graphics
21
+
22
+ # All the styles
23
+ module Styles
24
+
25
+ # This style represents a scope, ie something that translates
26
+ # (first) and scales (second) figure coordinates.
27
+ class ScopeStyle < BasicStyle
28
+
29
+ typed_attribute 'xshift', 'dimension'
30
+ typed_attribute 'xscale', 'float'
31
+
32
+ typed_attribute 'yshift', 'dimension'
33
+ typed_attribute 'yscale', 'float'
34
+
35
+
36
+ def initialize
37
+ end
38
+
39
+ # applies the transformation to the current figure coordinates
40
+ def apply_to_figure(t)
41
+ bl = t.bounds_left
42
+ br = t.bounds_right
43
+ bt = t.bounds_top
44
+ bb = t.bounds_bottom
45
+
46
+ if @xshift
47
+ dx = @xshift.to_figure(t,:x)
48
+ bl -= dx
49
+ br -= dx
50
+ end
51
+
52
+ if @yshift
53
+ dy = @yshift.to_figure(t,:y)
54
+ bt -= dy
55
+ bb -= dy
56
+ end
57
+
58
+ if @xscale
59
+ bl, br = *Utils::scale_segment(bl, br, 1/@xscale)
60
+ end
61
+ if @yscale
62
+ bt, bb = *Utils::scale_segment(bt, bb, 1/@yscale)
63
+ end
64
+
65
+ t.set_bounds([bl, br, bt, bb])
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
72
+
@@ -41,8 +41,9 @@ module CTioga2
41
41
  [LightPlum, PaleGreen, Gold, RedBrown, SkyBlue ],
42
42
  "gnuplot" =>
43
43
  [Red, [0,1.0,0], Blue, Magenta, Cyan, Yellow, Black, Coral, Gray],
44
+ 'nil' => [nil]
44
45
  }
45
-
46
+
46
47
  begin
47
48
  t = Tioga::FigureMaker.new
48
49
  lst = []
@@ -44,7 +44,7 @@ module CTioga2
44
44
  Dash_Dot_Dot = Line_Type_Dash_Dot_Dot
45
45
  end
46
46
 
47
- NoRE = /no(ne)?|off/i
47
+ NoRE = /no(ne)?|off|false/i
48
48
 
49
49
  ColorType = CmdType.new('color', {
50
50
  :type => :tioga_color,
@@ -51,10 +51,58 @@ module CTioga2
51
51
  # _value_ oriented along the given _orientation_
52
52
  def initialize(type, value, orientation = :x)
53
53
  @type = type
54
+ if not @type.is_a? Symbol
55
+ raise "Invalid value for the dimension type: '#{@type}'"
56
+ end
54
57
  @value = value
55
58
  @orientation = orientation
56
59
  end
57
60
 
61
+ def self.make_dimension(val, orient = :x, default = :figure)
62
+ if val.is_a? Dimension
63
+ return val
64
+ else
65
+ return Dimension.new(default, val, orient)
66
+ end
67
+ end
68
+
69
+ # Gets the angle along the given direction
70
+ def self.get_angle(t, dx, dy)
71
+ dx = make_dimension(dx, :x).to_bp(t)
72
+ dy = make_dimension(dy, :y).to_bp(t)
73
+ return 180 * Math::atan2(dy, dx)/Math::PI
74
+ end
75
+
76
+ def -@
77
+ return Dimension.new(@type, -@value, @orientation)
78
+ end
79
+
80
+ # Returns a dimension corresponding to the distance.
81
+ def self.get_distance(t, dx, dy)
82
+ dx = make_dimension(dx, :x).to_bp(t)
83
+ dy = make_dimension(dy, :y).to_bp(t)
84
+ return Dimension.new(:bp, (dx**2 + dy**2)**0.5)
85
+ end
86
+
87
+ # Adjusts the given line by adding the dimensions on the left
88
+ # and on the right (can be negative).
89
+ #
90
+ # Returns the new [x1, y1, x2, y2]
91
+ def self.adjust_line(t, x1, y1, x2, y2, left, right)
92
+ dx = x2 - x1
93
+ dy = y2 - y1
94
+ dst = get_distance(t, x2-x1, y2-y1).to_bp(t)
95
+ lf = left.to_bp(t)/dst
96
+ rf = right.to_bp(t)/dst
97
+
98
+ x1 -= lf * dx
99
+ y1 -= lf * dy
100
+ x2 += rf * dx
101
+ y2 += rf * dy
102
+ return [x1, y1, x2, y2]
103
+ end
104
+
105
+
58
106
  # Converts the Dimension to the *figure* coordinates of the
59
107
  # *current* figure in _t_.
60
108
  #
@@ -35,26 +35,31 @@ module CTioga2
35
35
  # is not implemented yet.
36
36
  def debug(channel = nil)
37
37
  @@logger.debug {yield + Log.context}
38
+ @@counts[:debug] += 1
38
39
  end
39
40
 
40
41
  # Prints a warning message
41
42
  def warn
42
43
  @@logger.warn {yield + Log.context}
44
+ @@counts[:warn] += 1
43
45
  end
44
46
 
45
47
  # Prints an informational message
46
48
  def info
47
49
  @@logger.info {yield + Log.context}
50
+ @@counts[:info] += 1
48
51
  end
49
52
 
50
53
  # Prints an error message
51
54
  def error
52
55
  @@logger.error {yield + Log.context}
56
+ @@counts[:error] += 1
53
57
  end
54
58
 
55
59
  # Prints a fatal error message and initiates program termination.
56
60
  def fatal
57
61
  @@logger.fatal {yield + Log.context}
62
+ @@counts[:fatal] += 1 # Though not very useful
58
63
  exit 1 # Fatal error.
59
64
  end
60
65
 
@@ -70,8 +75,15 @@ module CTioga2
70
75
  Logger::Formatter::Format.replace("[%4$s] %6$s\n")
71
76
  @@logger = Logger.new(stream)
72
77
  @@logger.level = Logger::WARN # Warnings and more only by default
78
+ @@counts = {}
79
+ for k in [:error, :debug, :warn, :info, :fatal]
80
+ @@counts[k] = 0
81
+ end
73
82
  end
74
83
 
84
+ def self.counts
85
+ return @@counts
86
+ end
75
87
 
76
88
  # Logs to the target file, and fall back onto stderr should
77
89
  # opening fail.
@@ -87,6 +87,8 @@ module CTioga2
87
87
  # to a Type child
88
88
  @@types = { }
89
89
 
90
+ @@type_names = {}
91
+
90
92
  # The initial type specification that was given to the Type
91
93
  attr_accessor :type
92
94
 
@@ -144,6 +146,7 @@ module CTioga2
144
146
  "from #{@@types[name]} to #{self}" }
145
147
  end
146
148
  @@types[name] = self
149
+ @@type_names[self] = name
147
150
  self.send(:define_method,:type_name) do
148
151
  public_name
149
152
  end
@@ -190,31 +193,40 @@ module CTioga2
190
193
  # function that can take advantage of a few general features. It
191
194
  # is recommanded to define a #string_to_type_internal function
192
195
  # rather to redefine #string_to_type
193
- def string_to_type(string)
194
- # First, passthrough
195
- if @passthrough && @passthrough === string
196
- return stt_run_hook(string)
197
- end
198
- # First, shortcuts:
199
- if @shortcuts and @shortcuts.key? string
200
- return stt_run_hook(@shortcuts[string])
201
- end
202
- if @re_shortcuts
203
- for k, v in @re_shortcuts
204
- if string =~ k
205
- return stt_run_hook(v)
196
+ def string_to_type(string, tn = nil)
197
+ begin
198
+ # First, passthrough
199
+ if @passthrough && @passthrough === string
200
+ return stt_run_hook(string)
201
+ end
202
+ # First, shortcuts:
203
+ if @shortcuts and @shortcuts.key? string
204
+ return stt_run_hook(@shortcuts[string])
205
+ end
206
+ if @re_shortcuts
207
+ for k, v in @re_shortcuts
208
+ if string =~ k
209
+ return stt_run_hook(v)
210
+ end
206
211
  end
207
212
  end
208
- end
209
213
 
210
- # Then, constants lookup.
211
- if @type.key?(:namespace)
212
- begin
213
- return stt_run_hook(lookup_const(string))
214
- rescue IncorrectInput
214
+ # Then, constants lookup.
215
+ if @type.key?(:namespace)
216
+ begin
217
+ return stt_run_hook(lookup_const(string))
218
+ rescue IncorrectInput
219
+ end
215
220
  end
221
+ return stt_run_hook(string_to_type_internal(string))
222
+ rescue Exception => e
223
+ txt = if tn
224
+ "to type '#{tn}' failed:\n\t -> "
225
+ else
226
+ "failed: "
227
+ end
228
+ raise "Conversion of '#{string}' #{txt}#{e.message}"
216
229
  end
217
- return stt_run_hook(string_to_type_internal(string))
218
230
  end
219
231
 
220
232
  # This function does the exact opposite of the #string_to_type
@@ -34,7 +34,7 @@ module CTioga2
34
34
  return 'text'
35
35
  end
36
36
 
37
- def string_to_type(str)
37
+ def string_to_type_internal(str)
38
38
  return str
39
39
  end
40
40
  end
@@ -67,7 +67,7 @@ module CTioga2
67
67
  return 'regexp'
68
68
  end
69
69
 
70
- def string_to_type(str)
70
+ def string_to_type_internal(str)
71
71
  if str =~ /^\/(.*)\/$/
72
72
  return Regexp.new($1)
73
73
  else