Я выбрала для решения своей задачи QuickGraph потому что не нашла ему альтернатив, кроме самостоятельной реализации алгоритма.
И я хотела добавить своему решению лоска визуализацией. У QuickGraph есть сборка QuickGraph.Glee Но, судя по всему, ее надо было ставить дополнительно.
А у GraphSharp есть WPF контроллер... и он использует QuickGraph. "Сказка же!" - думаю я: минимум зависимостей, все аккуратненько. С контроллером. Легко и просто...
Но пришлось создавать отдельный пост, потому что просто не получилось.
Все, казалось бы просто. У меня уже есть граф. Я его посчитала и теперь хочу отобразить.
Тем временем, чтобы отобразить граф с помощью Graph# есть два способа.
Простой способ.
Мануал: http://www.youtube.com/watch?v=VTbuvkaPGxE
Встроенный WPF контроллер GraphLayout позволяет привязать к себе IBidirectionalGraph<object, IEdge<object>>. Что и делают в имеющемся мануале.
Но только его.
Нюанс в том, что, например BidirectionalGraph<object, Edge<object>> не может быть преобразован к данному интерфейсу никаким приведением.
В то же время алгоритмы кратчайшего пути из QuickGraph работают именно с графами, а не интерфейсами.
В случае, если нас это не устраивает и хочется чего-то более сложного, мы можем воспользоваться вторым вариантом.
Полный и абсолютно настраиваемый способ.
Мануал: https://sachabarbs.wordpress.com/2010/08/31/pretty-cool-graphs-in-wpf/
Мы описываем с самого начала тип данных вершины, тип данных ребра, тип графа (наследуем от Bidirectional...), свой Layout для отображения (наследуем от встроенного) и далее по тексту.
Это трудоемко, но можно попробовать.
И все было бы хорошо, если бы не процесс заполнения. В исходных данных у меня перечислены ребра и смежные с ними вершины. Одна вершина может упоминаться для разных ребер, а добавить в граф мне ее надо единожды. И либо перерабатывать исходные данные.. либо, просто проверять. И я добавляю новую вершину только в том случае, если вершины с таким значением еще нет.
if (!graph.ContainsVertex(language_from))
graph.AddVertex(language_from);
А это прекрасно работает, только пока для класса реализующего вершины определены интерфейсы и методы сравнения... нюанс в том, что я понятия не имею какие именно этому методу нужны интерфейсы от моего класса вершины.
Мне надо сначала заполнить граф, потом посчитать, потом отобразить.
Заполнение и расчет требуют одних интерфейсов, а отображение другого (вполне конкретного).
Поэтому я не нашла ничего лучше, чем перед отображением копировать граф в новую структуру, приспособленную к GraphLayout:
private void ShowGraph(BidirectionalGraph<object, Edge<object>> graph)
{
var graphForVis = new BidirectionalGraph<object, IEdge<object>>();
foreach(object node in graph.Vertices)
{
graphForVis.AddVertex(node);
}
foreach (Edge<object> edge in graph.Edges)
{
graphForVis.AddEdge(new Edge<object>(edge.Source, edge.Target));
}
//this.LanguageGraphCanvas - мой LayoutGraph контроллер
this.LanguageGraphCanvas.Graph = graphForVis;
}
Буду считать это такой разновидностью контроллера между моделью данных (QuickGraph) и их представлением (Graph#).
Плюсы такого решения:
Ссылки (cобраны из обоих постов в кучку):
1. Визуализация средствами QuickGraph.Glee http://quickgraph.codeplex.com/wikipage?title=Visualization%20Using%20Glee .
2. Домашняя страница и конкретно мануалы по Graph# http://graphsharp.codeplex.com/wikipage?title=Tutorials&referringTitle=Home
3. Пример работы QuickGraph и Graphiz
http://dotnet.wonderu.com/2009/05/blog-post.html
Картинка, Проект. Музычка
И я хотела добавить своему решению лоска визуализацией. У QuickGraph есть сборка QuickGraph.Glee Но, судя по всему, ее надо было ставить дополнительно.
А у GraphSharp есть WPF контроллер... и он использует QuickGraph. "Сказка же!" - думаю я: минимум зависимостей, все аккуратненько. С контроллером. Легко и просто...
Но пришлось создавать отдельный пост, потому что просто не получилось.
Все, казалось бы просто. У меня уже есть граф. Я его посчитала и теперь хочу отобразить.
Тем временем, чтобы отобразить граф с помощью Graph# есть два способа.
Визуализация графа Graph#
Мануал: http://www.youtube.com/watch?v=VTbuvkaPGxE
Встроенный WPF контроллер GraphLayout позволяет привязать к себе IBidirectionalGraph<object, IEdge<object>>. Что и делают в имеющемся мануале.
Но только его.
Нюанс в том, что, например BidirectionalGraph<object, Edge<object>> не может быть преобразован к данному интерфейсу никаким приведением.
В то же время алгоритмы кратчайшего пути из QuickGraph работают именно с графами, а не интерфейсами.
В случае, если нас это не устраивает и хочется чего-то более сложного, мы можем воспользоваться вторым вариантом.
Полный и абсолютно настраиваемый способ.
Мануал: https://sachabarbs.wordpress.com/2010/08/31/pretty-cool-graphs-in-wpf/
Мы описываем с самого начала тип данных вершины, тип данных ребра, тип графа (наследуем от Bidirectional...), свой Layout для отображения (наследуем от встроенного) и далее по тексту.
Это трудоемко, но можно попробовать.
И все было бы хорошо, если бы не процесс заполнения. В исходных данных у меня перечислены ребра и смежные с ними вершины. Одна вершина может упоминаться для разных ребер, а добавить в граф мне ее надо единожды. И либо перерабатывать исходные данные.. либо, просто проверять. И я добавляю новую вершину только в том случае, если вершины с таким значением еще нет.
if (!graph.ContainsVertex(language_from))
graph.AddVertex(language_from);
А это прекрасно работает, только пока для класса реализующего вершины определены интерфейсы и методы сравнения... нюанс в том, что я понятия не имею какие именно этому методу нужны интерфейсы от моего класса вершины.
Визуализация произвольного графа с базовыми типами в Graph#
Не могу гарантировать, что это работает действительно для любого графа. Но мой, к счастью, достаточно прост и никаких граблей на моем пути не попалось.
Мне надо сначала заполнить граф, потом посчитать, потом отобразить.
Заполнение и расчет требуют одних интерфейсов, а отображение другого (вполне конкретного).
Поэтому я не нашла ничего лучше, чем перед отображением копировать граф в новую структуру, приспособленную к GraphLayout:
private void ShowGraph(BidirectionalGraph<object, Edge<object>> graph)
{
var graphForVis = new BidirectionalGraph<object, IEdge<object>>();
foreach(object node in graph.Vertices)
{
graphForVis.AddVertex(node);
}
foreach (Edge<object> edge in graph.Edges)
{
graphForVis.AddEdge(new Edge<object>(edge.Source, edge.Target));
}
//this.LanguageGraphCanvas - мой LayoutGraph контроллер
this.LanguageGraphCanvas.Graph = graphForVis;
}
Буду считать это такой разновидностью контроллера между моделью данных (QuickGraph) и их представлением (Graph#).
Плюсы такого решения:
- Я, в процессе экспериментов, изменила тип графа на Bidirectional. Но могла бы этого и не делать. Как следствие: мне не пришлось ради отображения менять данные и механику работы с ними.
- Минимальное количество дополнительного кода. Описание классов вершины, ребра, графа... - очень объемно и трудоемко, т.е. избыточно, при том что мне никаких особых свойств не надо.
- Так можно отобразить если не любой граф, то достаточное их количество и при этом решить проблему с совместимостью типа графа с мат. методами QuickGraph.
Минусы:
- this.LanguageGraphCanvas.Graph = graphForVis;
Привязка данных к WPF контроллеру из кода скорее моветон, чем норма. Но чтобы привязка была человеческая тип графа должен бы поддерживать INotifyPropertyChanged - как в примере - чтобы отображение привязанного сразу из XAML графа изменилось после заполнения.
Ссылки (cобраны из обоих постов в кучку):
1. Визуализация средствами QuickGraph.Glee http://quickgraph.codeplex.com/wikipage?title=Visualization%20Using%20Glee .
2. Домашняя страница и конкретно мануалы по Graph# http://graphsharp.codeplex.com/wikipage?title=Tutorials&referringTitle=Home
3. Пример работы QuickGraph и Graphiz
http://dotnet.wonderu.com/2009/05/blog-post.html
Картинка, Проект. Музычка

Комментариев нет:
Отправить комментарий