ctioga2 0.11 → 0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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