Skip to content

Commit e659f7d

Browse files
authored
Merge pull request #29 from JuliaRobotics/feat/3Q20/edgeweight
single edge with penwidth
2 parents 0bc5369 + 4e31797 commit e659f7d

File tree

3 files changed

+52
-30
lines changed

3 files changed

+52
-30
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name = "FunctionalStateMachine"
22
uuid = "3e9e306e-7e3c-11e9-12d2-8f8f67a2f951"
33
keywords = ["state machine"]
44
desc = "Functional state machine with stepping and visualization tools."
5-
version = "0.2.3"
5+
version = "0.2.4"
66

77
[deps]
88
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"

README.md

+28-24
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,34 @@ hist = statemachine.history
8989
drawStateMachineHistory(hist, show=true)
9090
```
9191

92+
Multiple state machines can be visualized together
93+
```julia
94+
using Graphs, FunctionalStateMachine
95+
96+
#...
97+
98+
# start multiple concurrent FSMs (this is only one)
99+
## they are likely interdependent
100+
statemachine = StateMachine{Nothing}(next=foo!)
101+
while statemachine(nothing, recordhistory=true); end
102+
103+
# add all histories to the `hists::Dict` as follows
104+
## ths example has userdata of type ::Nothing
105+
hists = Dict{Symbol,Vector{Tuple{DateTime,Int,Function,Nothing}}}(:first => statemachine.history)
106+
107+
# generate all the images that will make up the video
108+
animateStateMachineHistoryIntervalCompound(hists, interval=1)
109+
110+
# and convert images to video with ffmpeg as shell command
111+
fps = 5
112+
run(`ffmpeg -r 10 -i /tmp/caesar/csmCompound/csm_%d.png -c:v libtheora -vf fps=$fps -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -q 10 /tmp/caesar/csmCompound/out.ogv`)
113+
@async run(`totem /tmp/caesar/csmCompound/out.ogv`)
114+
```
115+
can combine multiple concurrent histories of the state machine execution into the same image frames. See function for more details.
116+
117+
118+
# Lower Level Visualization tools
119+
92120
## Animate Asyncronous State Machine Transitions
93121

94122
The following example function shows several state machines that were run asyncronously can be synchronously animated as separate frames (see below for single frame with multiple information):
@@ -149,30 +177,6 @@ A closely related function
149177
animateStateMachineHistoryByTime
150178
```
151179

152-
Multiple state machines can be visualized together
153-
```julia
154-
using Graphs, FunctionalStateMachine
155-
156-
#...
157-
158-
# start multiple concurrent FSMs (this is only one)
159-
## they are likely interdependent
160-
statemachine = StateMachine{Nothing}(next=foo!)
161-
while statemachine(nothing, recordhistory=true); end
162-
163-
# add all histories to the `hists::Dict` as follows
164-
## ths example has userdata of type ::Nothing
165-
hists = Dict{Symbol,Vector{Tuple{DateTime,Int,Function,Nothing}}}(:first => statemachine.history)
166-
167-
# generate all the images that will make up the video
168-
animateStateMachineHistoryIntervalCompound(hists, interval=1)
169-
170-
# and convert images to video with ffmpeg as shell command
171-
fps = 5
172-
run(`ffmpeg -r 10 -i /tmp/caesar/csmCompound/csm_%d.png -c:v libtheora -vf fps=$fps -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -q 10 /tmp/caesar/csmCompound/out.ogv`)
173-
@async run(`totem /tmp/caesar/csmCompound/out.ogv`)
174-
```
175-
can combine multiple concurrent histories of the state machine execution into the same image frames. See function for more details.
176180

177181
# Contribute
178182

src/StateMachineAnimation.jl

+23-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export
88
animateStateMachineHistoryByTimeCompound,
99
animateStateMachineHistoryIntervalCompound
1010

11+
import Graphs: incdict
12+
incdict(::Type{V}, ::Type{E}; is_directed::Bool = true) where {V,E} = incdict(Dict{Int,V}(), E{V}; is_directed=is_directed)
1113

1214
"""
1315
$SIGNATURES
@@ -18,9 +20,9 @@ according to the contents of parameters passed in.
1820
Notes:
1921
- Current implementation repeats duplicate transitions as new edges.
2022
"""
21-
function histGraphStateMachineTransitions(stateVisits, allStates::Vector{Symbol})
23+
function histGraphStateMachineTransitions(stateVisits, allStates::Vector{Symbol};maxpenwidth::Int=5)
2224

23-
g = Graphs.incdict(Graphs.ExVertex,is_directed=true)
25+
g = Graphs.incdict(Graphs.ExVertex,Graphs.ExEdge,is_directed=true)
2426
lookup = Dict{Symbol, Int}()
2527

2628
# add all required states as nodes to the visualization graph
@@ -41,9 +43,25 @@ function histGraphStateMachineTransitions(stateVisits, allStates::Vector{Symbol}
4143
count += 1
4244
exvf = g.vertices[lookup[from]]
4345
exvt = g.vertices[lookup[to]]
44-
# add the edge fom one to the next state
45-
edge = Graphs.make_edge(g, exvf, exvt)
46-
Graphs.add_edge!(g, edge)
46+
# add the edge from one to the next state
47+
# TODO, don't add if already there.
48+
addedge = true
49+
for oun in Graphs.out_neighbors(exvf, g)
50+
if oun.index == exvt.index
51+
addedge = false
52+
# increase penwidth+=1 on that edge
53+
for ed in Graphs.out_edges(exvf, g)
54+
haskey(ed.attributes, "penwidth") ? nothing : (ed.attributes["penwidth"] = 1)
55+
ed.attributes["penwidth"] += 1
56+
ed.attributes["penwidth"] = minimum([maxpenwidth;ed.attributes["penwidth"]])
57+
end
58+
break
59+
end
60+
end
61+
if addedge
62+
edge = Graphs.make_edge(g, exvf, exvt)
63+
Graphs.add_edge!(g, edge)
64+
end
4765
end
4866
end
4967

0 commit comments

Comments
 (0)