Code

c3cdb03c00f7e59478095260e16f2657e058ad0d
[inkscape.git] / src / libcola / cola.h
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 using vpsc::Rectangle;
22 namespace cola {
23     typedef pair<unsigned, unsigned> Edge;
25     // a graph component with a list of node_ids giving indices for some larger list of nodes
26     // for the nodes in this component, and a list of edges - node indices relative to this component
27     class Component {
28     public:
29         vector<unsigned> node_ids;
30         vector<Rectangle*> rects;
31         vector<Edge> edges;
32         SimpleConstraints scx, scy;
33         ~Component();
34         void moveRectangles(double x, double y);
35         Rectangle* getBoundingBox();
36     };
37     // for a graph of n nodes, return connected components
38     void connectedComponents(
39             const vector<Rectangle*> &rs,
40             const vector<Edge> &es,
41             const SimpleConstraints &scx,
42             const SimpleConstraints &scy, 
43             vector<Component*> &components);
45     // move the contents of each component so that the components do not
46     // overlap.
47     void separateComponents(const vector<Component*> &components);
49     // defines references to three variables for which the goal function
50     // will be altered to prefer points u-b-v are in a linear arrangement
51     // such that b is placed at u+t(v-u).
52     struct LinearConstraint {
53         LinearConstraint(unsigned u, unsigned v, unsigned b, double w, 
54                 double frac_ub, double frac_bv,
55                 double* X, double* Y) 
56             : u(u),v(v),b(b),w(w),frac_ub(frac_ub),frac_bv(frac_bv),
57               tAtProjection(true) 
58         {
59             assert(frac_ub<=1.0);
60             assert(frac_bv<=1.0);
61             assert(frac_ub>=0);
62             assert(frac_bv>=0);
63             if(tAtProjection) {
64                 double uvx = X[v] - X[u],
65                        uvy = Y[v] - Y[u],
66                        vbx = X[b] - X[u],
67                        vby = Y[b] - Y[u];
68                 t = uvx * vbx + uvy * vby;
69                 t/= uvx * uvx + uvy * uvy;
70                 // p is the projection point of b on line uv
71                 //double px = scalarProj * uvx + X[u];
72                 //double py = scalarProj * uvy + Y[u];
73                 // take t=|up|/|uv|
74             } else {
75                 double numerator=X[b]-X[u];
76                 double denominator=X[v]-X[u];
77                 if(fabs(denominator)<0.001) {
78                     // if line is close to vertical then use Y coords to compute T
79                     numerator=Y[b]-Y[u];
80                     denominator=Y[v]-Y[u];
81                 }
82                 if(fabs(denominator)<0.0001) {
83                     denominator=1;
84                 }
85                 t=numerator/denominator;
86             }
87             duu=(1-t)*(1-t);
88             duv=t*(1-t);
89             dub=t-1;
90             dvv=t*t;
91             dvb=-t;
92             dbb=1;
93              //printf("New LC: t=%f\n",t); 
94         }
95         unsigned u;
96         unsigned v;
97         unsigned b;
98         double w; // weight
99         double t;
100         // 2nd partial derivatives of the goal function
101         //   (X[b] - (1-t) X[u] - t X[v])^2
102         double duu;
103         double duv;
104         double dub;
105         double dvv;
106         double dvb;
107         double dbb;
108         // Length of each segment as a fraction of the total edge length
109         double frac_ub;
110         double frac_bv;
111         bool tAtProjection;
112     };
113     typedef vector<LinearConstraint*> LinearConstraints;
114         
115         class TestConvergence {
116     public:
117         double old_stress;
118                 TestConvergence(const double& tolerance = 0.001, const unsigned maxiterations = 1000)
119                         : tolerance(tolerance),
120               maxiterations(maxiterations) { reset(); }
121         virtual ~TestConvergence() {}
123                 virtual bool operator()(double new_stress, double* X, double* Y) {
124             //std::cout<<"iteration="<<iterations<<", new_stress="<<new_stress<<std::endl;
125                         if (old_stress == DBL_MAX) {
126                                 old_stress = new_stress;
127                 if(++iterations>=maxiterations) {;
128                     return true;
129                 } else {
130                                 return false;
131                 }
132                         }
133             bool converged = 
134                 fabs(new_stress - old_stress) / (new_stress + 1e-10) < tolerance
135                 || ++iterations > maxiterations;
136             old_stress = new_stress;
137                         return converged;
138                 }
139         void reset() {
140             old_stress = DBL_MAX;
141             iterations = 0;
142         }
143         private:
144         const double tolerance;
145         const unsigned maxiterations;
146         unsigned iterations;
147         };
148     static TestConvergence defaultTest(0.0001,100);
149         class ConstrainedMajorizationLayout {
150     public:
151                 ConstrainedMajorizationLayout(
152                 vector<Rectangle*>& rs,
153                 vector<Edge>& es,
154                                 double* eweights,
155                 double idealLength,
156                                 TestConvergence& done=defaultTest)
157                         : constrainedLayout(false),
158               n(rs.size()),
159               lapSize(n), lap2(new double*[lapSize]), 
160               Q(lap2), Dij(new double*[lapSize]),
161               tol(0.0001),
162               done(done),
163               X(new double[n]),
164               Y(new double[n]),
165               clusters(NULL),
166               linearConstraints(NULL),
167               gpX(NULL),
168               gpY(NULL),
169               straightenEdges(NULL)
170         {
171             assert(rs.size()==n);
172             boundingBoxes = new Rectangle*[rs.size()];
173             copy(rs.begin(),rs.end(),boundingBoxes);
175             done.reset();
177             double** D=new double*[n];
178             for(unsigned i=0;i<n;i++) {
179                 D[i]=new double[n];
180             }
181             shortest_paths::johnsons(n,D,es,eweights);
182             edge_length = idealLength;
183             // Lij_{i!=j}=1/(Dij^2)
184             //
185             for(unsigned i = 0; i<n; i++) {
186                 X[i]=rs[i]->getCentreX();
187                 Y[i]=rs[i]->getCentreY();
188                 double degree = 0;
189                 lap2[i]=new double[n];
190                 Dij[i]=new double[n];
191                 for(unsigned j=0;j<n;j++) {
192                     double w = edge_length * D[i][j];
193                     Dij[i][j]=w;
194                     if(i==j) continue;
195                     degree+=lap2[i][j]=w>1e-30?1.f/(w*w):0;
196                 }
197                 lap2[i][i]=-degree;
198                 delete [] D[i];
199             }
200             delete [] D;
201         }
203         void moveBoundingBoxes() {
204             for(unsigned i=0;i<lapSize;i++) {
205                 boundingBoxes[i]->moveCentreX(X[i]);
206                 boundingBoxes[i]->moveCentreY(Y[i]);
207             }
208         }
210         void setupConstraints(
211                 AlignmentConstraints* acsx, AlignmentConstraints* acsy,
212                 bool avoidOverlaps, 
213                 PageBoundaryConstraints* pbcx = NULL,
214                 PageBoundaryConstraints* pbcy = NULL,
215                 SimpleConstraints* scx = NULL,
216                 SimpleConstraints* scy = NULL,
217                 Clusters* cs = NULL,
218                 vector<straightener::Edge*>* straightenEdges = NULL);
220         void addLinearConstraints(LinearConstraints* linearConstraints);
222         void setupDummyVars();
224         ~ConstrainedMajorizationLayout() {
225             if(boundingBoxes) {
226                 delete [] boundingBoxes;
227             }
228             if(constrainedLayout) {
229                 delete gpX;
230                 delete gpY;
231             }
232             for(unsigned i=0;i<lapSize;i++) {
233                 delete [] lap2[i];
234                 delete [] Dij[i];
235             }
236             delete [] lap2;
237             delete [] Dij;
238             delete [] X;
239             delete [] Y;
240         }
241                 bool run();
242         void straighten(vector<straightener::Edge*>&, Dim);
243         bool avoidOverlaps;
244         bool constrainedLayout;
245     private:
246         double euclidean_distance(unsigned i, unsigned j) {
247             return sqrt(
248                 (X[i] - X[j]) * (X[i] - X[j]) +
249                 (Y[i] - Y[j]) * (Y[i] - Y[j]));
250         }
251         double compute_stress(double **Dij);
252         void majlayout(double** Dij,GradientProjection* gp, double* coords);
253         void majlayout(double** Dij,GradientProjection* gp, double* coords, 
254                 double* b);
255         unsigned n; // is lapSize + dummyVars
256         unsigned lapSize; // lapSize is the number of variables for actual nodes
257         double** lap2; // graph laplacian
258         double** Q; // quadratic terms matrix used in computations
259         double** Dij;
260         double tol;
261                 TestConvergence& done;
262         Rectangle** boundingBoxes;
263         double *X, *Y;
264         Clusters* clusters;
265         double edge_length;
266         LinearConstraints *linearConstraints;
267         GradientProjection *gpX, *gpY;
268         vector<straightener::Edge*>* straightenEdges;
269         };
271 #endif                          // COLA_H
272 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4