48std::ostream& operator <<(std::ostream &os,
const Rectangle &r) {
97 return Rectangle(newMinX, newMaxX, newMinY, newMaxY);
111struct CmpNodePos {
bool operator()(
const Node* u,
const Node* v)
const; };
119 Node *firstAbove, *firstBelow;
120 NodeSet *leftNeighbours, *rightNeighbours;
123 firstAbove(
nullptr), firstBelow(
nullptr),
124 leftNeighbours(
nullptr), rightNeighbours(
nullptr)
127 COLA_ASSERT(r->
width()<1e40);
130 delete leftNeighbours;
131 delete rightNeighbours;
133 void addLeftNeighbour(Node *u) {
134 COLA_ASSERT(leftNeighbours!=
nullptr);
135 leftNeighbours->insert(u);
137 void addRightNeighbour(Node *u) {
138 COLA_ASSERT(rightNeighbours!=
nullptr);
139 rightNeighbours->insert(u);
143 rightNeighbours=right;
144 for(NodeSet::iterator i=left->begin();i!=left->end();++i) {
146 v->addRightNeighbour(
this);
148 for(NodeSet::iterator i=right->begin();i!=right->end();++i) {
150 v->addLeftNeighbour(
this);
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) {
160 if (
v->pos < u->pos) {
168 NodeSet::iterator i=scanline.find(v);
169 while(i!=scanline.begin()) {
171 if(u->r->overlapX(v->r)<=0) {
175 if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
183 NodeSet::iterator i=scanline.find(v);
184 for(++i;i!=scanline.end(); ++i) {
186 if(u->r->overlapX(v->r)<=0) {
190 if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
202 Event(
EventType t, Node *v,
double p) : type(t),v(v),pos(p) {};
205 Event *ea=*(Event**)a;
206 Event *eb=*(Event**)b;
207 if(ea->pos==eb->pos) {
210 if(ea->type==
Open)
return -1;
212 }
else if(ea->pos > eb->pos) {
214 }
else if(ea->pos < eb->pos) {
216 }
else if(std::isnan(ea->pos) != std::isnan(ea->pos)) {
218 return ( std::isnan(ea->pos)
235 const unsigned n =
rs.size();
236 COLA_ASSERT(vars.size()>=n);
237 Event **events=
new Event*[2*n];
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());
245 qsort((Event*)events, (
size_t)2*n,
sizeof(Event*),
compare_events );
253 if(useNeighbourLists) {
259 NodeSet::iterator it=scanline.find(v);
260 if(it!=scanline.begin()) {
266 if(++it!=scanline.end()) {
275 if(useNeighbourLists) {
276 for(NodeSet::iterator i=v->leftNeighbours->begin();
277 i!=v->leftNeighbours->end();i++
280 double sep = (v->r->width()+u->r->width())/2.0;
282 result=u->rightNeighbours->erase(v);
286 for(NodeSet::iterator i=v->rightNeighbours->begin();
287 i!=v->rightNeighbours->end();i++
290 double sep = (v->r->width()+u->r->width())/2.0;
292 result=u->leftNeighbours->erase(v);
296 Node *l=v->firstAbove, *r=v->firstBelow;
298 double sep = (v->r->width()+l->r->width())/2.0;
300 l->firstBelow=v->firstBelow;
303 double sep = (v->r->width()+r->r->width())/2.0;
305 r->firstAbove=v->firstAbove;
314 COLA_ASSERT(scanline.size()==0);
325 const unsigned n =
rs.size();
326 COLA_ASSERT(vars.size()>=n);
327 Event **events=
new Event*[2*n];
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) {
340 COLA_ASSERT(ri==
rs.end());
341 qsort((Event*)events, (
size_t)2*n,
sizeof(Event*),
compare_events );
346 for(
unsigned i=0;i<2*n;i++) {
351 NodeSet::iterator it=scanline.find(v);
352 if(it!=scanline.begin()) {
358 if(++it!=scanline.end()) {
365 Node *l=v->firstAbove, *r=v->firstBelow;
367 double sep = (v->r->height()+l->r->height())/2.0;
369 l->firstBelow=v->firstBelow;
372 double sep = (v->r->height()+r->r->height())/2.0;
374 r->firstAbove=v->firstAbove;
381 COLA_ASSERT(erased==1);
386 COLA_ASSERT(scanline.size()==0);
387 COLA_ASSERT(deletes==n);
394 Vector const &intersection,
396 bool &side,
double &sideX,
double &sideY) {
400 sideX=intersection.x_;
401 sideY=intersection.y_;
417 l.
Intersect(top,intersection),intersection,
423 l.
Intersect(bottom,intersection),intersection,
429 l.
Intersect(left,intersection),intersection,
435 l.
Intersect(right,intersection),intersection,
441inline bool eq(
double a,
double b) {
454 std::vector<double> &xs, std::vector<double> &ys) {
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);
472 }
else if(righttop) {
475 }
else if(leftbottom) {
478 }
else if(rightbottom) {
481 }
else if(leftright) {
482 double midY = y1+(y2-y1)/2.0;
516 }
else if(topbottom) {
517 double midX = x1+(x2-x1)/2.0;
563 const set<unsigned> fixed = set<unsigned>();
566#define ISNOTNAN(d) (d)==(d)
583 static const double EXTRA_GAP=1e-3;
584 static const size_t ARRAY_UNUSED=1;
585 unsigned n=
rs.size();
591 Variables::iterator v;
593 vector<double> initX(thirdPass?n:ARRAY_UNUSED);
594 for(v=vs.begin();v!=vs.end();++v,++i) {
596 if(fixed.find(i)!=fixed.end()) {
601 initX[i]=
rs[i]->getCentreX();
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);
613 COLA_ASSERT(r==
rs.end());
623 for(v=vs.begin();v!=vs.end();++v,++r) {
624 COLA_ASSERT(ISNOTNAN((*v)->finalPosition));
625 (*r)->moveCentreY((*v)->finalPosition);
639 for(v=vs.begin();v!=vs.end();++v,++r) {
640 (*r)->moveCentreX(initX[(*v)->id]);
646 for(v=vs.begin();v!=vs.end();++v,++r) {
647 COLA_ASSERT(ISNOTNAN((*v)->finalPosition));
648 (*r)->moveCentreX((*v)->finalPosition);
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;
667 Rectangles::const_iterator i=
rs.begin(), j, e=
rs.end();
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",
713 printf(
"intersections:\n");
726 double dx, dy, l, minl = 999999999999999.0;
727 for(
unsigned i=0;i<4;i++)
constexpr auto is
Equivalent to the boolean value of dynamic_cast<T const *>(...).
IntersectResult Intersect(const LineSegment &other_line, Vector &intersection)
A constraint determines a minimum or exact spacing required between two Variable objects.
A rectangle represents a fixed-size shape in the diagram that may be moved to prevent overlaps and sa...
double overlapX(Rectangle *r) const
bool overlaps(double x1, double y1, double x2, double y2)
void lineIntersections(double x1, double y1, double x2, double y2, RectangleIntersections &ri) const
static void setXBorder(double x)
double getCentreY() const
void reset(const unsigned d, double x, double X)
double getCentreX() const
Rectangle unionWith(const Rectangle &rhs) const
bool inside(double x, double y) const
void routeAround(double x1, double y1, double x2, double y2, std::vector< double > &xs, std::vector< double > &ys)
static void setYBorder(double y)
double overlapY(Rectangle *r) const
Static solver for Variable Placement with Separation Constraints problem instance.
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.
vector< vpsc::Rectangle * > rs
Inkscape::XML::Node * node
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.
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.
void printIntersections(void)
void nearest(double x, double y, double &xi, double &yi)