summaryrefslogtreecommitdiffstats
path: root/src/removeoverlap/generate-constraints.cpp
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/removeoverlap/generate-constraints.cpp
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/removeoverlap/generate-constraints.cpp')
-rw-r--r--src/removeoverlap/generate-constraints.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/removeoverlap/generate-constraints.cpp b/src/removeoverlap/generate-constraints.cpp
new file mode 100644
index 000000000..3238a0ca9
--- /dev/null
+++ b/src/removeoverlap/generate-constraints.cpp
@@ -0,0 +1,302 @@
+/**
+ * \brief Remove overlaps function
+ *
+ * Authors:
+ * Tim Dwyer <tgdwyer@gmail.com>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#include <set>
+#include <cassert>
+#include "generate-constraints.h"
+#include "constraint.h"
+
+#include "isnan.h" /* Include last */
+
+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;
+ }
+ ~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;
+ }
+ if (isNaN(u->pos) != isNaN(v->pos)) {
+ return isNaN(u->pos);
+ }
+ return u < v;
+
+ /* I don't know how important it is to handle NaN correctly
+ * (e.g. we probably handle it badly in other code anyway, and
+ * in any case the best we can hope for is to reduce the
+ * badness of other nodes).
+ *
+ * Nevertheless, we try to do the right thing here and in
+ * event comparison. The issue is that (on platforms with
+ * ieee floating point comparison) NaN compares neither less
+ * than nor greater than any other number, yet sort wants a
+ * well-defined ordering. In particular, we want to ensure
+ * transitivity of equivalence, which normally wouldn't be
+ * guaranteed if the "middle" item in the transitivity
+ * involves a NaN. (NaN is neither less than nor greater than
+ * other numbers, so tends to be considered as equal to all
+ * other numbers: even unequal numbers.)
+ */
+}
+
+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->pos > eb->pos) {
+ return 1;
+ } else if(ea->pos < eb->pos) {
+ return -1;
+ } else if(isNaN(ea->pos) != isNaN(ea->pos)) {
+ /* See comment in CmpNodePos. */
+ return ( isNaN(ea->pos)
+ ? -1
+ : 1 );
+ } else if(ea->v->r==ea->v->r) {
+ // when comparing opening and closing from the same rect
+ // open must come first
+ if(ea->type==Open) return -1;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Prepares variables and constraints in order to apply VPSC horizontally.
+ * 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(Rectangle *rs[], double weights[], const int n, Variable **&vars, Constraint **&cs, bool useNeighbourLists) {
+ events=new Event*[2*n];
+ int i,m,ctr=0;
+ vector<Constraint*> constraints;
+ vars=new Variable*[n];
+ for(i=0;i<n;i++) {
+ vars[i]=new Variable(i,rs[i]->getCentreX(),weights[i]);
+ 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;
+ 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 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
+ 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 variables and constraints in order to apply VPSC vertically to remove ALL overlap.
+ */
+int generateYConstraints(Rectangle *rs[], double weights[], const int n, Variable **&vars, Constraint **&cs) {
+ events=new Event*[2*n];
+ int ctr=0,i,m;
+ vector<Constraint*> constraints;
+ vars=new Variable*[n];
+ for(i=0;i<n;i++) {
+ vars[i]=new Variable(i,rs[i]->getCentreY(),weights[i]);
+ 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;
+ 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;
+}