diff options
Diffstat (limited to 'src/libavoid/connector.cpp')
| -rw-r--r-- | src/libavoid/connector.cpp | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/src/libavoid/connector.cpp b/src/libavoid/connector.cpp new file mode 100644 index 000000000..cde387c5b --- /dev/null +++ b/src/libavoid/connector.cpp @@ -0,0 +1,408 @@ +/* + * vim: ts=4 sw=4 et tw=0 wm=0 + * + * libavoid - Fast, Incremental, Object-avoiding Line Router + * Copyright (C) 2004-2005 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 "libavoid/graph.h" +#include "libavoid/makepath.h" +#include "libavoid/visibility.h" +#include "libavoid/debug.h" + + +namespace Avoid { + + +ConnRefList connRefs; + + +ConnRef::ConnRef(const uint id) + : _id(id) + , _needs_reroute_flag(true) + , _false_path(false) + , _active(false) + , _route_dist(0) + , _srcVert(NULL) + , _dstVert(NULL) + , _initialised(false) + , _callback(NULL) + , _connector(NULL) +{ + // TODO: Store endpoints and details. + _route.pn = 0; + _route.ps = NULL; +} + + +ConnRef::ConnRef(const uint id, const Point& src, const Point& dst) + : _id(id) + , _needs_reroute_flag(true) + , _false_path(false) + , _active(false) + , _route_dist(0) + , _srcVert(NULL) + , _dstVert(NULL) + , _initialised(false) + , _callback(NULL) + , _connector(NULL) +{ + _route.pn = 0; + _route.ps = NULL; + + if (IncludeEndpoints) + { + bool isShape = false; + _srcVert = new VertInf(VertID(id, isShape, 1), src); + _dstVert = new VertInf(VertID(id, isShape, 2), dst); + vertices.addVertex(_srcVert); + vertices.addVertex(_dstVert); + makeActive(); + _initialised = true; + } +} + + +ConnRef::~ConnRef() +{ + freeRoute(); + + if (_srcVert) + { + vertices.removeVertex(_srcVert); + delete _srcVert; + _srcVert = NULL; + } + + if (_dstVert) + { + vertices.removeVertex(_dstVert); + delete _dstVert; + _dstVert = NULL; + } + + if (_active) + { + makeInactive(); + } +} + +void ConnRef::updateEndPoint(const uint type, const Point& point) +{ + assert((type == (uint) VertID::src) || (type == (uint) VertID::tar)); + //assert(IncludeEndpoints); + + VertInf *altered = NULL; + VertInf *partner = NULL; + bool isShape = false; + + if (type == (uint) VertID::src) + { + if (_srcVert) + { + _srcVert->Reset(point); + } + else + { + _srcVert = new VertInf(VertID(_id, isShape, type), point); + vertices.addVertex(_srcVert); + } + + altered = _srcVert; + partner = _dstVert; + } + else // if (type == (uint) VertID::dst) + { + if (_dstVert) + { + _dstVert->Reset(point); + } + else + { + _dstVert = new VertInf(VertID(_id, isShape, type), point); + vertices.addVertex(_dstVert); + } + + altered = _dstVert; + partner = _srcVert; + } + + bool knownNew = false; + vertexVisibility(altered, partner, knownNew, true); +} + + +void ConnRef::makeActive(void) +{ + assert(!_active); + + // Add to connRefs list. + _pos = connRefs.insert(connRefs.begin(), this); + _active = true; +} + + +void ConnRef::makeInactive(void) +{ + assert(_active); + + // Remove from connRefs list. + connRefs.erase(_pos); + _active = false; +} + + +void ConnRef::freeRoute(void) +{ + if (_route.ps) + { + _route.pn = 0; + std::free(_route.ps); + _route.ps = NULL; + } +} + + +PolyLine& ConnRef::route(void) +{ + return _route; +} + + +void ConnRef::calcRouteDist(void) +{ + _route_dist = 0; + for (int i = 1; i < _route.pn; i++) + { + _route_dist += dist(_route.ps[i], _route.ps[i - 1]); + } +} + + +bool ConnRef::needsReroute(void) +{ + return (_false_path || _needs_reroute_flag); +} + + +void ConnRef::moveRoute(const int& diff_x, const int& diff_y) +{ + for (int i = 0; i < _route.pn; i++) + { + _route.ps[i].x += diff_x; + _route.ps[i].y += diff_y; + } +} + + +void ConnRef::lateSetup(const Point& src, const Point& dst) +{ + assert(!_initialised); + + bool isShape = false; + _srcVert = new VertInf(VertID(_id, isShape, 1), src); + _dstVert = new VertInf(VertID(_id, isShape, 2), dst); + vertices.addVertex(_srcVert); + vertices.addVertex(_dstVert); + makeActive(); + _initialised = true; +} + + +VertInf *ConnRef::src(void) +{ + return _srcVert; +} + + +VertInf *ConnRef::dst(void) +{ + return _dstVert; +} + + +bool ConnRef::isInitialised(void) +{ + return _initialised; +} + + +void ConnRef::unInitialise(void) +{ + vertices.removeVertex(_srcVert); + vertices.removeVertex(_dstVert); + makeInactive(); + _initialised = false; +} + + +void ConnRef::removeFromGraph(void) +{ + for (VertInf *iter = _srcVert; iter != NULL; ) + { + VertInf *tmp = iter; + iter = (iter == _srcVert) ? _dstVert : NULL; + + // For each vertex. + EdgeInfList& visList = tmp->visList; + EdgeInfList::iterator finish = visList.end(); + EdgeInfList::iterator edge; + while ((edge = visList.begin()) != finish) + { + // Remove each visibility edge + delete (*edge); + } + + EdgeInfList& invisList = tmp->invisList; + finish = invisList.end(); + while ((edge = invisList.begin()) != finish) + { + // Remove each invisibility edge + delete (*edge); + } + } +} + + +void ConnRef::setCallback(void (*cb)(void *), void *ptr) +{ + _callback = cb; + _connector = ptr; +} + + +void ConnRef::handleInvalid(void) +{ + if (_false_path || _needs_reroute_flag) { + if (_callback) { + _callback(_connector); + } + } +} + + +void ConnRef::makePathInvalid(void) +{ + _needs_reroute_flag = true; +} + + +int ConnRef::generatePath(Point p0, Point p1) +{ + if (!_false_path && !_needs_reroute_flag) { + // This connector is up to date. + return (int) false; + } + + _false_path = false; + _needs_reroute_flag = false; + + VertInf *src = _srcVert; + VertInf *tar = _dstVert; + + if (!IncludeEndpoints) + { + lateSetup(p0, p1); + + // Update as they have just been set by lateSetup. + src = _srcVert; + tar = _dstVert; + + bool knownNew = true; + vertexVisibility(src, tar, knownNew); + vertexVisibility(tar, src, knownNew); + } + + bool *flag = &(_needs_reroute_flag); + + makePath(this, flag); + + bool result = true; + + int pathlen = 1; + for (VertInf *i = tar; i != src; i = i->pathNext) + { + pathlen++; + if (i == NULL) + { + db_printf("Warning: Path not found...\n"); + pathlen = 2; + tar->pathNext = src; + if (InvisibilityGrph) + { + // TODO: Could we know this edge already? + EdgeInf *edge = EdgeInf::existingEdge(src, tar); + assert(edge != NULL); + edge->addCycleBlocker(); + } + result = false; + break; + } + if (pathlen > 100) + { + fprintf(stderr, "ERROR: Should never be here...\n"); + exit(1); + } + } + Point *path = (Point *) malloc(pathlen * sizeof(Point)); + + int j = pathlen - 1; + for (VertInf *i = tar; i != src; i = i->pathNext) + { + if (InvisibilityGrph) + { + // TODO: Again, we could know this edge without searching. + EdgeInf *edge = EdgeInf::existingEdge(i, i->pathNext); + edge->addConn(flag); + } + else + { + _false_path = true; + } + path[j--] = i->point; + } + path[0] = src->point; + + + // Would clear visibility for endpoints here if required. + + PolyLine& output_route = route(); + output_route.pn = pathlen; + output_route.ps = path; + + return (int) result; +} + + +//============================================================================ + + + // It's intended this function is called after shape movement has + // happened to alert connectors that they need to be rerouted. +void callbackAllInvalidConnectors(void) +{ + ConnRefList::iterator fin = connRefs.end(); + for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) { + (*i)->handleInvalid(); + } +} + + +} + + |
