Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
cola.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-2014 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 * See the file LICENSE.LGPL distributed with the library.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * Author(s): Tim Dwyer
20*/
21
22#include <cmath>
23
24#include "libvpsc/assertions.h"
25#include "libcola/commondefs.h"
26#include "libcola/cola.h"
30#include "libcola/cluster.h"
31
32using namespace std;
33using namespace vpsc;
35
36namespace cola {
37
38ConstrainedMajorizationLayout
39::ConstrainedMajorizationLayout(
40 vector<Rectangle*>& rs,
41 const vector<Edge>& es,
42 RootCluster *clusterHierarchy,
43 const double idealLength,
44 EdgeLengths eLengths,
45 TestConvergence *doneTest,
46 PreIteration* preIteration,
47 bool useNeighbourStress)
48 : n(rs.size()),
49 lap2(valarray<double>(n*n)),
50 Dij(valarray<double>(n*n)),
51 tol(1e-7),
52 done(doneTest),
53 using_default_done(false),
54 preIteration(preIteration),
55 X(valarray<double>(n)), Y(valarray<double>(n)),
56 stickyNodes(false),
57 startX(valarray<double>(n)), startY(valarray<double>(n)),
58 constrainedLayout(false),
59 nonOverlappingClusters(false),
60 clusterHierarchy(clusterHierarchy),
61 gpX(nullptr), gpY(nullptr),
62 ccs(nullptr),
63 unsatisfiableX(nullptr), unsatisfiableY(nullptr),
64 avoidOverlaps(None),
65 straightenEdges(nullptr),
66 bendWeight(0.1), potBendWeight(0.1),
67 xSkipping(true),
68 scaling(true),
69 externalSolver(false),
70 majorization(true)
71{
72 if (done == nullptr)
73 {
74 done = new TestConvergence();
75 using_default_done = true;
76 }
77
78 boundingBoxes.resize(rs.size());
79 copy(rs.begin(),rs.end(),boundingBoxes.begin());
80
81 done->reset();
82
83 COLA_ASSERT(!straightenEdges||straightenEdges->size()==es.size());
84
85 double** D=new double*[n];
86 for(unsigned i=0;i<n;i++) {
87 D[i]=new double[n];
88 }
89
90 std::valarray<double> edgeLengths(eLengths.data(), eLengths.size());
91 // Correct zero or negative entries in eLengths array.
92 for (size_t i = 0; i < edgeLengths.size(); ++i)
93 {
94 if (edgeLengths[i] <= 0)
95 {
96 fprintf(stderr, "Warning: ignoring non-positive length at index %d "
97 "in ideal edge length array.\n", (int) i);
98 edgeLengths[i] = 1;
99 }
100 }
101
102 if (useNeighbourStress) {
103 for(unsigned i=0;i<n;i++) {
104 for(unsigned j=0;j<n;j++) {
105 D[i][j]=std::numeric_limits<double>::max();
106 }
107 }
108 bool haveLengths = edgeLengths.size() == es.size();
109 for (unsigned i = 0; i < es.size(); i++) {
110 unsigned source = es[i].first;
111 unsigned target = es[i].second;
112 D[source][target] = D[target][source] = (haveLengths ? edgeLengths[i] : 1.0);
113 }
114 } else {
115 shortest_paths::johnsons(n,D,es,edgeLengths);
116 //shortest_paths::neighbours(n,D,es,edgeLengths);
117 }
118
119 edge_length = idealLength;
120 if(clusterHierarchy) {
121 for(Clusters::const_iterator i=clusterHierarchy->clusters.begin();
122 i!=clusterHierarchy->clusters.end();i++) {
123 Cluster *c=*i;
124 for(set<unsigned>::iterator j=c->nodes.begin();j!=c->nodes.end();j++) {
125 for(set<unsigned>::iterator k=c->nodes.begin();k!=c->nodes.end();k++) {
126 unsigned a=*j, b=*k;
127 if(a==b) continue;
129 }
130 }
131 }
132 }
133 // Lij_{i!=j}=1/(Dij^2)
134 //
135 for(unsigned i = 0; i<n; i++) {
136 X[i]=rs[i]->getCentreX();
137 Y[i]=rs[i]->getCentreY();
138 double degree = 0;
139 for(unsigned j=0;j<n;j++) {
140 double d = edge_length * D[i][j];
141 Dij[i*n + j] = d;
142 if(i==j) continue;
143 double lij=0;
144 if(d!=0 && !std::isinf(d)) {
145 lij=1./(d*d);
146 }
147 degree += lap2[i*n + j] = lij;
148 }
149 lap2[i*n + i]=-degree;
150 delete [] D[i];
151 }
152 //GradientProjection::dumpSquareMatrix(Dij);
153 delete [] D;
154}
155// stickyNodes adds a small force attracting nodes
156// back to their starting positions
158 const double stickyWeight,
159 valarray<double> const & startX,
160 valarray<double> const & startY) {
161 COLA_ASSERT( startX.size()==n && startY.size()==n);
162 stickyNodes = true;
163 // not really constrained but we want to use GP solver rather than
164 // ConjugateGradient
165 constrainedLayout = true;
166 this->stickyWeight=stickyWeight;
167 this->startX = startX;
168 this->startY = startY;
169 for(unsigned i = 0; i<n; i++) {
170 lap2[i*n+i]-=stickyWeight;
171 }
172}
173
175 valarray<double> const & Dij, GradientProjection* gp,
176 valarray<double>& coords,
177 valarray<double> const & startCoords)
178{
179 double L_ij,dist_ij,degree;
180 /* compute the vector b */
181 /* multiply on-the-fly with distance-based laplacian */
182 valarray<double> b(n);
183 for (unsigned i = 0; i < n; i++) {
184 b[i] = degree = 0;
185 for (unsigned j = 0; j < n; j++) {
186 if (j == i) continue;
187 dist_ij = euclidean_distance(i, j);
188 /* skip zero distances */
189 if (dist_ij > 1e-30 && Dij[i*n+j] > 1e-30 && Dij[i*n+j] < 1e10) {
190 /* calculate L_ij := w_{ij}*d_{ij}/dist_{ij} */
191 L_ij = 1.0 / (dist_ij * Dij[i*n+j]);
192 degree -= L_ij;
193 b[i] += L_ij * coords[j];
194 }
195 }
196 if(stickyNodes) {
197 //double l = startCoords[i]-coords[i];
198 //l/=10.;
199 //b[i]-=stickyWeight*(coords[i]+l);
200 b[i] -= stickyWeight*startCoords[i];
201 }
202 b[i] += degree * coords[i];
203 COLA_ASSERT(!std::isnan(b[i]));
204 }
206 //printf("GP iteration...\n");
207 gp->solve(b,coords);
208 } else {
209 //printf("CG iteration...\n");
210 conjugate_gradient(lap2, coords, b, n, tol, n);
211 }
213}
215 valarray<double> const & Dij, GradientProjection* gp,
216 valarray<double>& coords,
217 valarray<double> const & startCoords)
218{
219 COLA_UNUSED(startCoords);
220 /* compute the vector b */
221 /* multiply on-the-fly with distance-based laplacian */
222 valarray<double> b(n);
223 valarray<double> A(n*n);
224 for (unsigned i = 0; i < n; i++) {
225 b[i] = 0;
226 double Aii = 0;
227 for (unsigned j = 0; j < n; j++) {
228 if (j == i) continue;
229 double d = Dij[i*n+j];
230 double l = euclidean_distance(i,j);
231 double dx = coords[i]-coords[j];
232 double dy2 = l*l - dx*dx;
233 /* skip zero distances */
234 if (l > 1e-30
235 && d > 1e-30 && d < 1e10) {
236 if(d>80 && l > d) continue;
237 b[i]+=dx*(l-d)/(l*d*d);
238 Aii-=A[i*n+j]=(d*dy2/(l*l*l)-1)/(d*d);
239 }
240 }
241 A[i*n+i]=Aii;
242 }
244 //printf("GP iteration...\n");
245 gp->solve(b,coords);
246 } else {
247 //printf("CG iteration...\n");
248 /*
249 unsigned N=n-1;
250 valarray<double> b2(N);
251 valarray<double> A2(N*N);
252 valarray<double> x(N);
253 for(unsigned i=0;i<N;i++) {
254 b2=b[i];
255 x=coords[i];
256 for(unsigned j=0;j<N;j++) {
257 A2[i*N+j]=A[i*n+j];
258 }
259 }
260 conjugate_gradient(A2, x, b2, N, tol, N);
261 */
262 //valarray<double> x=coords;
263 //x-=x.sum()/n;
264 //conjugate_gradient(A, x, b, n, tol, n);
265 //double stepsize=0.5;
266 valarray<double> x=b;
267 // stepsize = g.g / (g A g)
268 double numerator = 0;
269 for(unsigned i=0;i<n;i++) {
270 numerator+=x[i]*x[i];
271 }
272 double denominator = 0;
273 for(unsigned i=0;i<n;i++) {
274 double r=0;
275 for(unsigned j=0;j<n;j++) {
276 r+=A[i*n+j]*x[j];
277 }
278 denominator+=r*x[i];
279 }
280 double stepsize=numerator/(2*denominator);
281 double oldstress=compute_stress(Dij);
282 valarray<double> oldcoords=coords;
283 while(stepsize>0.00001) {
284 coords=oldcoords-stepsize*x;
285 double stress=compute_stress(Dij);
286 printf(" stress=%f, stepsize=%f\n",stress,stepsize);
287 if(oldstress>=stress) {
288 break;
289 }
290 coords=oldcoords;
291 stepsize*=0.5;
292 }
293 }
295}
296inline double ConstrainedMajorizationLayout
297::compute_stress(valarray<double> const &Dij) {
298 double sum = 0, d, diff;
299 for (unsigned i = 1; i < n; i++) {
300 for (unsigned j = 0; j < i; j++) {
301 d = Dij[i*n+j];
302 if(!std::isinf(d)&&d!=numeric_limits<double>::max()) {
303 diff = d - euclidean_distance(i,j);
304 if(d>80&&diff<0) continue;
305 sum += diff*diff / (d*d);
306 }
307 }
308 if(stickyNodes) {
309 double l = startX[i]-X[i];
310 sum += stickyWeight*l*l;
311 l = startY[i]-Y[i];
312 sum += stickyWeight*l*l;
313 }
314 }
315 //printf("stress=%f\n",sum);
316 return sum;
317}
318
321 vector<vpsc::Rectangle*>* pbb = boundingBoxes.empty()?nullptr:&boundingBoxes;
322 SolveWithMosek mosek = Off;
323 if(externalSolver) mosek=Outer;
324 // scaling doesn't currently work with straighten edges because sparse
325 // matrix used with dummy nodes is not properly scaled at the moment.
326 if(straightenEdges) setScaling(false);
333 }
334 if(n>0) do {
335 // to enforce clusters with non-intersecting, convex boundaries we
336 // could create cluster boundaries here with chains of dummy nodes (a
337 // dummy node for each vertex of the convex hull) connected by dummy
338 // straightenEdges and we'd then continue on to straightenEdges below.
339 // This should work assuming we already have a feasible (i.e. non
340 // overlapping cluster) state. The former could be enforced by an
341 // earlier stage involving simple rectangular cluster boundaries.
342 vector<straightener::Edge*> cedges;
344 straightenEdges = &cedges;
345 }
346 if(preIteration) {
347 if ((*preIteration)()) {
348 for(vector<Lock>::iterator l=preIteration->locks.begin();
349 l!=preIteration->locks.end();l++) {
350 unsigned id=l->getID();
351 double x=l->pos(HORIZONTAL), y=l->pos(VERTICAL);
352 X[id]=x;
353 Y[id]=y;
354 if(stickyNodes) {
355 startX[id]=x;
356 startY[id]=y;
357 }
358 boundingBoxes[id]->moveCentre(x,y);
360 gpX->fixPos(id,X[id]);
361 gpY->fixPos(id,Y[id]);
362 }
363 }
364 } else { break; }
365 }
366 /* Axis-by-axis optimization: */
367 if(straightenEdges) {
370 } else {
371 if(majorization) {
372 if(x) majorize(Dij,gpX,X,startX);
373 if(y) majorize(Dij,gpY,Y,startY);
374 } else {
375 if(x) newton(Dij,gpX,X,startX);
376 if(y) newton(Dij,gpY,Y,startY);
377 }
378 }
379 if(clusterHierarchy) {
380 for(Clusters::iterator c=clusterHierarchy->clusters.begin();
381 c!=clusterHierarchy->clusters.end();c++) {
382 (*c)->computeBoundary(boundingBoxes);
383 }
384 }
386 for(vector<Lock>::iterator l=preIteration->locks.begin();
387 l!=preIteration->locks.end();l++) {
388 gpX->unfixPos(l->getID());
389 gpY->unfixPos(l->getID());
390 }
391 }
392 } while(!(*done)(compute_stress(Dij),X,Y));
393}
399 vector<vpsc::Rectangle*>* pbb = boundingBoxes.empty()?nullptr:&boundingBoxes;
400 SolveWithMosek mosek = Off;
401 if(externalSolver) mosek=Outer;
402 // scaling doesn't currently work with straighten edges because sparse
403 // matrix used with dummy nodes is not properly scaled at the moment.
404 if(straightenEdges) setScaling(false);
411 }
412 if(n>0) {
413 // to enforce clusters with non-intersecting, convex boundaries we
414 // could create cluster boundaries here with chains of dummy nodes (a
415 // dummy node for each vertex of the convex hull) connected by dummy
416 // straightenEdges and we'd then continue on to straightenEdges below.
417 // This should work assuming we already have a feasible (i.e. non
418 // overlapping cluster) state. The former could be enforced by an
419 // earlier stage involving simple rectangular cluster boundaries.
420 vector<straightener::Edge*> cedges;
422 straightenEdges = &cedges;
423 }
424 if(preIteration) {
425 if ((*preIteration)()) {
426 for(vector<Lock>::iterator l=preIteration->locks.begin();
427 l!=preIteration->locks.end();l++) {
428 unsigned id=l->getID();
429 double x=l->pos(HORIZONTAL), y=l->pos(VERTICAL);
430 X[id]=x;
431 Y[id]=y;
432 if(stickyNodes) {
433 startX[id]=x;
434 startY[id]=y;
435 }
436 boundingBoxes[id]->moveCentre(x,y);
438 gpX->fixPos(id,X[id]);
439 gpY->fixPos(id,Y[id]);
440 }
441 }
442 } else { return; }
443 }
444 /* Axis-by-axis optimization: */
445 if(straightenEdges) {
448 } else {
449 if(majorization) {
450 if(x) majorize(Dij,gpX,X,startX);
451 if(y) majorize(Dij,gpY,Y,startY);
452 } else {
453 if(x) newton(Dij,gpX,X,startX);
454 if(y) newton(Dij,gpY,Y,startY);
455 }
456 }
457 if(clusterHierarchy) {
458 for(Clusters::iterator c=clusterHierarchy->clusters.begin();
459 c!=clusterHierarchy->clusters.end();c++) {
460 (*c)->computeBoundary(boundingBoxes);
461 }
462 }
464 for(vector<Lock>::iterator l=preIteration->locks.begin();
465 l!=preIteration->locks.end();l++) {
466 gpX->unfixPos(l->getID());
467 gpY->unfixPos(l->getID());
468 }
469 }
470 }
471}
472void ConstrainedMajorizationLayout::straighten(vector<straightener::Edge*>& sedges, Dim dim) {
474 valarray<double>* coords;
475 valarray<double>* startCoords;
476 if(dim==HORIZONTAL) {
477 gp=gpX;
478 coords=&X;
479 startCoords=&startX;
480 } else {
481 gp=gpY;
482 coords=&Y;
483 startCoords=&startY;
484 }
485 vector<straightener::Node*> snodes;
486 if(dim==HORIZONTAL) {
487 Rectangle::setXBorder(0.0001);
488 }
489 for (unsigned i=0;i<n;i++) {
490 snodes.push_back(new straightener::Node(i,boundingBoxes[i]));
491 }
492 if(dim==HORIZONTAL) {
494 }
495 for (unsigned i=n;i<gp->getNumStaticVars();i++) {
496 // insert some dummy nodes
497 snodes.push_back(new straightener::Node(i,-100,-100));
498 }
499 vector<straightener::Cluster*> sclusters;
500
502 generateClusterBoundaries(dim,snodes,sedges,boundingBoxes,
503 *clusterHierarchy,sclusters);
504 }
505 vector<SeparationConstraint*> cs;
506 straightener::generateConstraints(dim,snodes,sedges,cs,xSkipping);
507 straightener::LinearConstraints linearConstraints;
508 for(unsigned i=0;i<sedges.size();i++) {
509 sedges[i]->nodePath(snodes,!nonOverlappingClusters);
510 vector<unsigned>& path=sedges[i]->path;
511 vector<unsigned>& activePath=sedges[i]->activePath;
512 // take u and v as the ends of the line
513 // unsigned u=path[0];
514 // unsigned v=path[path.size()-1];
515 double total_length=0;
516 for(unsigned j=1;j<path.size();j++) {
517 unsigned u=path[j-1], v=path[j];
518 total_length+=snodes[u]->euclidean_distance(snodes[v]);
519 }
520 // keep potential bends straight
521 for(unsigned j=1;j<activePath.size();j++) {
522 unsigned uj=activePath[j-1], vj=activePath[j];
523 unsigned u=path[uj], v=path[vj];
524 for(unsigned k=uj+1;k<vj;k++) {
525 unsigned b=path[k];
526 // might be useful to have greater weight for potential bends than actual bends
527 linearConstraints.push_back(new straightener::LinearConstraint(
528 *snodes[u],*snodes[v],*snodes[b],-potBendWeight));
529 }
530 }
531 // straighten actual bends
532 for(unsigned j=1;j<activePath.size()-1;j++) {
533 unsigned u=path[activePath[j-1]],
534 b=path[activePath[j]],
535 v=path[activePath[j+1]];
536 linearConstraints.push_back(new straightener::LinearConstraint(
537 *snodes[u],*snodes[v],*snodes[b],-bendWeight));
538 }
539 }
540 //std::cout << (dim==HORIZONTAL?"X":"Y") << " snodes.size "<<snodes.size()<< " n="<<n<<std::endl;
541 //std::cout << "Generated "<<linearConstraints.size()<< " linear constraints"<<std::endl;
542 SparseMap Q(snodes.size());
543 for(straightener::LinearConstraints::iterator i=linearConstraints.begin();
544 i!= linearConstraints.end();i++) {
546 Q(c->u,c->u)+=c->w*c->duu;
547 Q(c->u,c->v)+=c->w*c->duv;
548 Q(c->u,c->b)+=c->w*c->dub;
549 Q(c->v,c->u)+=c->w*c->duv;
550 Q(c->v,c->v)+=c->w*c->dvv;
551 Q(c->v,c->b)+=c->w*c->dvb;
552 Q(c->b,c->b)+=c->w*c->dbb;
553 Q(c->b,c->u)+=c->w*c->dub;
554 Q(c->b,c->v)+=c->w*c->dvb;
555 }
556 double boundaryWeight = 0.0001;
557 for(unsigned i=0;i<sclusters.size();i++) {
558 // for each cluster boundary chain create an attractive force between
559 // each pair of adjacent nodes
560 straightener::Cluster* c = sclusters[i];
561 for(unsigned j=0;j<c->boundary.size();j++) {
562 straightener::Edge* e = c->boundary[j];
563 Q(e->startNode,e->endNode)+=boundaryWeight;
564 Q(e->endNode,e->startNode)+=boundaryWeight;
565 Q(e->startNode,e->startNode)-=boundaryWeight;
566 Q(e->endNode,e->endNode)-=boundaryWeight;
567 }
568 }
569 constrainedLayout = true;
570 SparseMatrix sparseQ(Q);
571 gp->straighten(&sparseQ,cs,snodes);
572 //return;
573 majorize(Dij,gp,*coords,*startCoords);
574 valarray<double> const & r=gp->getFullResult();
575 for(unsigned i=0;i<snodes.size();i++) {
576 snodes[i]->pos[dim] = r[i];
577 }
578 for(unsigned i=0;i<sedges.size();i++) {
579 sedges[i]->createRouteFromPath(snodes);
580 sedges[i]->dummyNodes.clear();
581 sedges[i]->path.clear();
582 }
583 for(unsigned i=0;i<sclusters.size();i++) {
584 straightener::Cluster *sc = sclusters[i];
585 //sc->updateActualBoundary();
586 delete sc;
587 }
588 for(unsigned i=0;i<cs.size();i++) {
589 delete cs[i];
590 }
591 for(unsigned i=0;i<linearConstraints.size();i++) {
592 delete linearConstraints[i];
593 }
594 for(unsigned i=0;i<snodes.size();i++) {
595 delete snodes[i];
596 }
597}
598
599Rectangle bounds(vector<Rectangle*>& rs) {
600 COLA_ASSERT(!rs.empty());
601
602 double left = rs[0]->getMinX(), right = rs[0]->getMaxX(),
603 top = rs[0]->getMinY(), bottom = rs[0]->getMaxY();
604
605 for(unsigned i = 1; i < rs.size(); i++) {
606 left = min(left,rs[i]->getMinX());
607 right = max(right,rs[i]->getMaxX());
608 top = min(top,rs[i]->getMinY());
609 bottom = max(bottom,rs[i]->getMaxY());
610 }
611 return Rectangle(left, right, top, bottom);
612}
613
614#if 0
615 void removeClusterOverlap(RootCluster& clusterHierarchy, vpsc::Rectangles& rs, Locks& locks, vpsc::Dim dim) {
616 if(clusterHierarchy.nodes.size()>0 || clusterHierarchy.clusters.size()>0) {
617 vpsc::Variables vars;
619 for(unsigned i=0;i<rs.size();i++) {
620 vars.push_back(new vpsc::Variable(i, rs[i]->getCentreD(dim)));
621 }
622
623 clusterHierarchy.computeBoundingRect(rs);
624 clusterHierarchy.createVars(dim,rs,vars);
625 clusterHierarchy.generateNonOverlapConstraints(dim, cola::Both, rs, vars, cs);
626
627 /*
628 if(dim==vpsc::HORIZONTAL) {
629 vpsc::Rectangle::setXBorder(0.001);
630 // use rs->size() rather than n because some of the variables may
631 // be dummy vars with no corresponding rectangle
632 generateXConstraints(rs,vars,cs,true);
633 vpsc::Rectangle::setXBorder(0);
634 } else {
635 generateYConstraints(rs,vars,cs);
636 }
637 */
638 for(Locks::iterator l=locks.begin();
639 l!=locks.end();l++) {
640 unsigned id=l->getID();
641 double x=l->pos(HORIZONTAL), y=l->pos(VERTICAL);
642 Variable* v=vars[id];
643 v->desiredPosition = (dim==vpsc::HORIZONTAL)?x:y;
644 v->weight = 1000;
645 }
646 /*
647 vpsc::Solver s(vars,cs);
648 try {
649 s.satisfy();
650 } catch(const char* e) {
651 cerr << "ERROR from solver in GraphData::removeOverlap : " << e << endl;
652 }
653 */
654 vpsc::IncSolver s(vars,cs);
655 try {
656 s.solve();
657 } catch(const char* e) {
658 cerr << "ERROR from solver in GraphData::removeOverlap : " << e << endl;
659 }
660 clusterHierarchy.updateBounds(dim);
661 /*
662 for(unsigned i=0;i<cs.size();++i) {
663 if(cs[i]->unsatisfiable) {
664 cout << "Unsatisfiable constraint: " << *cs[i] << endl;
665 }
666 }
667 */
668 for(unsigned i=0;i<rs.size();i++) {
669 rs[i]->moveCentreD(dim,vars[i]->finalPosition);
670 }
671 for(Locks::iterator l=locks.begin();
672 l!=locks.end();l++) {
673 //unsigned id=l->getID();
674 }
675 for_each(vars.begin(),vars.end(),delete_object());
676 for_each(cs.begin(),cs.end(),delete_object());
677 }
678 }
680 removeClusterOverlap(clusterHierarchy, rs, locks, vpsc::HORIZONTAL);
681 removeClusterOverlap(clusterHierarchy, rs, locks, vpsc::VERTICAL);
682 }
683#endif
684
687 std::vector<Edge> const & es,
688 RootCluster* clusterHierarchy,
689 const double idealLength,
690 bool useNeighbourStress
691 ) {
692 cola::EdgeLengths eLengths;
693 for(size_t i = 0; i < es.size(); ++i) {
694 eLengths.push_back(1);
695 }
696 return new ConstrainedMajorizationLayout(rs, es, clusterHierarchy, idealLength,
697 eLengths, nullptr, nullptr, useNeighbourStress);
698 };
699
700} // namespace cola
Geom::IntRect bounds
Definition canvas.cpp:182
A cluster defines a hierarchical partitioning over the nodes which should be kept disjoint by the lay...
Definition cluster.h:51
void updateBounds(const vpsc::Dim dim)
Definition cluster.cpp:628
double internalEdgeWeightFactor
Definition cluster.h:114
std::vector< Cluster * > clusters
Definition cluster.h:116
virtual void computeBoundingRect(const vpsc::Rectangles &rs)
Definition cluster.cpp:99
std::set< unsigned > nodes
Definition cluster.h:115
void createVars(const vpsc::Dim dim, const vpsc::Rectangles &rs, vpsc::Variables &vars)
Definition cluster.cpp:647
Implements the Constrained Majorization graph layout algorithm (deprecated).
Definition cola.h:270
std::valarray< double > Q
Definition cola.h:457
GradientProjection * gpY
Definition cola.h:497
std::valarray< double > X
Definition cola.h:469
void runOnce(bool x=true, bool y=true)
Same as run(), but only applies one iteration.
Definition cola.cpp:397
std::valarray< double > lap2
Definition cola.h:456
std::valarray< double > Dij
Definition cola.h:458
double euclidean_distance(unsigned i, unsigned j)
Definition cola.h:446
cola::CompoundConstraints * ccs
Definition cola.h:498
void newton(std::valarray< double > const &Dij, GradientProjection *gp, std::valarray< double > &coords, std::valarray< double > const &startCoords)
Definition cola.cpp:214
std::valarray< double > startX
Definition cola.h:472
vpsc::Rectangles boundingBoxes
Definition cola.h:463
void straighten(std::vector< straightener::Edge * > &, vpsc::Dim)
Definition cola.cpp:472
UnsatisfiableConstraintInfos * unsatisfiableX
Definition cola.h:499
NonOverlapConstraintsMode avoidOverlaps
Definition cola.h:500
void setStickyNodes(const double stickyWeight, std::valarray< double > const &startX, std::valarray< double > const &startY)
Sticky nodes causes nodes to spring back to (startX,startY) when unconstrained.
Definition cola.cpp:157
std::valarray< double > Y
Definition cola.h:469
void moveBoundingBoxes()
Update position of bounding boxes.
Definition cola.h:401
double compute_stress(std::valarray< double > const &Dij)
Definition cola.cpp:297
void setScaling(bool scaling)
Scaling speeds up the solver by conditioning the quadratic terms matrix.
Definition cola.h:352
GradientProjection * gpX
Definition cola.h:497
std::vector< straightener::Edge * > * straightenEdges
Definition cola.h:501
UnsatisfiableConstraintInfos * unsatisfiableY
Definition cola.h:499
std::valarray< double > startY
Definition cola.h:473
void run(bool x=true, bool y=true)
Implements the main layout loop, taking descent steps until stress is no-longer significantly reduced...
Definition cola.cpp:319
void majorize(std::valarray< double > const &Dij, GradientProjection *gp, std::valarray< double > &coords, std::valarray< double > const &startCoords)
Definition cola.cpp:174
void fixPos(const unsigned i, const double pos)
void straighten(cola::SparseMatrix const *Q, std::vector< SeparationConstraint * > const &ccs, std::vector< straightener::Node * > const &snodes)
unsigned getNumStaticVars() const
unsigned solve(std::valarray< double > const &b, std::valarray< double > &x)
std::valarray< double > const & getFullResult() const
A default functor that is called before each iteration in the main loop of the ConstrainedFDLayout::r...
Definition cola.h:168
Locks & locks
Definition cola.h:197
Holds the cluster hierarchy specification for a diagram.
Definition cluster.h:173
A default functor that is called after each iteration of the layout algorithm.
Definition cola.h:216
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 void setXBorder(double x)
Definition rectangle.h:237
A variable is comprised of an ideal position, final position and a weight.
Definition variable.h:45
void conjugate_gradient(valarray< double > const &A, valarray< double > &x, valarray< double > const &b, unsigned const n, double const tol, unsigned const max_iterations)
vector< Edge > es
vector< vpsc::Rectangle * > rs
Geom::IntPoint size
double c[8][4]
libcola: Force-directed network layout subject to separation constraints library.
Definition box.cpp:25
std::vector< cola::Lock > Locks
A vector of Lock objects.
Definition cola.h:102
void removeClusterOverlapFast(RootCluster &clusterHierarchy, vpsc::Rectangles &rs, Locks &locks)
Definition cola.cpp:679
void removeClusterOverlap(RootCluster &clusterHierarchy, vpsc::Rectangles &rs, Locks &locks, vpsc::Dim dim)
Definition cola.cpp:615
ConstrainedMajorizationLayout * simpleCMLFactory(vpsc::Rectangles &rs, std::vector< Edge > const &es, RootCluster *clusterHierarchy, const double idealLength, bool useNeighbourStress)
Definition cola.cpp:685
@ None
Definition commondefs.h:47
@ Both
Definition commondefs.h:47
std::vector< double > EdgeLengths
EdgeLengths is a vector of ideal lengths for edges corresponding to edges in the edge list.
Definition cola.h:72
void johnsons(unsigned const n, T **D, std::vector< Edge > const &es, std::valarray< T > const &eweights=std::valarray< T >())
find all pairs shortest paths, faster, uses dijkstra
STL namespace.
void generateClusterBoundaries(const vpsc::Dim dim, vector< straightener::Node * > &nodes, vector< straightener::Edge * > &edges, vector< vpsc::Rectangle * > const &rs, cola::Cluster const &clusterHierarchy, vector< straightener::Cluster * > &sclusters)
set up straightener clusters.
std::vector< LinearConstraint * > LinearConstraints
void generateConstraints(const vpsc::Dim dim, vector< Node * > &nodes, vector< Edge * > const &edges, vector< cola::SeparationConstraint * > &cs, bool xSkipping=true)
Generates constraints to prevent node/edge and edge/edge intersections.
libvpsc: Variable Placement with Separation Constraints quadratic program solver library.
Dim
Indicates the x- or y-dimension.
Definition rectangle.h:41
@ HORIZONTAL
The x-dimension (0).
Definition rectangle.h:43
@ VERTICAL
The y-dimension (1).
Definition rectangle.h:47
std::vector< vpsc::Variable * > Variables
A vector of pointers to Variable objects.
std::vector< vpsc::Constraint * > Constraints
A vector of pointers to Constraint objects.
std::vector< Rectangle * > Rectangles
A vector of pointers to Rectangle objects.
Definition rectangle.h:246
size_t degree
double sum(const double alpha[16], const double &x, const double &y)