ctioga 1.11.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/ctioga/bin/ctable +28 -0
- data/ctioga/bin/ctioga +37 -0
- data/ctioga/doc/ctable.1 +156 -0
- data/ctioga/doc/ctioga.1 +2363 -0
- data/ctioga/examples/README +46 -0
- data/ctioga/examples/ctioga.gnuplot +4 -0
- data/ctioga/examples/ctioga_within_tioga.rb +53 -0
- data/ctioga/examples/ctiogarc.rb +24 -0
- data/ctioga/examples/include_1.rb +15 -0
- data/ctioga/examples/noise.dat +100 -0
- data/ctioga/examples/noise.rb +13 -0
- data/ctioga/examples/trig.csv +100 -0
- data/ctioga/examples/trig.dat +100 -0
- data/ctioga/examples/trig.rb +14 -0
- data/ctioga/examples/trigh.dat +100 -0
- data/ctioga/examples/trigh.rb +10 -0
- data/ctioga/examples/tutorial +763 -0
- data/ctioga/examples/tutorial.sh +269 -0
- data/ctioga/tests/README +14 -0
- data/ctioga/tests/axes.sh +40 -0
- data/ctioga/tests/basic.sh +11 -0
- data/ctioga/tests/draw.sh +24 -0
- data/ctioga/tests/histograms.sh +14 -0
- data/ctioga/tests/insets.sh +41 -0
- data/ctioga/tests/layouts.sh +29 -0
- data/ctioga/tests/legends.sh +113 -0
- data/ctioga/tests/styles.sh +43 -0
- data/ctioga/tests/test_style.sh +8 -0
- data/ctioga/tests/tests.sh +24 -0
- data/ctioga/tests/text_backend.sh +83 -0
- data/ctioga/tests/tioga_defaults.rb +18 -0
- data/lib/CTioga/axes.rb +904 -0
- data/lib/CTioga/backends.rb +88 -0
- data/lib/CTioga/boundaries.rb +224 -0
- data/lib/CTioga/ctable.rb +134 -0
- data/lib/CTioga/curve_style.rb +246 -0
- data/lib/CTioga/debug.rb +199 -0
- data/lib/CTioga/dimension.rb +133 -0
- data/lib/CTioga/elements.rb +17 -0
- data/lib/CTioga/elements/base.rb +84 -0
- data/lib/CTioga/elements/containers.rb +578 -0
- data/lib/CTioga/elements/curves.rb +368 -0
- data/lib/CTioga/elements/tioga_primitives.rb +440 -0
- data/lib/CTioga/layout.rb +595 -0
- data/lib/CTioga/legends.rb +29 -0
- data/lib/CTioga/legends/cmdline.rb +187 -0
- data/lib/CTioga/legends/item.rb +164 -0
- data/lib/CTioga/legends/style.rb +257 -0
- data/lib/CTioga/log.rb +73 -0
- data/lib/CTioga/movingarrays.rb +131 -0
- data/lib/CTioga/partition.rb +271 -0
- data/lib/CTioga/plot_style.rb +230 -0
- data/lib/CTioga/plotmaker.rb +1677 -0
- data/lib/CTioga/shortcuts.rb +69 -0
- data/lib/CTioga/structures.rb +82 -0
- data/lib/CTioga/styles.rb +140 -0
- data/lib/CTioga/themes.rb +581 -0
- data/lib/CTioga/themes/classical.rb +82 -0
- data/lib/CTioga/themes/demo.rb +63 -0
- data/lib/CTioga/themes/fits.rb +91 -0
- data/lib/CTioga/themes/mono.rb +33 -0
- data/lib/CTioga/tioga.rb +32 -0
- data/lib/CTioga/utils.rb +173 -0
- data/lib/MetaBuilder/Parameters/dates.rb +38 -0
- data/lib/MetaBuilder/Parameters/lists.rb +132 -0
- data/lib/MetaBuilder/Parameters/numbers.rb +69 -0
- data/lib/MetaBuilder/Parameters/strings.rb +86 -0
- data/lib/MetaBuilder/Parameters/styles.rb +75 -0
- data/lib/MetaBuilder/Qt4/Parameters/dates.rb +51 -0
- data/lib/MetaBuilder/Qt4/Parameters/numbers.rb +65 -0
- data/lib/MetaBuilder/Qt4/Parameters/strings.rb +106 -0
- data/lib/MetaBuilder/Qt4/parameter.rb +172 -0
- data/lib/MetaBuilder/Qt4/parameters.rb +9 -0
- data/lib/MetaBuilder/descriptions.rb +603 -0
- data/lib/MetaBuilder/factory.rb +101 -0
- data/lib/MetaBuilder/group.rb +57 -0
- data/lib/MetaBuilder/metabuilder.rb +10 -0
- data/lib/MetaBuilder/parameter.rb +374 -0
- data/lib/MetaBuilder/parameters.rb +11 -0
- data/lib/MetaBuilder/qt4.rb +8 -0
- data/lib/SciYAG/Backends/backend.rb +379 -0
- data/lib/SciYAG/Backends/binner.rb +168 -0
- data/lib/SciYAG/Backends/cache.rb +102 -0
- data/lib/SciYAG/Backends/dataset.rb +158 -0
- data/lib/SciYAG/Backends/descriptions.rb +469 -0
- data/lib/SciYAG/Backends/filters.rb +25 -0
- data/lib/SciYAG/Backends/filters/average.rb +134 -0
- data/lib/SciYAG/Backends/filters/cumulate.rb +37 -0
- data/lib/SciYAG/Backends/filters/filter.rb +70 -0
- data/lib/SciYAG/Backends/filters/norm.rb +39 -0
- data/lib/SciYAG/Backends/filters/smooth.rb +63 -0
- data/lib/SciYAG/Backends/filters/sort.rb +43 -0
- data/lib/SciYAG/Backends/filters/strip.rb +34 -0
- data/lib/SciYAG/Backends/filters/trim.rb +64 -0
- data/lib/SciYAG/Backends/gnuplot.rb +131 -0
- data/lib/SciYAG/Backends/math.rb +108 -0
- data/lib/SciYAG/Backends/mdb.rb +462 -0
- data/lib/SciYAG/Backends/multitext.rb +96 -0
- data/lib/SciYAG/Backends/source.rb +64 -0
- data/lib/SciYAG/Backends/text.rb +339 -0
- data/lib/SciYAG/backends.rb +16 -0
- metadata +191 -0
data/lib/CTioga/log.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# log.rb, copyright (c) 2006 by Vincent Fourmond:
|
2
|
+
# The general logging functions for Ctioga
|
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 'logger'
|
15
|
+
require 'forwardable'
|
16
|
+
|
17
|
+
module CTioga
|
18
|
+
|
19
|
+
Version::register_svn_info('$Revision: 653 $', '$Date: 2007-11-15 21:58:42 +0100 (Thu, 15 Nov 2007) $')
|
20
|
+
|
21
|
+
# This module contains code to be included by PlotMaker for debugging.
|
22
|
+
# Even if it doesn't deserve a real module of it's own, it makes sense
|
23
|
+
# to have it separated anyway.
|
24
|
+
module Log
|
25
|
+
|
26
|
+
extend Forwardable
|
27
|
+
def_delegators :@@log, :debug, :warn, :info, :error, :fatal
|
28
|
+
|
29
|
+
def init_logger(stream = STDERR)
|
30
|
+
Logger::Formatter::Format.replace("[%4$s] %6$s\n")
|
31
|
+
@@log = Logger.new(stream)
|
32
|
+
@@log.level = Logger::WARN # Warnings and more only by default
|
33
|
+
end
|
34
|
+
|
35
|
+
# Simple accessor for the @@log class variable.
|
36
|
+
def logger
|
37
|
+
return @@log
|
38
|
+
end
|
39
|
+
|
40
|
+
def logger_options(opt)
|
41
|
+
opt.on("-v", "--verbose", "Display useful information") do
|
42
|
+
@@log.level = Logger::INFO
|
43
|
+
end
|
44
|
+
opt.on("--debug", "Turn on debugging info") do
|
45
|
+
@@log.level = Logger::DEBUG
|
46
|
+
end
|
47
|
+
opt.on("--quiet", "Display only errors") do
|
48
|
+
@@log.level = Logger::ERROR
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# A logging replacement for system
|
53
|
+
def spawn(cmd, priority = :info)
|
54
|
+
retval = system(cmd)
|
55
|
+
self.send(priority, "Running #{cmd} -> " +
|
56
|
+
if retval
|
57
|
+
"success"
|
58
|
+
else
|
59
|
+
"failure"
|
60
|
+
end
|
61
|
+
)
|
62
|
+
return retval
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns a string suitable for identification of an object, but
|
66
|
+
# without instance variables.
|
67
|
+
def identify(obj)
|
68
|
+
return "#<#{obj.class} 0x%x>" % obj.object_id
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# movingarray.rb, copyright (c) 2007 by Vincent Fourmond:
|
2
|
+
# Moving arrays
|
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 'Dobjects/Dvector'
|
15
|
+
require 'Tioga/FigureConstants'
|
16
|
+
|
17
|
+
|
18
|
+
module CTioga
|
19
|
+
|
20
|
+
Version::register_svn_info('$Revision: 854 $', '$Date: 2008-11-27 23:21:51 +0100 (Thu, 27 Nov 2008) $')
|
21
|
+
|
22
|
+
# A helper function that converts user input into a Tioga
|
23
|
+
# color.
|
24
|
+
#
|
25
|
+
# TODO: allow designs such as in LaTeX xcolor: Red!10!Blue !
|
26
|
+
def self.get_tioga_color(str)
|
27
|
+
if str =~ /([\d.]+),([\d.]+),([\d.]+)/ # Array notation
|
28
|
+
color = Dobjects::Dvector.new([$1.to_f,$2.to_f,$3.to_f])
|
29
|
+
if color.max > 1
|
30
|
+
color *= 1.0/255.0
|
31
|
+
end
|
32
|
+
return color.to_a
|
33
|
+
elsif str =~ /#([0-9a-fA-F]{6})/ # HTML notation
|
34
|
+
return $1.scan(/../).map { |i| i.to_i(16)/255.0 }
|
35
|
+
else
|
36
|
+
return Tioga::FigureConstants.const_get(str)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# This class is just a means to make an instance of Array stand out
|
41
|
+
class SpecialArray < Array
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# The MovingArray class provides a way to scroll through an array,
|
46
|
+
# such as a set of colors, markers, linstyles, and so on. The class
|
47
|
+
# provides a way to set the value directly as well, and to forget it.
|
48
|
+
class MovingArray
|
49
|
+
include Tioga
|
50
|
+
|
51
|
+
def initialize(sets, current = nil, startpoint = 0)
|
52
|
+
@sets = sets
|
53
|
+
|
54
|
+
# Pick the first key as a default
|
55
|
+
current = @sets.keys.first unless current
|
56
|
+
choose_current_set(current)
|
57
|
+
|
58
|
+
@current_point = startpoint # the current point in the current set
|
59
|
+
end
|
60
|
+
|
61
|
+
def value
|
62
|
+
@current_point += 1
|
63
|
+
if @current_point >= @current_set.length
|
64
|
+
@current_point %= @current_set.length
|
65
|
+
end
|
66
|
+
return @current_set[@current_point - 1]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Chooses the current set. If the name refers to an existing set,
|
70
|
+
# this one is chosen. If not, and if the name looks like a gradient
|
71
|
+
# specification, we interpret it as such. In any other case,
|
72
|
+
# the chosen set is the set containing only the argument. This way,
|
73
|
+
# to get a set containing a single color, you can use
|
74
|
+
#
|
75
|
+
# choose_current_set(Pink)
|
76
|
+
def choose_current_set(name)
|
77
|
+
@current_set_name = name
|
78
|
+
if @sets.key?(name)
|
79
|
+
@current_set_name = name
|
80
|
+
@current_set = @sets[name]
|
81
|
+
elsif name =~ /gradient:(.+)--(.+),(\d+)/
|
82
|
+
# Special case for color gradients
|
83
|
+
s = CTioga.get_tioga_color($1)
|
84
|
+
e = CTioga.get_tioga_color($2)
|
85
|
+
nb = $3.to_i
|
86
|
+
fact = if nb > 1
|
87
|
+
1.0/(nb - 1) # The famous off-by one...
|
88
|
+
else
|
89
|
+
warn "Incorrect gradient number: #{nb}"
|
90
|
+
1.0
|
91
|
+
end
|
92
|
+
array = []
|
93
|
+
nb.times do |i|
|
94
|
+
a = []
|
95
|
+
f = i * fact
|
96
|
+
e.each_index do |c|
|
97
|
+
a << s[c] * (1 - f) + e[c] * f
|
98
|
+
end
|
99
|
+
array << a
|
100
|
+
end
|
101
|
+
@current_set = array
|
102
|
+
else
|
103
|
+
if name.is_a? SpecialArray
|
104
|
+
@current_set = name
|
105
|
+
else
|
106
|
+
@current_set = [name]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the available sets.
|
112
|
+
def available_sets
|
113
|
+
return @sets.keys
|
114
|
+
end
|
115
|
+
|
116
|
+
# Tells whether the given name is a valid set. Takes care of the special
|
117
|
+
# case of gradients.
|
118
|
+
#
|
119
|
+
# TODO: this looks hackish, somehow, but I don't see a way to make
|
120
|
+
# that less so...
|
121
|
+
def valid_set?(name)
|
122
|
+
if name =~ /^gradient:/
|
123
|
+
return true
|
124
|
+
else
|
125
|
+
return @sets.key? name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
# partition.rb: segment partitioning functions
|
2
|
+
# Copyright (c) 2008 by Vincent Fourmond
|
3
|
+
|
4
|
+
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; either version 2 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details (in the COPYING file).
|
14
|
+
|
15
|
+
require 'CTioga/utils'
|
16
|
+
|
17
|
+
|
18
|
+
module CTioga
|
19
|
+
|
20
|
+
Version::register_svn_info('$Revision: 792 $', '$Date: 2008-05-23 00:19:31 +0200 (Fri, 23 May 2008) $')
|
21
|
+
|
22
|
+
# A module for small convenience functions.
|
23
|
+
module Utils
|
24
|
+
|
25
|
+
# The following code is stolen from SciYAG/lib/utils.rb,
|
26
|
+
# and is used to partition segments in natural-looking
|
27
|
+
# subdivisions.
|
28
|
+
|
29
|
+
|
30
|
+
# Our natural way to split decades
|
31
|
+
NaturalDistances = Dobjects::Dvector[1, 2, 2.5, 5, 10]
|
32
|
+
|
33
|
+
# Attempts to partition the given segment in at most _nb_
|
34
|
+
# segments of equal size. The segments don't necessarily start on
|
35
|
+
# the edge of the original segment
|
36
|
+
def self.partition_segment(min, max, nb)
|
37
|
+
if min > max
|
38
|
+
return partition_segment(max, min, nb)
|
39
|
+
elsif min.nan? or max.nan?
|
40
|
+
return [0] * nb
|
41
|
+
elsif min == max
|
42
|
+
return self.partition_segment(min * 0.7, min * 1.3, nb)
|
43
|
+
end
|
44
|
+
distance = max - min
|
45
|
+
min_distance = distance/(nb + 1.0) # Why + 1.0 ? To account
|
46
|
+
# for the space that could be left on the side.
|
47
|
+
|
48
|
+
# The order of magnitude of the distance:
|
49
|
+
order = min_distance.log10.floor
|
50
|
+
|
51
|
+
# A distance which is within [1, 10 [ (but the latter is never reached.
|
52
|
+
normalized_distance = min_distance * 10**(-order)
|
53
|
+
final_distance = NaturalDistances.min_gt(normalized_distance) *
|
54
|
+
10**(order)
|
55
|
+
# puts "Distance: #{distance} in #{nb} : #{normalized_distance} #{final_distance}"
|
56
|
+
|
57
|
+
# We're getting closer now: we found the natural distance between
|
58
|
+
# ticks.
|
59
|
+
|
60
|
+
start = (min/final_distance).ceil * final_distance
|
61
|
+
retval = []
|
62
|
+
val = start
|
63
|
+
while val <= max
|
64
|
+
retval << val
|
65
|
+
# I use this to avoid potential cumulative addition
|
66
|
+
# rounding errors
|
67
|
+
val = start + final_distance * retval.size
|
68
|
+
end
|
69
|
+
return retval
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
# Our natural way to split decades - except that all successive
|
74
|
+
# element now divide each other.
|
75
|
+
NaturalDistancesNonLinear = Dobjects::Dvector[1, 2.5, 5, 10]
|
76
|
+
|
77
|
+
# A class that handles a "natural distance". Create it by giving
|
78
|
+
# the initial distance. You can then get its value, lower it,
|
79
|
+
# increase it, find the first/last element of an interval that is
|
80
|
+
# a multiple if it
|
81
|
+
class NaturalDistance
|
82
|
+
|
83
|
+
# Creates the biggest 'natural distance' that is smaller
|
84
|
+
# than _distance_
|
85
|
+
def initialize(distance)
|
86
|
+
@order = distance.log10.floor
|
87
|
+
normalized = distance * 10**(-@order)
|
88
|
+
@index = 0
|
89
|
+
for dist in NaturalDistances
|
90
|
+
if dist > normalized
|
91
|
+
break
|
92
|
+
else
|
93
|
+
@index += 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns the actual value of the distance
|
99
|
+
def value
|
100
|
+
return NaturalDistances[@index] * 10**(@order)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Goes to the natural distance immediately under the current one
|
104
|
+
def decrease
|
105
|
+
if @index > 0
|
106
|
+
@index -= 1
|
107
|
+
else
|
108
|
+
@index = NaturalDistances.size - 1
|
109
|
+
@order -= 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Goes to the natural distance immediately under the current one
|
114
|
+
def increase
|
115
|
+
if @index < NaturalDistances.size - 1
|
116
|
+
@index += 1
|
117
|
+
else
|
118
|
+
@index = 0
|
119
|
+
@order += 1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Find the minimum element inside the given interval
|
124
|
+
# that is a multiple of this distance
|
125
|
+
def find_minimum(x1, x2)
|
126
|
+
x1,x2 = x2, x1 if x1 > x2
|
127
|
+
|
128
|
+
dist = value
|
129
|
+
v = (x1/dist).ceil * dist
|
130
|
+
if v <= x2
|
131
|
+
return v
|
132
|
+
else
|
133
|
+
return false
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns the value of the next decade (ascending)
|
138
|
+
def next_decade(x)
|
139
|
+
decade = 10.**(@order + 1)
|
140
|
+
if @index == 0 # We stop at 0.5 if the increase is 0.5
|
141
|
+
decade *= 0.5
|
142
|
+
end
|
143
|
+
nb = Float((x/decade).ceil)
|
144
|
+
if nb == x/decade
|
145
|
+
return (nb + 1)*decade
|
146
|
+
else
|
147
|
+
return nb * decade
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Returns the number of elements to #next_decade
|
152
|
+
def nb_to_next_decade(x)
|
153
|
+
dist = value
|
154
|
+
dec = next_decade(x)
|
155
|
+
return dec/dist - (x/dist).ceil + 1
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns a list of all the values corresponding to
|
159
|
+
# the distance
|
160
|
+
def to_next_decade(x)
|
161
|
+
next_decade = next_decade(x)
|
162
|
+
dist = value
|
163
|
+
start = (x/dist).ceil * dist
|
164
|
+
retval = []
|
165
|
+
while start + retval.size * dist <= next_decade
|
166
|
+
retval << start + retval.size * dist
|
167
|
+
end
|
168
|
+
return retval
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# Attempts to partition the segment image of _min_, _max_
|
175
|
+
# by the Proc object _to_ into at most _nb_ elements. The
|
176
|
+
# reverse of the transformation, _from_, has to be provided.
|
177
|
+
def self.partition_nonlinear(to, from, x1, x2, nb)
|
178
|
+
x1, x2 = x2, x1 if x1 > x2
|
179
|
+
if x1.nan? or x2.nan?
|
180
|
+
return [0] * nb
|
181
|
+
elsif x1 == x2 # Nothing to do
|
182
|
+
return self.partition_segment(x1 * 0.7, x2 * 1.3, nb)
|
183
|
+
end
|
184
|
+
|
185
|
+
xdist = x2 - x1
|
186
|
+
xdist_min = xdist/(nb + 1.0) # Why + 1.0 ? To account
|
187
|
+
# for the space that could be left on the side.
|
188
|
+
|
189
|
+
y1 = to.call(x1)
|
190
|
+
y2 = to.call(x2)
|
191
|
+
|
192
|
+
# Make sure y1 < y2
|
193
|
+
y1, y2 = y2, y1 if y1 > y2
|
194
|
+
|
195
|
+
# We first need to check if the linear partitioning of
|
196
|
+
# the target segment could be enough:
|
197
|
+
|
198
|
+
candidate = self.partition_segment(y1, y2, nb)
|
199
|
+
candidate_real = candidate.map(&from)
|
200
|
+
|
201
|
+
# We inspect the segment: if one of the length deviates from the
|
202
|
+
# average expected by more than 25%, we drop it
|
203
|
+
|
204
|
+
length = []
|
205
|
+
p candidate_real, xdist_min
|
206
|
+
0.upto(candidate.size - 2) do |i|
|
207
|
+
length << (candidate_real[i+1] - candidate_real[i]).abs/(xdist_min)
|
208
|
+
end
|
209
|
+
p length
|
210
|
+
# If everything stays within 25% off, we keep that
|
211
|
+
if length.min > 0.75 and length.max < 1.7
|
212
|
+
return candidate
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
# We start with a geometric measure of the distance, that
|
217
|
+
# will most likely scale better:
|
218
|
+
ydist = y1 * (y2/y1).abs ** (1/(nb + 1.0))
|
219
|
+
|
220
|
+
cur_dist = NaturalDistance.new(ydist)
|
221
|
+
|
222
|
+
retval = []
|
223
|
+
|
224
|
+
cur_y = y1
|
225
|
+
# This flag is necessary to avoid infinite loops
|
226
|
+
last_was_decrease = false
|
227
|
+
|
228
|
+
distance_unchanged = 0
|
229
|
+
last_real_distance = false
|
230
|
+
while cur_y < y2
|
231
|
+
candidates = cur_dist.to_next_decade(cur_y)
|
232
|
+
# We now evaluate the distance in real
|
233
|
+
real_distance = (from.call(cur_y) - from.call(candidates.last)).abs/
|
234
|
+
candidates.size
|
235
|
+
if last_real_distance && (real_distance == last_real_distance)
|
236
|
+
distance_unchanged += 1
|
237
|
+
else
|
238
|
+
distance_unchanged = 0
|
239
|
+
end
|
240
|
+
# p [:cur_y=, cur_y, :y2=, y2, :real_distance, real_distance,
|
241
|
+
# :distance=, cur_dist, :xdist_min, xdist_min,
|
242
|
+
# :candidates=, *candidates]
|
243
|
+
|
244
|
+
if (real_distance > 1.25 * xdist_min) &&
|
245
|
+
(distance_unchanged < 3)
|
246
|
+
cur_dist.decrease
|
247
|
+
last_was_decrease = true
|
248
|
+
elsif real_distance < 0.75 * xdist_min &&
|
249
|
+
!last_was_decrease && (distance_unchanged < 3) &&
|
250
|
+
candidates.last <= 10 * y2
|
251
|
+
cur_dist.increase
|
252
|
+
last_was_decrease = false
|
253
|
+
else
|
254
|
+
retval += candidates
|
255
|
+
cur_y = candidates.last
|
256
|
+
last_was_decrease = false
|
257
|
+
end
|
258
|
+
last_real_distance = real_distance
|
259
|
+
end
|
260
|
+
|
261
|
+
# We need to select them so
|
262
|
+
return retval.select do |y|
|
263
|
+
y >= y1 and y <= y2
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|