line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Map::Tube::GraphViz; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Pragmas. |
4
|
3
|
|
|
3
|
|
42535
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
129
|
|
5
|
3
|
|
|
3
|
|
19
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
130
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# Modules. |
8
|
3
|
|
|
3
|
|
1876
|
use Class::Utils qw(set_params); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use English; |
10
|
|
|
|
|
|
|
use Error::Pure qw(err); |
11
|
|
|
|
|
|
|
use GraphViz2; |
12
|
|
|
|
|
|
|
use List::MoreUtils qw(none); |
13
|
|
|
|
|
|
|
use Map::Tube::GraphViz::Utils qw(node_color); |
14
|
|
|
|
|
|
|
use Scalar::Util qw(blessed); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# Version. |
17
|
|
|
|
|
|
|
our $VERSION = 0.04; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Constructor. |
20
|
|
|
|
|
|
|
sub new { |
21
|
|
|
|
|
|
|
my ($class, @params) = @_; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Create object. |
24
|
|
|
|
|
|
|
my $self = bless {}, $class; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Edge callback. |
27
|
|
|
|
|
|
|
$self->{'callback_edge'} = sub { |
28
|
|
|
|
|
|
|
my ($self, $from, $to) = @_; |
29
|
|
|
|
|
|
|
$self->{'g'}->add_edge( |
30
|
|
|
|
|
|
|
'from' => $from, |
31
|
|
|
|
|
|
|
'to' => $to, |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
return; |
34
|
|
|
|
|
|
|
}; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# Node callback. |
37
|
|
|
|
|
|
|
$self->{'callback_node'} = \&node_color; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Driver. |
40
|
|
|
|
|
|
|
$self->{'driver'} = 'neato'; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Name of map. |
43
|
|
|
|
|
|
|
$self->{'name'} = undef; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# GraphViz2 object. |
46
|
|
|
|
|
|
|
$self->{'g'} = undef; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Output. |
49
|
|
|
|
|
|
|
$self->{'output'} = 'png'; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Map::Tube object. |
52
|
|
|
|
|
|
|
$self->{'tube'} = undef; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Process params. |
55
|
|
|
|
|
|
|
set_params($self, @params); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# Check Map::Tube object. |
58
|
|
|
|
|
|
|
if (! defined $self->{'tube'}) { |
59
|
|
|
|
|
|
|
err "Parameter 'tube' is required."; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
if (! blessed($self->{'tube'}) |
62
|
|
|
|
|
|
|
|| ! $self->{'tube'}->does('Map::Tube')) { |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
err "Parameter 'tube' must be 'Map::Tube' object."; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# GraphViz2 object. |
68
|
|
|
|
|
|
|
if (defined $self->{'g'}) { |
69
|
|
|
|
|
|
|
if (defined $self->{'name'}) { |
70
|
|
|
|
|
|
|
err "Parameter 'name' cannot be used with ". |
71
|
|
|
|
|
|
|
"'g' parameter."; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# Check GraphViz2 object. |
75
|
|
|
|
|
|
|
if (! blessed($self->{'g'}) |
76
|
|
|
|
|
|
|
|| ! $self->{'g'}->isa('GraphViz2')) { |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
err "Parameter 'g' must be 'GraphViz2' object."; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
} else { |
81
|
|
|
|
|
|
|
my $name = $self->{'name'}; |
82
|
|
|
|
|
|
|
if (! defined $name) { |
83
|
|
|
|
|
|
|
$name = $self->{'tube'}->name; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
$self->{'g'} = GraphViz2->new( |
86
|
|
|
|
|
|
|
'global' => { |
87
|
|
|
|
|
|
|
'directed' => 0, |
88
|
|
|
|
|
|
|
}, |
89
|
|
|
|
|
|
|
$name ? ( |
90
|
|
|
|
|
|
|
'graph' => { |
91
|
|
|
|
|
|
|
'label' => $name, |
92
|
|
|
|
|
|
|
'labelloc' => 'top', |
93
|
|
|
|
|
|
|
}, |
94
|
|
|
|
|
|
|
) : (), |
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# Check output format. |
99
|
|
|
|
|
|
|
if (! defined $self->{'output'}) { |
100
|
|
|
|
|
|
|
err "Parameter 'output' is required."; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
if (none { $self->{'output'} eq $_ } |
103
|
|
|
|
|
|
|
keys %{$self->{'g'}->valid_attributes->{'output_format'}}) { |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
err "Unsupported 'output' parameter '$self->{'output'}'."; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Object. |
109
|
|
|
|
|
|
|
return $self; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# Get graph. |
113
|
|
|
|
|
|
|
sub graph { |
114
|
|
|
|
|
|
|
my ($self, $output_file) = @_; |
115
|
|
|
|
|
|
|
foreach my $node (values %{$self->{'tube'}->nodes}) { |
116
|
|
|
|
|
|
|
$self->{'callback_node'}->($self, $node); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
my @processed; |
119
|
|
|
|
|
|
|
foreach my $node (values %{$self->{'tube'}->nodes}) { |
120
|
|
|
|
|
|
|
foreach my $link (split m/,/ms, $node->link) { |
121
|
|
|
|
|
|
|
if (none { |
122
|
|
|
|
|
|
|
($_->[0] eq $node->id && $_->[1] eq $link) |
123
|
|
|
|
|
|
|
|| |
124
|
|
|
|
|
|
|
($_->[0] eq $link && $_->[1] eq $node->id) |
125
|
|
|
|
|
|
|
} @processed) { |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
$self->{'callback_edge'}->($self, $node->id, |
128
|
|
|
|
|
|
|
$link); |
129
|
|
|
|
|
|
|
push @processed, [$node->id, $link]; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
eval { |
134
|
|
|
|
|
|
|
$self->{'g'}->run( |
135
|
|
|
|
|
|
|
'driver' => $self->{'driver'}, |
136
|
|
|
|
|
|
|
'format' => $self->{'output'}, |
137
|
|
|
|
|
|
|
'output_file' => $output_file, |
138
|
|
|
|
|
|
|
); |
139
|
|
|
|
|
|
|
}; |
140
|
|
|
|
|
|
|
if ($EVAL_ERROR) { |
141
|
|
|
|
|
|
|
err 'Cannot create GraphViz output.', |
142
|
|
|
|
|
|
|
'Error', $EVAL_ERROR, |
143
|
|
|
|
|
|
|
'Dot input', $self->{'g'}->dot_input; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
return; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
1; |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
__END__ |