From: erg Date: Fri, 28 Apr 2006 19:03:46 +0000 (+0000) Subject: Add the vpsc library for IPSEPCOLA features X-Git-Tag: LAST_LIBGRAPH~32^2~6668 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c25d68b93f52cb0250471adf0147f155b8bc834e;p=graphviz Add the vpsc library for IPSEPCOLA features --- diff --git a/lib/vpsc/constraint.h b/lib/vpsc/constraint.h new file mode 100644 index 000000000..00c0076de --- /dev/null +++ b/lib/vpsc/constraint.h @@ -0,0 +1,64 @@ +/** + * \brief A constraint determines a minimum or exact spacing required between + * two variables. + * + * Authors: + * Tim Dwyer + * + * 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 +#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 +#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->idright->id) return true; + return false; + } + if(l->left->idleft->id) return true; + return false; + } + return sl < sr; +} + +#endif // SEEN_REMOVEOVERLAP_CONSTRAINT_H diff --git a/lib/vpsc/csolve_VPSC.cpp b/lib/vpsc/csolve_VPSC.cpp new file mode 100644 index 000000000..c838011a9 --- /dev/null +++ b/lib/vpsc/csolve_VPSC.cpp @@ -0,0 +1,130 @@ +/** + * \brief Bridge for C programs to access solve_VPSC (which is in C++) + * + * Authors: + * Tim Dwyer + * + * 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 +#include +#include +#include +#include +#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;isatisfy(); + } 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; +} +} diff --git a/lib/vpsc/csolve_VPSC.h b/lib/vpsc/csolve_VPSC.h new file mode 100644 index 000000000..1d84382e9 --- /dev/null +++ b/lib/vpsc/csolve_VPSC.h @@ -0,0 +1,60 @@ +/** + * \brief Bridge for C programs to access solve_VPSC (which is in C++) + * + * Authors: + * Tim Dwyer + * + * 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_ */ diff --git a/lib/vpsc/generate-constraints.cpp b/lib/vpsc/generate-constraints.cpp new file mode 100644 index 000000000..a2a69fb91 --- /dev/null +++ b/lib/vpsc/generate-constraints.cpp @@ -0,0 +1,282 @@ +/** + * \brief Functions to automatically generate constraints for the rectangular + * node overlap removal problem. + * + * Authors: + * Tim Dwyer + * + * 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 +#include +#include "generate-constraints.h" +#include "constraint.h" + +using std::set; +using std::vector; + +std::ostream& operator <<(std::ostream &os, const Rectangle &r) { + os << "{"< 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;idesiredPosition=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 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;idesiredPosition=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 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 + * + * 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 + +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