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