1 #ifndef COLA_H
2 #define COLA_H
4 #include <utility>
5 #include <iterator>
6 #include <vector>
7 #include <algorithm>
8 #include <cmath>
9 #include <iostream>
10 #include <cassert>
11 #include "shortest_paths.h"
12 #include "gradient_projection.h"
13 #include <libvpsc/generate-constraints.h>
14 #include "straightener.h"
17 typedef vector<unsigned> Cluster;
18 typedef vector<Cluster*> Clusters;
20 namespace cola {
21 typedef pair<unsigned, unsigned> Edge;
23 // defines references to three variables for which the goal function
24 // will be altered to prefer points u-b-v are in a linear arrangement
25 // such that b is placed at u+t(v-u).
26 struct LinearConstraint {
27 LinearConstraint(unsigned u, unsigned v, unsigned b, double w,
28 double frac_ub, double frac_bv,
29 double* X, double* Y)
30 : u(u),v(v),b(b),w(w),frac_ub(frac_ub),frac_bv(frac_bv),
31 tAtProjection(true)
32 {
33 assert(frac_ub<=1.0);
34 assert(frac_bv<=1.0);
35 assert(frac_ub>=0);
36 assert(frac_bv>=0);
37 if(tAtProjection) {
38 double uvx = X[v] - X[u],
39 uvy = Y[v] - Y[u],
40 vbx = X[b] - X[u],
41 vby = Y[b] - Y[u];
42 t = uvx * vbx + uvy * vby;
43 t/= uvx * uvx + uvy * uvy;
44 // p is the projection point of b on line uv
45 //double px = scalarProj * uvx + X[u];
46 //double py = scalarProj * uvy + Y[u];
47 // take t=|up|/|uv|
48 } else {
49 double numerator=X[b]-X[u];
50 double denominator=X[v]-X[u];
51 if(fabs(denominator)<0.001) {
52 // if line is close to vertical then use Y coords to compute T
53 numerator=Y[b]-Y[u];
54 denominator=Y[v]-Y[u];
55 }
56 if(fabs(denominator)<0.0001) {
57 denominator=1;
58 }
59 t=numerator/denominator;
60 }
61 duu=(1-t)*(1-t);
62 duv=t*(1-t);
63 dub=t-1;
64 dvv=t*t;
65 dvb=-t;
66 dbb=1;
67 //printf("New LC: t=%f\n",t);
68 }
69 unsigned u;
70 unsigned v;
71 unsigned b;
72 double w; // weight
73 double t;
74 // 2nd partial derivatives of the goal function
75 // (X[b] - (1-t) X[u] - t X[v])^2
76 double duu;
77 double duv;
78 double dub;
79 double dvv;
80 double dvb;
81 double dbb;
82 // Length of each segment as a fraction of the total edge length
83 double frac_ub;
84 double frac_bv;
85 bool tAtProjection;
86 };
87 typedef vector<LinearConstraint*> LinearConstraints;
89 class TestConvergence {
90 public:
91 double old_stress;
92 TestConvergence(const double& tolerance = 0.001, const unsigned maxiterations = 1000)
93 : old_stress(DBL_MAX),
94 tolerance(tolerance),
95 maxiterations(maxiterations),
96 iterations(0) { }
97 virtual ~TestConvergence() {}
99 virtual bool operator()(double new_stress, double* X, double* Y) {
100 //std::cout<<"iteration="<<iterations<<", new_stress="<<new_stress<<std::endl;
101 if (old_stress == DBL_MAX) {
102 old_stress = new_stress;
103 if(++iterations>=maxiterations) {;
104 return true;
105 } else {
106 return false;
107 }
108 }
109 bool converged =
110 fabs(new_stress - old_stress) / (new_stress + 1e-10) < tolerance
111 || ++iterations > maxiterations;
112 old_stress = new_stress;
113 return converged;
114 }
115 private:
116 double tolerance;
117 unsigned maxiterations;
118 unsigned iterations;
119 };
120 static TestConvergence defaultTest(0.0001,100);
121 class ConstrainedMajorizationLayout {
122 public:
123 ConstrainedMajorizationLayout(
124 vector<Rectangle*>& rs,
125 vector<Edge>& es,
126 double* eweights,
127 double idealLength,
128 TestConvergence& done=defaultTest)
129 : constrainedLayout(false),
130 n(rs.size()),
131 lapSize(n), lap2(new double*[lapSize]),
132 Q(lap2), Dij(new double*[lapSize]),
133 tol(0.0001),
134 done(done),
135 X(new double[n]),
136 Y(new double[n]),
137 clusters(NULL),
138 linearConstraints(NULL),
139 gpX(NULL),
140 gpY(NULL),
141 straightenEdges(NULL)
142 {
143 assert(rs.size()==n);
144 boundingBoxes = new Rectangle*[rs.size()];
145 copy(rs.begin(),rs.end(),boundingBoxes);
147 double** D=new double*[n];
148 for(unsigned i=0;i<n;i++) {
149 D[i]=new double[n];
150 }
151 shortest_paths::johnsons(n,D,es,eweights);
152 edge_length = idealLength;
153 // Lij_{i!=j}=1/(Dij^2)
154 //
155 for(unsigned i = 0; i<n; i++) {
156 X[i]=rs[i]->getCentreX();
157 Y[i]=rs[i]->getCentreY();
158 double degree = 0;
159 lap2[i]=new double[n];
160 Dij[i]=new double[n];
161 for(unsigned j=0;j<n;j++) {
162 double w = edge_length * D[i][j];
163 Dij[i][j]=w;
164 if(i==j) continue;
165 degree+=lap2[i][j]=w>1e-30?1.f/(w*w):0;
166 }
167 lap2[i][i]=-degree;
168 delete [] D[i];
169 }
170 delete [] D;
171 }
173 void moveBoundingBoxes() {
174 for(unsigned i=0;i<lapSize;i++) {
175 boundingBoxes[i]->moveCentreX(X[i]);
176 boundingBoxes[i]->moveCentreY(Y[i]);
177 }
178 }
180 void setupConstraints(
181 AlignmentConstraints* acsx, AlignmentConstraints* acsy,
182 bool avoidOverlaps,
183 PageBoundaryConstraints* pbcx = NULL,
184 PageBoundaryConstraints* pbcy = NULL,
185 SimpleConstraints* scx = NULL,
186 SimpleConstraints* scy = NULL,
187 Clusters* cs = NULL,
188 vector<straightener::Edge*>* straightenEdges = NULL);
190 void addLinearConstraints(LinearConstraints* linearConstraints);
192 void setupDummyVars();
194 ~ConstrainedMajorizationLayout() {
195 if(boundingBoxes) {
196 delete [] boundingBoxes;
197 }
198 if(constrainedLayout) {
199 delete gpX;
200 delete gpY;
201 }
202 for(unsigned i=0;i<lapSize;i++) {
203 delete [] lap2[i];
204 delete [] Dij[i];
205 }
206 delete [] lap2;
207 delete [] Dij;
208 delete [] X;
209 delete [] Y;
210 }
211 bool run();
212 void straighten(vector<straightener::Edge*>&, Dim);
213 bool avoidOverlaps;
214 bool constrainedLayout;
215 private:
216 double euclidean_distance(unsigned i, unsigned j) {
217 return sqrt(
218 (X[i] - X[j]) * (X[i] - X[j]) +
219 (Y[i] - Y[j]) * (Y[i] - Y[j]));
220 }
221 double compute_stress(double **Dij);
222 void majlayout(double** Dij,GradientProjection* gp, double* coords);
223 void majlayout(double** Dij,GradientProjection* gp, double* coords,
224 double* b);
225 unsigned n; // is lapSize + dummyVars
226 unsigned lapSize; // lapSize is the number of variables for actual nodes
227 double** lap2; // graph laplacian
228 double** Q; // quadratic terms matrix used in computations
229 double** Dij;
230 double tol;
231 TestConvergence& done;
232 Rectangle** boundingBoxes;
233 double *X, *Y;
234 Clusters* clusters;
235 double edge_length;
236 LinearConstraints *linearConstraints;
237 GradientProjection *gpX, *gpY;
238 vector<straightener::Edge*>* straightenEdges;
239 };
240 }
241 #endif // COLA_H
242 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4