ctioga2 0.13.1 → 0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +26 -0
- data/bin/ct2-make-movie +4 -1
- data/bin/ctioga2 +1 -1
- data/lib/ctioga2/commands/commands.rb +2 -0
- data/lib/ctioga2/commands/doc/doc.rb +1 -1
- data/lib/ctioga2/commands/doc/documentation-commands.rb +38 -0
- data/lib/ctioga2/commands/doc/html.rb +84 -0
- data/lib/ctioga2/commands/general-commands.rb +20 -1
- data/lib/ctioga2/commands/general-functions.rb +26 -0
- data/lib/ctioga2/commands/general-types.rb +1 -0
- data/lib/ctioga2/commands/instruction.rb +61 -0
- data/lib/ctioga2/commands/interpreter.rb +12 -2
- data/lib/ctioga2/data/datacolumn.rb +38 -0
- data/lib/ctioga2/data/dataset.rb +6 -5
- data/lib/ctioga2/data/filters.rb +12 -5
- data/lib/ctioga2/data/stack.rb +105 -22
- data/lib/ctioga2/graphics/elements.rb +1 -1
- data/lib/ctioga2/graphics/elements/curve2d.rb +1 -1
- data/lib/ctioga2/graphics/elements/element.rb +29 -10
- data/lib/ctioga2/graphics/elements/primitive.rb +26 -2
- data/lib/ctioga2/graphics/elements/subplot.rb +7 -1
- data/lib/ctioga2/graphics/generator.rb +1 -2
- data/lib/ctioga2/graphics/legends/area.rb +3 -0
- data/lib/ctioga2/graphics/root.rb +18 -2
- data/lib/ctioga2/graphics/styles/curve.rb +6 -0
- data/lib/ctioga2/graphics/styles/drawable.rb +4 -0
- data/lib/ctioga2/graphics/styles/factory.rb +4 -5
- data/lib/ctioga2/graphics/styles/plot-types.rb +22 -7
- data/lib/ctioga2/graphics/subplot-commands.rb +2 -4
- data/lib/ctioga2/graphics/types.rb +17 -0
- data/lib/ctioga2/graphics/types/boundaries.rb +10 -0
- data/lib/ctioga2/graphics/types/boxes.rb +18 -0
- data/lib/ctioga2/graphics/types/dimensions.rb +4 -0
- data/lib/ctioga2/graphics/types/grid.rb +98 -4
- data/lib/ctioga2/graphics/types/point.rb +9 -0
- data/lib/ctioga2/metabuilder/types/lists.rb +1 -1
- data/lib/ctioga2/metabuilder/types/styles.rb +5 -3
- data/lib/ctioga2/plotmaker.rb +28 -5
- data/lib/ctioga2/postprocess.rb +28 -0
- data/lib/ctioga2/ruby.rb +7 -0
- data/lib/ctioga2/utils.rb +45 -0
- data/lib/ctioga2/version.rb +2 -2
- metadata +4 -3
data/lib/ctioga2/data/dataset.rb
CHANGED
@@ -225,7 +225,7 @@ module CTioga2
|
|
225
225
|
# _x_, _xmin_, _xmax_, _y_, _ymin_, _ymax_, _y1_, _y1min_, _y1max_,
|
226
226
|
# _z_, _zmin_, _zmax_, _y2_, _y2min_, _y2max_, _y3_, _y3min_, _y3max_
|
227
227
|
#
|
228
|
-
def select!(
|
228
|
+
def select!(evaluator)
|
229
229
|
target = []
|
230
230
|
@x.size.times do |i|
|
231
231
|
args = @x.values_at(i, true)
|
@@ -236,7 +236,7 @@ module CTioga2
|
|
236
236
|
args.concat(yvect.values_at(i, true))
|
237
237
|
end
|
238
238
|
end
|
239
|
-
if
|
239
|
+
if evaluator.compute_unsafe(*args)
|
240
240
|
target << i
|
241
241
|
end
|
242
242
|
end
|
@@ -260,8 +260,8 @@ module CTioga2
|
|
260
260
|
i += 1
|
261
261
|
end
|
262
262
|
end
|
263
|
-
|
264
|
-
select!(
|
263
|
+
evaluator = Ruby.make_evaluator(formula, names)
|
264
|
+
select!(evaluator)
|
265
265
|
end
|
266
266
|
|
267
267
|
# \todo a dup !
|
@@ -755,13 +755,14 @@ module CTioga2
|
|
755
755
|
|
756
756
|
end
|
757
757
|
|
758
|
-
protected
|
759
758
|
|
760
759
|
# Returns all DataColumn objects held by this Dataset
|
761
760
|
def all_columns
|
762
761
|
return [@x, *@ys]
|
763
762
|
end
|
764
763
|
|
764
|
+
protected
|
765
|
+
|
765
766
|
# Returns all Dvectors of the columns one by one.
|
766
767
|
def all_vectors
|
767
768
|
return all_columns.map {|x| x.vectors}.flatten(1)
|
data/lib/ctioga2/data/filters.rb
CHANGED
@@ -42,13 +42,16 @@ dataset pushed unto the data stack: they can be viewed as filters.",
|
|
42
42
|
Sorts the last dataset pushed unto the stack according to X values. Can be
|
43
43
|
used as a filter.
|
44
44
|
|
45
|
+
This command sorts in-place.
|
46
|
+
|
45
47
|
See also {command: sort}.
|
46
48
|
EOH
|
47
49
|
|
48
50
|
SortFilter =
|
49
51
|
Cmd.new("sort", nil, "--sort",
|
50
52
|
[], {}) do |plotmaker, opts|
|
51
|
-
plotmaker.data_stack.
|
53
|
+
plotmaker.data_stack.
|
54
|
+
add_to_dataset_hook(Commands::Instruction.new('sort-last', [], {}))
|
52
55
|
end
|
53
56
|
|
54
57
|
SortFilter.describe("Systematically sort subsequent datasets",
|
@@ -80,7 +83,8 @@ EOH
|
|
80
83
|
[CmdArg.new('integer')], {}) do |plotmaker, number, opts|
|
81
84
|
## @todo There should be a way to add commands in a type-safe
|
82
85
|
## way, without having to convert to string first.
|
83
|
-
plotmaker.data_stack.
|
86
|
+
plotmaker.data_stack.
|
87
|
+
add_to_dataset_hook(Commands::Instruction.new('trim-last', [number], {}))
|
84
88
|
end
|
85
89
|
|
86
90
|
TrimFilter.describe("Systematically trim subsequent datasets",
|
@@ -113,7 +117,8 @@ EOH
|
|
113
117
|
CherryPickFilter =
|
114
118
|
Cmd.new("cherry-pick", nil, "--cherry-pick",
|
115
119
|
[CmdArg.new('text')], {}) do |plotmaker, formula|
|
116
|
-
plotmaker.data_stack.
|
120
|
+
plotmaker.data_stack.
|
121
|
+
add_to_dataset_hook(Commands::Instruction.new('cherry-pick-last', [formula], {}))
|
117
122
|
end
|
118
123
|
|
119
124
|
CherryPickFilter.describe("Systematicallly remove data for which the formula is false",
|
@@ -162,7 +167,8 @@ EOH
|
|
162
167
|
AverageDupFilter =
|
163
168
|
Cmd.new("avg-dup", nil, "--avg-dup",
|
164
169
|
[], {}) do |plotmaker, formula|
|
165
|
-
plotmaker.data_stack.
|
170
|
+
plotmaker.data_stack.
|
171
|
+
add_to_dataset_hook(Commands::Instruction.new('avg-dup-last', [], {}))
|
166
172
|
end
|
167
173
|
|
168
174
|
AverageDupFilter.describe("Systematicallly average successive elements with identical X values",
|
@@ -189,7 +195,8 @@ EOH
|
|
189
195
|
SmoothFilter =
|
190
196
|
Cmd.new("smooth", nil, "--smooth",
|
191
197
|
[CmdArg.new('integer')], {}) do |plotmaker, nb|
|
192
|
-
plotmaker.data_stack.
|
198
|
+
plotmaker.data_stack.
|
199
|
+
add_to_dataset_hook(Commands::Instruction.new('smooth-last', [nb], {}))
|
193
200
|
end
|
194
201
|
|
195
202
|
SmoothFilter.describe("Systematicallly smooth data",
|
data/lib/ctioga2/data/stack.rb
CHANGED
@@ -52,13 +52,7 @@ module CTioga2
|
|
52
52
|
# A hook executed every time a dataset is pushed unto the stack
|
53
53
|
# using #add_dataset.
|
54
54
|
#
|
55
|
-
#
|
56
|
-
# #add_dataset. Perhaps it would be good to provide a way to
|
57
|
-
# record a Command call, without parsing it from scratch ???
|
58
|
-
#
|
59
|
-
# Although, with variables, that could be interesting to reparse
|
60
|
-
# everytime, since any change in the variables would be taken
|
61
|
-
# into account.
|
55
|
+
# This is a list of Instruction
|
62
56
|
attr_accessor :dataset_hook
|
63
57
|
|
64
58
|
# Creates a new DataStack object.
|
@@ -70,6 +64,8 @@ module CTioga2
|
|
70
64
|
# Defaults to the 'text' backend
|
71
65
|
@backend_factory = Data::Backends::BackendFactory.new('text')
|
72
66
|
|
67
|
+
@dataset_hook = []
|
68
|
+
|
73
69
|
# Probably a bit out of place...
|
74
70
|
csv =
|
75
71
|
Cmd.new('csv', nil, '--csv', []) do |plotmaker|
|
@@ -88,7 +84,7 @@ EOH
|
|
88
84
|
# Performs expansion on the given _set_ with the current
|
89
85
|
# backend, retrieves corresponding Dataset objects, pushes them
|
90
86
|
# onto the stack and returns them.
|
91
|
-
def get_datasets(set, options = {})
|
87
|
+
def get_datasets(set, options = {}, add = true)
|
92
88
|
backend = @backend_factory.specified_backend(options)
|
93
89
|
sets = backend.expand_sets(set)
|
94
90
|
datasets = []
|
@@ -100,7 +96,9 @@ EOH
|
|
100
96
|
debug { "#{e.backtrace.join("\n")}" }
|
101
97
|
end
|
102
98
|
end
|
103
|
-
|
99
|
+
if add
|
100
|
+
add_datasets(datasets, options)
|
101
|
+
end
|
104
102
|
return datasets
|
105
103
|
end
|
106
104
|
|
@@ -152,7 +150,16 @@ EOH
|
|
152
150
|
end
|
153
151
|
end
|
154
152
|
else
|
155
|
-
if
|
153
|
+
if spec =~ /^\s*#(.*)/
|
154
|
+
# graph idea -> get dataset from the plot element
|
155
|
+
eln = $1
|
156
|
+
obj = Elements::TiogaElement.find_object(eln)
|
157
|
+
if !obj.respond_to(:dataset)
|
158
|
+
raise "Object '##{eln}' does not name a plot"
|
159
|
+
end
|
160
|
+
ds = obj.dataset
|
161
|
+
index = @stack.index(ds)
|
162
|
+
elsif @named_datasets.key? spec
|
156
163
|
name = spec
|
157
164
|
ds = @named_datasets[spec]
|
158
165
|
i = 0
|
@@ -189,13 +196,14 @@ EOH
|
|
189
196
|
def store_dataset(dataset, ignore_hooks = false)
|
190
197
|
@stack << dataset
|
191
198
|
if @dataset_hook && (! ignore_hooks)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
+
for ins in @dataset_hook
|
200
|
+
begin
|
201
|
+
ins.run(PlotMaker.plotmaker)
|
202
|
+
rescue Exception => e
|
203
|
+
error { "There was a problem running the dataset hook '#{ins.to_s}', disabling it" }
|
204
|
+
@dataset_hook.delete(ins)
|
205
|
+
info { "-> '#{format_exception e}'" }
|
206
|
+
end
|
199
207
|
end
|
200
208
|
end
|
201
209
|
end
|
@@ -222,9 +230,9 @@ EOH
|
|
222
230
|
# Appends a set of commands to the dataset hook
|
223
231
|
def add_to_dataset_hook(commands)
|
224
232
|
if @dataset_hook
|
225
|
-
@dataset_hook
|
233
|
+
@dataset_hook += [commands].flatten
|
226
234
|
else
|
227
|
-
@dataset_hook = commands
|
235
|
+
@dataset_hook = [commands].flatten
|
228
236
|
end
|
229
237
|
end
|
230
238
|
|
@@ -314,13 +322,34 @@ EOH
|
|
314
322
|
"Commands for manipulation of the data stack",
|
315
323
|
100)
|
316
324
|
|
317
|
-
|
318
|
-
'name' => CmdArg.new('text'),
|
325
|
+
AppendDatasetOptions = {
|
319
326
|
'as' => CmdArg.new('text'),
|
320
327
|
'where' => CmdArg.new('text'),
|
321
328
|
'ignore_hooks' => CmdArg.new('boolean')
|
322
329
|
}
|
323
330
|
|
331
|
+
AppendDataCommand =
|
332
|
+
Cmd.new("append", nil, "--append",
|
333
|
+
[ CmdArg.new('dataset'), ],
|
334
|
+
AppendDatasetOptions) do |plotmaker, set, opts|
|
335
|
+
datasets = plotmaker.data_stack.get_datasets(set, opts, false)
|
336
|
+
# Now, we append them to the last dataset
|
337
|
+
plotmaker.data_stack.concatenate_datasets(datasets)
|
338
|
+
end
|
339
|
+
|
340
|
+
AppendDataCommand.describe("Appends the datasets to the last in the stack",
|
341
|
+
<<EOH, DataStackGroup)
|
342
|
+
Use the current backend to load the given dataset(s) and append to the
|
343
|
+
last dataset on the stack (without creating a new dataset). Roughly
|
344
|
+
the equivalent of first running {command: load} and then
|
345
|
+
{command: join-datasets}.
|
346
|
+
EOH
|
347
|
+
|
348
|
+
LoadDatasetOptions = AppendDatasetOptions.dup.merge(
|
349
|
+
{
|
350
|
+
'name' => CmdArg.new('text')
|
351
|
+
})
|
352
|
+
|
324
353
|
LoadDataCommand =
|
325
354
|
Cmd.new("load", '-L', "--load",
|
326
355
|
[ CmdArg.new('dataset'), ],
|
@@ -338,9 +367,10 @@ similar construct), each dataset gets named with %d replace with the
|
|
338
367
|
number of the dataset within the expansion (starting at 0). This name
|
339
368
|
can be used to further use the dataset without remembering its
|
340
369
|
number. See the type {type: stored-dataset} for more information.
|
341
|
-
|
342
370
|
EOH
|
343
371
|
|
372
|
+
|
373
|
+
|
344
374
|
ContourOptions = LoadDatasetOptions.dup.update({
|
345
375
|
'which' => CmdArg.new('stored-dataset'),
|
346
376
|
})
|
@@ -439,6 +469,57 @@ EOH
|
|
439
469
|
ApplyLastCommand.describe("Applies a formula to the last dataset",
|
440
470
|
<<EOH, DataStackGroup)
|
441
471
|
Applies a formula to the last dataset (or the named one)
|
472
|
+
EOH
|
473
|
+
|
474
|
+
BinLastCommand =
|
475
|
+
Cmd.new("bin", nil, "--bin",
|
476
|
+
[],
|
477
|
+
{
|
478
|
+
'number' => CmdArg.new('integer'),
|
479
|
+
'column' => CmdArg.new('integer'),
|
480
|
+
'delta' => CmdArg.new('float'),
|
481
|
+
'min' => CmdArg.new('float'),
|
482
|
+
'max' => CmdArg.new('float'),
|
483
|
+
'normalize' => CmdArg.new('boolean'),
|
484
|
+
'which' => CmdArg.new('stored-dataset'),
|
485
|
+
'name' => CmdArg.new('text')
|
486
|
+
}) do |plotmaker, opts|
|
487
|
+
stack = plotmaker.data_stack
|
488
|
+
ds = plotmaker.data_stack.specified_dataset(opts)
|
489
|
+
|
490
|
+
cn = opts['column'] || 1
|
491
|
+
col = ds.all_columns[cn]
|
492
|
+
|
493
|
+
|
494
|
+
if opts.key? 'number'
|
495
|
+
min = opts['min'] || col.min
|
496
|
+
max = opts['max'] || col.max
|
497
|
+
number = opts['number']
|
498
|
+
elsif opts.key? 'delta'
|
499
|
+
delta = opts['delta']
|
500
|
+
if opts.key? 'min'
|
501
|
+
min = opts['min']
|
502
|
+
max = min+((col.max-min)/delta).ceil*delta
|
503
|
+
elsif opts.key? 'max'
|
504
|
+
max = opts['max']
|
505
|
+
min = max-((max-col.min)/delta).floor*delta
|
506
|
+
else
|
507
|
+
min = (col.min/delta).floor * delta
|
508
|
+
max = (col.max/delta).ceil * delta
|
509
|
+
end
|
510
|
+
number = ((max-min)/delta).to_i
|
511
|
+
else
|
512
|
+
raise "Must specify either the option 'number' or the option 'delta'"
|
513
|
+
end
|
514
|
+
|
515
|
+
newds = Dataset.new("bin", col.bin(min, max, number, opts['normalize']))
|
516
|
+
plotmaker.data_stack.add_datasets([newds], opts)
|
517
|
+
end
|
518
|
+
|
519
|
+
BinLastCommand.describe("Bins the last dataset",
|
520
|
+
<<EOH, DataStackGroup)
|
521
|
+
This command bins the contents of the Y column of the last dataset on the
|
522
|
+
stack, and pushes the results as a new dataset.
|
442
523
|
EOH
|
443
524
|
|
444
525
|
ShowStackCommand =
|
@@ -537,6 +618,7 @@ EOH
|
|
537
618
|
SetDatasetHookCommand =
|
538
619
|
Cmd.new("dataset-hook", nil, "--dataset-hook",
|
539
620
|
[CmdArg.new('commands')], {}) do |plotmaker, commands, opts|
|
621
|
+
raise 'This command is disabled as of now'
|
540
622
|
plotmaker.data_stack.dataset_hook = commands
|
541
623
|
end
|
542
624
|
|
@@ -562,6 +644,7 @@ EOH
|
|
562
644
|
AddDatasetHookCommand =
|
563
645
|
Cmd.new("dataset-hook-add", nil, "--dataset-hook-add",
|
564
646
|
[CmdArg.new('commands')], {}) do |plotmaker, commands, opts|
|
647
|
+
raise 'This command is disabled as of now'
|
565
648
|
plotmaker.data_stack.add_to_dataset_hook(commands)
|
566
649
|
end
|
567
650
|
|
@@ -71,7 +71,7 @@ EOH
|
|
71
71
|
Sets the range of the #{x.to_s.upcase} coordinates.
|
72
72
|
|
73
73
|
*Important note:* when the axis is in log range (using
|
74
|
-
{command: #{x.to_s
|
74
|
+
{command: #{x.to_s}log}), the numbers you give are not the or
|
75
75
|
{command: ylog} values, but their @log10@, so that to
|
76
76
|
display #{x.to_s.upcase} values from @1e-2@ to @1e3@, use:
|
77
77
|
|
@@ -205,7 +205,7 @@ module CTioga2
|
|
205
205
|
|
206
206
|
## Actually draws the curve
|
207
207
|
def real_do(t)
|
208
|
-
debug { "Plotting curve #{
|
208
|
+
debug { "Plotting curve #{to_yaml}" }
|
209
209
|
t.context do
|
210
210
|
## \todo allow customization of the order of drawing,
|
211
211
|
## using a simple user-specificable array of path,
|
@@ -167,6 +167,7 @@ module CTioga2
|
|
167
167
|
|
168
168
|
def self.register_object(obj)
|
169
169
|
@registered_objects ||= {}
|
170
|
+
@objects_by_class ||= {}
|
170
171
|
if i = obj.object_id
|
171
172
|
if @registered_objects.key? i
|
172
173
|
warn { "Second object with ID #{i}, ignoring the name" }
|
@@ -174,6 +175,10 @@ module CTioga2
|
|
174
175
|
@registered_objects[i] = obj
|
175
176
|
end
|
176
177
|
end
|
178
|
+
for cls in (obj.object_classes || [])
|
179
|
+
@objects_by_class[cls] ||= []
|
180
|
+
@objects_by_class[cls] << obj
|
181
|
+
end
|
177
182
|
end
|
178
183
|
|
179
184
|
def self.find_object(obj_id)
|
@@ -184,12 +189,27 @@ module CTioga2
|
|
184
189
|
raise "No such object: '#{obj_id}'"
|
185
190
|
end
|
186
191
|
end
|
187
|
-
|
192
|
+
|
193
|
+
def self.find_objects(id_list)
|
194
|
+
# First split on commas:
|
195
|
+
ids = id_list.split(/\s*,\s*/)
|
196
|
+
objs = []
|
197
|
+
@objects_by_class ||= {}
|
198
|
+
for oi in ids
|
199
|
+
if oi =~ /^\.(.*)/
|
200
|
+
objs += (@objects_by_class[$1] || [])
|
201
|
+
elsif oi =~ /^\#?(.*)/
|
202
|
+
objs << self.find_object($1)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
return objs
|
206
|
+
end
|
207
|
+
|
188
208
|
|
189
209
|
def setup_style(obj_parent, opts)
|
190
210
|
@cached_options = opts
|
191
211
|
@object_id = opts["id"] || nil
|
192
|
-
@object_classes = opts["class"]
|
212
|
+
@object_classes = opts.key?("class") ? [opts["class"]].flatten : []
|
193
213
|
@object_parent = obj_parent
|
194
214
|
|
195
215
|
TiogaElement.register_object(self)
|
@@ -232,10 +252,10 @@ module CTioga2
|
|
232
252
|
# redefine _do_ too if you need another debugging output.
|
233
253
|
def do(f)
|
234
254
|
if @hidden
|
235
|
-
debug { "not plotting hidden #{self.
|
255
|
+
debug { "not plotting hidden #{self.to_yaml}" }
|
236
256
|
return
|
237
257
|
else
|
238
|
-
debug { "plotting #{self.
|
258
|
+
debug { "plotting #{self.to_yaml}" }
|
239
259
|
end
|
240
260
|
@gp_cache = {}
|
241
261
|
real_do(f)
|
@@ -313,12 +333,11 @@ appropriate command).
|
|
313
333
|
EOD
|
314
334
|
|
315
335
|
ObjectsType =
|
316
|
-
CmdType.new('objects', {:type => :
|
317
|
-
:
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
A list of comma-separated {type: object}s.
|
336
|
+
CmdType.new('objects', {:type => :function_based,
|
337
|
+
:class => Elements::TiogaElement,
|
338
|
+
:func_name => :find_objects}, <<EOD)
|
339
|
+
A list of comma-separated {type: object}s, or a class specification
|
340
|
+
starting with a .
|
322
341
|
EOD
|
323
342
|
|
324
343
|
end
|
@@ -161,6 +161,29 @@ module CTioga2
|
|
161
161
|
return primitive_class
|
162
162
|
end
|
163
163
|
|
164
|
+
|
165
|
+
|
166
|
+
primitive("legend-pictogram", "legend-pictogram",
|
167
|
+
["point", "object"], {
|
168
|
+
'width' => 'dimension'
|
169
|
+
},
|
170
|
+
"Draws the legend pictogram for the given curve"
|
171
|
+
) do |t, point, obj, opts|
|
172
|
+
al = Types::AlignedPoint::from_point(point)
|
173
|
+
cs = obj.curve_style
|
174
|
+
|
175
|
+
dx = opts['width'] || Types::Dimension.new(:dy, 2.5)
|
176
|
+
# dy = opts['height'] || Types::Dimension.new(:dy, 1)
|
177
|
+
dy = dx*0.4 # I'm not sure it really matters
|
178
|
+
pbb = Types::PointBasedBox.new(al, dx, dy)
|
179
|
+
pbb.within_frames(t) do
|
180
|
+
cs.draw_legend_pictogram(t)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
164
187
|
# This creates a primitive base on a style object, given a
|
165
188
|
# _style_class_, the base _style_name_ for the underlying
|
166
189
|
# styling system, options to remove and options to add.
|
@@ -265,8 +288,9 @@ EOD
|
|
265
288
|
[ 'point', 'dimension' ],
|
266
289
|
Styles::OrientedLineStyle,
|
267
290
|
'oriented-line'
|
268
|
-
|
269
|
-
|
291
|
+
) do |t, org, dim, style, options|
|
292
|
+
|
293
|
+
style.draw_oriented_arrow(t, *(org.to_figure_xy(t) + [dim]))
|
270
294
|
end
|
271
295
|
|
272
296
|
|