diff options
| author | Tim Dwyer <tgdwyer@gmail.com> | 2006-02-13 02:00:14 +0000 |
|---|---|---|
| committer | tgdwyer <tgdwyer@users.sourceforge.net> | 2006-02-13 02:00:14 +0000 |
| commit | 19a528cb8e524239aaeea16df87558ca4be4cced (patch) | |
| tree | b6fea2f930a3f6c9b78ac8bfc74a27fb50e24f46 /src/graphlayout | |
| parent | optimization: do not notify any listeners if attributes' new value is the sam... (diff) | |
| download | inkscape-19a528cb8e524239aaeea16df87558ca4be4cced.tar.gz inkscape-19a528cb8e524239aaeea16df87558ca4be4cced.zip | |
Added connector graph layout functionality
(bzr r122)
Diffstat (limited to '')
| -rw-r--r-- | src/graphlayout/Makefile_insert | 10 | ||||
| -rw-r--r-- | src/graphlayout/graphlayout.cpp | 147 | ||||
| -rw-r--r-- | src/graphlayout/graphlayout.h | 17 | ||||
| -rw-r--r-- | src/graphlayout/makefile | 17 |
4 files changed, 191 insertions, 0 deletions
diff --git a/src/graphlayout/Makefile_insert b/src/graphlayout/Makefile_insert new file mode 100644 index 000000000..fc490743d --- /dev/null +++ b/src/graphlayout/Makefile_insert @@ -0,0 +1,10 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +graphlayout/all: graphlayout/libgraphlayout.a + +graphlayout/clean: + rm -f graphlayout/libgraphlayout.a $(graphlayout_libgraphlayout_a_OBJECTS) + +graphlayout_libgraphlayout_a_SOURCES = \ + graphlayout/graphlayout.cpp \ + graphlayout/graphlayout.h diff --git a/src/graphlayout/graphlayout.cpp b/src/graphlayout/graphlayout.cpp new file mode 100644 index 000000000..9828e22fe --- /dev/null +++ b/src/graphlayout/graphlayout.cpp @@ -0,0 +1,147 @@ +/** \file + * Interface between Inkscape code (SPItem) and graphlayout functions. + */ +/* +* Authors: +* Tim Dwyer <tgdwyer@gmail.com> +* +* Copyright (C) 2005 Authors +* +* Released under GNU GPL. Read the file 'COPYING' for more information. +*/ +#include "graphlayout/graphlayout.h" +#include <iostream> +#include <config.h> + +#ifdef HAVE_BOOST_GRAPH_LIB +#include "sp-item.h" +#include "sp-item-transform.h" +#include "sp-conn-end-pair.h" +#include "conn-avoid-ref.h" +#include "libavoid/connector.h" +#include <boost/graph/kamada_kawai_spring_layout.hpp> +#include <boost/graph/circle_layout.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/simple_point.hpp> +#include <boost/graph/graphviz.hpp> +#include <map> +#include <vector> +#include <algorithm> +#include <float.h> +#include <string.h> + +using namespace boost; +// create a typedef for the Graph type +typedef adjacency_list<vecS, vecS, undirectedS, no_property, + property<edge_weight_t, double> > Graph; +typedef property_map<Graph, edge_weight_t>::type WeightMap; +typedef graph_traits<Graph>::vertex_descriptor Vertex; +typedef std::vector<simple_point<double> > PositionVec; +typedef iterator_property_map<PositionVec::iterator, property_map<Graph, vertex_index_t>::type> PositionMap; +#endif // HAVE_BOOST_GRAPH_LIB + +/** +* Takes a list of inkscape items, extracts the graph defined by +* connectors between them, and uses graph layout techniques to find +* a nice layout +*/ +void graphlayout(GSList const *const items) { + if(!items) { + return; + } +#ifdef HAVE_BOOST_GRAPH_LIB + + + using Inkscape::Util::GSListConstIterator; + std::list<SPItem *> selected; + selected.insert<GSListConstIterator<SPItem *> >(selected.end(), items, NULL); + if (selected.empty()) return; + int n=selected.size(); + + //Check 2 or more selected objects + if (n < 2) return; + + Graph g; + + std::cout<<"Building graph with "<<n<<" nodes"<<std::endl; + double minX=DBL_MAX, minY=DBL_MAX, maxX=-DBL_MAX, maxY=-DBL_MAX; + + std::map<std::string,Vertex> nodelookup; + for (std::list<SPItem *>::iterator it(selected.begin()); + it != selected.end(); + ++it) + { + SPItem *u=*it; + std::cout<<"id:"<<u->id<<std::endl; + if(strncmp(u->id,"path",4)) { + nodelookup[u->id]=add_vertex(g); + } + } + WeightMap weightmap=get(edge_weight, g); + std::cout<<"Added vertices: Graph has |V|="<<num_vertices(g)<<std::endl; + + NR::Point const gap(0, 0); + int i=0; + for (std::list<SPItem *>::iterator it(selected.begin()); + it != selected.end(); + ++it) + { + using NR::X; using NR::Y; + SPItem *itu=*it; + Vertex u=nodelookup[itu->id]; + GSList *nlist=itu->avoidRef->getAttachedConnectors(Avoid::ConnRef::runningFrom); + std::list<SPItem *> neighbours; + neighbours.insert<GSListConstIterator<SPItem *> >(neighbours.end(),nlist,NULL); + std::cout<<" Node "<<itu->id<<" has "<<neighbours.size()<<" neighbours"<<std::endl; + for (std::list<SPItem *>::iterator ne(neighbours.begin()); + ne != neighbours.end(); + ++ne) { + + SPItem *itv=*ne; + std::cout<<"neighbour: "<<itv->id<<std::endl; + Vertex v=nodelookup[itv->id]; + std::cout<<" Neighbour: "<<v; + Graph::edge_descriptor e; bool inserted; + tie(e, inserted)=add_edge(u,v,g); + weightmap[e]=1.0; + } + if(nlist) { + g_slist_free(nlist); + } + NR::Rect const item_box(sp_item_bbox_desktop(*it)); + + NR::Point ll(item_box.min()); + minX=std::min(ll[0],minX); + minY=std::min(ll[1],minY); + NR::Point ur(item_box.max()); + maxX=std::max(ur[0],maxX); + maxY=std::max(ur[1],maxY); + } + double width=maxX-minX; + double height=maxY-minY; + std::cout<<"Graph has |V|="<<num_vertices(g)<<" Width="<<width<<" Height="<<height<<std::endl; + PositionVec position_vec(num_vertices(g)); + PositionMap position(position_vec.begin(), get(vertex_index, g)); + write_graphviz(std::cout, g); + circle_graph_layout(g, position, width/2.0); + kamada_kawai_spring_layout(g, position, weightmap, side_length(width)); + + graph_traits<Graph>::vertex_iterator vi, vi_end; + i=0; + for (std::list<SPItem *>::iterator it(selected.begin()); + it != selected.end(); + ++it) + { + SPItem *u=*it; + if(strncmp(u->id,"path",4)) { + NR::Rect const item_box(sp_item_bbox_desktop(u)); + NR::Point const curr(item_box.midpoint()); + NR::Point const dest(minX+width/2.0+position[nodelookup[u->id]].x, + minY+height/2.0+position[nodelookup[u->id]].y); + sp_item_move_rel(u, NR::translate(dest - curr)); + } + } +#else + std::cout<<"Connector network layout not available! Install boost graph library and recompile to enable."<<std::endl; +#endif // HAVE_BOOST_GRAPH_LIB +} diff --git a/src/graphlayout/graphlayout.h b/src/graphlayout/graphlayout.h new file mode 100644 index 000000000..e37f4c4fa --- /dev/null +++ b/src/graphlayout/graphlayout.h @@ -0,0 +1,17 @@ +/** + * \brief graph layout functions + * + * Authors: + * Tim Dwyer <tgdwyer@gmail.com> + * + * Copyright (C) 2005 Authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef SEEN_GRAPHLAYOUT_H +#define SEEN_GRAPHLAYOUT_H +#include "util/glib-list-iterators.h" + +void graphlayout(GSList const *const items); +#endif // SEEN_GRAPHLAYOUT_H diff --git a/src/graphlayout/makefile b/src/graphlayout/makefile new file mode 100644 index 000000000..5d8ac906e --- /dev/null +++ b/src/graphlayout/makefile @@ -0,0 +1,17 @@ +# Convenience stub makefile to call the real Makefile. + + + +# Explicit so that it's the default rule. +all: + cd .. && $(MAKE) graphlayout/all + +clean %.a %.o: + cd .. && $(MAKE) graphlayout/$@ + +.PHONY: all clean + +OBJEXT = o + +.SUFFIXES: +.SUFFIXES: .a .$(OBJEXT) |
