summaryrefslogtreecommitdiffstats
path: root/src/libavoid/region.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libavoid/region.cpp')
-rw-r--r--src/libavoid/region.cpp858
1 files changed, 0 insertions, 858 deletions
diff --git a/src/libavoid/region.cpp b/src/libavoid/region.cpp
deleted file mode 100644
index 5a46d7cbb..000000000
--- a/src/libavoid/region.cpp
+++ /dev/null
@@ -1,858 +0,0 @@
-/*
- * 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 <stdio.h>
-#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("%p - list %d add %d\n", 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("%p - list %d add %d\n", 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 %p\n", 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 %p\n", 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 %p\n", 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 %p\n", 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("%p - list %d remove %d\n", 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;
-}
-
-
-}
-