line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Graph::Layouter - lay out graph onto an abstract plane |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=cut |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Graph::Layouter; |
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
784
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
40
|
|
11
|
1
|
|
|
1
|
|
5
|
use Carp qw (croak); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
61
|
|
12
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
15
|
use vars qw ($VERSION @ISA @EXPORT_OK); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
76
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# $Id: Layouter.pm,v 1.3 2006/02/11 17:11:39 pasky Exp $ |
16
|
|
|
|
|
|
|
$VERSION = 0.03; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
my $graph = new Graph; |
22
|
|
|
|
|
|
|
... |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use Graph::Layouter qw(layout); |
25
|
|
|
|
|
|
|
my $layouted = layout($graph); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
use Graph::Layouter; |
28
|
|
|
|
|
|
|
my $layouted = Graph::Layouter->layout($graph); |
29
|
|
|
|
|
|
|
... |
30
|
|
|
|
|
|
|
$layouted->layout(); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=cut |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
35
|
1
|
|
|
1
|
|
6
|
use base qw (Graph); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1190
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
require Exporter; |
38
|
|
|
|
|
|
|
push @ISA, 'Exporter'; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
@EXPORT_OK = qw (layout); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 DESCRIPTION |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
This module provides an abstract class for various algorithms of graph nodes |
46
|
|
|
|
|
|
|
positioning at a virtual surface. That is, if you have a graph stuffed into a |
47
|
|
|
|
|
|
|
C object, C will take it and assign each node in the |
48
|
|
|
|
|
|
|
graph virtual coordinates in a plane. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
C does not do anything besides assigning the coordinates --- |
51
|
|
|
|
|
|
|
you will need to have the nodes and edges laid out to some real plane on your |
52
|
|
|
|
|
|
|
own, or use a bundled C modules family. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
This module contains only the abstract class, you will probably want to get an |
55
|
|
|
|
|
|
|
instance of some particular layouting algorithm instead; |
56
|
|
|
|
|
|
|
C is bundled with this distribution. The general |
57
|
|
|
|
|
|
|
interface for all the subclasses is described below, but be sure consult also |
58
|
|
|
|
|
|
|
the particular class' documentation for remarks, special notes and specific |
59
|
|
|
|
|
|
|
extensions. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 Interface |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=over 4 |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=cut |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
1
|
|
|
1
|
|
183509
|
use Graph; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
429
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=item B |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
This subroutine is the only entry point of this module, taking a given graph |
75
|
|
|
|
|
|
|
and laying it out appropriately. The subroutine can be called in several ways: |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=over 4 |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=item I |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The subroutine can be called as a function (it is not automatically exported, |
82
|
|
|
|
|
|
|
but you can import it on your own if you really want; see the synopsis above). |
83
|
|
|
|
|
|
|
It takes one parameter, the C class (or any descendant) instance. It |
84
|
|
|
|
|
|
|
will set the layout back into the graph and return its parameter back for |
85
|
|
|
|
|
|
|
convenience. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=item I |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
The subroutine can be called as a class constructor, like C<$g = |
90
|
|
|
|
|
|
|
Graph::Layouter->layout($graph)>. It will take the C<$graph>, do stuff on it |
91
|
|
|
|
|
|
|
and returns reference to C<$graph> back, however reblessed to a |
92
|
|
|
|
|
|
|
C instance. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
In human language this means that after the call C<$graph> will still be the |
95
|
|
|
|
|
|
|
original object, only with some more attributes attached, whereas C<$g> will be |
96
|
|
|
|
|
|
|
a C instance; however any changes to C<$g> will be propagated |
97
|
|
|
|
|
|
|
to C<$graph> and vice versa. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item I |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
When you already got a C instance, you can call this |
102
|
|
|
|
|
|
|
subroutine as C<$g->layout()>. It will relayout an already layouted graph. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=back |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=cut |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub layout { |
109
|
0
|
|
|
0
|
1
|
|
my $graph = shift; |
110
|
|
|
|
|
|
|
|
111
|
0
|
|
|
|
|
|
croak "You want to use some subclass instead!"; |
112
|
0
|
|
|
|
|
|
$graph; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Make sure the appropriate attributes are set up on all the nodes. |
117
|
|
|
|
|
|
|
# |
118
|
|
|
|
|
|
|
# This is a private device for subclasses, which are expected to call this in |
119
|
|
|
|
|
|
|
# layout, when they are just about to start doing the work. Note that some |
120
|
|
|
|
|
|
|
# subclasses might want to set the attributes to a different initial value or |
121
|
|
|
|
|
|
|
# so. |
122
|
|
|
|
|
|
|
sub _layout_prepare($) { |
123
|
0
|
|
|
0
|
|
|
my $graph = shift; |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
foreach my $vertex ($graph->vertices) { |
126
|
0
|
|
|
|
|
|
$graph->set_vertex_attribute($vertex, 'layout_pos1', 0); |
127
|
0
|
|
|
|
|
|
$graph->set_vertex_attribute($vertex, 'layout_pos2', 0); |
128
|
0
|
|
|
|
|
|
$graph->set_vertex_attribute($vertex, 'layout_force1', 0); |
129
|
0
|
|
|
|
|
|
$graph->set_vertex_attribute($vertex, 'layout_force2', 0); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
|
$graph; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Calculate the bounding coordinate values (min/max extremes in a given |
136
|
|
|
|
|
|
|
# dimension) and store them into global graph attributes. |
137
|
|
|
|
|
|
|
# |
138
|
|
|
|
|
|
|
# This is a private device for subclasses, which are expected to call this in |
139
|
|
|
|
|
|
|
# layout, when they are already done with the work. |
140
|
|
|
|
|
|
|
sub _layout_calc_bounds($) { |
141
|
0
|
|
|
0
|
|
|
my $graph = shift; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Make sure Perl does not emit a metric ton of warnings blab when |
144
|
|
|
|
|
|
|
# counting with infinity numbers. Blah. |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
local $^W = 0; |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
my ($minx, $maxx, $miny, $maxy) = ('Infinity', -'Infinity', 'Infinity', -'Infinity'); |
149
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
foreach my $vertex ($graph->vertices) { |
151
|
0
|
|
|
|
|
|
my @pos = ($graph->get_vertex_attribute($vertex, 'layout_pos1'), |
152
|
|
|
|
|
|
|
$graph->get_vertex_attribute($vertex, 'layout_pos2')); |
153
|
0
|
0
|
|
|
|
|
$maxx = $pos[0] if $pos[0] > $maxx; |
154
|
0
|
0
|
|
|
|
|
$minx = $pos[0] if $pos[0] < $minx; |
155
|
0
|
0
|
|
|
|
|
$maxy = $pos[1] if $pos[1] > $maxy; |
156
|
0
|
0
|
|
|
|
|
$miny = $pos[1] if $pos[1] < $miny; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
$graph->set_graph_attribute('layout_min1', $minx); |
160
|
0
|
|
|
|
|
|
$graph->set_graph_attribute('layout_max1', $maxx); |
161
|
0
|
|
|
|
|
|
$graph->set_graph_attribute('layout_min2', $miny); |
162
|
0
|
|
|
|
|
|
$graph->set_graph_attribute('layout_max2', $maxy); |
163
|
0
|
|
|
|
|
|
$graph; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=back |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head2 Data encoding |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
The layouting function saves the layout data (coordinates of nodes) back to the |
172
|
|
|
|
|
|
|
C object, in a form of vertex attributes - C and |
173
|
|
|
|
|
|
|
C (C is the x dimension, C the y dimension; it is |
174
|
|
|
|
|
|
|
planned to make it possible to layout in three or unlimited number of |
175
|
|
|
|
|
|
|
dimensions space). |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
We also provide C, C as well as C, |
178
|
|
|
|
|
|
|
C global graph attributes, containing the extreme values in the |
179
|
|
|
|
|
|
|
respective dimensions. This is usually needed to properly map the virtual |
180
|
|
|
|
|
|
|
coordinates to some physical points. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
If you intend to use C attributes in conjunction with the |
183
|
|
|
|
|
|
|
C, you are advised not to infrige the C namespace. If |
184
|
|
|
|
|
|
|
you are writing a C subclass, you are advised to put your |
185
|
|
|
|
|
|
|
attributes to a C namespace. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head1 SEE ALSO |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
C, C |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head1 BUGS |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Some more universal layout calling interface (hash parameters) is missing. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=head1 COPYRIGHT |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Copyright 2004 by Petr Baudis Epasky@ucw.czE. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
This code is distributed under the same copyright terms as |
203
|
|
|
|
|
|
|
Perl itself. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head1 VERSION |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Version 0.03 |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
$Id: Layouter.pm,v 1.3 2006/02/11 17:11:39 pasky Exp $ |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=cut |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
1; |