Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
makefeasible.cpp
Go to the documentation of this file.
1/*
2 * vim: ts=4 sw=4 et tw=0 wm=0
3 *
4 * libcola - A library providing force-directed network layout using the
5 * stress-majorization method subject to separation constraints.
6 *
7 * Copyright (C) 2006-2008 Monash University
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library in the file LICENSE; if not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307 USA
23 *
24*/
25
26#include <iostream>
27#include <vector>
28#include <cmath>
29#include <time.h>
30#include <valarray>
31#include <fstream>
32#include <sstream>
33
34#include <libavoid/libavoid.h>
35#include <libavoid/router.h>
36
37#include "graphlayouttest.h"
38
39using namespace std;
40using namespace cola;
41using namespace vpsc;
42
43/*
44// |V|=12, |E|=23
45static const unsigned DAGDEPTH = 3;
46static const unsigned BRANCHFACTOR = 3;
47static const double EXTRAEDGEPROB = 0.5;
48*/
49/*
50// |V|=26, |E|=61
51static const unsigned DAGDEPTH = 3;
52static const unsigned BRANCHFACTOR = 4;
53static const double EXTRAEDGEPROB = 0.1;
54*/
55
56/*
57// |V|=62, |E|=85
58static const unsigned DAGDEPTH = 4;
59static const unsigned BRANCHFACTOR = 4;
60static const double EXTRAEDGEPROB = 0.01;
61*/
62/*
63// |V|=131, |E|=166
64static const unsigned DAGDEPTH = 5;
65static const unsigned BRANCHFACTOR = 4;
66static const double EXTRAEDGEPROB = 0.005;
67*/
68
69static const unsigned DAGDEPTH = 6;
70static const unsigned BRANCHFACTOR = 4;
71static const double EXTRAEDGEPROB = 0.002;
72/*
73// |V|=343, |E|=487
74seed=1208390913;
75static const unsigned DAGDEPTH = 6;
76static const unsigned BRANCHFACTOR = 4;
77static const double EXTRAEDGEPROB = 0.002;
78*/
79
80void makeEdge(unsigned u, unsigned v,
81 vector<Edge> &edges, CompoundConstraints &ccs) {
82 edges.push_back(make_pair(u,v));
83 ccs.push_back(new SeparationConstraint(vpsc::YDIM, u,v,5));
84}
85vector<Edge> random_dag(unsigned depth, unsigned maxbranch, unsigned &V,
87 printf("DAG depth=%d\nmaxbranch=%d\nextraedgeprob%f\n",depth,maxbranch,EXTRAEDGEPROB);
88 vector<Edge> edges;
89 unsigned lstart=0, lend=1;
90 V=0;
91 for(unsigned i=0;i<depth;i++) {
92 for(unsigned j=lstart;j<lend;j++) {
93 //makeEdge(j,++V,edges,cy);
94 //makeEdge(j,++V,edges,cy);
95 for(unsigned k=0;k<maxbranch;k++) {
96 double r=(double)rand()/(double)RAND_MAX;
97 if(r < 0.5) {
98 makeEdge(j,++V,edges,ccs);
99 }
100 }
101 }
102 lstart=lend;
103 lend=V+1;
104 }
105 V++;
106 /*
107 DFS::Graph dfs(V,edges);
108 for(unsigned i=1;i<dfs.order.size();i++) {
109 cx.push_back(
110 new SeparationConstraint(dfs.order[i-1],dfs.order[i],0.5));
111 }
112 */
113 for(unsigned i=0;i<V;++i) {
114 for(unsigned j=i+1;j<V;++j) {
115 double r=(double)rand()/(double)RAND_MAX;
116 if(r < EXTRAEDGEPROB) {
117 makeEdge(i,j,edges,ccs);
118 }
119 }
120 }
121 /*
122 for(unsigned i=0;i<dfs.leaves.size();i++) {
123 for(unsigned j=1;j<dfs.leaves[i].size();j++) {
124 cx.push_back( new SeparationConstraint(dfs.leaves[i][j-1],dfs.leaves[i][j],10));
125 }
126 }
127 */
128 return edges;
129}
130void removeoverlaps(vpsc::Rectangles &rs, bool bothaxes) {
131 double xBorder=0, yBorder=0;
132 static const double EXTRA_GAP=1e-5;
133 unsigned n=rs.size();
134 try {
135 // The extra gap avoids numerical imprecision problems
136 Rectangle::setXBorder(xBorder+EXTRA_GAP);
137 Rectangle::setYBorder(yBorder+EXTRA_GAP);
138 vpsc::Variables vs(n);
139 unsigned i=0;
140 for(Variables::iterator v=vs.begin();v!=vs.end();++v,++i) {
141 *v=new Variable(i,0,1);
142 }
144 vpsc::generateXConstraints(rs,vs,cs,bothaxes);
145 vpsc::IncSolver vpsc_x(vs,cs);
146 vpsc_x.solve();
147 vpsc::Rectangles::iterator r=rs.begin();
148 for(Variables::iterator v=vs.begin();v!=vs.end();++v,++r) {
149 assert((*v)->finalPosition==(*v)->finalPosition);
150 (*r)->moveCentreX((*v)->finalPosition);
151 }
152 assert(r==rs.end());
153 for_each(cs.begin(),cs.end(),vpsc::delete_object());
154 cs.clear();
155 if(bothaxes) {
156 // Removing the extra gap here ensures things that were moved to be adjacent to one another above are not considered overlapping
159 vpsc::IncSolver vpsc_y(vs,cs);
160 vpsc_y.solve();
161 r=rs.begin();
162 for(Variables::iterator v=vs.begin();v!=vs.end();++v,++r) {
163 (*r)->moveCentreY((*v)->finalPosition);
164 }
165 for_each(cs.begin(),cs.end(),vpsc::delete_object());
166 cs.clear();
168 vpsc::generateXConstraints(rs,vs,cs,false);
169 vpsc::IncSolver vpsc_x2(vs,cs);
170 vpsc_x2.solve();
171 r=rs.begin();
172 for(Variables::iterator v=vs.begin();v!=vs.end();++v,++r) {
173 (*r)->moveCentreX((*v)->finalPosition);
174 }
175 for_each(cs.begin(),cs.end(),vpsc::delete_object());
176 }
177 for_each(vs.begin(),vs.end(),vpsc::delete_object());
178 } catch (char *str) {
179 std::cerr<<str<<std::endl;
180 for(vpsc::Rectangles::iterator r=rs.begin();r!=rs.end();++r) {
181 std::cerr << **r <<std::endl;
182 }
183 }
184 Rectangle::setXBorder(xBorder);
185 Rectangle::setYBorder(yBorder);
186}
187/*
188void writeTextFile(vector<cola::Edge>& edges) {
189 ofstream outfile("new.txt",ofstream::binary);
190 for(vector<cola::Edge>::iterator e=edges.begin();e!=edges.end();++e) {
191 outfile<<"node"<<e->first<<",node"<<e->second<<endl;
192 }
193 outfile.close();
194}
195*/
196/*
197 * Make feasible:
198 * - remove overlaps between rectangular boundaries of nodes/clusters
199 * (respecting structural constraints)
200 * - perform routing (preserve previous topology using rubber banding)
201 */
202void makeFeasible(vpsc::Rectangles& rs, vector<cola::Edge>& edges,
203 std::vector<topology::Edge*>& routes,
204 std::vector<topology::Node*>& topologyNodes, double defaultEdgeLength) {
205 printf("Removing overlaps...\n");
206 removeoverlaps(rs,false);
207 printf("done.\n");
208 printf("Running libavoid to compute routes...\n");
209 clock_t libavoidstarttime=clock();
210 // find feasible routes for edges
212 // Use rotational sweep for point visibility
213 router->UseLeesAlgorithm = true;
214 // Don't use invisibility graph.
215 router->InvisibilityGrph = false;
216 double g=0; // make shape that libavoid sees slightly smaller
217 for(unsigned i=0;i<rs.size();++i) {
218 vpsc::Rectangle* r=rs[i];
219 double x=r->getMinX()+g;
220 double X=r->getMaxX()-g;
221 double y=r->getMinY()+g;
222 double Y=r->getMaxY()-g;
223 // Create the ShapeRef:
224 Avoid::Polygon shapePoly(4);
225 // AntiClockwise!
226 shapePoly.ps[0] = Avoid::Point(X,y);
227 shapePoly.ps[1] = Avoid::Point(X,Y);
228 shapePoly.ps[2] = Avoid::Point(x,Y);
229 shapePoly.ps[3] = Avoid::Point(x,y);
230 //if(i==4||i==13||i==9) {
231 //printf("rect[%d]:{%f,%f,%f,%f}\n",i,x,y,X,Y);
232 //}
233 unsigned int shapeID = i + 1;
234 Avoid::ShapeRef *shapeRef = new Avoid::ShapeRef(router, shapePoly,
235 shapeID);
236 // ShapeRef constructor makes a copy of polygon so we can free it:
237 router->addShape(shapeRef);
238 }
239 for(unsigned i=0;i<edges.size();++i) {
240 cola::Edge e=edges[i];
241 Avoid::ConnRef *connRef;
242 unsigned int connID = i + rs.size() + 1;
243 Rectangle* r0=rs[e.first], *r1=rs[e.second];
244 Avoid::Point srcPt(r0->getCentreX(),r0->getCentreY());
245 Avoid::Point dstPt(r1->getCentreX(),r1->getCentreY());
246 connRef = new Avoid::ConnRef(router, srcPt, dstPt, connID);
247 router->processTransaction();
248 const Avoid::Polygon& route = connRef->route();
249 vector<topology::EdgePoint*> eps;
250 eps.push_back( new topology::EdgePoint( topologyNodes[e.first],
251 topology::EdgePoint::CENTRE));
252 for(size_t j=1;j+1<route.size();j++) {
253 const Avoid::Point& p = route.ps[j];
254 const unsigned nodeID=p.id-1;
255 topology::Node* node=topologyNodes[nodeID];
256 topology::EdgePoint::RectIntersect ri;
257 switch(p.vn) {
258 case 0: ri=topology::EdgePoint::BR;
259 break;
260 case 1: ri=topology::EdgePoint::TR;
261 break;
262 case 2: ri=topology::EdgePoint::TL;
263 break;
264 case 3: ri=topology::EdgePoint::BL;
265 break;
266 default: ri=topology::EdgePoint::CENTRE;
267 }
268 eps.push_back(new topology::EdgePoint(node,ri));
269 }
270 eps.push_back(new topology::EdgePoint(topologyNodes[e.second],
271 topology::EdgePoint::CENTRE));
272 topology::Edge* edgeRoute=new topology::Edge(i,defaultEdgeLength, eps);
273 edgeRoute->assertConvexBends();
274 routes.push_back(edgeRoute);
275
276 }
277 writeFile(topologyNodes,routes,"beautify0.svg");
278 assert(topology::assertNoSegmentRectIntersection(topologyNodes,routes));
279 double libavoidtime=double(clock()-libavoidstarttime)/double(CLOCKS_PER_SEC);
280 cout << "done. Libavoid ran in " << libavoidtime << " seconds" << endl;
281 delete router;
282}
283int main() {
284 unsigned V;
286
287 int seed = time(nullptr);
288 //seed=1207906420;
289 //seed=1207920674;
290 //seed=1207982613;
291 //seed=1207984219;
292 seed=1207984299;
293 //seed=1207984743;
294 //seed=1207985027; // very short edge which seems to cause problems
295 //seed=1207986026; // error if we don't check neighbour is actually on scanline when determining visibility when generating straight constraints
296 //seed=1207991731;
297 //seed=1208303930;
298 //seed=1208304508;
299 //seed=1208316284;
300 //seed=1208319019;
301 //seed=1208321702;
302 printf("random seed=%d\n",seed);
303 srand(seed);
304 vector<Edge> es = random_dag(DAGDEPTH,BRANCHFACTOR,V,ccs);
305 double defaultEdgeLength=40;
306
307 cout << "V="<<V<<endl;
308 cout << "E="<<es.size()<<endl;
309 double width=700;
310 double height=700;
311 vector<pair<double,double> > startpos(V);
312 for(unsigned i=0;i<V;i++) {
313 double x=getRand(width), y=getRand(height);
314 startpos[i]=make_pair(x,y);
315 }
316 vector<vpsc::Rectangle*> rs;
317 vector<topology::Node*> topologyNodes;
318 vector<topology::Edge*> routes;
319 for(unsigned i=0;i<V;i++) {
320 double x=getRand(width), y=getRand(height);
321 vpsc::Rectangle* r =new vpsc::Rectangle(x,x+30,y,y+10);
322 rs.push_back(r);
323 topologyNodes.push_back(new topology::Node(i,r));
324 }
325 CheckProgress test(0.01,100);
326 clock_t unconstrainedstarttime=clock();
327 //writeTextFile(es);
328 es.clear();
329 ConstrainedFDLayout alg2(rs,es,defaultEdgeLength,nullptr,test);
330 //alg2.setConstraints(&ccs);
331
332 alg2.makeFeasible(true);
333 alg2.run();
334
335 alg2.outputInstanceToSVG();
336#if 0
337 double totaltime=0;
338 double unconstrainedtime=double(clock()-unconstrainedstarttime)/double(CLOCKS_PER_SEC);
339 totaltime+=unconstrainedstarttime;
340 cout<<"unconstrained layout ran in "<<unconstrainedtime<<" seconds"<<endl;
341 clock_t makefeasiblestarttime=clock();
342 makeFeasible(rs,es,routes,topologyNodes,defaultEdgeLength);
343 double makefeasibletime=double(clock()-makefeasiblestarttime)/double(CLOCKS_PER_SEC);
344 totaltime+=makefeasibletime;
345 cout<<"makefeasible ran in "<<makefeasibletime<<" seconds"<<endl;
346 clock_t beautifystarttime=clock();
347 test.reset();
348 alg2.setTopology(&topologyNodes, &routes);
349 writeFile(topologyNodes,routes,"beautify1.svg");
350 std::stringstream dunnartfile;
351 dunnartfile << "v" << V << "e" << (int) es.size() << ".svg";
352 writeDunnartFile(topologyNodes,es,dunnartfile.str().c_str());
353
354 alg2.run();
355 double beautifytime=double(clock()-beautifystarttime)/double(CLOCKS_PER_SEC);
356 totaltime+=beautifytime;
357 cout<<"beautify ran in "<<beautifytime<<" seconds"<<endl;
358 cout<<"TOTAL="<<totaltime<<endl;
359 cout <<"---------------------------------------------"<< endl;
360 cout <<V<<" & "<<es.size()<<" & "<<unconstrainedtime<<" & "<<makefeasibletime<<" & "<<beautifytime<<" & "<<totaltime<<" \\\\ % Seed: "<< seed <<endl;
361 writeFile(topologyNodes,routes,"beautify2.svg");
362#endif
363 for(unsigned i=0;i<V;i++) {
364 delete rs[i];
365 }
366 return 0;
367}
368// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:textwidth=99 :
The ConnRef class represents a connector object.
Definition connector.h:132
const PolyLine & route(void) const
Returns a reference to the current raw "debug" route for the connector.
The Point class defines a point in the plane.
Definition geomtypes.h:53
unsigned short vn
The vertex number associated with this point.
Definition geomtypes.h:113
unsigned int id
The ID associated with this point.
Definition geomtypes.h:111
A dynamic Polygon, to which points can be easily added and removed.
Definition geomtypes.h:208
size_t size(void) const
Returns the number of points in this polygon.
std::vector< Point > ps
A vector of the points that make up the Polygon.
Definition geomtypes.h:285
The Router class represents a libavoid router instance.
Definition router.h:386
bool InvisibilityGrph
Definition router.h:418
bool UseLeesAlgorithm
Definition router.h:417
void addShape(ShapeRef *shape)
Definition router.cpp:255
bool processTransaction(void)
Finishes the current transaction and processes all the queued object changes efficiently.
Definition router.cpp:640
The ShapeRef class represents a shape object.
Definition shape.h:82
Implements a constrained force-directed layout algorithm.
Definition cola.h:622
void run(bool x=true, bool y=true)
Implements the main layout loop, taking descent steps until stress is no-longer significantly reduced...
Definition colafd.cpp:316
void setTopology(TopologyAddonInterface *topology)
Set an addon for doing topology preserving layout.
Definition colafd.cpp:944
void makeFeasible(double xBorder=1, double yBorder=1)
Finds a feasible starting position for nodes that satisfies the given constraints.
Definition colafd.cpp:604
void outputInstanceToSVG(std::string filename=std::string())
Generates an SVG file containing debug output and code that can be used to regenerate the instance.
Definition colafd.cpp:1369
A separation constraint specifies a simple horizontal or vertical spacing constraint between 2 nodes ...
Incremental solver for Variable Placement with Separation Constraints problem instance.
Definition solve_VPSC.h:105
bool solve()
Results in an optimum solution subject to the constraints.
A rectangle represents a fixed-size shape in the diagram that may be moved to prevent overlaps and sa...
Definition rectangle.h:78
static double yBorder
Definition rectangle.h:236
static void setXBorder(double x)
Definition rectangle.h:237
double getCentreY() const
Definition rectangle.h:131
static double xBorder
Definition rectangle.h:236
double getMaxX() const
Definition rectangle.h:108
double getCentreX() const
Definition rectangle.h:130
double getMaxY() const
Definition rectangle.h:109
double getMinY() const
Definition rectangle.h:111
static void setYBorder(double y)
Definition rectangle.h:238
double getMinX() const
Definition rectangle.h:110
A variable is comprised of an ideal position, final position and a weight.
Definition variable.h:45
double getRand(double range)
vector< Edge > es
vector< vpsc::Rectangle * > rs
void writeFile(const topology::Nodes &vs, const topology::Edges &es, const string &outputFileName)
void writeDunnartFile(const topology::Nodes &vs, const vector< std::pair< unsigned int, unsigned int > > &es, const string &outputFileName)
Inkscape::XML::Node * node
Standard libavoid include file which includes all libavoid header files.
static const unsigned BRANCHFACTOR
void removeoverlaps(vpsc::Rectangles &rs, bool bothaxes)
void makeEdge(unsigned u, unsigned v, vector< Edge > &edges, CompoundConstraints &ccs)
static const unsigned DAGDEPTH
void makeFeasible(vpsc::Rectangles &rs, vector< cola::Edge > &edges, std::vector< topology::Edge * > &routes, std::vector< topology::Node * > &topologyNodes, double defaultEdgeLength)
int main()
vector< Edge > random_dag(unsigned depth, unsigned maxbranch, unsigned &V, CompoundConstraints &ccs)
static const double EXTRAEDGEPROB
@ PolyLineRouting
This option specifies that the router should maintain the structures necessary to allow poly-line con...
Definition router.h:74
libcola: Force-directed network layout subject to separation constraints library.
Definition box.cpp:25
std::vector< CompoundConstraint * > CompoundConstraints
A vector of pointers to CompoundConstraint objects.
std::pair< unsigned, unsigned > Edge
Edges are simply a pair of indices to entries in the Node vector.
Definition cola.h:68
STL namespace.
libvpsc: Variable Placement with Separation Constraints quadratic program solver library.
@ YDIM
The y-dimension (1).
Definition rectangle.h:49
std::vector< vpsc::Variable * > Variables
A vector of pointers to Variable objects.
std::vector< vpsc::Constraint * > Constraints
A vector of pointers to Constraint objects.
void generateXConstraints(const Rectangles &rs, const Variables &vars, Constraints &cs, const bool useNeighbourLists)
void generateYConstraints(const Rectangles &rs, const Variables &vars, Constraints &cs)
std::vector< Rectangle * > Rectangles
A vector of pointers to Rectangle objects.
Definition rectangle.h:246
Contains the interface for the Router class.
Edges edges(Path const &p, Crossings const &cr, unsigned ix)
Definition sanitize.cpp:36
double height
double width