/** @file * @brief Interface between Inkscape code (SPItem) and graphlayout functions. */ /* * Authors: * Tim Dwyer * * Copyright (C) 2005 Authors * * Released under GNU GPL. Read the file 'COPYING' for more information. */ #include #include #include #include #include #include #include #include #include "desktop.h" #include "inkscape.h" #include "sp-namedview.h" #include "util/glib-list-iterators.h" #include "graphlayout/graphlayout.h" #include "sp-path.h" #include "sp-item.h" #include "sp-item-transform.h" #include "sp-conn-end-pair.h" #include "style.h" #include "conn-avoid-ref.h" #include "libavoid/connector.h" #include "libavoid/geomtypes.h" #include "libcola/cola.h" #include "libvpsc/generate-constraints.h" #include "preferences.h" using namespace std; using namespace cola; using namespace vpsc; /** * Returns true if item is a connector */ bool isConnector(SPItem const *const i) { SPPath *path = NULL; if(SP_IS_PATH(i)) { path = SP_PATH(i); } return path && path->connEndPair.isAutoRoutingConn(); } struct CheckProgress : TestConvergence { CheckProgress(double d,unsigned i,list& selected,vector& rs,map& nodelookup) : TestConvergence(d,i), selected(selected), rs(rs), nodelookup(nodelookup) {} bool operator()(double new_stress, double* X, double* Y) { /* This is where, if we wanted to animate the layout, we would need to update * the positions of all objects and redraw the canvas and maybe sleep a bit cout << "stress="<getDouble("/tools/connector/length", 100.0); double directed_edge_height_modifier = 1.0; bool directed = prefs->getBool("/tools/connector/directedlayout"); bool avoid_overlaps = prefs->getBool("/tools/connector/avoidoverlaplayout"); for (list::iterator i(selected.begin()); i != selected.end(); ++i) { SPItem *iu=*i; map::iterator i=nodelookup.find(iu->id); if(i==nodelookup.end()) { continue; } unsigned u=i->second; GSList *nlist=iu->avoidRef->getAttachedConnectors(Avoid::runningFrom); list connectors; connectors.insert >(connectors.end(),nlist,NULL); for (list::iterator j(connectors.begin()); j != connectors.end(); ++j) { SPItem *conn=*j; SPItem *iv; SPItem *items[2]; assert(isConnector(conn)); SP_PATH(conn)->connEndPair.getAttachedItems(items); if(items[0]==iu) { iv=items[1]; } else { iv=items[0]; } if (iv == NULL) { // The connector is not attached to anything at the // other end so we should just ignore it. continue; } // If iv not in nodelookup we again treat the connector // as disconnected and continue map::iterator v_pair=nodelookup.find(iv->id); if(v_pair!=nodelookup.end()) { unsigned v=v_pair->second; //cout << "Edge: (" << u <<","<style->marker[SP_MARKER_LOC_END].set) { if(directed && strcmp(conn->style->marker[SP_MARKER_LOC_END].value,"none")) { scy.push_back(new SimpleConstraint(v, u, (ideal_connector_length * directed_edge_height_modifier))); } } } } if(nlist) { g_slist_free(nlist); } } const unsigned E = es.size(); double eweights[E]; fill(eweights,eweights+E,1); vector cs; connectedComponents(rs,es,scx,scy,cs); for(unsigned i=0;iedges.size()<2) continue; CheckProgress test(0.0001,100,selected,rs,nodelookup); ConstrainedMajorizationLayout alg(c->rects,c->edges,eweights,ideal_connector_length,test); alg.setupConstraints(NULL,NULL,avoid_overlaps, NULL,NULL,&c->scx,&c->scy,NULL,NULL); alg.run(); } separateComponents(cs); for (list::iterator it(selected.begin()); it != selected.end(); ++it) { SPItem *u=*it; if(!isConnector(u)) { map::iterator i=nodelookup.find(u->id); if(i!=nodelookup.end()) { Rectangle* r=rs[i->second]; Geom::OptRect item_box(sp_item_bbox_desktop(u)); if(item_box) { Geom::Point const curr(item_box->midpoint()); Geom::Point const dest(r->getCentreX(),r->getCentreY()); sp_item_move_rel(u, Geom::Translate(dest - curr)); } } } } for(unsigned i=0;i