Графика
April 8, 2023
Рисование взвешенного ориентированного графа
Пусть задан взвешенный ориентированный граф
var graph := Dict(
('A',Dict(('B',2),('E',5))),
('C',Dict(('B',7),('D',9))),
('D',Dict(('B',34))),
('E',Dict(('C',12),('B',66)))
);Он представляется как словарь словарей весов дуг.
Изобразим его с помощью модуля GraphWPF и нового графического примитива Arrow.
Вначале создадим словарь точек A B C D E, расположив их по кругу в вершинах правильного n-угольника:
var dPoints := new Dictionary<char,Point>;
var R := 200;
var n := ('A'..'E').Count;
var Phi := 0.0;
for var c := 'A' to 'E' do
begin
dPoints[c] := Window.Center + R * Vect(Cos(Phi),Sin(Phi));
Phi += 2 * Pi/n;
end;Затем нарисуем в этих точках вершины с их метками:
var Radius := 10;
foreach var kv in dPoints do
begin
var p := kv.Value;
Circle(p,Radius);
TextOut(p.x,p.y,kv.Key,Alignment.Center);
end;И наконец собственно нарисуем дуги графа, а в центре каждой дуги укажем её вес:
foreach var k1 in graph.Keys do
foreach var k2 in graph[k1].Keys do
begin
var weight := graph[k1][k2];
var (p1,p2) := (dPoints[k1],dPoints[k2]);
var v := p2 - p1;
var pp1 := p1 + v.Norm * Radius;
var pp2 := p2 - v.Norm * Radius;
Arrow(pp1,pp2);
var cc := p1 + v/2;
var txt := weight.ToString;
var sz := TextSize(txt);
FillRectangle(cc.X - sz.Width/2, cc.Y - sz.Height/2,
sz.Width, sz.Height);
TextOut(cc.x,cc.y,weight,Alignment.Center);
end;В последнем коде следует обратить внимание на несколько вещей:
foreach var k1 in graph.Keys do foreach var k2 in graph[k1].Keys do
В итоге dPoints[k1] и dPoints[k2] - соответственно - начало и конец дуги
var pp1 := p1 + v.Norm * Radius; var pp2 := p2 - v.Norm * Radius; Arrow(pp1,pp2);
Вес рисуется в центре вектора дуги
p1 + v/2
begin
// Представление взвешенного графа как словаря словарей
//var EmptyDict := new Dictionary<char,integer>;
var graph := Dict(
('A',Dict(('B',2),('E',5))),
//('B',EmptyDict),
('C',Dict(('B',7),('D',9))),
('D',Dict(('B',34))),
('E',Dict(('C',12),('B',66)))
);
var dPoints := new Dictionary<char,Point>;
var R := 200;
var n := ('A'..'E').Count;
var Phi := 0.0;
for var c := 'A' to 'E' do
begin
dPoints[c] := Window.Center + R * Vect(Cos(Phi),Sin(Phi));
Phi += 2 * Pi/n;
end;
Window.Title := 'Рисование ориентированного графа';
var Radius := 10;
foreach var kv in dPoints do
begin
var p := kv.Value;
Circle(p,Radius);
TextOut(p.x,p.y,kv.Key,Alignment.Center);
end;
foreach var k1 in graph.Keys do
foreach var k2 in graph[k1].Keys do
begin
var weight := graph[k1][k2];
var (p1,p2) := (dPoints[k1],dPoints[k2]);
var v := p2 - p1;
var pp1 := p1 + v.Norm * Radius;
var pp2 := p2 - v.Norm * Radius;
Arrow(pp1,pp2);
var cc := p1 + v/2;
var txt := weight.ToString;
var sz := TextSize(txt);
FillRectangle(cc.X - sz.Width/2, cc.Y - sz.Height/2,
sz.Width, sz.Height);
TextOut(cc.x,cc.y,weight,Alignment.Center);
end;
end.