redshift 1.3.16 → 1.3.17
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.
- data/RELEASE-NOTES +8 -0
- data/examples/shell.rb +224 -0
- data/lib/redshift/mixins/irb-shell.rb +151 -0
- data/lib/redshift/redshift.rb +1 -1
- data/lib/redshift/syntax.rb +8 -4
- data/lib/redshift/target/c/flow/buffer.rb +69 -2
- data/lib/redshift/target/c/flow/delay.rb +12 -52
- data/lib/redshift/util/tkar-driver.rb +93 -0
- data/lib/redshift/world.rb +1 -1
- data/rakefile +2 -0
- data/test/test_delay.rb +2 -0
- metadata +10 -7
data/RELEASE-NOTES
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
redshift 1.3.17
|
2
|
+
|
3
|
+
- added shell example with plotting and tk animation
|
4
|
+
|
5
|
+
- added supporting libs for tk and for irb shells
|
6
|
+
|
7
|
+
- delay buffer automatically rotates around offset when dumping to array
|
8
|
+
|
1
9
|
redshift 1.3.16
|
2
10
|
|
3
11
|
- added util dir and modified requires to use libs from there
|
data/examples/shell.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
# Shows how to use a customized IRB shell to handle Ctrl-C interrupts
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
require 'redshift/mixins/irb-shell'
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
require 'redshift/util/plot'
|
8
|
+
include Plot::PlotUtils
|
9
|
+
|
10
|
+
# Adds an interactive ruby shell with plotting and animation commands.
|
11
|
+
module ShellWorld
|
12
|
+
include RedShift::Shellable
|
13
|
+
|
14
|
+
def help
|
15
|
+
puts <<-END
|
16
|
+
The current object is #{self.inspect}. Some commands:
|
17
|
+
|
18
|
+
q -- quit
|
19
|
+
sh! -- enter a system command shell
|
20
|
+
t.plot -- plot recent history of t (try t=components[0])
|
21
|
+
plot -- plot recent history of all T instances
|
22
|
+
run N -- run quickly for N time steps (integer)
|
23
|
+
evolve T -- run quickly for T seconds (float)
|
24
|
+
tk -- turn on Tk window
|
25
|
+
tk false -- turn off Tk window
|
26
|
+
|
27
|
+
Local vars persist between interrupts.
|
28
|
+
Continue slow execution by pressing Ctrl-D (maybe Ctrl-Z on windows).
|
29
|
+
Press Ctrl-C again to break into the shell.
|
30
|
+
END
|
31
|
+
end
|
32
|
+
|
33
|
+
def sh!
|
34
|
+
system ENV['SHELL'] || default_shell
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_shell
|
38
|
+
puts "No SHELL environment variable, trying /bin/bash"
|
39
|
+
"/bin/bash"
|
40
|
+
end
|
41
|
+
|
42
|
+
def next_id
|
43
|
+
@next_id ||= 1
|
44
|
+
@next_id += 1
|
45
|
+
end
|
46
|
+
|
47
|
+
def plot
|
48
|
+
gnuplot do |plot|
|
49
|
+
plot.command 'set title "recent history"'
|
50
|
+
plot.command "set xrange [*:*]"
|
51
|
+
plot.command "set yrange [*:*]"
|
52
|
+
grep(T) do |t|
|
53
|
+
t.add_history_to_plot(plot)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def before_shell
|
60
|
+
@tkar.catch_up_within 0 if @tkar
|
61
|
+
puts "\nStopped #{self.inspect}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def after_shell
|
65
|
+
@tkar.catch_up_within 0 if @tkar
|
66
|
+
puts "\nRunning #{self.inspect}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def dragger id, x, y
|
70
|
+
@th ||= {}
|
71
|
+
t = @th[id] ||= grep(T).find {|t| t.id == id}
|
72
|
+
t.x, t.y = x, y
|
73
|
+
end
|
74
|
+
|
75
|
+
def tk turn_on = true
|
76
|
+
require 'redshift/util/tkar-driver'
|
77
|
+
if turn_on
|
78
|
+
if not @tkar or @tkar.closed?
|
79
|
+
@tkar = TkarDriver.new(method :dragger) do |pipe|
|
80
|
+
pipe.puts <<-END
|
81
|
+
title Animation example
|
82
|
+
background gray95
|
83
|
+
height 600
|
84
|
+
width 600
|
85
|
+
view_at -50 -50
|
86
|
+
zoom_to 4
|
87
|
+
|
88
|
+
shape cone \ arc5,5,10,10,fc:yellow,oc:black,extent:30,start:165,style:pieslice \
|
89
|
+
text2,2,anchor:c,justify:center,width:100,text:*0,fc:blue
|
90
|
+
|
91
|
+
shape circle oval*0,*0,*1,*1,oc:red
|
92
|
+
END
|
93
|
+
## the view_at seems to be needed to overcome a little
|
94
|
+
## centering bug in tkar
|
95
|
+
|
96
|
+
(1..10).each do |i|
|
97
|
+
pipe.puts "add circle #{next_id} - 0 0 0 0 #{5*i} #{-5*i}"
|
98
|
+
end
|
99
|
+
|
100
|
+
grep(T) do |t|
|
101
|
+
pipe.puts t.tk_add
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
tk_update
|
106
|
+
end
|
107
|
+
|
108
|
+
elsif not turn_on and @tkar
|
109
|
+
@tkar.close
|
110
|
+
@tkar = nil
|
111
|
+
end
|
112
|
+
@tkar
|
113
|
+
end
|
114
|
+
|
115
|
+
def tk_update
|
116
|
+
@tkar and @tkar.update do |pipe|
|
117
|
+
grep(T) do |t|
|
118
|
+
pipe.puts t.tk_update
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class T < Component
|
125
|
+
attr_accessor :name, :id
|
126
|
+
|
127
|
+
default do
|
128
|
+
@id = world.next_id
|
129
|
+
end
|
130
|
+
|
131
|
+
flow do
|
132
|
+
diff " x' = -y "
|
133
|
+
diff " y' = x "
|
134
|
+
|
135
|
+
alg " r = atan2(x, -y) " # atan2(y', x'): angle of velocity vector
|
136
|
+
|
137
|
+
# A simple, but crude, way to store recent history of a var
|
138
|
+
delay " z = x ", :by => 10
|
139
|
+
end
|
140
|
+
|
141
|
+
def history
|
142
|
+
ts = world.time_step
|
143
|
+
t0 = world.clock - z_delay
|
144
|
+
data = []
|
145
|
+
z_buffer_data.each_with_index do |xi, i|
|
146
|
+
if i % 4 == 0 # skip the integrator steps
|
147
|
+
time = t0 + (i/4)*ts
|
148
|
+
data << [time, xi] if time >= 0
|
149
|
+
end
|
150
|
+
end
|
151
|
+
data << [world.clock, x]
|
152
|
+
data
|
153
|
+
end
|
154
|
+
|
155
|
+
def add_history_to_plot(plot)
|
156
|
+
plot.add history, "using 1:2 title \"#{name}.x\" with lines"
|
157
|
+
end
|
158
|
+
|
159
|
+
def plot
|
160
|
+
gnuplot do |plot|
|
161
|
+
plot.command 'set title "recent history"'
|
162
|
+
plot.command "set xrange [*:*]"
|
163
|
+
plot.command "set yrange [*:*]"
|
164
|
+
add_history_to_plot(plot)
|
165
|
+
end
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
|
169
|
+
# return string that adds an instance of the shape with label t.name,
|
170
|
+
# position based on (x, y), and
|
171
|
+
# rotation based on (x', y')
|
172
|
+
def tk_add
|
173
|
+
"add cone #{id} - 10 #{x} #{y} #{r}\n" +
|
174
|
+
"param #{id} 0 #{name}"
|
175
|
+
end
|
176
|
+
|
177
|
+
# emit string representing current state
|
178
|
+
def tk_update
|
179
|
+
"moveto #{id} #{x} #{y}\n" +
|
180
|
+
"rot #{id} #{r}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
w = World.new
|
185
|
+
w.time_step = 0.01
|
186
|
+
w.extend ShellWorld
|
187
|
+
|
188
|
+
w.create T do |t|
|
189
|
+
t.name = "a"
|
190
|
+
t.x = 40
|
191
|
+
t.y = 0
|
192
|
+
end
|
193
|
+
w.create T do |t|
|
194
|
+
t.name = "b"
|
195
|
+
t.x = 0
|
196
|
+
t.y = 20
|
197
|
+
end
|
198
|
+
|
199
|
+
if false
|
200
|
+
(1..10).each do |i|
|
201
|
+
w.create T do |t|
|
202
|
+
t.name = "c#{i}"
|
203
|
+
t.x = i*5
|
204
|
+
t.y = i*5
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
puts "^C to break into shell; 'help' for shell help"
|
210
|
+
|
211
|
+
if ARGV.delete "-t"
|
212
|
+
w.tk
|
213
|
+
end
|
214
|
+
|
215
|
+
start_in_shell = ARGV.delete "-s"
|
216
|
+
w.shell.run if start_in_shell
|
217
|
+
|
218
|
+
loop do
|
219
|
+
w.evolve 100000000 do
|
220
|
+
puts "clock: #{w.clock}"
|
221
|
+
w.tk_update
|
222
|
+
sleep 0.01
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'irb'
|
2
|
+
require 'irb/completion'
|
3
|
+
|
4
|
+
class Object
|
5
|
+
include IRB::ExtendCommandBundle
|
6
|
+
# so that Marshal.dump still works, even when doing ">> irb obj"
|
7
|
+
end
|
8
|
+
|
9
|
+
def IRB.parse_opts
|
10
|
+
# Don't touch ARGV, which belongs to the app which called this module.
|
11
|
+
end
|
12
|
+
|
13
|
+
class RedShift::IRBShell
|
14
|
+
@@irb_setup_done = false
|
15
|
+
|
16
|
+
# +args+ are binding, self (both optional)
|
17
|
+
def initialize(*args)
|
18
|
+
## maybe set some opts here, as in parse_opts in irb/init.rb?
|
19
|
+
|
20
|
+
unless @@irb_setup_done
|
21
|
+
@@irb_setup_done = true
|
22
|
+
|
23
|
+
conf = IRB.conf
|
24
|
+
|
25
|
+
if File.directory?("tmp")
|
26
|
+
conf[:HISTORY_FILE] = "tmp/.redshift_irb_shell_history"
|
27
|
+
else
|
28
|
+
conf[:HISTORY_FILE] = ".redshift_irb_shell_history"
|
29
|
+
end
|
30
|
+
|
31
|
+
IRB.setup nil
|
32
|
+
|
33
|
+
at_exit do
|
34
|
+
IRB.irb_at_exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
workspace = IRB::WorkSpace.new(*args)
|
39
|
+
|
40
|
+
if conf[:SCRIPT] ## normally, set by parse_opts
|
41
|
+
@irb = IRB::Irb.new(workspace, conf[:SCRIPT])
|
42
|
+
else
|
43
|
+
@irb = IRB::Irb.new(workspace)
|
44
|
+
end
|
45
|
+
|
46
|
+
conf[:IRB_RC].call(@irb.context) if conf[:IRB_RC]
|
47
|
+
conf[:MAIN_CONTEXT] = @irb.context
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
@interrupt_requests = nil
|
52
|
+
|
53
|
+
trap("INT") do
|
54
|
+
@irb.signal_handle
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
catch(:IRB_EXIT) do
|
59
|
+
@irb.eval_input
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
install_interrupt_handler
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def install_interrupt_handler
|
67
|
+
unless @interrupt_requests
|
68
|
+
@interrupt_requests = 0
|
69
|
+
trap("INT") do
|
70
|
+
@interrupt_requests += 1
|
71
|
+
if @interrupt_requests == 2
|
72
|
+
puts "\nType one more ^C to abort, or wait for RedShift shell."
|
73
|
+
elsif @interrupt_requests >= 3
|
74
|
+
exit!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def handle_interrupt after = nil
|
81
|
+
if @interrupt_requests && @interrupt_requests > 0
|
82
|
+
yield if block_given?
|
83
|
+
run
|
84
|
+
true
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# extend a World instance with this (or include in a World subclass)
|
92
|
+
module RedShift::Shellable
|
93
|
+
def shell
|
94
|
+
@shell ||= RedShift::IRBShell.new(binding, self)
|
95
|
+
end
|
96
|
+
|
97
|
+
def run(*)
|
98
|
+
shell.install_interrupt_handler
|
99
|
+
super
|
100
|
+
end
|
101
|
+
|
102
|
+
def step(*)
|
103
|
+
super do
|
104
|
+
yield self if block_given?
|
105
|
+
if shell.handle_interrupt {before_shell}
|
106
|
+
after_shell
|
107
|
+
return
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Override to complete some action before dropping into shell.
|
113
|
+
def before_shell
|
114
|
+
end
|
115
|
+
|
116
|
+
# Override to complete some action after leaving shell.
|
117
|
+
def after_shell
|
118
|
+
end
|
119
|
+
|
120
|
+
# Typically, call this in a rescue clause, if you to let the user
|
121
|
+
# examine state and possibly continue:
|
122
|
+
#
|
123
|
+
# rescue ... => e
|
124
|
+
# require 'redshift/mixins/irb-shell'
|
125
|
+
# world.extend RedShift::IRBShell
|
126
|
+
# world.recoverable_error e, "Assertion failure", e.backtrace
|
127
|
+
#
|
128
|
+
def recoverable_error e, msg = "Error", bt = []
|
129
|
+
puts "#{msg} at time #{clock}"
|
130
|
+
puts "From " + bt[0..2].join("\n ") unless bt.empty
|
131
|
+
puts " ..." if bt.length > 3
|
132
|
+
shell.run
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def q
|
137
|
+
exit
|
138
|
+
end
|
139
|
+
|
140
|
+
## commands:
|
141
|
+
## step [n] {block}
|
142
|
+
## step_until/while
|
143
|
+
## continue -- safer than ^D, does step_discrete in case of changes
|
144
|
+
## step_continuous
|
145
|
+
## step_discrete [n]
|
146
|
+
## break [class/component/transition/comp.event/condition]
|
147
|
+
## until step_until, stops inside step_discrete
|
148
|
+
## clear
|
149
|
+
##
|
150
|
+
## customize prompt
|
151
|
+
end
|
data/lib/redshift/redshift.rb
CHANGED
data/lib/redshift/syntax.rb
CHANGED
@@ -211,7 +211,11 @@ module FlowSyntax
|
|
211
211
|
|
212
212
|
def initialize block
|
213
213
|
@flows = []
|
214
|
-
instance_eval(&block)
|
214
|
+
val = instance_eval(&block)
|
215
|
+
if val.kind_of? String and val =~ /=/
|
216
|
+
warn "Equation appears to be missing a specifier (alg, diff, etc.):" +
|
217
|
+
val
|
218
|
+
end
|
215
219
|
end
|
216
220
|
|
217
221
|
def algebraic(*equations)
|
@@ -224,7 +228,7 @@ module FlowSyntax
|
|
224
228
|
end
|
225
229
|
|
226
230
|
def euler(*equations)
|
227
|
-
|
231
|
+
equations.each do |equation|
|
228
232
|
unless equation =~ /^\s*(\w+)\s*'\s*=\s*(.+)/m
|
229
233
|
raise SyntaxError, "parse error in\n\t#{equation}."
|
230
234
|
end
|
@@ -233,7 +237,7 @@ module FlowSyntax
|
|
233
237
|
end
|
234
238
|
|
235
239
|
def rk4(*equations)
|
236
|
-
|
240
|
+
equations.each do |equation|
|
237
241
|
unless equation =~ /^\s*(\w+)\s*'\s*=\s*(.+)/m
|
238
242
|
raise SyntaxError, "parse error in\n\t#{equation}."
|
239
243
|
end
|
@@ -252,7 +256,7 @@ module FlowSyntax
|
|
252
256
|
## rename 'feedback'?
|
253
257
|
end
|
254
258
|
feedback = opts[:feedback]
|
255
|
-
|
259
|
+
equations.each do |equation|
|
256
260
|
unless equation =~ /^\s*(\w+)\s*=\s*(.+)'\s*\z/m
|
257
261
|
raise SyntaxError, "parse error in\n\t#{equation}."
|
258
262
|
end
|
@@ -8,10 +8,72 @@ class RedShift::Library
|
|
8
8
|
include_file.declare :Buffer => %{
|
9
9
|
typedef struct {
|
10
10
|
long len;
|
11
|
+
long offset;
|
11
12
|
double *ptr;
|
12
13
|
} Buffer;
|
13
14
|
}.tabto(0)
|
14
15
|
|
16
|
+
source_file.define_c_function(:buffer_init).instance_eval {
|
17
|
+
arguments "Buffer *buf", "long len", "double fill"
|
18
|
+
scope :extern
|
19
|
+
body %{
|
20
|
+
int i;
|
21
|
+
buf->ptr = ALLOC_N(double, len);
|
22
|
+
buf->len = len;
|
23
|
+
buf->offset = 0;
|
24
|
+
for (i=0; i<len; i++) {
|
25
|
+
buf->ptr[i] = fill;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
source_file.define_c_function(:buffer_resize).instance_eval {
|
31
|
+
arguments "Buffer *buf", "long len"
|
32
|
+
scope :extern
|
33
|
+
body %{
|
34
|
+
long i;
|
35
|
+
long old_len = buf->len;
|
36
|
+
long offset = buf->offset;
|
37
|
+
double *ptr = buf->ptr;
|
38
|
+
double *dst, *src;
|
39
|
+
double fill;
|
40
|
+
|
41
|
+
if (len < old_len) {
|
42
|
+
if (offset < len) {
|
43
|
+
dst = ptr + offset;
|
44
|
+
src = ptr + offset + old_len - len;
|
45
|
+
memmove(dst, src, (len - offset) * sizeof(double));
|
46
|
+
}
|
47
|
+
else {
|
48
|
+
dst = ptr;
|
49
|
+
src = ptr + offset - len;
|
50
|
+
offset = 0;
|
51
|
+
memmove(dst, src, len * sizeof(double));
|
52
|
+
}
|
53
|
+
REALLOC_N(ptr, double, len);
|
54
|
+
// ## maybe better: don't release space, just use less of it
|
55
|
+
}
|
56
|
+
else if (len > old_len) {
|
57
|
+
REALLOC_N(ptr, double, len);
|
58
|
+
|
59
|
+
fill = ptr[offset];
|
60
|
+
dst = ptr + offset + len - old_len;
|
61
|
+
src = ptr + offset;
|
62
|
+
memmove(dst, src, (old_len - offset) * sizeof(double));
|
63
|
+
|
64
|
+
for (i = 0; i < len - old_len; i++) {
|
65
|
+
ptr[offset + i] = fill;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
else
|
69
|
+
return;
|
70
|
+
|
71
|
+
buf->len = len;
|
72
|
+
buf->offset = offset;
|
73
|
+
buf->ptr = ptr;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
15
77
|
source_file.define_c_function(:buffer_inhale_array).instance_eval {
|
16
78
|
arguments "Buffer *buf", "VALUE ary"
|
17
79
|
scope :extern
|
@@ -28,6 +90,7 @@ class RedShift::Library
|
|
28
90
|
buf->ptr = ALLOC_N(double, size);
|
29
91
|
}
|
30
92
|
buf->len = size;
|
93
|
+
buf->offset = 0;
|
31
94
|
|
32
95
|
for (i = 0; i < size; i++) {
|
33
96
|
buf->ptr[i] = NUM2DBL(RARRAY(ary)->ptr[i]);
|
@@ -42,13 +105,17 @@ class RedShift::Library
|
|
42
105
|
scope :extern
|
43
106
|
declare :size => "int size",
|
44
107
|
:i => "int i",
|
108
|
+
:j => "int j",
|
45
109
|
:ary => "VALUE ary"
|
46
110
|
body %{
|
47
111
|
size = buf->len;
|
48
112
|
ary = rb_ary_new2(size);
|
49
113
|
RARRAY(ary)->len = size;
|
50
|
-
for (i = 0; i < size; i++) {
|
51
|
-
RARRAY(ary)->ptr[
|
114
|
+
for (i = buf->offset, j=0; i < size; i++, j++) {
|
115
|
+
RARRAY(ary)->ptr[j] = rb_float_new(buf->ptr[i]);
|
116
|
+
}
|
117
|
+
for (i = 0; i < buf->offset; i++, j++) {
|
118
|
+
RARRAY(ary)->ptr[j] = rb_float_new(buf->ptr[i]);
|
52
119
|
}
|
53
120
|
}
|
54
121
|
}
|
@@ -17,13 +17,11 @@ module RedShift; class DelayFlow
|
|
17
17
|
RedShift.library.define_buffer
|
18
18
|
|
19
19
|
bufname = "#{var_name}_buffer_data"
|
20
|
-
offsetname = "#{var_name}_buffer_offset"
|
21
20
|
delayname = "#{var_name}_delay"
|
22
21
|
tsname = "#{var_name}_time_step"
|
23
22
|
|
24
23
|
cl.class_eval do
|
25
24
|
shadow_attr_accessor bufname => "Buffer #{bufname}"
|
26
|
-
shadow_attr_accessor offsetname => "long #{offsetname}"
|
27
25
|
shadow_attr_accessor delayname => "double #{delayname}"
|
28
26
|
# delay should be set only using the expr designated in :by => "expr"
|
29
27
|
shadow_attr tsname => "double #{tsname}"
|
@@ -50,7 +48,7 @@ module RedShift; class DelayFlow
|
|
50
48
|
|
51
49
|
ContVar *var;
|
52
50
|
double *ptr;
|
53
|
-
long
|
51
|
+
long len, offset, steps;
|
54
52
|
double delay, fill;
|
55
53
|
}
|
56
54
|
setup :shadow => %{
|
@@ -77,7 +75,7 @@ module RedShift; class DelayFlow
|
|
77
75
|
switch (shadow->world->rk_level) {
|
78
76
|
case 0:
|
79
77
|
ptr = shadow->#{bufname}.ptr;
|
80
|
-
offset = shadow->#{
|
78
|
+
offset = shadow->#{bufname}.offset;
|
81
79
|
|
82
80
|
if (shadow->world->time_step != shadow->#{tsname}) {
|
83
81
|
if (shadow->#{tsname} == 0.0)
|
@@ -106,57 +104,17 @@ module RedShift; class DelayFlow
|
|
106
104
|
#{flow.translate(self, "fill", 0, cl).join("
|
107
105
|
")};
|
108
106
|
|
109
|
-
|
110
|
-
shadow->#{bufname}.ptr = ptr;
|
111
|
-
shadow->#{bufname}.len = len;
|
112
|
-
shadow->#{offsetname} = 0;
|
113
|
-
shadow->#{delayname} = delay;
|
114
|
-
|
115
|
-
for (i=0; i<len; i++) {
|
116
|
-
ptr[i] = fill;
|
117
|
-
}
|
107
|
+
buffer_init(&shadow->#{bufname}, len, fill);
|
118
108
|
}
|
119
109
|
else { // # delay != shadow->#{delayname}
|
120
|
-
|
121
|
-
double *dst, *src;
|
122
|
-
|
123
|
-
if (delay < shadow->#{delayname}) {
|
124
|
-
if (offset < len) {
|
125
|
-
dst = ptr + offset;
|
126
|
-
src = ptr + offset + old_len - len;
|
127
|
-
}
|
128
|
-
else {
|
129
|
-
dst = ptr;
|
130
|
-
src = ptr + offset - len;
|
131
|
-
offset = 0;
|
132
|
-
}
|
133
|
-
memmove(dst, src, (len - offset) * sizeof(double));
|
134
|
-
REALLOC_N(ptr, double, len);
|
135
|
-
// ## maybe better: don't release space, just use less of it
|
136
|
-
}
|
137
|
-
else { // # delay > shadow->#{delayname}
|
138
|
-
REALLOC_N(ptr, double, len);
|
139
|
-
|
140
|
-
fill = ptr[offset];
|
141
|
-
dst = ptr + offset + len - old_len;
|
142
|
-
src = ptr + offset;
|
143
|
-
memmove(dst, src, (old_len - offset) * sizeof(double));
|
144
|
-
|
145
|
-
for (i = 0; i < len - old_len; i++) {
|
146
|
-
ptr[offset + i] = fill;
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
shadow->#{bufname}.ptr = ptr;
|
151
|
-
shadow->#{bufname}.len = len;
|
152
|
-
shadow->#{offsetname} = offset;
|
153
|
-
shadow->#{delayname} = delay;
|
110
|
+
buffer_resize(&shadow->#{bufname}, len);
|
154
111
|
}
|
112
|
+
|
113
|
+
shadow->#{delayname} = delay;
|
114
|
+
ptr = shadow->#{bufname}.ptr;
|
115
|
+
offset = shadow->#{bufname}.offset;
|
155
116
|
}
|
156
117
|
|
157
|
-
offset = (offset + 4) % len;
|
158
|
-
shadow->#{offsetname} = offset;
|
159
|
-
|
160
118
|
var->value_0 = ptr[offset];
|
161
119
|
var->value_1 = ptr[offset + 1];
|
162
120
|
var->value_2 = ptr[offset + 2];
|
@@ -173,7 +131,7 @@ module RedShift; class DelayFlow
|
|
173
131
|
case 3:
|
174
132
|
ptr = shadow->#{bufname}.ptr;
|
175
133
|
len = shadow->#{bufname}.len;
|
176
|
-
offset = shadow->#{
|
134
|
+
offset = shadow->#{bufname}.offset;
|
177
135
|
|
178
136
|
#{flow.translate(self, "ptr[offset+1]", 1, cl).join("
|
179
137
|
")};
|
@@ -182,7 +140,9 @@ module RedShift; class DelayFlow
|
|
182
140
|
#{flow.translate(self, "ptr[offset+3]", 3, cl).join("
|
183
141
|
")};
|
184
142
|
|
185
|
-
|
143
|
+
offset = (offset + 4) % len;
|
144
|
+
var->value_0 = ptr[offset];
|
145
|
+
shadow->#{bufname}.offset = offset;
|
186
146
|
break;
|
187
147
|
|
188
148
|
default:
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# Manages interface to external animation process.
|
2
|
+
# Depends on:
|
3
|
+
# gem install tkar
|
4
|
+
# See also:
|
5
|
+
# http://tkar.rubyforge.org
|
6
|
+
class TkarDriver
|
7
|
+
# +dragger+ is a callable object that takes (id, x, y) and should
|
8
|
+
# move object id to (x,y)
|
9
|
+
def initialize dragger
|
10
|
+
@dragger = dragger
|
11
|
+
cmd =
|
12
|
+
case RUBY_PLATFORM
|
13
|
+
when /mswin/
|
14
|
+
"tkar --radians 2>nul"
|
15
|
+
else
|
16
|
+
# Use setsid so that ^C doesn't kill it
|
17
|
+
"setsid tkar --radians 2>/dev/null"
|
18
|
+
end
|
19
|
+
|
20
|
+
@pipe = IO.popen(cmd, "w+")
|
21
|
+
yield @pipe if block_given?
|
22
|
+
|
23
|
+
@buf = 0
|
24
|
+
update
|
25
|
+
end
|
26
|
+
|
27
|
+
# never let the simulation get more than this many steps ahead
|
28
|
+
MAX_LAG = 10
|
29
|
+
|
30
|
+
# let the visualization lag by this many steps, or more
|
31
|
+
MIN_LAG = 5
|
32
|
+
|
33
|
+
def close
|
34
|
+
if @pipe
|
35
|
+
@pipe.close
|
36
|
+
@pipe = nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def closed?
|
41
|
+
return true if not @pipe or @pipe.closed?
|
42
|
+
|
43
|
+
begin
|
44
|
+
@pipe.puts " " # no-op
|
45
|
+
@pipe.flush
|
46
|
+
rescue Errno::EPIPE
|
47
|
+
close
|
48
|
+
true
|
49
|
+
else
|
50
|
+
@pipe.closed?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# :yields: pipe
|
55
|
+
def update
|
56
|
+
return unless @pipe
|
57
|
+
|
58
|
+
yield @pipe if block_given?
|
59
|
+
|
60
|
+
@pipe.puts "update"
|
61
|
+
@pipe.flush
|
62
|
+
@buf += 1
|
63
|
+
if @buf > MAX_LAG
|
64
|
+
catch_up_within MIN_LAG
|
65
|
+
end
|
66
|
+
rescue Errno::EPIPE
|
67
|
+
close
|
68
|
+
end
|
69
|
+
|
70
|
+
def catch_up_within steps
|
71
|
+
return unless @pipe
|
72
|
+
|
73
|
+
while @buf > steps || (steps==0 && select([@pipe],[],[],0))
|
74
|
+
## alternately: if steps==0, send "echo ..." and wait for ...
|
75
|
+
case line=@pipe.gets
|
76
|
+
when nil
|
77
|
+
close
|
78
|
+
return
|
79
|
+
when /^update$/
|
80
|
+
@buf -= 1
|
81
|
+
when /^drag (\S+) (\S+) (\S+)/
|
82
|
+
drag_parms = $1.to_i, $2.to_f, $3.to_f
|
83
|
+
when /^drop/
|
84
|
+
@dragger[*drag_parms] if @dragger
|
85
|
+
## TODO: handle dropping on another object
|
86
|
+
else
|
87
|
+
puts "tkar: #{line}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
rescue Errno::EPIPE
|
91
|
+
close
|
92
|
+
end
|
93
|
+
end
|
data/lib/redshift/world.rb
CHANGED
data/rakefile
CHANGED
data/test/test_delay.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redshift
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 57
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 17
|
10
|
+
version: 1.3.17
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joel VanderWerf
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-13 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -40,12 +40,12 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 27
|
44
44
|
segments:
|
45
45
|
- 3
|
46
46
|
- 4
|
47
|
-
-
|
48
|
-
version: 3.4.
|
47
|
+
- 6
|
48
|
+
version: 3.4.6
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
51
|
description: |
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- examples/reset-with-event-val.rb
|
97
97
|
- examples/scheduler.rb
|
98
98
|
- examples/set-dest.rb
|
99
|
+
- examples/shell.rb
|
99
100
|
- examples/simulink/README
|
100
101
|
- examples/simulink/delay.mdl
|
101
102
|
- examples/simulink/derivative.mdl
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- lib/redshift.rb
|
111
112
|
- lib/redshift/component.rb
|
112
113
|
- lib/redshift/meta.rb
|
114
|
+
- lib/redshift/mixins/irb-shell.rb
|
113
115
|
- lib/redshift/mixins/zeno-debugger.rb
|
114
116
|
- lib/redshift/port.rb
|
115
117
|
- lib/redshift/queue.rb
|
@@ -136,6 +138,7 @@ files:
|
|
136
138
|
- lib/redshift/util/plot.rb
|
137
139
|
- lib/redshift/util/random.rb
|
138
140
|
- lib/redshift/util/superhash.rb
|
141
|
+
- lib/redshift/util/tkar-driver.rb
|
139
142
|
- lib/redshift/util/tracer.rb
|
140
143
|
- lib/redshift/util/tracer/trace.rb
|
141
144
|
- lib/redshift/util/tracer/var.rb
|