diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
commit | cca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch) | |
tree | 146f39ded1c938019e1ed42d30923c2ac9e86789 /src/3rdparty/adaptagrams/libavoid/vertices.cpp | |
parent | Initial commit. (diff) | |
download | inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.tar.xz inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.zip |
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/3rdparty/adaptagrams/libavoid/vertices.cpp')
-rw-r--r-- | src/3rdparty/adaptagrams/libavoid/vertices.cpp | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/src/3rdparty/adaptagrams/libavoid/vertices.cpp b/src/3rdparty/adaptagrams/libavoid/vertices.cpp new file mode 100644 index 0000000..6034e0a --- /dev/null +++ b/src/3rdparty/adaptagrams/libavoid/vertices.cpp @@ -0,0 +1,739 @@ +/* + * vim: ts=4 sw=4 et tw=0 wm=0 + * + * libavoid - Fast, Incremental, Object-avoiding Line Router + * + * Copyright (C) 2004-2009 Monash University + * + * 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. + * See the file LICENSE.LGPL distributed with the library. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * library. + * + * 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. + * + * Author(s): Michael Wybrow +*/ + + +#include <iostream> +#include <cstdlib> + +#include "libavoid/vertices.h" +#include "libavoid/geometry.h" +#include "libavoid/graph.h" // For alertConns +#include "libavoid/debug.h" +#include "libavoid/router.h" +#include "libavoid/assertions.h" +#include "libavoid/connend.h" + +using std::ostream; + + +namespace Avoid { + + +VertID::VertID() +{ +} + + +VertID::VertID(unsigned int id, unsigned short n, VertIDProps p) + : objID(id), + vn(n), + props(p) +{ +} + + +VertID::VertID(const VertID& other) + : objID(other.objID), + vn(other.vn), + props(other.props) +{ +} + + +VertID& VertID::operator= (const VertID& rhs) +{ + // Gracefully handle self assignment + //if (this == &rhs) return *this; + + objID = rhs.objID; + vn = rhs.vn; + props = rhs.props; + + return *this; +} + + +bool VertID::operator==(const VertID& rhs) const +{ + if ((objID != rhs.objID) || (vn != rhs.vn)) + { + return false; + } + return true; +} + + +bool VertID::operator!=(const VertID& rhs) const +{ + if ((objID != rhs.objID) || (vn != rhs.vn)) + { + return true; + } + return false; +} + + +bool VertID::operator<(const VertID& rhs) const +{ + if ((objID < rhs.objID) || + ((objID == rhs.objID) && (vn < rhs.vn))) + { + return true; + } + return false; +} + + +VertID VertID::operator+(const int& rhs) const +{ + return VertID(objID, vn + rhs, props); +} + + +VertID VertID::operator-(const int& rhs) const +{ + return VertID(objID, vn - rhs, props); +} + + +VertID& VertID::operator++(int) +{ + vn += 1; + return *this; +} + + +void VertID::print(FILE *file) const +{ + fprintf(file, "[%u,%d, p=%u]", objID, vn, (unsigned int) props); +} + +void VertID::db_print(void) const +{ + db_printf("[%u,%d, p=%u]", objID, vn, (unsigned int) props); +} + + +const unsigned short VertID::src = 1; +const unsigned short VertID::tar = 2; + +// Property flags: +const unsigned short VertID::PROP_ConnPoint = 1; +const unsigned short VertID::PROP_OrthShapeEdge = 2; +const unsigned short VertID::PROP_ConnectionPin = 4; +const unsigned short VertID::PROP_ConnCheckpoint = 8; +const unsigned short VertID::PROP_DummyPinHelper = 16; + + +ostream& operator<<(ostream& os, const VertID& vID) +{ + return os << '[' << vID.objID << ',' << vID.vn << ']'; +} + + + +VertInf::VertInf(Router *router, const VertID& vid, const Point& vpoint, + const bool addToRouter) + : _router(router), + id(vid), + point(vpoint), + lstPrev(nullptr), + lstNext(nullptr), + shPrev(nullptr), + shNext(nullptr), + visListSize(0), + orthogVisListSize(0), + invisListSize(0), + pathNext(nullptr), + m_orthogonalPartner(nullptr), + m_treeRoot(nullptr), + visDirections(ConnDirNone), + orthogVisPropFlags(0) +{ + point.id = vid.objID; + point.vn = vid.vn; + + if (addToRouter) + { + _router->vertices.addVertex(this); + } +} + + +VertInf::~VertInf() +{ + COLA_ASSERT(orphaned()); +} + + +EdgeInf *VertInf::hasNeighbour(VertInf *target, bool orthogonal) const +{ + const EdgeInfList& visEdgeList = (orthogonal) ? orthogVisList : visList; + EdgeInfList::const_iterator finish = visEdgeList.end(); + for (EdgeInfList::const_iterator edge = visEdgeList.begin(); edge != finish; ++edge) + { + if ((*edge)->otherVert(this) == target) + { + return *edge; + } + } + return nullptr; +} + +void VertInf::Reset(const VertID& vid, const Point& vpoint) +{ + id = vid; + point = vpoint; + point.id = id.objID; + point.vn = id.vn; +} + + +void VertInf::Reset(const Point& vpoint) +{ + point = vpoint; + point.id = id.objID; + point.vn = id.vn; +} + + +// Returns true if this vertex is not involved in any (in)visibility graphs. +bool VertInf::orphaned(void) +{ + return (visList.empty() && invisList.empty() && orthogVisList.empty()); +} + + +void VertInf::removeFromGraph(const bool isConnVert) +{ + if (isConnVert) + { + COLA_ASSERT(id.isConnPt()); + } + + // For each vertex. + EdgeInfList::const_iterator finish = visList.end(); + EdgeInfList::const_iterator edge; + while ((edge = visList.begin()) != finish) + { + // Remove each visibility edge + (*edge)->alertConns(); + delete (*edge); + } + + finish = orthogVisList.end(); + while ((edge = orthogVisList.begin()) != finish) + { + // Remove each orthogonal visibility edge. + (*edge)->alertConns(); + delete (*edge); + } + + finish = invisList.end(); + while ((edge = invisList.begin()) != finish) + { + // Remove each invisibility edge + delete (*edge); + } +} + + +void VertInf::orphan(void) +{ + // For each vertex. + EdgeInfList::const_iterator finish = visList.end(); + EdgeInfList::const_iterator edge; + while ((edge = visList.begin()) != finish) + { + // Remove each visibility edge + (*edge)->makeInactive(); + } + + finish = orthogVisList.end(); + while ((edge = orthogVisList.begin()) != finish) + { + // Remove each orthogonal visibility edge. + (*edge)->makeInactive(); + } + + finish = invisList.end(); + while ((edge = invisList.begin()) != finish) + { + // Remove each invisibility edge + (*edge)->makeInactive(); + } +} + +// Returns the direction of this vertex relative to the other specified vertex. +// +ConnDirFlags VertInf::directionFrom(const VertInf *other) const +{ + double epsilon = 0.000001; + Point thisPoint = point; + Point otherPoint = other->point; + Point diff = thisPoint - otherPoint; + + ConnDirFlags directions = ConnDirNone; + if (diff.y > epsilon) + { + directions |= ConnDirUp; + } + if (diff.y < -epsilon) + { + directions |= ConnDirDown; + } + if (diff.x > epsilon) + { + directions |= ConnDirRight; + } + if (diff.x < -epsilon) + { + directions |= ConnDirLeft; + } + return directions; +} + +// Given a set of directions, mark visibility edges in all other directions +// as being invalid so they get ignored during the search. +// +void VertInf::setVisibleDirections(const ConnDirFlags directions) +{ + for (EdgeInfList::const_iterator edge = visList.begin(); + edge != visList.end(); ++edge) + { + if (directions == ConnDirAll) + { + (*edge)->setDisabled(false); + } + else + { + VertInf *otherVert = (*edge)->otherVert(this); + ConnDirFlags direction = otherVert->directionFrom(this); + bool visible = (direction & directions); + (*edge)->setDisabled(!visible); + } + } + + for (EdgeInfList::const_iterator edge = orthogVisList.begin(); + edge != orthogVisList.end(); ++edge) + { + if (directions == ConnDirAll) + { + (*edge)->setDisabled(false); + } + else + { + VertInf *otherVert = (*edge)->otherVert(this); + ConnDirFlags direction = otherVert->directionFrom(this); + bool visible = (direction & directions); + (*edge)->setDisabled(!visible); + } + } +} + +// Number of points in path from end back to start, or zero if no path exists. +// +unsigned int VertInf::pathLeadsBackTo(const VertInf *start) const +{ + unsigned int pathlen = 1; + for (const VertInf *i = this; i != start; i = i->pathNext) + { + if ((pathlen > 1) && (i == this)) + { + // We have a circular path, so path not found. + return 0; + } + + pathlen++; + if (i == nullptr) + { + // Path not found. + return 0; + } + + // Check we don't have an apparent infinite connector path. + COLA_ASSERT(pathlen < 20000); + } + return pathlen; +} + +VertInf **VertInf::makeTreeRootPointer(VertInf *root) +{ + m_treeRoot = (VertInf **) malloc(sizeof(VertInf *)); + *m_treeRoot = root; + return m_treeRoot; +} + +VertInf *VertInf::treeRoot(void) const +{ + return (m_treeRoot) ? *m_treeRoot : nullptr; +} + +VertInf **VertInf::treeRootPointer(void) const +{ + return m_treeRoot; +} + +void VertInf::clearTreeRootPointer(void) +{ + m_treeRoot = nullptr; +} + +void VertInf::setTreeRootPointer(VertInf **pointer) +{ + m_treeRoot = pointer; +} + +void VertInf::setSPTFRoot(VertInf *root) +{ + // Use the m_treeRoot instance var, but as just a normal VertInf pointer. + m_treeRoot = (VertInf **) root; +} + + +VertInf *VertInf::sptfRoot(void) const +{ + // Use the m_treeRoot instance var, but as just a normal VertInf pointer. + return (VertInf *) m_treeRoot; +} + + +bool directVis(VertInf *src, VertInf *dst) +{ + ShapeSet ss = ShapeSet(); + + Point& p = src->point; + Point& q = dst->point; + + VertID& pID = src->id; + VertID& qID = dst->id; + + // We better be part of the same instance of libavoid. + Router *router = src->_router; + COLA_ASSERT(router == dst->_router); + + ContainsMap& contains = router->contains; + if (pID.isConnPt()) + { + ss.insert(contains[pID].begin(), contains[pID].end()); + } + if (qID.isConnPt()) + { + ss.insert(contains[qID].begin(), contains[qID].end()); + } + + // The "beginning" should be the first shape vertex, rather + // than an endpoint, which are also stored in "vertices". + VertInf *endVert = router->vertices.end(); + for (VertInf *k = router->vertices.shapesBegin(); k != endVert; + k = k->lstNext) + { + if ((ss.find(k->id.objID) == ss.end())) + { + if (segmentIntersect(p, q, k->point, k->shNext->point)) + { + return false; + } + } + } + return true; +} + + +VertInfList::VertInfList() + : _firstShapeVert(nullptr), + _firstConnVert(nullptr), + _lastShapeVert(nullptr), + _lastConnVert(nullptr), + _shapeVertices(0), + _connVertices(0) +{ +} + + +#define checkVertInfListConditions() \ + do { \ + COLA_ASSERT((!_firstConnVert && (_connVertices == 0)) || \ + ((_firstConnVert->lstPrev == nullptr) && (_connVertices > 0))); \ + COLA_ASSERT((!_firstShapeVert && (_shapeVertices == 0)) || \ + ((_firstShapeVert->lstPrev == nullptr) && (_shapeVertices > 0))); \ + COLA_ASSERT(!_lastShapeVert || (_lastShapeVert->lstNext == nullptr)); \ + COLA_ASSERT(!_lastConnVert || (_lastConnVert->lstNext == _firstShapeVert)); \ + COLA_ASSERT((!_firstConnVert && !_lastConnVert) || \ + (_firstConnVert && _lastConnVert) ); \ + COLA_ASSERT((!_firstShapeVert && !_lastShapeVert) || \ + (_firstShapeVert && _lastShapeVert) ); \ + COLA_ASSERT(!_firstShapeVert || !(_firstShapeVert->id.isConnPt())); \ + COLA_ASSERT(!_lastShapeVert || !(_lastShapeVert->id.isConnPt())); \ + COLA_ASSERT(!_firstConnVert || _firstConnVert->id.isConnPt()); \ + COLA_ASSERT(!_lastConnVert || _lastConnVert->id.isConnPt()); \ + } while(0) + + +void VertInfList::addVertex(VertInf *vert) +{ + checkVertInfListConditions(); + COLA_ASSERT(vert->lstPrev == nullptr); + COLA_ASSERT(vert->lstNext == nullptr); + + if (vert->id.isConnPt()) + { + // A Connector vertex + if (_firstConnVert) + { + // Join with previous front + vert->lstNext = _firstConnVert; + _firstConnVert->lstPrev = vert; + + // Make front + _firstConnVert = vert; + } + else + { + // Make front and back + _firstConnVert = vert; + _lastConnVert = vert; + + // Link to front of shapes list + vert->lstNext = _firstShapeVert; + } + _connVertices++; + } + else // if (vert->id.shape > 0) + { + // A Shape vertex + if (_lastShapeVert) + { + // Join with previous back + vert->lstPrev = _lastShapeVert; + _lastShapeVert->lstNext = vert; + + // Make back + _lastShapeVert = vert; + } + else + { + // Make first and last + _firstShapeVert = vert; + _lastShapeVert = vert; + + // Join with conns list + if (_lastConnVert) + { + COLA_ASSERT(_lastConnVert->lstNext == nullptr); + + _lastConnVert->lstNext = vert; + } + } + _shapeVertices++; + } + checkVertInfListConditions(); +} + + +// Removes a vertex from the list and returns a pointer to the vertex +// following the removed one. +VertInf *VertInfList::removeVertex(VertInf *vert) +{ + if (vert == nullptr) + { + return nullptr; + } + // Conditions for correct data structure + checkVertInfListConditions(); + + VertInf *following = vert->lstNext; + + if (vert->id.isConnPt()) + { + // A Connector vertex + if (vert == _firstConnVert) + { + + if (vert == _lastConnVert) + { + _firstConnVert = nullptr; + _lastConnVert = nullptr; + } + else + { + // Set new first + _firstConnVert = _firstConnVert->lstNext; + + if (_firstConnVert) + { + // Set previous + _firstConnVert->lstPrev = nullptr; + } + } + } + else if (vert == _lastConnVert) + { + // Set new last + _lastConnVert = _lastConnVert->lstPrev; + + // Make last point to shapes list + _lastConnVert->lstNext = _firstShapeVert; + } + else + { + vert->lstNext->lstPrev = vert->lstPrev; + vert->lstPrev->lstNext = vert->lstNext; + } + _connVertices--; + } + else // if (vert->id.shape > 0) + { + // A Shape vertex + if (vert == _lastShapeVert) + { + // Set new last + _lastShapeVert = _lastShapeVert->lstPrev; + + if (vert == _firstShapeVert) + { + _firstShapeVert = nullptr; + if (_lastConnVert) + { + _lastConnVert->lstNext = nullptr; + } + } + + if (_lastShapeVert) + { + _lastShapeVert->lstNext = nullptr; + } + } + else if (vert == _firstShapeVert) + { + // Set new first + _firstShapeVert = _firstShapeVert->lstNext; + + // Correct the last conn vertex + if (_lastConnVert) + { + _lastConnVert->lstNext = _firstShapeVert; + } + + if (_firstShapeVert) + { + _firstShapeVert->lstPrev = nullptr; + } + } + else + { + vert->lstNext->lstPrev = vert->lstPrev; + vert->lstPrev->lstNext = vert->lstNext; + } + _shapeVertices--; + } + vert->lstPrev = nullptr; + vert->lstNext = nullptr; + + checkVertInfListConditions(); + + return following; +} + + +VertInf *VertInfList::getVertexByID(const VertID& id) +{ + VertID searchID = id; + if (searchID.vn == kUnassignedVertexNumber) + { + unsigned int topbit = ((unsigned int) 1) << 31; + if (searchID.objID & topbit) + { + searchID.objID = searchID.objID & ~topbit; + searchID.vn = VertID::src; + } + else + { + searchID.vn = VertID::tar; + } + } + VertInf *last = end(); + for (VertInf *curr = connsBegin(); curr != last; curr = curr->lstNext) + { + if (curr->id == searchID) + { + return curr; + } + } + return nullptr; +} + + +VertInf *VertInfList::getVertexByPos(const Point& p) +{ + VertInf *last = end(); + for (VertInf *curr = shapesBegin(); curr != last; curr = curr->lstNext) + { + if (curr->point == p) + { + return curr; + } + } + return nullptr; +} + + +VertInf *VertInfList::shapesBegin(void) +{ + return _firstShapeVert; +} + + +VertInf *VertInfList::connsBegin(void) +{ + if (_firstConnVert) + { + return _firstConnVert; + } + // No connector vertices + return _firstShapeVert; +} + + +VertInf *VertInfList::end(void) +{ + return nullptr; +} + + +unsigned int VertInfList::connsSize(void) const +{ + return _connVertices; +} + + +unsigned int VertInfList::shapesSize(void) const +{ + return _shapeVertices; +} + + +} + + |