2
* \brief Functions to automatically generate constraints for the
3
* rectangular node overlap removal problem.
6
* Tim Dwyer <tgdwyer@gmail.com>
8
* Copyright (C) 2005 Authors
10
* Released under GNU LGPL. Read the file 'COPYING' for more information.
16
#include "generate-constraints.h"
17
#include "constraint.h"
19
#include "2geom/isnan.h" /* Include last */
25
std::ostream& operator <<(std::ostream &os, const Rectangle &r) {
26
os << "{"<<r.minX<<","<<r.maxX<<","<<r.minY<<","<<r.maxY<<"},";
30
Rectangle::Rectangle(double x, double X, double y, double Y)
31
: minX(x),maxX(X),minY(y),maxY(Y) {
37
struct CmpNodePos { bool operator()(const Node* u, const Node* v) const; };
39
typedef set<Node*,CmpNodePos> NodeSet;
45
Node *firstAbove, *firstBelow;
46
NodeSet *leftNeighbours, *rightNeighbours;
47
Node(Variable *v, Rectangle *r, double p) : v(v),r(r),pos(p) {
48
firstAbove=firstBelow=NULL;
49
leftNeighbours=rightNeighbours=NULL;
50
assert(r->width()<1e40);
53
delete leftNeighbours;
54
delete rightNeighbours;
56
void addLeftNeighbour(Node *u) {
57
leftNeighbours->insert(u);
59
void addRightNeighbour(Node *u) {
60
rightNeighbours->insert(u);
62
void setNeighbours(NodeSet *left, NodeSet *right) {
64
rightNeighbours=right;
65
for(NodeSet::iterator i=left->begin();i!=left->end();++i) {
67
v->addRightNeighbour(this);
69
for(NodeSet::iterator i=right->begin();i!=right->end();++i) {
71
v->addLeftNeighbour(this);
75
bool CmpNodePos::operator() (const Node* u, const Node* v) const {
76
if (u->pos < v->pos) {
79
if (v->pos < u->pos) {
82
if (IS_NAN(u->pos) != IS_NAN(v->pos)) {
83
return IS_NAN(u->pos);
87
/* I don't know how important it is to handle NaN correctly
88
* (e.g. we probably handle it badly in other code anyway, and
89
* in any case the best we can hope for is to reduce the
90
* badness of other nodes).
92
* Nevertheless, we try to do the right thing here and in
93
* event comparison. The issue is that (on platforms with
94
* ieee floating point comparison) NaN compares neither less
95
* than nor greater than any other number, yet sort wants a
96
* well-defined ordering. In particular, we want to ensure
97
* transitivity of equivalence, which normally wouldn't be
98
* guaranteed if the "middle" item in the transitivity
99
* involves a NaN. (NaN is neither less than nor greater than
100
* other numbers, so tends to be considered as equal to all
101
* other numbers: even unequal numbers.)
105
NodeSet* getLeftNeighbours(NodeSet &scanline,Node *v) {
106
NodeSet *leftv = new NodeSet;
107
NodeSet::iterator i=scanline.find(v);
108
while(i--!=scanline.begin()) {
110
if(u->r->overlapX(v->r)<=0) {
114
if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
120
NodeSet* getRightNeighbours(NodeSet &scanline,Node *v) {
121
NodeSet *rightv = new NodeSet;
122
NodeSet::iterator i=scanline.find(v);
123
for(++i;i!=scanline.end(); ++i) {
125
if(u->r->overlapX(v->r)<=0) {
129
if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
136
typedef enum {Open, Close} EventType;
141
Event(EventType t, Node *v, double p) : type(t),v(v),pos(p) {};
144
int compare_events(const void *a, const void *b) {
145
Event *ea=*(Event**)a;
146
Event *eb=*(Event**)b;
147
if(ea->v->r==eb->v->r) {
148
// when comparing opening and closing from the same rect
149
// open must come first
150
if(ea->type==Open) return -1;
152
} else if(ea->pos > eb->pos) {
154
} else if(ea->pos < eb->pos) {
156
} else if(IS_NAN(ea->pos) != IS_NAN(ea->pos)) {
157
/* See comment in CmpNodePos. */
158
return ( IS_NAN(ea->pos)
166
* Prepares constraints in order to apply VPSC horizontally. Assumes variables have already been created.
167
* useNeighbourLists determines whether or not a heuristic is used to deciding whether to resolve
168
* all overlap in the x pass, or leave some overlaps for the y pass.
170
int generateXConstraints(const int n, Rectangle** rs, Variable** vars, Constraint** &cs, const bool useNeighbourLists) {
171
events=new Event*[2*n];
174
vars[i]->desiredPosition=rs[i]->getCentreX();
175
Node *v = new Node(vars[i],rs[i],rs[i]->getCentreX());
176
events[ctr++]=new Event(Open,v,rs[i]->getMinY());
177
events[ctr++]=new Event(Close,v,rs[i]->getMaxY());
179
qsort((Event*)events, (size_t)2*n, sizeof(Event*), compare_events );
182
vector<Constraint*> constraints;
188
if(useNeighbourLists) {
190
getLeftNeighbours(scanline,v),
191
getRightNeighbours(scanline,v)
194
NodeSet::iterator it=scanline.find(v);
195
if(it--!=scanline.begin()) {
201
if(++it!=scanline.end()) {
210
if(useNeighbourLists) {
211
for(NodeSet::iterator i=v->leftNeighbours->begin();
212
i!=v->leftNeighbours->end();i++
215
double sep = (v->r->width()+u->r->width())/2.0;
216
constraints.push_back(new Constraint(u->v,v->v,sep));
217
r=u->rightNeighbours->erase(v);
220
for(NodeSet::iterator i=v->rightNeighbours->begin();
221
i!=v->rightNeighbours->end();i++
224
double sep = (v->r->width()+u->r->width())/2.0;
225
constraints.push_back(new Constraint(v->v,u->v,sep));
226
r=u->leftNeighbours->erase(v);
229
Node *l=v->firstAbove, *r=v->firstBelow;
231
double sep = (v->r->width()+l->r->width())/2.0;
232
constraints.push_back(new Constraint(l->v,v->v,sep));
233
l->firstBelow=v->firstBelow;
236
double sep = (v->r->width()+r->r->width())/2.0;
237
constraints.push_back(new Constraint(v->v,r->v,sep));
238
r->firstAbove=v->firstAbove;
247
cs=new Constraint*[m=constraints.size()];
248
for(i=0;i<m;i++) cs[i]=constraints[i];
253
* Prepares constraints in order to apply VPSC vertically to remove ALL overlap.
255
int generateYConstraints(const int n, Rectangle** rs, Variable** vars, Constraint** &cs) {
256
events=new Event*[2*n];
259
vars[i]->desiredPosition=rs[i]->getCentreY();
260
Node *v = new Node(vars[i],rs[i],rs[i]->getCentreY());
261
events[ctr++]=new Event(Open,v,rs[i]->getMinX());
262
events[ctr++]=new Event(Close,v,rs[i]->getMaxX());
264
qsort((Event*)events, (size_t)2*n, sizeof(Event*), compare_events );
266
vector<Constraint*> constraints;
272
NodeSet::iterator i=scanline.find(v);
273
if(i--!=scanline.begin()) {
279
if(++i!=scanline.end()) {
286
Node *l=v->firstAbove, *r=v->firstBelow;
288
double sep = (v->r->height()+l->r->height())/2.0;
289
constraints.push_back(new Constraint(l->v,v->v,sep));
290
l->firstBelow=v->firstBelow;
293
double sep = (v->r->height()+r->r->height())/2.0;
294
constraints.push_back(new Constraint(v->v,r->v,sep));
295
r->firstAbove=v->firstAbove;
303
cs=new Constraint*[m=constraints.size()];
304
for(i=0;i<m;i++) cs[i]=constraints[i];