Graphviz 12.1.0~dev.20240716.1117
Loading...
Searching...
No Matches
generate-constraints.cpp
Go to the documentation of this file.
1
19#include <algorithm>
20#include <set>
21#include <cassert>
22#include <cstdlib>
23#include <memory>
24#include <vector>
26#include <vpsc/constraint.h>
27
28using std::set;
29using std::vector;
30
31std::ostream& operator <<(std::ostream &os, const Rectangle &r) {
32 os << "{"<<r.minX<<","<<r.maxX<<","<<r.minY<<","<<r.maxY<<"},";
33 return os;
34}
35Rectangle::Rectangle(double x, double X, double y, double Y)
36: minX(x),maxX(X),minY(y),maxY(Y) {
37 assert(x<=X);
38 assert(y<=Y);
39}
40
41namespace {
42struct Node;
43struct CmpNodePos { bool operator()(const Node* u, const Node* v) const; };
44
45typedef set<Node*,CmpNodePos> NodeSet;
46
47struct Node {
48 Variable *v;
49 const Rectangle &r;
50 double pos;
51 Node *firstAbove, *firstBelow;
52 NodeSet leftNeighbours, rightNeighbours;
53 Node(Variable *v, const Rectangle &r, double p) : v(v),r(r),pos(p) {
54 firstAbove=firstBelow=nullptr;
55 assert(r.width()<1e40);
56 }
57 void addLeftNeighbour(Node *u) {
58 leftNeighbours.insert(u);
59 }
60 void addRightNeighbour(Node *u) {
61 rightNeighbours.insert(u);
62 }
63 void setNeighbours(const NodeSet &left, const NodeSet &right) {
64 leftNeighbours=left;
65 rightNeighbours=right;
66 for(Node *n : left) {
67 n->addRightNeighbour(this);
68 }
69 for(Node *n : right) {
70 n->addLeftNeighbour(this);
71 }
72 }
73};
74bool CmpNodePos::operator() (const Node* u, const Node* v) const {
75 if (u->pos < v->pos) {
76 return true;
77 }
78 if (v->pos < u->pos) {
79 return false;
80 }
81 return u < v;
82}
83}
84
85static NodeSet getLeftNeighbours(NodeSet &scanline,Node *v) {
86 NodeSet leftv;
87 NodeSet::iterator i=scanline.find(v);
88 while(i!=scanline.begin()) {
89 Node *u=*(--i);
90 if(u->r.overlapX(v->r)<=0) {
91 leftv.insert(u);
92 return leftv;
93 }
94 if(u->r.overlapX(v->r)<=u->r.overlapY(v->r)) {
95 leftv.insert(u);
96 }
97 }
98 return leftv;
99}
100static NodeSet getRightNeighbours(NodeSet &scanline,Node *v) {
101 NodeSet rightv;
102 NodeSet::iterator i=scanline.find(v);
103 for(i++;i!=scanline.end(); i++) {
104 Node *u=*(i);
105 if(u->r.overlapX(v->r)<=0) {
106 rightv.insert(u);
107 return rightv;
108 }
109 if(u->r.overlapX(v->r)<=u->r.overlapY(v->r)) {
110 rightv.insert(u);
111 }
112 }
113 return rightv;
114}
115
116typedef enum {Open, Close} EventType;
117struct Event {
119 std::shared_ptr<Node> v;
120 double pos;
121 Event(EventType t, const std::shared_ptr<Node> &v, double p)
122 : type(t),v(v),pos(p) {};
123};
124
125static bool compare_events(const Event &ea, const Event &eb) {
126 if(&ea.v->r==&eb.v->r) {
127 // when comparing opening and closing from the same rect
128 // open must come first
129 if(ea.type == Open && eb.type != Open) return true;
130 return false;
131 } else if(ea.pos > eb.pos) {
132 return false;
133 } else if(ea.pos < eb.pos) {
134 return true;
135 }
136 return false;
137}
138
144int generateXConstraints(const vector<Rectangle> &rs, Variable** vars,
145 Constraint** &cs, const bool useNeighbourLists) {
146
147 vector<Event> events;
148 events.reserve(2 * rs.size());
149 for(size_t i=0;i<rs.size();i++) {
150 vars[i]->desiredPosition=rs[i].getCentreX();
151 auto v = std::make_shared<Node>(vars[i],rs[i],rs[i].getCentreX());
152 events.emplace_back(Open,v,rs[i].getMinY());
153 events.emplace_back(Close,v,rs[i].getMaxY());
154 }
155 std::sort(events.begin(), events.end(), compare_events);
156
157 NodeSet scanline;
158 vector<Constraint*> constraints;
159 for(Event &e : events) {
160 Node *v = e.v.get();
161 if(e.type==Open) {
162 scanline.insert(v);
163 if(useNeighbourLists) {
164 v->setNeighbours(
165 getLeftNeighbours(scanline,v),
166 getRightNeighbours(scanline,v)
167 );
168 } else {
169 NodeSet::iterator it=scanline.find(v);
170 if(it!=scanline.begin()) {
171 Node *u=*--it;
172 v->firstAbove=u;
173 u->firstBelow=v;
174 }
175 it=scanline.find(v);
176 if(++it!=scanline.end()) {
177 Node *u=*it;
178 v->firstBelow=u;
179 u->firstAbove=v;
180 }
181 }
182 } else {
183 // Close event
184 if(useNeighbourLists) {
185 for(Node *u : v->leftNeighbours) {
186 double sep = (v->r.width()+u->r.width())/2.0;
187 constraints.push_back(new Constraint(u->v,v->v,sep));
188 u->rightNeighbours.erase(v);
189 }
190
191 for(Node *u : v->rightNeighbours) {
192 double sep = (v->r.width()+u->r.width())/2.0;
193 constraints.push_back(new Constraint(v->v,u->v,sep));
194 u->leftNeighbours.erase(v);
195 }
196 } else {
197 Node *l=v->firstAbove, *r=v->firstBelow;
198 if(l!=nullptr) {
199 double sep = (v->r.width()+l->r.width())/2.0;
200 constraints.push_back(new Constraint(l->v,v->v,sep));
201 l->firstBelow=v->firstBelow;
202 }
203 if(r!=nullptr) {
204 double sep = (v->r.width()+r->r.width())/2.0;
205 constraints.push_back(new Constraint(v->v,r->v,sep));
206 r->firstAbove=v->firstAbove;
207 }
208 }
209 scanline.erase(v);
210 }
211 }
212 int m =constraints.size();
213 cs=new Constraint*[m];
214 for(int i=0;i<m;i++) cs[i]=constraints[i];
215 return m;
216}
217
221int generateYConstraints(const vector<Rectangle> &rs, Variable** vars,
222 Constraint** &cs) {
223
224 vector<Event> events;
225 events.reserve(2 * rs.size());
226 for(size_t i=0;i<rs.size();i++) {
227 vars[i]->desiredPosition=rs[i].getCentreY();
228 auto v = std::make_shared<Node>(vars[i],rs[i],rs[i].getCentreY());
229 events.emplace_back(Open,v,rs[i].getMinX());
230 events.emplace_back(Close,v,rs[i].getMaxX());
231 }
232 std::sort(events.begin(), events.end(), compare_events);
233 NodeSet scanline;
234 vector<Constraint*> constraints;
235 for(Event &e : events) {
236 Node *v = e.v.get();
237 if(e.type==Open) {
238 scanline.insert(v);
239 NodeSet::iterator i=scanline.find(v);
240 if(i!=scanline.begin()) {
241 Node *u=*--i;
242 v->firstAbove=u;
243 u->firstBelow=v;
244 }
245 i=scanline.find(v);
246 if(++i!=scanline.end()) {
247 Node *u=*i;
248 v->firstBelow=u;
249 u->firstAbove=v;
250 }
251 } else {
252 // Close event
253 Node *l=v->firstAbove, *r=v->firstBelow;
254 if(l!=nullptr) {
255 double sep = (v->r.height()+l->r.height())/2.0;
256 constraints.push_back(new Constraint(l->v,v->v,sep));
257 l->firstBelow=v->firstBelow;
258 }
259 if(r!=nullptr) {
260 double sep = (v->r.height()+r->r.height())/2.0;
261 constraints.push_back(new Constraint(v->v,r->v,sep));
262 r->firstAbove=v->firstAbove;
263 }
264 scanline.erase(v);
265 }
266 }
267 int m =constraints.size();
268 cs=new Constraint*[m];
269 for(int i=0;i<m;i++) cs[i]=constraints[i];
270 return m;
271}
Functions to automatically generate constraints for the rectangular node overlap removal problem.
double width() const
Rectangle(double x, double X, double y, double Y)
double height() const
#define right(i)
Definition closest.c:77
#define left
Definition dthdr.h:12
#define Y(i)
Definition gdefs.h:3
#define X(prefix, name, str, type, subtype,...)
Definition gdefs.h:14
static NodeSet getRightNeighbours(NodeSet &scanline, Node *v)
static NodeSet getLeftNeighbours(NodeSet &scanline, Node *v)
static bool compare_events(const Event &ea, const Event &eb)
int generateYConstraints(const vector< Rectangle > &rs, Variable **vars, Constraint **&cs)
int generateXConstraints(const vector< Rectangle > &rs, Variable **vars, Constraint **&cs, const bool useNeighbourLists)
std::ostream & operator<<(std::ostream &os, const Rectangle &r)
A constraint determines a minimum or exact spacing required between two variables.
Definition constraint.h:25
std::shared_ptr< Node > v
Event(EventType t, const std::shared_ptr< Node > &v, double p)
Definition node.h:24
double desiredPosition
Definition variable.h:30