summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b5e66c5)
raw | patch | inline | side by side (parent: b5e66c5)
author | mjwybrow <mjwybrow@users.sourceforge.net> | |
Fri, 14 Jul 2006 05:42:46 +0000 (05:42 +0000) | ||
committer | mjwybrow <mjwybrow@users.sourceforge.net> | |
Fri, 14 Jul 2006 05:42:46 +0000 (05:42 +0000) |
src/libavoid/region.cpp | [new file with mode: 0644] | patch | blob |
src/libavoid/region.h | [new file with mode: 0644] | patch | blob |
diff --git a/src/libavoid/region.cpp b/src/libavoid/region.cpp
--- /dev/null
+++ b/src/libavoid/region.cpp
@@ -0,0 +1,857 @@
+/*
+ * vim: ts=4 sw=4 et tw=0 wm=0
+ *
+ * libavoid - Fast, Incremental, Object-avoiding Line Router
+ * Copyright (C) 2004-2006 Michael Wybrow <mjwybrow@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#include <cstdlib>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+
+#include "libavoid/shape.h"
+#include "libavoid/region.h"
+
+
+namespace Avoid {
+
+Region *centerRegion = NULL;
+
+static const BBox screenBBox =
+ {Point(-INFINITY, -INFINITY), Point(INFINITY, INFINITY)};
+
+
+Region::Region()
+ : _bbox(screenBBox)
+ , _left(NULL), _right(NULL), _up(NULL), _down(NULL)
+{
+ _blocks.clear();
+}
+
+
+Region::Region(double x1, double y1, double x2, double y2)
+ : _left(NULL), _right(NULL), _up(NULL), _down(NULL)
+{
+ _bbox.a.x = x1;
+ _bbox.a.y = y1;
+ _bbox.b.x = x2;
+ _bbox.b.y = y2;
+
+ _blocks.clear();
+}
+
+
+static const unsigned int R_INSIDE = 0;
+static const unsigned int R_LEFT = 1;
+static const unsigned int R_LEDGE = 2;
+static const unsigned int R_RIGHT = 4;
+static const unsigned int R_REDGE = 8;
+static const unsigned int R_ABOVE = 16;
+static const unsigned int R_TEDGE = 32;
+static const unsigned int R_BELOW = 64;
+static const unsigned int R_BEDGE = 128;
+
+static const unsigned int R_NONE = R_INSIDE;
+static const unsigned int R_UP = R_ABOVE;
+static const unsigned int R_DOWN = R_BELOW;
+static const unsigned int R_HORI = R_LEFT | R_RIGHT;
+static const unsigned int R_VERT = R_UP | R_DOWN;
+
+
+static void printBBox(const char *label, const BBox &bbox)
+{
+ if (label)
+ {
+ printf("%s: ", label);
+ }
+ printf("(%.2f, %.2f)-(%.2f, %.2f)\n", bbox.a.x, bbox.a.y,
+ bbox.b.x, bbox.b.y);
+}
+
+
+bool Region::overlapCheck(BBox& bbox, unsigned int& p)
+{
+ p = R_INSIDE;
+ Point& a = bbox.a;
+ Point& b = bbox.b;
+ Point& r = _bbox.a;
+ Point& s = _bbox.b;
+
+ if (s.x <= a.x)
+ {
+ // Wholly right.
+ p = R_RIGHT;
+ return false;
+ }
+ else if (r.x >= b.x)
+ {
+ // Wholly left.
+ p = R_LEFT;
+ return false;
+ }
+
+ if (s.y <= a.y)
+ {
+ // Wholly below.
+ p = R_BELOW;
+ return false;
+ }
+ else if (r.y >= b.y)
+ {
+ // Wholly above.
+ p = R_ABOVE;
+ return false;
+ }
+
+ if (a.y == r.y)
+ {
+ // Shared top edge.
+ p |= R_TEDGE;
+ }
+ else if (a.y < r.y)
+ {
+ // Need to split above.
+ p |= R_ABOVE;
+ }
+
+ if (b.y == s.y)
+ {
+ // Shared bottom edge.
+ p |= R_BEDGE;
+ }
+ else if (b.y > s.y)
+ {
+ // Need to split below.
+ p |= R_BELOW;
+ }
+
+ if (a.x == r.x)
+ {
+ // Shared left edge.
+ p |= R_LEDGE;
+ }
+ else if (a.x < r.x)
+ {
+ // Need to split left.
+ p |= R_LEFT;
+ }
+
+ if (b.x == s.x)
+ {
+ // Shared right edge.
+ p |= R_REDGE;
+ }
+ else if (b.x > s.x)
+ {
+ // Need to split right.
+ p |= R_RIGHT;
+ }
+
+ return true;
+}
+
+
+void Region::getBBox(BBox& bb)
+{
+ bb.a = _bbox.a;
+ bb.b = _bbox.b;
+}
+
+
+Region *Region::up(void)
+{
+ return _up;
+}
+
+
+Region *Region::down(void)
+{
+ return _down;
+}
+
+
+Region *Region::left(void)
+{
+ return _left;
+}
+
+
+Region *Region::right(void)
+{
+ return _right;
+}
+
+
+bool Region::isBlock(void)
+{
+ return !(_blocks.empty());
+}
+
+
+void Region::initialSplit(BBox& bbox, unsigned int pos, unsigned int& shapeId)
+{
+ Point& n1 = bbox.a;
+ Point& n2 = bbox.b;
+ Region *newR = this;
+ Region *left, *right, *top, *bottom;
+
+ if (pos == R_INSIDE)
+ {
+ split(n2.y, R_HORI);
+ split(n2.x, R_VERT);
+ newR = split(n1.y, R_HORI);
+ newR = newR->split(n1.x, R_VERT);
+
+ printf("%X - list %d add %d\n", (int) newR,
+ (int) newR->_blocks.size(), shapeId);
+ newR->_blocks.push_back((int) shapeId);
+ newR->_blocks.sort();
+ newR->_blocks.unique();
+ }
+ else
+ {
+ Region *tar = NULL;
+ tar = newR->findRegion(n1.x, R_VERT);
+ if (pos & R_LEFT)
+ {
+ if (n1.x == tar->_bbox.a.x)
+ {
+ newR = tar->_right;
+ }
+ else if (n1.x == tar->_bbox.b.x)
+ {
+ newR = tar;
+ }
+ else
+ {
+ newR = tar->split(n1.x, R_VERT);
+ }
+ }
+ else if (!(pos & R_LEDGE))
+ {
+ newR = tar->split(n1.x, R_VERT);
+ }
+ left = newR;
+
+ tar = left->findRegion(n1.y, R_HORI);
+ if (pos & R_ABOVE)
+ {
+ if (n1.y == tar->_bbox.a.y)
+ {
+ newR = tar->_down;
+ }
+ else if (n1.y == tar->_bbox.b.y)
+ {
+ newR = tar;
+ }
+ else
+ {
+ newR = tar->split(n1.y, R_HORI);
+ }
+ }
+ else if (!(pos & R_TEDGE))
+ {
+ newR = tar->split(n1.y, R_HORI);
+ }
+ top = newR;
+
+ right = newR;
+ tar = newR->findRegion(n2.x, R_VERT);
+ if (pos & R_RIGHT)
+ {
+
+ if (n2.x == tar->_bbox.a.x)
+ {
+ right = tar->_left;
+ }
+ else if (n2.x == tar->_bbox.b.x)
+ {
+ right = tar;
+ }
+ else
+ {
+ tar->split(n2.x, R_VERT);
+ right = tar;
+ }
+ }
+ else if (!(pos & R_REDGE))
+ {
+ tar->split(n2.x, R_VERT);
+ right = tar;
+ }
+
+ bottom = right;
+ tar = right->findRegion(n2.y, R_HORI);
+ if (pos & R_BELOW)
+ {
+ if (n2.y == tar->_bbox.a.y)
+ {
+ bottom = tar->_up;
+ }
+ else if (n2.y == tar->_bbox.b.y)
+ {
+ bottom = tar;
+ }
+ else
+ {
+ tar->split(n2.y, R_HORI);
+ bottom = tar;
+ }
+ }
+ else if (!(pos & R_BEDGE))
+ {
+ tar->split(n2.y, R_HORI);
+ bottom = tar;
+ }
+
+ // top is actually top-left, and bottom is bottom-right.
+ Region *curr = top, *cptr = NULL;
+ while (curr->_bbox.b.y <= bottom->_bbox.b.y)
+ {
+ cptr = curr;
+ while (cptr->_bbox.b.x <= bottom->_bbox.b.x)
+ {
+ printf("%X - list %d add %d\n", (int) cptr,
+ (int) cptr->_blocks.size(), shapeId);
+ cptr->_blocks.push_back((int) shapeId);
+ cptr->_blocks.sort();
+ cptr->_blocks.unique();
+
+ cptr = cptr->_right;
+ }
+
+ curr = curr->_down;
+ }
+ }
+}
+
+
+// Returns the region containing the value 'pos' in the direction 'dir'.
+// Thus, if looking for the x value 55, you would pass R_VERT as 'dir'.
+// 'forMerge' specifies that the left or top block of a pair of regions
+// with the split value of 'pos' should be returned.
+Region *Region::findRegion(double pos, unsigned int dir, const bool forMerge)
+{
+ Region *curr = this;
+
+ if (dir & R_VERT)
+ {
+ while (pos > curr->_bbox.b.x)
+ {
+ curr = curr->_right;
+ }
+ while (pos < curr->_bbox.a.x)
+ {
+ curr = curr->_left;
+ }
+ if (forMerge)
+ {
+ if (pos == curr->_bbox.a.x)
+ {
+ curr = curr->_left;
+ }
+ if (pos != curr->_bbox.b.x)
+ {
+ // 'pos' is not on the boundary.
+ return NULL;
+ }
+ }
+ }
+ else if (dir & R_HORI)
+ {
+ while (pos > curr->_bbox.b.y)
+ {
+ curr = curr->_down;
+ }
+ while (pos < curr->_bbox.a.y)
+ {
+ curr = curr->_up;
+ }
+ if (forMerge)
+ {
+ if (pos == curr->_bbox.a.y)
+ {
+ curr = curr->_up;
+ }
+ if (pos != curr->_bbox.b.y)
+ {
+ // 'pos' is not on the boundary.
+ return NULL;
+ }
+ }
+ }
+ return curr;
+}
+
+
+Region *Region::split(double pos, unsigned int dir)
+{
+ Region *newR = NULL;
+ bool first = true;
+
+ if (dir & R_VERT)
+ {
+ newR = splitDir(pos, R_UP, first);
+ if (_down) _down->splitDir(pos, R_DOWN);
+ }
+ else if (dir & R_HORI)
+ {
+ newR = splitDir(pos, R_RIGHT, first);
+ if (_left) _left->splitDir(pos, R_LEFT);
+ }
+ return newR;
+}
+
+
+void Region::merge(unsigned int dir)
+{
+ bool first = true;
+
+ if (dir & R_VERT)
+ {
+ mergeDir(R_UP, first);
+ if (_down) _down->mergeDir(R_DOWN);
+ }
+ else if (dir & R_HORI)
+ {
+ mergeDir(R_RIGHT, first);
+ if (_left) _left->mergeDir(R_LEFT);
+ }
+}
+
+
+void Region::mergeRegion(Region *src)
+{
+ assert(src != NULL);
+
+ if (src == _left)
+ {
+ pairHor(src->_left, this);
+ _bbox.a.x = src->_bbox.a.x;
+ }
+ else if (src == _right)
+ {
+ pairHor(this, src->_right);
+ _bbox.b.x = src->_bbox.b.x;
+ }
+ else if (src == _up)
+ {
+ pairVer(src->_up, this);
+ _bbox.a.y = src->_bbox.a.y;
+ }
+ else if (src == _down)
+ {
+ pairVer(this, src->_down);
+ _bbox.b.y = src->_bbox.b.y;
+ }
+ else
+ {
+ fprintf(stderr, "Error: Avoid::Region::merge(): "
+ "Argument not adjoining region.\n");
+ abort();
+ }
+ mergeAttributes(src);
+ printf("DEL %X\n", (int) src);
+ delete src;
+}
+
+
+Region *Region::splitDir(double pos, unsigned int dir, bool first)
+{
+ Point& o1 = _bbox.a;
+ Point& o2 = _bbox.b;
+
+ Region *newR = NULL;
+
+ if (dir & R_VERT)
+ {
+ assert(pos > _bbox.a.x);
+ assert(pos < _bbox.b.x);
+
+ // Vertical recursion:
+
+ // Create new block.
+ Region *r = new Region(pos, o1.y, o2.x, o2.y);
+ printf("NEW %X\n", (int) r);
+ r->copyAttributes(this);
+
+ Region *o_up = _up;
+ Region *o_down = _down;
+
+ // Resize old block.
+ o2.x = pos;
+
+ pairHor(r, _right);
+ pairHor(this, r);
+
+ if (dir & R_UP)
+ {
+ if (!first) pairVer(r, _down->_right);
+
+ if (o_up) o_up->splitDir(pos, R_UP);
+ }
+ else if (dir & R_DOWN)
+ {
+ if (!first) pairVer(_up->_right, r);
+
+ if (o_down) o_down->splitDir(pos, R_DOWN);
+ }
+ newR = r;
+ }
+ else if (dir & R_HORI)
+ {
+ // Vertical recursion:
+
+ // Create new block.
+ Region *b = new Region(o1.x, pos, o2.x, o2.y);
+ printf("NEW %X\n", (int) b);
+ b->copyAttributes(this);
+
+ Region *o_left = _left;
+ Region *o_right = _right;
+
+ // Resize old block.
+ o2.y = pos;
+
+ pairVer(b, _down);
+ pairVer(this, b);
+
+ if (dir & R_LEFT)
+ {
+ if (!first) pairHor(b, _right->_down);
+
+ if (o_left) o_left->splitDir(pos, R_LEFT);
+ }
+ else if (dir & R_RIGHT)
+ {
+ if (!first) pairHor(_left->_down, b);
+
+ if (o_right) o_right->splitDir(pos, R_RIGHT);
+ }
+ newR = b;
+ }
+ return newR;
+}
+
+
+void Region::mergeDir(unsigned int dir, bool first)
+{
+ if (dir & R_VERT)
+ {
+ assert(_right != NULL);
+
+ mergeRegion(_right);
+
+ if (dir & R_UP)
+ {
+ if (_up) _up->mergeDir(dir, R_UP);
+ }
+ else if (dir & R_DOWN)
+ {
+ if (_down) _down->mergeDir(dir, R_DOWN);
+ }
+ }
+ else if (dir & R_HORI)
+ {
+ assert(_down != NULL);
+
+ mergeRegion(_down);
+
+ if (dir & R_LEFT)
+ {
+ if (_left) _left->mergeDir(dir, R_LEFT);
+ }
+ else if (dir & R_RIGHT)
+ {
+ if (_right) _right->mergeDir(dir, R_RIGHT);
+ }
+ }
+}
+
+
+void Region::copyAttributes(Region *src)
+{
+ _blocks = src->_blocks;
+}
+
+
+void Region::mergeAttributes(Region *src)
+{
+ _blocks.merge(src->_blocks);
+ _blocks.sort();
+ _blocks.unique();
+}
+
+
+//---------------------------
+// Static member functions:
+
+
+void Region::pairHor(Region *l, Region *r)
+{
+ if (l) l->_right = r;
+ if (r) r->_left = l;
+}
+
+
+void Region::pairVer(Region *a, Region *b)
+{
+ if (a) a->_down = b;
+ if (b) b->_up = a;
+}
+
+
+void Region::addShape(ShapeRef *shape)
+{
+ if (!centerRegion)
+ {
+ // Add new default region.
+ centerRegion = new Region();
+ printf("NEW %X\n", (int) centerRegion);
+ }
+ BBox bbox;
+ // Get bounding box for added shape.
+ shape->boundingBox(bbox);
+ printBBox("Add", bbox);
+
+ unsigned int shapeId = shape->id();
+
+ // Find starting point for overlap
+ Region *curr = centerRegion;
+ unsigned int pos = R_INSIDE;
+ while (!(curr->overlapCheck(bbox, pos)))
+ {
+ if (pos & R_LEFT)
+ {
+ curr = curr->_left;
+ }
+ else if (pos & R_RIGHT)
+ {
+ curr = curr->_right;
+ }
+ else if (pos & R_ABOVE)
+ {
+ curr = curr->_up;
+ }
+ else if (pos & R_BELOW)
+ {
+ curr = curr->_down;
+ }
+ }
+
+ curr->initialSplit(bbox, pos, shapeId);
+ centerRegion = curr;
+}
+
+
+void Region::removeShape(ShapeRef *shape)
+{
+ const bool forMerge = true;
+
+ BBox bbox;
+ // Get bounding box for added shape.
+ shape->boundingBox(bbox);
+ printBBox("Remove", bbox);
+
+ unsigned int shapeId = shape->id();
+
+ Region *aboveTop = centerRegion->findRegion(bbox.a.y, R_HORI, forMerge);
+ Region *aboveBottom = aboveTop->findRegion(bbox.b.y, R_HORI, forMerge);
+ Region *leftOfLeft = aboveBottom->findRegion(bbox.a.x, R_VERT, forMerge);
+ Region *leftOfRight = leftOfLeft->findRegion(bbox.b.x, R_VERT, forMerge);
+
+ assert(aboveTop != NULL);
+ assert(aboveBottom != NULL);
+ assert(leftOfLeft != NULL);
+ assert(leftOfRight != NULL);
+
+ // Find Top Left.
+ Region *topLeft = leftOfLeft->_right;
+ while (topLeft->_bbox.a.y != aboveTop->_bbox.b.y)
+ {
+ topLeft = topLeft->_up;
+ }
+
+ // Find Bottom Right.
+ Region *botRight = leftOfRight;
+ while (botRight->_bbox.b.y != aboveBottom->_bbox.b.y)
+ {
+ botRight = botRight->_down;
+ }
+
+ // Clear blocking flag.
+ Region *curr = topLeft, *cptr = NULL;
+ while (curr->_bbox.b.y <= botRight->_bbox.b.y)
+ {
+ cptr = curr;
+ while (cptr->_bbox.b.x <= botRight->_bbox.b.x)
+ {
+ ShapeList& blocks = cptr->_blocks;
+
+ assert(std::find(blocks.begin(), blocks.end(), (int) shapeId) !=
+ blocks.end());
+ printf("%X - list %d remove %d\n", (int) cptr,
+ (int) blocks.size(), shapeId);
+ cptr->_blocks.remove((int) shapeId);
+
+ cptr = cptr->_right;
+ }
+
+ curr = curr->_down;
+ }
+
+ // These two are safe since they don't invalidate the pointers
+ // to the regions that are inside the shape.
+ if (aboveBottom->safeToMerge(R_HORI))
+ {
+ aboveBottom->merge(R_HORI);
+ }
+ if (leftOfRight->safeToMerge(R_VERT))
+ {
+ leftOfRight->merge(R_VERT);
+ }
+
+ // Be a bit more careful with these.
+ double leftX = leftOfLeft->_bbox.b.x;
+ if (aboveTop->safeToMerge(R_HORI))
+ {
+ aboveTop->merge(R_HORI);
+ }
+ // leftOfLeft may have been freed, so look for the new block at
+ // that position.
+ leftOfLeft = aboveTop->findRegion(leftX, R_VERT, forMerge);
+ assert(leftOfLeft);
+ if (leftOfLeft->safeToMerge(R_VERT))
+ {
+ leftOfLeft->merge(R_VERT);
+ }
+}
+
+
+bool Region::safeToMerge(unsigned int dir)
+{
+ bool unsafe = false;
+
+ if (dir == R_HORI)
+ {
+ printf("safeToMerge? y = %.3f... ", _bbox.b.y);
+ unsafe |= unsafeToMerge(R_RIGHT);
+ if (_left) unsafe |= _left->unsafeToMerge(R_LEFT);
+ }
+ else if (dir == R_VERT)
+ {
+ printf("safeToMerge? x = %.3f... ", _bbox.b.x);
+ unsafe |= unsafeToMerge(R_DOWN);
+ if (_up) unsafe |= _up->unsafeToMerge(R_UP);
+ }
+ printf("%s.\n", (unsafe) ? "no" : "yes");
+
+ return !unsafe;
+}
+
+
+bool Region::unsafeToMerge(unsigned int dir)
+{
+ bool unsafe = false;
+
+ if (dir & R_HORI)
+ {
+ // If they are not the same on both sides then we can merge.
+ if (_blocks != _down->_blocks)
+ {
+ printf("\n _blocks:\n ");
+ for (ShapeList::iterator i = _blocks.begin(); i != _blocks.end();
+ ++i)
+ {
+ printf("%d ", *i);
+ }
+ printf("\n _down->_blocks:\n ");
+ for (ShapeList::iterator i = _down->_blocks.begin();
+ i != _down->_blocks.end(); ++i)
+ {
+ printf("%d ", *i);
+ }
+ unsafe |= true;
+ printf("\n");
+ }
+
+ if ((dir == R_LEFT) && _left)
+ {
+ unsafe |= _left->unsafeToMerge(dir);
+ }
+ else if ((dir == R_RIGHT) && _right)
+ {
+ unsafe |= _right->unsafeToMerge(dir);
+ }
+ }
+ else if (dir & R_VERT)
+ {
+ if (_blocks != _right->_blocks)
+ {
+ printf("\n _blocks:\n ");
+ for (ShapeList::iterator i = _blocks.begin(); i != _blocks.end();
+ ++i)
+ {
+ printf("%d ", *i);
+ }
+ printf("\n _right->_blocks:\n ");
+ for (ShapeList::iterator i = _right->_blocks.begin();
+ i != _right->_blocks.end(); ++i)
+ {
+ printf("%d ", *i);
+ }
+ unsafe |= true;
+ printf("\n");
+ }
+
+ if ((dir == R_UP) && _up)
+ {
+ unsafe |= _up->unsafeToMerge(dir);
+ }
+ else if ((dir == R_DOWN) && _down)
+ {
+ unsafe |= _down->unsafeToMerge(dir);
+ }
+ }
+ return unsafe;
+
+}
+
+
+Region *Region::getTopLeftRegion(void)
+{
+ Region *curr = centerRegion;
+
+ while (curr && (curr->_up || curr->_left))
+ {
+ if (curr->_up)
+ {
+ curr = curr->_up;
+ }
+ else
+ {
+ curr = curr->_left;
+ }
+ }
+ return curr;
+}
+
+
+}
+
diff --git a/src/libavoid/region.h b/src/libavoid/region.h
--- /dev/null
+++ b/src/libavoid/region.h
@@ -0,0 +1,79 @@
+/*
+ * vim: ts=4 sw=4 et tw=0 wm=0
+ *
+ * libavoid - Fast, Incremental, Object-avoiding Line Router
+ * Copyright (C) 2004-2006 Michael Wybrow <mjwybrow@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#ifndef AVOID_REGION_H
+#define AVOID_REGION_H
+
+
+namespace Avoid {
+
+class ShapeRef;
+
+typedef std::list<int> ShapeList;
+
+
+class Region
+{
+ public:
+ Region();
+ Region(double x1, double y1, double x2, double y2);
+
+ bool overlapCheck(BBox& bbox, unsigned int& p);
+ void getBBox(BBox& bb);
+ Region *up(void);
+ Region *down(void);
+ Region *left(void);
+ Region *right(void);
+ void initialSplit(BBox& bbox, unsigned int pos, unsigned int& shapeId);
+ bool isBlock(void);
+
+ static void pairHor(Region *l, Region *r);
+ static void pairVer(Region *a, Region *b);
+ static void addShape(ShapeRef *shape);
+ static void removeShape(ShapeRef *shape);
+ static Region *getTopLeftRegion(void);
+
+ private:
+ BBox _bbox;
+ Region *_left;
+ Region *_right;
+ Region *_up;
+ Region *_down;
+ ShapeList _blocks;
+
+ Region *split(double pos, unsigned int dir);
+ void merge(unsigned int dir);
+ void mergeRegion(Region *src);
+ Region *findRegion(double pos, unsigned int dir,
+ const bool forMerge = false);
+ Region *splitDir(double pos, unsigned int dir, bool first = false);
+ void mergeDir(unsigned int dir, bool first = false);
+ void copyAttributes(Region *src);
+ void mergeAttributes(Region *src);
+ bool safeToMerge(unsigned int dir);
+ bool unsafeToMerge(unsigned int dir);
+};
+
+
+}
+
+#endif