--- /dev/null
+/**
+ * \brief A constraint determines a minimum or exact spacing required between
+ * two variables.
+ *
+ * Authors:
+ * Tim Dwyer <tgdwyer@gmail.com>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * This version is released under the CPL (Common Public License) with
+ * the Graphviz distribution.
+ * A version is also available under the LGPL as part of the Adaptagrams
+ * project: http://sourceforge.net/projects/adaptagrams.
+ * If you make improvements or bug fixes to this code it would be much
+ * appreciated if you could also contribute those changes back to the
+ * Adaptagrams repository.
+ */
+
+#ifndef SEEN_REMOVEOVERLAP_CONSTRAINT_H
+#define SEEN_REMOVEOVERLAP_CONSTRAINT_H
+
+#include <iostream>
+#include "variable.h"
+
+class Constraint
+{
+ friend std::ostream& operator <<(std::ostream &os,const Constraint &c);
+public:
+ Variable *left;
+ Variable *right;
+ double gap;
+ double lm;
+ Constraint(Variable *left, Variable *right, double gap, bool equality=false);
+ ~Constraint();
+ inline double Constraint::slack() const { return right->position() - gap - left->position(); }
+ long timeStamp;
+ bool active;
+ bool visited;
+ bool equality;
+};
+#include <float.h>
+#include "block.h"
+static inline bool compareConstraints(Constraint *const &l, Constraint *const &r) {
+ double const sl =
+ l->left->block->timeStamp > l->timeStamp
+ ||l->left->block==l->right->block
+ ?-DBL_MAX:l->slack();
+ double const sr =
+ r->left->block->timeStamp > r->timeStamp
+ ||r->left->block==r->right->block
+ ?-DBL_MAX:r->slack();
+ if(sl==sr) {
+ // arbitrary choice based on id
+ if(l->left->id==r->left->id) {
+ if(l->right->id<r->right->id) return true;
+ return false;
+ }
+ if(l->left->id<r->left->id) return true;
+ return false;
+ }
+ return sl < sr;
+}
+
+#endif // SEEN_REMOVEOVERLAP_CONSTRAINT_H
--- /dev/null
+/**
+ * \brief Bridge for C programs to access solve_VPSC (which is in C++)
+ *
+ * Authors:
+ * Tim Dwyer <tgdwyer@gmail.com>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * This version is released under the CPL (Common Public License) with
+ * the Graphviz distribution.
+ * A version is also available under the LGPL as part of the Adaptagrams
+ * project: http://sourceforge.net/projects/adaptagrams.
+ * If you make improvements or bug fixes to this code it would be much
+ * appreciated if you could also contribute those changes back to the
+ * Adaptagrams repository.
+ */
+
+#include <iostream>
+#include <variable.h>
+#include <constraint.h>
+#include <generate-constraints.h>
+#include <solve_VPSC.h>
+#include "csolve_VPSC.h"
+extern "C" {
+Variable* newVariable(int id, double desiredPos, double weight) {
+ return new Variable(id,desiredPos,weight);
+}
+Constraint* newConstraint(Variable* left, Variable* right, double gap) {
+ return new Constraint(left,right,gap);
+}
+VPSC* newVPSC(int n, Variable* vs[], int m, Constraint* cs[]) {
+ return new VPSC(n,vs,m,cs);
+}
+VPSC* newIncVPSC(int n, Variable* vs[], int m, Constraint* cs[]) {
+ return (VPSC*)new IncVPSC(n,vs,m,cs);
+}
+
+int genXConstraints(int n, boxf* bb, Variable** vs, Constraint*** cs,int transitiveClosure) {
+ Rectangle* rs[n];
+ for(int i=0;i<n;i++) {
+ rs[i]=new Rectangle(bb[i].LL.x,bb[i].UR.x,bb[i].LL.y,bb[i].UR.y);
+ }
+ int m = generateXConstraints(n,rs,vs,*cs,transitiveClosure);
+ for(int i=0;i<n;i++) {
+ delete rs[i];
+ }
+ return m;
+}
+int genYConstraints(int n, boxf* bb, Variable** vs, Constraint*** cs) {
+ Rectangle* rs[n];
+ for(int i=0;i<n;i++) {
+ rs[i]=new Rectangle(bb[i].LL.x,bb[i].UR.x,bb[i].LL.y,bb[i].UR.y);
+ }
+ int m = generateYConstraints(n,rs,vs,*cs);
+ for(int i=0;i<n;i++) {
+ delete rs[i];
+ }
+ return m;
+}
+
+Constraint** newConstraints(int m) {
+ return new Constraint*[m];
+}
+void deleteConstraints(int m, Constraint **cs) {
+ for(int i=0;i<m;i++) {
+ delete cs[i];
+ }
+ delete [] cs;
+}
+void deleteConstraint(Constraint* c) {
+ delete c;
+}
+void deleteVariable(Variable* v) {
+ delete v;
+}
+void satisfyVPSC(VPSC* vpsc) {
+ try {
+ vpsc->satisfy();
+ } catch(const char *e) {
+ std::cerr << e << std::endl;
+ exit(1);
+ }
+}
+int getSplitCnt(IncVPSC *vpsc) {
+ return vpsc->splitCnt;
+}
+void deleteVPSC(VPSC *vpsc) {
+ assert(vpsc!=NULL);
+ delete vpsc;
+}
+void solveVPSC(VPSC* vpsc) {
+ vpsc->solve();
+}
+void splitIncVPSC(IncVPSC* vpsc) {
+ vpsc->splitBlocks();
+}
+void setVariableDesiredPos(Variable *v, double desiredPos) {
+ v->desiredPosition = desiredPos;
+}
+double getVariablePos(Variable *v) {
+ return v->position();
+}
+void remapInConstraints(Variable *u, Variable *v, double dgap) {
+ for(Constraints::iterator i=u->in.begin();i!=u->in.end();i++) {
+ Constraint* c=*i;
+ c->right=v;
+ c->gap+=dgap;
+ v->in.push_back(c);
+ }
+ u->in.clear();
+}
+void remapOutConstraints(Variable *u, Variable *v, double dgap) {
+ for(Constraints::iterator i=u->out.begin();i!=u->out.end();i++) {
+ Constraint* c=*i;
+ c->left=v;
+ c->gap+=dgap;
+ v->out.push_back(c);
+ }
+ u->out.clear();
+}
+int getLeftVarID(Constraint *c) {
+ return c->left->id;
+}
+int getRightVarID(Constraint *c){
+ return c->right->id;
+}
+double getSeparation(Constraint *c){
+ return c->gap;
+}
+}
--- /dev/null
+/**
+ * \brief Bridge for C programs to access solve_VPSC (which is in C++)
+ *
+ * Authors:
+ * Tim Dwyer <tgdwyer@gmail.com>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * This version is released under the CPL (Common Public License) with
+ * the Graphviz distribution.
+ * A version is also available under the LGPL as part of the Adaptagrams
+ * project: http://sourceforge.net/projects/adaptagrams.
+ * If you make improvements or bug fixes to this code it would be much
+ * appreciated if you could also contribute those changes back to the
+ * Adaptagrams repository.
+ */
+#ifndef _CSOLVE_VPSC_H_
+#define _CSOLVE_VPSC_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef struct Variable Variable;
+Variable* newVariable(int id, double desiredPos, double weight);
+void setVariableDesiredPos(Variable *, double desiredPos);
+double getVariablePos(Variable*);
+
+typedef struct Constraint Constraint;
+Constraint* newConstraint(Variable* left, Variable* right, double gap);
+
+typedef struct VPSC VPSC;
+VPSC* newVPSC(int n, Variable* vs[], int m, Constraint* cs[]);
+void deleteVPSC(VPSC*);
+void deleteConstraint(Constraint*);
+void deleteVariable(Variable*);
+Constraint** newConstraints(int m);
+void deleteConstraints(int m,Constraint**);
+void remapInConstraints(Variable *u, Variable *v, double dgap);
+void remapOutConstraints(Variable *u, Variable *v, double dgap);
+int getLeftVarID(Constraint *c);
+int getRightVarID(Constraint *c);
+double getSeparation(Constraint *c);
+
+#ifndef HAVE_POINTF_S
+typedef struct pointf_s { double x, y; } pointf;
+typedef struct { pointf LL, UR; } boxf;
+#endif
+int genXConstraints(int n, boxf[], Variable** vs, Constraint*** cs,
+ int transitiveClosure);
+int genYConstraints(int n, boxf[], Variable** vs, Constraint*** cs);
+
+void satisfyVPSC(VPSC*);
+void solveVPSC(VPSC*);
+typedef struct IncVPSC IncVPSC;
+VPSC* newIncVPSC(int n, Variable* vs[], int m, Constraint* cs[]);
+void splitIncVPSC(IncVPSC*);
+int getSplitCnt(IncVPSC *vpsc);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _CSOLVE_VPSC_H_ */
--- /dev/null
+/**
+ * \brief Functions to automatically generate constraints for the rectangular
+ * node overlap removal problem.
+ *
+ * Authors:
+ * Tim Dwyer <tgdwyer@gmail.com>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * This version is released under the CPL (Common Public License) with
+ * the Graphviz distribution.
+ * A version is also available under the LGPL as part of the Adaptagrams
+ * project: http://sourceforge.net/projects/adaptagrams.
+ * If you make improvements or bug fixes to this code it would be much
+ * appreciated if you could also contribute those changes back to the
+ * Adaptagrams repository.
+ */
+
+#include <set>
+#include <cassert>
+#include "generate-constraints.h"
+#include "constraint.h"
+
+using std::set;
+using std::vector;
+
+std::ostream& operator <<(std::ostream &os, const Rectangle &r) {
+ os << "{"<<r.minX<<","<<r.maxX<<","<<r.minY<<","<<r.maxY<<"},";
+ return os;
+}
+Rectangle::Rectangle(double x, double X, double y, double Y)
+: minX(x),maxX(X),minY(y),maxY(Y) {
+ assert(x<=X);
+ assert(y<=Y);
+}
+
+struct Node;
+struct CmpNodePos { bool operator()(const Node* u, const Node* v) const; };
+
+typedef set<Node*,CmpNodePos> NodeSet;
+
+struct Node {
+ Variable *v;
+ Rectangle *r;
+ double pos;
+ Node *firstAbove, *firstBelow;
+ NodeSet *leftNeighbours, *rightNeighbours;
+ Node(Variable *v, Rectangle *r, double p) : v(v),r(r),pos(p) {
+ firstAbove=firstBelow=NULL;
+ leftNeighbours=rightNeighbours=NULL;
+ assert(r->width()<1e40);
+ }
+ ~Node() {
+ delete leftNeighbours;
+ delete rightNeighbours;
+ }
+ void addLeftNeighbour(Node *u) {
+ leftNeighbours->insert(u);
+ }
+ void addRightNeighbour(Node *u) {
+ rightNeighbours->insert(u);
+ }
+ void setNeighbours(NodeSet *left, NodeSet *right) {
+ leftNeighbours=left;
+ rightNeighbours=right;
+ for(NodeSet::iterator i=left->begin();i!=left->end();i++) {
+ Node *v=*(i);
+ v->addRightNeighbour(this);
+ }
+ for(NodeSet::iterator i=right->begin();i!=right->end();i++) {
+ Node *v=*(i);
+ v->addLeftNeighbour(this);
+ }
+ }
+};
+bool CmpNodePos::operator() (const Node* u, const Node* v) const {
+ if (u->pos < v->pos) {
+ return true;
+ }
+ if (v->pos < u->pos) {
+ return false;
+ }
+ return u < v;
+}
+
+NodeSet* getLeftNeighbours(NodeSet &scanline,Node *v) {
+ NodeSet *leftv = new NodeSet;
+ NodeSet::iterator i=scanline.find(v);
+ while(i--!=scanline.begin()) {
+ Node *u=*(i);
+ if(u->r->overlapX(v->r)<=0) {
+ leftv->insert(u);
+ return leftv;
+ }
+ if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
+ leftv->insert(u);
+ }
+ }
+ return leftv;
+}
+NodeSet* getRightNeighbours(NodeSet &scanline,Node *v) {
+ NodeSet *rightv = new NodeSet;
+ NodeSet::iterator i=scanline.find(v);
+ for(i++;i!=scanline.end(); i++) {
+ Node *u=*(i);
+ if(u->r->overlapX(v->r)<=0) {
+ rightv->insert(u);
+ return rightv;
+ }
+ if(u->r->overlapX(v->r)<=u->r->overlapY(v->r)) {
+ rightv->insert(u);
+ }
+ }
+ return rightv;
+}
+
+typedef enum {Open, Close} EventType;
+struct Event {
+ EventType type;
+ Node *v;
+ double pos;
+ Event(EventType t, Node *v, double p) : type(t),v(v),pos(p) {};
+};
+Event **events;
+int compare_events(const void *a, const void *b) {
+ Event *ea=*(Event**)a;
+ Event *eb=*(Event**)b;
+ if(ea->v->r==eb->v->r) {
+ // when comparing opening and closing from the same rect
+ // open must come first
+ if(ea->type==Open) return -1;
+ return 1;
+ } else if(ea->pos > eb->pos) {
+ return 1;
+ } else if(ea->pos < eb->pos) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Prepares constraints in order to apply VPSC horizontally. Assumes variables have already been created.
+ * useNeighbourLists determines whether or not a heuristic is used to deciding whether to resolve
+ * all overlap in the x pass, or leave some overlaps for the y pass.
+ */
+int generateXConstraints(const int n, Rectangle** rs, Variable** vars, Constraint** &cs, const bool useNeighbourLists) {
+ events=new Event*[2*n];
+ int i,m,ctr=0;
+ for(i=0;i<n;i++) {
+ vars[i]->desiredPosition=rs[i]->getCentreX();
+ Node *v = new Node(vars[i],rs[i],rs[i]->getCentreX());
+ events[ctr++]=new Event(Open,v,rs[i]->getMinY());
+ events[ctr++]=new Event(Close,v,rs[i]->getMaxY());
+ }
+ qsort((Event*)events, (size_t)2*n, sizeof(Event*), compare_events );
+
+ NodeSet scanline;
+ vector<Constraint*> constraints;
+ for(i=0;i<2*n;i++) {
+ Event *e=events[i];
+ Node *v=e->v;
+ if(e->type==Open) {
+ scanline.insert(v);
+ if(useNeighbourLists) {
+ v->setNeighbours(
+ getLeftNeighbours(scanline,v),
+ getRightNeighbours(scanline,v)
+ );
+ } else {
+ NodeSet::iterator it=scanline.find(v);
+ if(it--!=scanline.begin()) {
+ Node *u=*it;
+ v->firstAbove=u;
+ u->firstBelow=v;
+ }
+ it=scanline.find(v);
+ if(++it!=scanline.end()) {
+ Node *u=*it;
+ v->firstBelow=u;
+ u->firstAbove=v;
+ }
+ }
+ } else {
+ // Close event
+ int r;
+ if(useNeighbourLists) {
+ for(NodeSet::iterator i=v->leftNeighbours->begin();
+ i!=v->leftNeighbours->end();i++
+ ) {
+ Node *u=*i;
+ double sep = (v->r->width()+u->r->width())/2.0;
+ constraints.push_back(new Constraint(u->v,v->v,sep));
+ r=u->rightNeighbours->erase(v);
+ }
+
+ for(NodeSet::iterator i=v->rightNeighbours->begin();
+ i!=v->rightNeighbours->end();i++
+ ) {
+ Node *u=*i;
+ double sep = (v->r->width()+u->r->width())/2.0;
+ constraints.push_back(new Constraint(v->v,u->v,sep));
+ r=u->leftNeighbours->erase(v);
+ }
+ } else {
+ Node *l=v->firstAbove, *r=v->firstBelow;
+ if(l!=NULL) {
+ double sep = (v->r->width()+l->r->width())/2.0;
+ constraints.push_back(new Constraint(l->v,v->v,sep));
+ l->firstBelow=v->firstBelow;
+ }
+ if(r!=NULL) {
+ double sep = (v->r->width()+r->r->width())/2.0;
+ constraints.push_back(new Constraint(v->v,r->v,sep));
+ r->firstAbove=v->firstAbove;
+ }
+ }
+ r=scanline.erase(v);
+ delete v;
+ }
+ delete e;
+ }
+ delete [] events;
+ cs=new Constraint*[m=constraints.size()];
+ for(i=0;i<m;i++) cs[i]=constraints[i];
+ return m;
+}
+
+/**
+ * Prepares constraints in order to apply VPSC vertically to remove ALL overlap.
+ */
+int generateYConstraints(const int n, Rectangle** rs, Variable** vars, Constraint** &cs) {
+ events=new Event*[2*n];
+ int ctr=0,i,m;
+ for(i=0;i<n;i++) {
+ vars[i]->desiredPosition=rs[i]->getCentreY();
+ Node *v = new Node(vars[i],rs[i],rs[i]->getCentreY());
+ events[ctr++]=new Event(Open,v,rs[i]->getMinX());
+ events[ctr++]=new Event(Close,v,rs[i]->getMaxX());
+ }
+ qsort((Event*)events, (size_t)2*n, sizeof(Event*), compare_events );
+ NodeSet scanline;
+ vector<Constraint*> constraints;
+ for(i=0;i<2*n;i++) {
+ Event *e=events[i];
+ Node *v=e->v;
+ if(e->type==Open) {
+ scanline.insert(v);
+ NodeSet::iterator i=scanline.find(v);
+ if(i--!=scanline.begin()) {
+ Node *u=*i;
+ v->firstAbove=u;
+ u->firstBelow=v;
+ }
+ i=scanline.find(v);
+ if(++i!=scanline.end()) {
+ Node *u=*i;
+ v->firstBelow=u;
+ u->firstAbove=v;
+ }
+ } else {
+ // Close event
+ Node *l=v->firstAbove, *r=v->firstBelow;
+ if(l!=NULL) {
+ double sep = (v->r->height()+l->r->height())/2.0;
+ constraints.push_back(new Constraint(l->v,v->v,sep));
+ l->firstBelow=v->firstBelow;
+ }
+ if(r!=NULL) {
+ double sep = (v->r->height()+r->r->height())/2.0;
+ constraints.push_back(new Constraint(v->v,r->v,sep));
+ r->firstAbove=v->firstAbove;
+ }
+ scanline.erase(v);
+ delete v;
+ }
+ delete e;
+ }
+ delete [] events;
+ cs=new Constraint*[m=constraints.size()];
+ for(i=0;i<m;i++) cs[i]=constraints[i];
+ return m;
+}
--- /dev/null
+/**
+ * \brief Functions to automatically generate constraints for the rectangular
+ * node overlap removal problem.
+ *
+ * Authors:
+ * Tim Dwyer <tgdwyer@gmail.com>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * This version is released under the CPL (Common Public License) with
+ * the Graphviz distribution.
+ * A version is also available under the LGPL as part of the Adaptagrams
+ * project: http://sourceforge.net/projects/adaptagrams.
+ * If you make improvements or bug fixes to this code it would be much
+ * appreciated if you could also contribute those changes back to the
+ * Adaptagrams repository.
+ */
+#ifndef SEEN_REMOVEOVERLAP_GENERATE_CONSTRAINTS_H
+#define SEEN_REMOVEOVERLAP_GENERATE_CONSTRAINTS_H
+#include <iostream>
+
+class Rectangle {
+ friend std::ostream& operator <<(std::ostream &os, const Rectangle &r);
+public:
+ static double xBorder,yBorder;
+ Rectangle(double x, double X, double y, double Y);
+ double getMaxX() const { return maxX+xBorder; }
+ double getMaxY() const { return maxY+yBorder; }
+ double getMinX() const { return minX; }
+ double getMinY() const { return minY; }
+ double getMinD(unsigned const d) const {
+ return ( d == 0 ? getMinX() : getMinY() );
+ }
+ double getMaxD(unsigned const d) const {
+ return ( d == 0 ? getMaxX() : getMaxY() );
+ }
+ double getCentreX() const { return minX+width()/2.0; }
+ double getCentreY() const { return minY+height()/2.0; }
+ double width() const { return getMaxX()-minX; }
+ double height() const { return getMaxY()-minY; }
+ static void setXBorder(double x) {xBorder=x;}
+ static void setYBorder(double y) {yBorder=y;}
+ void moveCentreX(double x) {
+ moveMinX(x-width()/2.0);
+ }
+ void moveCentreY(double y) {
+ moveMinY(y-height()/2.0);
+ }
+ void moveMinX(double x) {
+ maxX=x+width()-xBorder;
+ minX=x;
+ }
+ void moveMinY(double y) {
+ maxY=y+height()-yBorder;
+ minY=y;
+ }
+ inline double overlapX(Rectangle *r) const {
+ if (getCentreX() <= r->getCentreX() && r->minX < getMaxX())
+ return getMaxX() - r->minX;
+ if (r->getCentreX() <= getCentreX() && minX < r->getMaxX())
+ return r->getMaxX() - minX;
+ return 0;
+ }
+ inline double overlapY(Rectangle *r) const {
+ if (getCentreY() <= r->getCentreY() && r->minY < getMaxY())
+ return getMaxY() - r->minY;
+ if (r->getCentreY() <= getCentreY() && minY < r->getMaxY())
+ return r->getMaxY() - minY;
+ return 0;
+ }
+private:
+ double minX,maxX,minY,maxY;
+};
+
+
+class Variable;
+class Constraint;
+
+// returns number of constraints generated
+int generateXConstraints(const int n, Rectangle** rs, Variable** vars, Constraint** &cs, const bool useNeighbourLists);
+int generateYConstraints(const int n, Rectangle** rs, Variable** vars, Constraint** &cs);
+
+
+#endif // SEEN_REMOVEOVERLAP_GENERATE_CONSTRAINTS_H