Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
rectangle.cpp
Go to the documentation of this file.
1/*
2 * vim: ts=4 sw=4 et tw=0 wm=0
3 *
4 * libvpsc - A solver for the problem of Variable Placement with
5 * Separation Constraints.
6 *
7 * Copyright (C) 2005-2008 Monash University
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 * See the file LICENSE.LGPL distributed with the library.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * Author(s): Tim Dwyer
20*/
21
22/*
23 * @brief Functions to automatically generate constraints for the
24 * rectangular node overlap removal problem.
25 *
26 */
27
28#include <cmath>
29#include <set>
30#include <cstdlib>
31#include <algorithm>
32#include <cstdio>
33
34#include "libvpsc/assertions.h"
35#include "libvpsc/solve_VPSC.h"
36#include "libvpsc/rectangle.h"
37#include "libvpsc/constraint.h"
38#include "libvpsc/variable.h"
39
40using std::set;
41using std::vector;
42
43namespace vpsc {
44
45double Rectangle::xBorder = 0;
46double Rectangle::yBorder = 0;
47
48std::ostream& operator <<(std::ostream &os, const Rectangle &r) {
49 os << "Hue[0.17],Rectangle[{"<<r.getMinX()<<","<<r.getMinY()<<"},{"<<r.getMaxX()<<","<<r.getMaxY()<<"}]";
50 return os;
51}
52
53Rectangle::Rectangle(double x, double X, double y, double Y,bool allowOverlap)
54 : minX(x),
55 maxX(X),
56 minY(y),
57 maxY(Y),
58 overlap(allowOverlap)
59{
60 COLA_ASSERT(x<X);
61 COLA_ASSERT(y<Y);
62 COLA_ASSERT(getMinX()<getMaxX());
63 COLA_ASSERT(getMinY()<getMaxY());
64}
65
67 : minX(1),
68 maxX(-1),
69 minY(1),
70 maxY(-1),
71 overlap(false)
72{
73 // Creates an invalid Rectangle
74}
75
76bool Rectangle::isValid(void) const
77{
78 return ((minX <= maxX) && (minY <= maxY));
79}
80
82{
83 if (!isValid())
84 {
85 return Rectangle(rhs);
86 }
87 else if (!rhs.isValid())
88 {
89 return Rectangle(*this);
90 }
91
92 double newMaxY = std::max(rhs.getMaxY(),maxY);
93 double newMinY = std::min(rhs.getMinY(),minY);
94 double newMinX = std::min(rhs.getMinX(),minX);
95 double newMaxX = std::max(rhs.getMaxX(),maxX);
96
97 return Rectangle(newMinX, newMaxX, newMinY, newMaxY);
98}
99
100void Rectangle::reset(unsigned d, double x, double X) {
101 if(d==0) {
102 minX=x;
103 maxX=X;
104 } else {
105 minY=x;
106 maxY=X;
107 }
108}
109
110struct Node;
111struct CmpNodePos { bool operator()(const Node* u, const Node* v) const; };
112
113typedef set<Node*,CmpNodePos> NodeSet;
114
115struct Node {
116 Variable *v;
117 Rectangle *r;
118 double pos;
119 Node *firstAbove, *firstBelow;
120 NodeSet *leftNeighbours, *rightNeighbours;
121 Node(Variable *v, Rectangle *r, double p)
122 : v(v),r(r),pos(p),
123 firstAbove(nullptr), firstBelow(nullptr),
124 leftNeighbours(nullptr), rightNeighbours(nullptr)
125
126 {
127 COLA_ASSERT(r->width()<1e40);
128 }
129 ~Node() {
130 delete leftNeighbours;
131 delete rightNeighbours;
132 }
133 void addLeftNeighbour(Node *u) {
134 COLA_ASSERT(leftNeighbours!=nullptr);
135 leftNeighbours->insert(u);
136 }
137 void addRightNeighbour(Node *u) {
138 COLA_ASSERT(rightNeighbours!=nullptr);
139 rightNeighbours->insert(u);
140 }
141 void setNeighbours(NodeSet *left, NodeSet *right) {
142 leftNeighbours=left;
143 rightNeighbours=right;
144 for(NodeSet::iterator i=left->begin();i!=left->end();++i) {
145 Node *v=*(i);
146 v->addRightNeighbour(this);
147 }
148 for(NodeSet::iterator i=right->begin();i!=right->end();++i) {
149 Node *v=*(i);
150 v->addLeftNeighbour(this);
151 }
152 }
153};
154bool CmpNodePos::operator() (const Node* u, const Node* v) const {
155 COLA_ASSERT(!std::isnan(u->pos));
156 COLA_ASSERT(!std::isnan(v->pos));
157 if (u->pos < v->pos) {
158 return true;
159 }
160 if (v->pos < u->pos) {
161 return false;
162 }
163 return u < v;
164}
165
166NodeSet* getLeftNeighbours(NodeSet &scanline,Node *v) {
167 NodeSet *leftv = new NodeSet;
168 NodeSet::iterator i=scanline.find(v);
169 while(i!=scanline.begin()) {
170 Node *u=*(--i);
171 if(u->r->overlapX(v->r)<=0) {
172 leftv->insert(u);
173 return leftv;
174 }
175 if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
176 leftv->insert(u);
177 }
178 }
179 return leftv;
180}
181NodeSet* getRightNeighbours(NodeSet &scanline,Node *v) {
182 NodeSet *rightv = new NodeSet;
183 NodeSet::iterator i=scanline.find(v);
184 for(++i;i!=scanline.end(); ++i) {
185 Node *u=*(i);
186 if(u->r->overlapX(v->r)<=0) {
187 rightv->insert(u);
188 return rightv;
189 }
190 if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
191 rightv->insert(u);
192 }
193 }
194 return rightv;
195}
196
197typedef enum {Open, Close} EventType;
198struct Event {
199 EventType type;
200 Node *v;
201 double pos;
202 Event(EventType t, Node *v, double p) : type(t),v(v),pos(p) {};
203};
204int compare_events(const void *a, const void *b) {
205 Event *ea=*(Event**)a;
206 Event *eb=*(Event**)b;
207 if(ea->pos==eb->pos) {
208 // when comparing opening and closing
209 // open must come first
210 if(ea->type==Open) return -1;
211 return 1;
212 } else if(ea->pos > eb->pos) {
213 return 1;
214 } else if(ea->pos < eb->pos) {
215 return -1;
216 } else if(std::isnan(ea->pos) != std::isnan(ea->pos)) {
217 /* See comment in CmpNodePos. */
218 return ( std::isnan(ea->pos)
219 ? -1
220 : 1 );
221 }
222 return 0;
223}
224
225/*
226 * Prepares constraints in order to apply VPSC horizontally. Assumes
227 * variables have already been created.
228 * useNeighbourLists determines whether or not a heuristic is used to
229 * deciding whether to resolve all overlap in the x pass, or leave some
230 * overlaps for the y pass.
231 */
233 Constraints& cs, const bool useNeighbourLists)
234{
235 const unsigned n = rs.size();
236 COLA_ASSERT(vars.size()>=n);
237 Event **events=new Event*[2*n];
238 unsigned i,ctr=0;
239 for(i=0;i<n;i++) {
240 vars[i]->desiredPosition=rs[i]->getCentreX();
241 Node *v = new Node(vars[i],rs[i],rs[i]->getCentreX());
242 events[ctr++]=new Event(Open,v,rs[i]->getMinY());
243 events[ctr++]=new Event(Close,v,rs[i]->getMaxY());
244 }
245 qsort((Event*)events, (size_t)2*n, sizeof(Event*), compare_events );
246
247 NodeSet scanline;
248 for(i=0;i<2*n;i++) {
249 Event *e=events[i];
250 Node *v=e->v;
251 if(e->type==Open) {
252 scanline.insert(v);
253 if(useNeighbourLists) {
254 v->setNeighbours(
255 getLeftNeighbours(scanline,v),
256 getRightNeighbours(scanline,v)
257 );
258 } else {
259 NodeSet::iterator it=scanline.find(v);
260 if(it!=scanline.begin()) {
261 Node *u=*(--it);
262 v->firstAbove=u;
263 u->firstBelow=v;
264 }
265 it=scanline.find(v);
266 if(++it!=scanline.end()) {
267 Node *u=*it;
268 v->firstBelow=u;
269 u->firstAbove=v;
270 }
271 }
272 } else {
273 size_t result;
274 // Close event
275 if(useNeighbourLists) {
276 for(NodeSet::iterator i=v->leftNeighbours->begin();
277 i!=v->leftNeighbours->end();i++
278 ) {
279 Node *u=*i;
280 double sep = (v->r->width()+u->r->width())/2.0;
281 cs.push_back(new Constraint(u->v,v->v,sep));
282 result=u->rightNeighbours->erase(v);
283 COLA_ASSERT(result==1);
284 }
285
286 for(NodeSet::iterator i=v->rightNeighbours->begin();
287 i!=v->rightNeighbours->end();i++
288 ) {
289 Node *u=*i;
290 double sep = (v->r->width()+u->r->width())/2.0;
291 cs.push_back(new Constraint(v->v,u->v,sep));
292 result=u->leftNeighbours->erase(v);
293 COLA_ASSERT(result==1);
294 }
295 } else {
296 Node *l=v->firstAbove, *r=v->firstBelow;
297 if(l!=nullptr) {
298 double sep = (v->r->width()+l->r->width())/2.0;
299 cs.push_back(new Constraint(l->v,v->v,sep));
300 l->firstBelow=v->firstBelow;
301 }
302 if(r!=nullptr) {
303 double sep = (v->r->width()+r->r->width())/2.0;
304 cs.push_back(new Constraint(v->v,r->v,sep));
305 r->firstAbove=v->firstAbove;
306 }
307 }
308 result=scanline.erase(v);
309 COLA_ASSERT(result==1);
310 delete v;
311 }
312 delete e;
313 }
314 COLA_ASSERT(scanline.size()==0);
315 delete [] events;
316}
317
318/*
319 * Prepares constraints in order to apply VPSC vertically to remove ALL
320 * overlap.
321 */
323 Constraints& cs)
324{
325 const unsigned n = rs.size();
326 COLA_ASSERT(vars.size()>=n);
327 Event **events=new Event*[2*n];
328 unsigned ctr=0;
329 Rectangles::const_iterator ri=rs.begin(), re=rs.end();
330 Variables::const_iterator vi=vars.begin(), ve=vars.end();
331 for(;ri!=re&&vi!=ve;++ri,++vi) {
332 Rectangle* r=*ri;
333 Variable* v=*vi;
334 v->desiredPosition=r->getCentreY();
335 Node *node = new Node(v,r,r->getCentreY());
336 COLA_ASSERT(r->getMinX()<r->getMaxX());
337 events[ctr++]=new Event(Open,node,r->getMinX());
338 events[ctr++]=new Event(Close,node,r->getMaxX());
339 }
340 COLA_ASSERT(ri==rs.end());
341 qsort((Event*)events, (size_t)2*n, sizeof(Event*), compare_events );
342 NodeSet scanline;
343#ifndef NDEBUG
344 size_t deletes=0;
345#endif
346 for(unsigned i=0;i<2*n;i++) {
347 Event *e=events[i];
348 Node *v=e->v;
349 if(e->type==Open) {
350 scanline.insert(v);
351 NodeSet::iterator it=scanline.find(v);
352 if(it!=scanline.begin()) {
353 Node *u=*(--it);
354 v->firstAbove=u;
355 u->firstBelow=v;
356 }
357 it=scanline.find(v);
358 if(++it!=scanline.end()) {
359 Node *u=*it;
360 v->firstBelow=u;
361 u->firstAbove=v;
362 }
363 } else {
364 // Close event
365 Node *l=v->firstAbove, *r=v->firstBelow;
366 if(l!=nullptr) {
367 double sep = (v->r->height()+l->r->height())/2.0;
368 cs.push_back(new Constraint(l->v,v->v,sep));
369 l->firstBelow=v->firstBelow;
370 }
371 if(r!=nullptr) {
372 double sep = (v->r->height()+r->r->height())/2.0;
373 cs.push_back(new Constraint(v->v,r->v,sep));
374 r->firstAbove=v->firstAbove;
375 }
376#ifndef NDEBUG
377 deletes++;
378 size_t erased=
379#endif
380 scanline.erase(v);
381 COLA_ASSERT(erased==1);
382 delete v;
383 }
384 delete e;
385 }
386 COLA_ASSERT(scanline.size()==0);
387 COLA_ASSERT(deletes==n);
388 delete [] events;
389}
390#include "libvpsc/linesegment.h"
391using namespace linesegment;
394 Vector const &intersection,
396 bool &side, double &sideX, double &sideY) {
397 switch(result) {
399 ri.intersects=side=true;
400 sideX=intersection.x_;
401 sideY=intersection.y_;
404 return true;
406 ri.intersects=ri.top=ri.bottom=ri.left=ri.right=false;
407 return false;
408 }
409 return false;
410}
412lineIntersections(double x1, double y1, double x2, double y2, RectangleIntersections &ri) const {
413 Vector intersection;
414 LineSegment l(Vector(x1,y1),Vector(x2,y2));
417 l.Intersect(top,intersection),intersection,
418 ri,ri.top,ri.topX,ri.topY)) {
419 return;
420 }
423 l.Intersect(bottom,intersection),intersection,
424 ri,ri.bottom,ri.bottomX,ri.bottomY)) {
425 return;
426 }
429 l.Intersect(left,intersection),intersection,
430 ri,ri.left,ri.leftX,ri.leftY)) {
431 return;
432 }
435 l.Intersect(right,intersection),intersection,
436 ri,ri.right,ri.rightX,ri.rightY)) {
437 return;
438 }
439}
440static const double ERROR_MARGIN = 1e-4;
441inline bool eq(double a, double b) {
442 return fabs(a-b)<ERROR_MARGIN;
443 //return a==b;
444}
445/*
446bool Rectangle::inside(double x, double y) const {
447 return x>(minX+ERROR_MARGIN) && x<(maxX-ERROR_MARGIN)
448 && y>(minY+ERROR_MARGIN) && y<(maxY-ERROR_MARGIN);
449}
450*/
451// p1=(x1,y1),p2=(x2,y2) are points on the boundary. Puts the shortest
452// path round the outside of the rectangle from p1 to p2 into xs, ys.
453void Rectangle::routeAround(double x1, double y1, double x2, double y2,
454 std::vector<double> &xs, std::vector<double> &ys) {
455 COLA_ASSERT(eq(x1,minX) || eq(x1,maxX) || eq(y1,minY) || eq(y1,maxY));
456 COLA_ASSERT(eq(x2,minX) || eq(x2,maxX) || eq(y2,minY) || eq(y2,maxY));
457 xs.push_back(x1);
458 ys.push_back(y1);
459 bool top1=eq(y1,maxY), top2=eq(y2,maxY),
460 bottom1=eq(y1,minY), bottom2=eq(y2,minY);
461 bool left1=eq(x1,minX), left2=eq(x2,minX),
462 right1=eq(x1,maxX), right2=eq(x2,maxX);
463 bool leftright = (left1 && right2) || (right1 && left2);
464 bool topbottom = (top1 && bottom2) || (bottom1 && top2);
465 bool lefttop = (left1 && top2) || (top1 && left2);
466 bool righttop = (right1 && top2) || (top1 && right2);
467 bool leftbottom = (left1 && bottom2) || (bottom1 && left2);
468 bool rightbottom = (right1 && bottom2) || (bottom1 && right2);
469 if(lefttop) {
470 xs.push_back(minX);
471 ys.push_back(maxY);
472 } else if(righttop) {
473 xs.push_back(maxX);
474 ys.push_back(maxY);
475 } else if(leftbottom) {
476 xs.push_back(minX);
477 ys.push_back(minY);
478 } else if(rightbottom) {
479 xs.push_back(maxX);
480 ys.push_back(minY);
481 } else if(leftright) {
482 double midY = y1+(y2-y1)/2.0;
483 if(left1) { // left to right
484 if(midY<getCentreY()) { // route below
485 // bottom left
486 xs.push_back(getMinX());
487 ys.push_back(getMinY());
488 // bottom right
489 xs.push_back(getMaxX());
490 ys.push_back(getMinY());
491 } else { // route above
492 // top left
493 xs.push_back(getMinX());
494 ys.push_back(getMaxY());
495 // top right
496 xs.push_back(getMaxX());
497 ys.push_back(getMaxY());
498 }
499 } else { // right to left
500 if(midY<getCentreY()) { // route below
501 // bottom right
502 xs.push_back(getMaxX());
503 ys.push_back(getMinY());
504 // bottom left
505 xs.push_back(getMinX());
506 ys.push_back(getMinY());
507 } else { // route above
508 // top right
509 xs.push_back(getMaxX());
510 ys.push_back(getMaxY());
511 // top left
512 xs.push_back(getMinX());
513 ys.push_back(getMaxY());
514 }
515 }
516 } else if(topbottom) {
517 double midX = x1+(x2-x1)/2.0;
518 if(top1) {
519 if(midX<getCentreX()) { // route left
520 // top left
521 xs.push_back(getMinX());
522 ys.push_back(getMaxY());
523 // bottom left
524 xs.push_back(getMinX());
525 ys.push_back(getMinY());
526 } else { // route right
527 // top right
528 xs.push_back(getMaxX());
529 ys.push_back(getMaxY());
530 // bottom right
531 xs.push_back(getMaxX());
532 ys.push_back(getMinY());
533 }
534 } else { // bottom to top
535 if(midX<getCentreX()) { // route left
536 // bottom left
537 xs.push_back(getMinX());
538 ys.push_back(getMinY());
539 // top left
540 xs.push_back(getMinX());
541 ys.push_back(getMaxY());
542 } else { // route right
543 // bottom right
544 xs.push_back(getMaxX());
545 ys.push_back(getMinY());
546 // top right
547 xs.push_back(getMaxX());
548 ys.push_back(getMaxY());
549 }
550 }
551 }
552 xs.push_back(x2);
553 ys.push_back(y2);
554}
555
556/*
557 * moves all the rectangles to remove all overlaps. Heuristic
558 * attempts to move by as little as possible.
559 * no overlaps guaranteed.
560 * @param rs the rectangles which will be moved to remove overlap
561 */
563 const set<unsigned> fixed = set<unsigned>();
564 removeoverlaps(rs,fixed);
565}
566#define ISNOTNAN(d) (d)==(d)
567/*
568 * Moves rectangles to remove all overlaps. A heuristic
569 * attempts to move by as little as possible. The heuristic is
570 * that the overlaps are removed horizontally and then vertically,
571 * each pass being a quadratic program in which the total squared movement
572 * is minimised subject to non-overlap constraints. An optional third
573 * horizontal pass (in addition to the first horizontal pass and the second
574 * vertical pass) can be applied wherein the x-positions of rectangles are reset to their
575 * original positions and overlap removal repeated. This may avoid some
576 * unnecessary movement.
577 * @param rs the rectangles which will be moved to remove overlap
578 * @param fixed a set of indices to rectangles which should not be moved
579 * @param thirdPass optionally run the third horizontal pass described above.
580 */
581void removeoverlaps(Rectangles& rs, const set<unsigned>& fixed, bool thirdPass) {
582 const double xBorder=Rectangle::xBorder, yBorder=Rectangle::yBorder;
583 static const double EXTRA_GAP=1e-3;
584 static const size_t ARRAY_UNUSED=1;
585 unsigned n=rs.size();
586 try {
587 // The extra gap avoids numerical imprecision problems
588 Rectangle::setXBorder(xBorder+EXTRA_GAP);
589 Rectangle::setYBorder(yBorder+EXTRA_GAP);
590 Variables vs(n);
591 Variables::iterator v;
592 unsigned i=0;
593 vector<double> initX(thirdPass?n:ARRAY_UNUSED);
594 for(v=vs.begin();v!=vs.end();++v,++i) {
595 double weight=1;
596 if(fixed.find(i)!=fixed.end()) {
597 weight=10000;
598 }
599 *v=new Variable(i,0,weight);
600 if(thirdPass) {
601 initX[i]=rs[i]->getCentreX();
602 }
603 }
604 Constraints cs;
605 generateXConstraints(rs,vs,cs,true);
606 Solver vpsc_x(vs,cs);
607 vpsc_x.solve();
608 Rectangles::iterator r=rs.begin();
609 for(v=vs.begin();v!=vs.end();++v,++r) {
610 COLA_ASSERT(ISNOTNAN((*v)->finalPosition));
611 (*r)->moveCentreX((*v)->finalPosition);
612 }
613 COLA_ASSERT(r==rs.end());
614 for_each(cs.begin(),cs.end(),delete_object());
615 cs.clear();
616 // Removing the extra gap here ensures things that were moved to be
617 // adjacent to one another above are not considered overlapping
618 Rectangle::setXBorder(xBorder);
620 Solver vpsc_y(vs,cs);
621 vpsc_y.solve();
622 r=rs.begin();
623 for(v=vs.begin();v!=vs.end();++v,++r) {
624 COLA_ASSERT(ISNOTNAN((*v)->finalPosition));
625 (*r)->moveCentreY((*v)->finalPosition);
626 }
627 for_each(cs.begin(),cs.end(),delete_object());
628 cs.clear();
629 Rectangle::setYBorder(yBorder);
630 if(thirdPass) {
631 // we reset x positions to their original values
632 // and apply a third pass horizontally so that
633 // rectangles which were moved unnecessarily in the
634 // first horizontal pass (i.e. their overlap
635 // was later resolved vertically) have an
636 // opportunity now to stay put.
637 Rectangle::setXBorder(xBorder+EXTRA_GAP);
638 r=rs.begin();
639 for(v=vs.begin();v!=vs.end();++v,++r) {
640 (*r)->moveCentreX(initX[(*v)->id]);
641 }
642 generateXConstraints(rs,vs,cs,false);
643 Solver vpsc_x2(vs,cs);
644 vpsc_x2.solve();
645 r=rs.begin();
646 for(v=vs.begin();v!=vs.end();++v,++r) {
647 COLA_ASSERT(ISNOTNAN((*v)->finalPosition));
648 (*r)->moveCentreX((*v)->finalPosition);
649 }
650 }
651 Rectangle::setXBorder(xBorder);
652 for_each(cs.begin(),cs.end(),delete_object());
653 for_each(vs.begin(),vs.end(),delete_object());
654 } catch (char *str) {
655 std::cerr<<str<<std::endl;
656 for(Rectangles::iterator r=rs.begin();r!=rs.end();++r) {
657 std::cerr << **r <<std::endl;
658 }
659 }
660 COLA_ASSERT(noRectangleOverlaps(rs));
661}
662
663
665{
666 Rectangle *u, *v;
667 Rectangles::const_iterator i=rs.begin(), j, e=rs.end();
668 for (;i!=e;++i)
669 {
670 u=*i;
671 for (j=i+1;j!=e;++j)
672 {
673 v=*j;
674 if (u->overlapX(v)>0)
675 {
676 COLA_ASSERT(u->overlapY(v)==0);
677 }
678 }
679 }
680 return true;
681}
682
683// checks if line segment is strictly overlapping.
684// That is, if any point on the line is inside the rectangle.
685bool Rectangle::overlaps(double x1, double y1, double x2, double y2)
686{
688 lineIntersections(x1,y1,x2,y2,ri);
689 if(ri.intersects) {
690 if(ri.countIntersections()==1) {
691 // special case when one point is touching
692 // the boundary of the rectangle but no part
693 // of the line is interior
694 if(!inside(x1,y1)&&!inside(x2,y2)) {
695 return false;
696 }
697 }
698 printf("Rectangle/Segment intersection (SVG):\n");
699 printf("<svg style=\"stroke: black; fill: none;\">\n");
700 printf("<polyline points=\"%f,%f %f,%f\" />\n",x1,y1,x2,y2);
701 printf("<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" />\n",
702 getMinX(),getMinY(),width(),height());
703 printf("</svg>\n");
705 return true;
706 }
707 return false;
708}
709
710
712{
713 printf("intersections:\n");
714 if(top) printf(" top=%d:(%f,%f)\n",top,topX,topY);
715 if(bottom) printf(" bottom=%d:(%f,%f)\n",bottom,bottomX,bottomY);
716 if(left) printf(" left=%d:(%f,%f)\n",left,leftX,leftY);
717 if(right) printf(" right=%d:(%f,%f)\n",right,rightX,rightY);
718}
719
720// Of the stored intersections, this returns the one closest to the
721// specified point
722void RectangleIntersections::nearest(double x, double y, double &xi, double &yi) {
723 bool is[]={top, right, bottom, left};
724 double xs[]={topX, rightX, bottomX, leftX};
725 double ys[]={topY, rightY, bottomY, leftY};
726 double dx, dy, l, minl = 999999999999999.0;
727 for(unsigned i=0;i<4;i++)
728 {
729 if(is[i])
730 {
731 dx=xs[i]-x;
732 dy=ys[i]-y;
733 l=dx*dx + dy*dy;
734 if(l<minl)
735 {
736 minl=l;
737 xi=xs[i];
738 yi=ys[i];
739 }
740 }
741 }
742}
743
744}
constexpr auto is
Equivalent to the boolean value of dynamic_cast<T const *>(...).
Definition cast.h:40
IntersectResult Intersect(const LineSegment &other_line, Vector &intersection)
Definition linesegment.h:58
A constraint determines a minimum or exact spacing required between two Variable objects.
Definition constraint.h:45
A rectangle represents a fixed-size shape in the diagram that may be moved to prevent overlaps and sa...
Definition rectangle.h:78
double overlapX(Rectangle *r) const
Definition rectangle.h:185
bool overlaps(double x1, double y1, double x2, double y2)
static double yBorder
Definition rectangle.h:236
void lineIntersections(double x1, double y1, double x2, double y2, RectangleIntersections &ri) const
static void setXBorder(double x)
Definition rectangle.h:237
double getCentreY() const
Definition rectangle.h:131
static double xBorder
Definition rectangle.h:236
void reset(const unsigned d, double x, double X)
double getMaxX() const
Definition rectangle.h:108
double height() const
Definition rectangle.h:140
double getCentreX() const
Definition rectangle.h:130
Rectangle unionWith(const Rectangle &rhs) const
Definition rectangle.cpp:81
bool isValid(void) const
Definition rectangle.cpp:76
double width() const
Definition rectangle.h:139
bool inside(double x, double y) const
Definition rectangle.h:217
double getMaxY() const
Definition rectangle.h:109
void routeAround(double x1, double y1, double x2, double y2, std::vector< double > &xs, std::vector< double > &ys)
double getMinY() const
Definition rectangle.h:111
static void setYBorder(double y)
Definition rectangle.h:238
double overlapY(Rectangle *r) const
Definition rectangle.h:193
double getMinX() const
Definition rectangle.h:110
Static solver for Variable Placement with Separation Constraints problem instance.
Definition solve_VPSC.h:60
virtual bool solve()
Results in an optimum solution subject to the constraints.
A variable is comprised of an ideal position, final position and a weight.
Definition variable.h:45
vector< vpsc::Rectangle * > rs
Css & result
Inkscape::XML::Node * node
size_t v
libvpsc: Variable Placement with Separation Constraints quadratic program solver library.
NodeSet * getRightNeighbours(NodeSet &scanline, Node *v)
NodeSet * getLeftNeighbours(NodeSet &scanline, Node *v)
std::vector< vpsc::Variable * > Variables
A vector of pointers to Variable objects.
set< Node *, CmpNodePos > NodeSet
bool eq(double a, double b)
bool noRectangleOverlaps(const Rectangles &rs)
std::vector< vpsc::Constraint * > Constraints
A vector of pointers to Constraint objects.
void generateXConstraints(const Rectangles &rs, const Variables &vars, Constraints &cs, const bool useNeighbourLists)
void generateYConstraints(const Rectangles &rs, const Variables &vars, Constraints &cs)
static const double ERROR_MARGIN
std::vector< Rectangle * > Rectangles
A vector of pointers to Rectangle objects.
Definition rectangle.h:246
int compare_events(const void *a, const void *b)
bool checkIntersection(const LineSegment::IntersectResult result, Vector const &intersection, RectangleIntersections &ri, bool &side, double &sideX, double &sideY)
void removeoverlaps(Rectangles &rs)
Uses VPSC to remove overlaps between rectangles.
unsigned long weight
Definition quantize.cpp:37
void nearest(double x, double y, double &xi, double &yi)