From 5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 24 Feb 2010 01:49:02 +0000 Subject: Added KDE3 version of ktechlab git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- src/nodegroup.cpp | 572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 572 insertions(+) create mode 100644 src/nodegroup.cpp (limited to 'src/nodegroup.cpp') diff --git a/src/nodegroup.cpp b/src/nodegroup.cpp new file mode 100644 index 0000000..fe55293 --- /dev/null +++ b/src/nodegroup.cpp @@ -0,0 +1,572 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "icndocument.h" +#include "connector.h" +#include "conrouter.h" +#include "node.h" +#include "nodegroup.h" + +#include +#include +#include + +NodeGroup::NodeGroup( ICNDocument *icnDocument, const char *name ) + : QObject( icnDocument, name ) +{ + p_icnDocument = icnDocument; + b_visible = true; +} + + +NodeGroup::~NodeGroup() +{ + clearConList(); + + m_extNodeList.remove( (Node*)0l ); + const NodeList::iterator xnEnd = m_extNodeList.end(); + for ( NodeList::iterator it = m_extNodeList.begin(); it != xnEnd; ++it ) + (*it)->setNodeGroup(0l); + m_extNodeList.clear(); + + m_nodeList.remove( (Node*)0l ); + const NodeList::iterator nEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nEnd; ++it ) + (*it)->setNodeGroup(0l); + m_nodeList.clear(); +} + + +void NodeGroup::setVisible( bool visible ) +{ + if ( b_visible == visible ) + return; + + b_visible = visible; + + m_nodeList.remove( (Node*)0l ); + const NodeList::iterator nEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nEnd; ++it ) + (*it)->setVisible(visible); +} + + +void NodeGroup::addNode( Node *node, bool checkSurrouding ) +{ + if ( !node || node->isChildNode() || m_nodeList.contains(node) ) { + return; + } + + m_nodeList.append(node); + node->setNodeGroup(this); + node->setVisible(b_visible); + + if (checkSurrouding) + { + ConnectorList con = node->inputConnectorList(); + ConnectorList::iterator end = con.end(); + for ( ConnectorList::iterator it = con.begin(); it != end; ++it ) + { + if (*it) { + addNode( (*it)->startNode(), true ); + } + } + + con = node->outputConnectorList(); + end = con.end(); + for ( ConnectorList::iterator it = con.begin(); it != end; ++it ) + { + if (*it) { + addNode( (*it)->endNode(), true ); + } + } + } +} + + +void NodeGroup::translate( int dx, int dy ) +{ + if ( (dx == 0) && (dy == 0) ) + return; + + m_conList.remove((Connector*)0l); + m_nodeList.remove((Node*)0l); + + const ConnectorList::iterator conEnd = m_conList.end(); + for ( ConnectorList::iterator it = m_conList.begin(); it != conEnd; ++it ) + { + (*it)->updateConnectorPoints(false); + (*it)->translateRoute( dx, dy ); + } + + const NodeList::iterator nodeEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it ) + (*it)->moveBy( dx, dy ); +} + + +void NodeGroup::updateRoutes() +{ + resetRoutedMap(); + + // Basic algorithm used here: starting with the external nodes, find the + // pair with the shortest distance between them. Route the connectors + // between the two nodes appropriately. Remove that pair of nodes from the + // list, and add the nodes along the connector route (which have been spaced + // equally along the route). Repeat until all the nodes are connected. + + + const ConnectorList::iterator conEnd = m_conList.end(); + for ( ConnectorList::iterator it = m_conList.begin(); it != conEnd; ++it ) + { + if (*it) + (*it)->updateConnectorPoints(false); + } + + Node *n1, *n2; + NodeList currentList = m_extNodeList; + while ( !currentList.isEmpty() ) + { + findBestPair( ¤tList, &n1, &n2 ); + if ( n1 == 0l || n2 == 0l ) { + return; + } + NodeList route = findRoute( n1, n2 ); + currentList += route; + + ConRouter cr(p_icnDocument); + cr.mapRoute( (int)n1->x(), (int)n1->y(), (int)n2->x(), (int)n2->y() ); + QPointListList pl = cr.dividePoints( route.size()+1 ); + + const NodeList::iterator routeEnd = route.end(); + const QPointListList::iterator plEnd = pl.end(); + Node *prev = n1; + NodeList::iterator routeIt = route.begin(); + for ( QPointListList::iterator it = pl.begin(); it != plEnd; ++it ) + { + Node *next = (routeIt == routeEnd) ? n2 : (Node*)*(routeIt++); + removeRoutedNodes( ¤tList, prev, next ); + QPointList pointList = *it; + if ( prev != n1 ) + { + QPoint first = pointList.first(); + prev->moveBy( first.x() - prev->x(), first.y() - prev->y() ); + } + Connector *con = findCommonConnector( prev, next ); + if (con) + { + con->updateConnectorPoints(false); + con->setRoutePoints( pointList, false, false ); + con->updateConnectorPoints(true); +// con->conRouter()->setPoints( &pointList, con->startNode() != prev ); +// con->conRouter()->setPoints( &pointList, con->pointsAreReverse( &pointList ) ); +// con->calcBoundingPoints(); + } + prev = next; + } + } +} + + +NodeList NodeGroup::findRoute( Node *startNode, Node *endNode ) +{ + NodeList nl; + if ( !startNode || !endNode || startNode == endNode ) { + return nl; + } + + IntList temp; + IntList il = findRoute( temp, getNodePos(startNode), getNodePos(endNode) ); + + const IntList::iterator end = il.end(); + for ( IntList::iterator it = il.begin(); it != end; ++it ) + { + Node *node = getNodePtr(*it); + if (node) { + nl += node; + } + } + + nl.remove(startNode); + nl.remove(endNode); + + return nl; +} + + +IntList NodeGroup::findRoute( IntList used, int currentNode, int endNode, bool *success ) +{ + bool temp; + if (!success) { + success = &temp; + } + *success = false; + + if ( !used.contains(currentNode) ) { + used.append(currentNode); + } + + if ( currentNode == endNode ) { + *success = true; + return used; + } + + const uint n = m_nodeList.size()+m_extNodeList.size(); + for ( uint i=0; iinputConnectorList() + n1->outputConnectorList(); + ConnectorList n2Con = n2->inputConnectorList() + n2->outputConnectorList(); + + const ConnectorList::iterator end = n1Con.end(); + for ( ConnectorList::iterator it = n1Con.begin(); it != end; ++it ) + { + if ( n2Con.contains(*it) ) { + return *it; + } + } + return 0l; +} + + +void NodeGroup::findBestPair( NodeList *list, Node **n1, Node **n2 ) +{ + *n1 = 0l; + *n2 = 0l; + + if ( list->size() < 2 ) { + return; + } + + const NodeList::iterator end = list->end(); + int shortest = 1<<30; + + // Try and find any that are aligned horizontally + for ( NodeList::iterator it1 = list->begin(); it1 != end; ++it1 ) + { + NodeList::iterator it2 = it1; + for ( ++it2; it2 != end; ++it2 ) + { + if ( *it1 != *it2 && (*it1)->y() == (*it2)->y() && canRoute( *it1, *it2 ) ) + { + const int distance = std::abs((double)( (*it1)->x()-(*it2)->x() )); + if ( distance < shortest ) + { + shortest = distance; + *n1 = *it1; + *n2 = *it2; + } + } + } + } + if (*n1) { + return; + } + + // Try and find any that are aligned vertically + for ( NodeList::iterator it1 = list->begin(); it1 != end; ++it1 ) + { + NodeList::iterator it2 = it1; + for ( ++it2; it2 != end; ++it2 ) + { + if ( *it1 != *it2 && (*it1)->x() == (*it2)->x() && canRoute( *it1, *it2 ) ) + { + const int distance = std::abs((double)( (*it1)->y()-(*it2)->y() )); + if ( distance < shortest ) + { + shortest = distance; + *n1 = *it1; + *n2 = *it2; + } + } + } + } + if (*n1) { + return; + } + + // Now, lets just find the two closest nodes + for ( NodeList::iterator it1 = list->begin(); it1 != end; ++it1 ) + { + NodeList::iterator it2 = it1; + for ( ++it2; it2 != end; ++it2 ) + { + if ( *it1 != *it2 && canRoute( *it1, *it2 ) ) + { + const int dx = (int)((*it1)->x()-(*it2)->x()); + const int dy = (int)((*it1)->y()-(*it2)->y()); + const int distance = std::abs((double)dx) + std::abs((double)dy); + if ( distance < shortest ) + { + shortest = distance; + *n1 = *it1; + *n2 = *it2; + } + } + } + } + + if (!*n1) { + kdError() << "NodeGroup::findBestPair: Could not find a routable pair of nodes!"<contains(node) ) { + return; + } + reachable->append(node); + + const uint n = m_nodeList.size() + m_extNodeList.size(); + assert( node < int(n) ); + for ( uint i=0; istartNode()); + int n2 = getNodePos(con->endNode()); + if ( n1 != -1 && n2 != -1 ) + { + b_routedMap[n1*n + n2] = b_routedMap[n2*n + n1] = true; + } + } + } +} + + +void NodeGroup::removeRoutedNodes( NodeList *nodes, Node *n1, Node *n2 ) +{ + if (!nodes) { + return; + } + + // Lets get rid of any duplicate nodes in nodes (as a general cleaning operation) + const NodeList::iterator end = nodes->end(); + for ( NodeList::iterator it = nodes->begin(); it != end; ++it ) + { + if ( nodes->contains(*it) > 1 ) { + *it = 0l; + } + } + nodes->remove((Node*)0l); + + const int n1pos = getNodePos(n1); + const int n2pos = getNodePos(n2); + + if ( n1pos == -1 || n2pos == -1 ) { + return; + } + + const uint n = m_nodeList.size() + m_extNodeList.size(); + + b_routedMap[n1pos*n + n2pos] = b_routedMap[n2pos*n + n1pos] = false; + + bool n1HasCon = false; + bool n2HasCon = false; + + for ( uint i=0; iremove(n1); + } + if (!n2HasCon) { + nodes->remove(n2); + } +} + + +int NodeGroup::getNodePos( Node *n ) +{ + if (!n) { + return -1; + } + int pos = m_nodeList.findIndex(n); + if ( pos != -1 ) { + return pos; + } + pos = m_extNodeList.findIndex(n); + if ( pos != -1 ) { + return pos+m_nodeList.size(); + } + return -1; +} + + +Node* NodeGroup::getNodePtr( int n ) +{ + if ( n<0 ) { + return 0l; + } + const int a = m_nodeList.size(); + if (nsetNodeGroup(0l); + disconnect( con, SIGNAL(removed(Connector*)), this, SLOT(connectorRemoved(Connector*)) ); + } + } + m_conList.clear(); +} + + +void NodeGroup::init() +{ + NodeList::iterator xnEnd = m_extNodeList.end(); + for ( NodeList::iterator it = m_extNodeList.begin(); it != xnEnd; ++it ) + { + (*it)->setNodeGroup(0l); + } + m_extNodeList.clear(); + + clearConList(); + + // First, lets get all of our external nodes and internal connectors + const NodeList::iterator nlEnd = m_nodeList.end(); + for ( NodeList::iterator nodeIt = m_nodeList.begin(); nodeIt != nlEnd; ++nodeIt ) + { + ConnectorList inCon = (*nodeIt)->inputConnectorList(); + ConnectorList outCon = (*nodeIt)->outputConnectorList(); + ConnectorList::iterator conEnd; + + conEnd = inCon.end(); + for ( ConnectorList::iterator conIt = inCon.begin(); conIt != conEnd; ++conIt ) + { + Connector *con = *conIt; + addExtNode(con->startNode()); + if ( !m_conList.contains(con) ) { + m_conList += con; + con->setNodeGroup(this); + } + connect( con, SIGNAL(removed(Connector*)), this, SLOT(connectorRemoved(Connector*)) ); + } + + conEnd = outCon.end(); + for ( ConnectorList::iterator conIt = outCon.begin(); conIt != conEnd; ++conIt ) + { + Connector *con = *conIt; + addExtNode(con->endNode()); + if ( !m_conList.contains(con) ) { + m_conList += con; + con->setNodeGroup(this); + } + connect( con, SIGNAL(removed(Connector*)), this, SLOT(connectorRemoved(Connector*)) ); + } + + // Connect the node up to us + connect( *nodeIt, SIGNAL(removed(Node*)), this, SLOT(nodeRemoved(Node*)) ); + } + + // And connect up our external nodes + xnEnd = m_extNodeList.end(); + for ( NodeList::iterator it = m_extNodeList.begin(); it != xnEnd; ++it ) + { +// connect( *it, SIGNAL(moved(Node*)), this, SLOT(extNodeMoved()) ); + connect( *it, SIGNAL(removed(Node*)), this, SLOT(nodeRemoved(Node*)) ); + } +} + + +void NodeGroup::nodeRemoved( Node *node ) +{ + // We are probably about to get deleted by ICNDocument anyway...so no point in doing anything + m_nodeList.remove(node); + node->setNodeGroup(0l); + node->setVisible(true); + m_extNodeList.remove(node); +} + + +void NodeGroup::connectorRemoved( Connector *connector ) +{ + m_conList.remove(connector); +} + + +void NodeGroup::addExtNode( Node *node ) +{ + if ( !m_extNodeList.contains(node) && !m_nodeList.contains(node) ) + { + m_extNodeList.append(node); + node->setNodeGroup(this); + } +} + +#include "nodegroup.moc" -- cgit v1.2.3