EVOLUTION-MANAGER
Edit File: BufferSubgraph.cpp
/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2005 Refractions Research Inc. * Copyright (C) 2001-2002 Vivid Solutions Inc. * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * ********************************************************************** * * Last port: operation/buffer/BufferSubgraph.java r378 (JTS-1.12) * **********************************************************************/ #include <geos/operation/buffer/BufferSubgraph.h> #include <geos/util/TopologyException.h> #include <geos/geom/Envelope.h> #include <geos/geom/CoordinateSequence.h> #include <geos/geomgraph/Node.h> #include <geos/geomgraph/Edge.h> #include <geos/geomgraph/DirectedEdge.h> #include <geos/geomgraph/DirectedEdgeStar.h> #include <geos/geomgraph/EdgeEndStar.h> #include <geos/geomgraph/Position.h> #include <cassert> #include <vector> #include <iostream> #include <list> #ifndef GEOS_DEBUG #define GEOS_DEBUG 0 #endif using namespace std; using namespace geos::geomgraph; using namespace geos::algorithm; using namespace geos::operation; using namespace geos::geom; namespace geos { namespace operation { // geos.operation namespace buffer { // geos.operation.buffer // Argument is unused BufferSubgraph::BufferSubgraph() : finder(), dirEdgeList(), nodes(), rightMostCoord(nullptr), env(nullptr) { } BufferSubgraph::~BufferSubgraph() { delete env; } /*public*/ void BufferSubgraph::create(Node* node) { addReachable(node); // We are assuming that dirEdgeList // contains *at leas* ONE forward DirectedEdge finder.findEdge(&dirEdgeList); rightMostCoord = &(finder.getCoordinate()); // this is what happen if no forward DirectedEdge // is passed to the RightmostEdgeFinder assert(rightMostCoord); } /*private*/ void BufferSubgraph::addReachable(Node* startNode) { vector<Node*> nodeStack; nodeStack.push_back(startNode); while(!nodeStack.empty()) { Node* node = nodeStack.back(); nodeStack.pop_back(); add(node, &nodeStack); } } /*private*/ void BufferSubgraph::add(Node* node, vector<Node*>* nodeStack) { node->setVisited(true); nodes.push_back(node); EdgeEndStar* ees = node->getEdges(); EdgeEndStar::iterator it = ees->begin(); EdgeEndStar::iterator endIt = ees->end(); for(; it != endIt; ++it) { assert(dynamic_cast<DirectedEdge*>(*it)); DirectedEdge* de = static_cast<DirectedEdge*>(*it); dirEdgeList.push_back(de); DirectedEdge* sym = de->getSym(); Node* symNode = sym->getNode(); /** * NOTE: this is a depth-first traversal of the graph. * This will cause a large depth of recursion. * It might be better to do a breadth-first traversal. */ if(! symNode->isVisited()) { nodeStack->push_back(symNode); } } } /*private*/ void BufferSubgraph::clearVisitedEdges() { for(size_t i = 0, n = dirEdgeList.size(); i < n; ++i) { DirectedEdge* de = dirEdgeList[i]; de->setVisited(false); } } /*public*/ void BufferSubgraph::computeDepth(int outsideDepth) { clearVisitedEdges(); // find an outside edge to assign depth to DirectedEdge* de = finder.getEdge(); #if GEOS_DEBUG cerr << "outside depth: " << outsideDepth << endl; #endif //Node *n=de->getNode(); //Label *label=de->getLabel(); // right side of line returned by finder is on the outside de->setEdgeDepths(Position::RIGHT, outsideDepth); copySymDepths(de); //computeNodeDepth(n, de); computeDepths(de); } void BufferSubgraph::computeNodeDepth(Node* n) // throw(TopologyException *) { // find a visited dirEdge to start at DirectedEdge* startEdge = nullptr; assert(dynamic_cast<DirectedEdgeStar*>(n->getEdges())); DirectedEdgeStar* ees = static_cast<DirectedEdgeStar*>(n->getEdges()); EdgeEndStar::iterator endIt = ees->end(); EdgeEndStar::iterator it = ees->begin(); for(; it != endIt; ++it) { assert(dynamic_cast<DirectedEdge*>(*it)); DirectedEdge* de = static_cast<DirectedEdge*>(*it); if(de->isVisited() || de->getSym()->isVisited()) { startEdge = de; break; } } // MD - testing Result: breaks algorithm //if (startEdge==null) return; // only compute string append if assertion would fail if(startEdge == nullptr) { throw util::TopologyException( "unable to find edge to compute depths at", n->getCoordinate()); } ees->computeDepths(startEdge); // copy depths to sym edges for(it = ees->begin(); it != endIt; ++it) { assert(dynamic_cast<DirectedEdge*>(*it)); DirectedEdge* de = static_cast<DirectedEdge*>(*it); de->setVisited(true); copySymDepths(de); } } /*private*/ void BufferSubgraph::copySymDepths(DirectedEdge* de) { #if GEOS_DEBUG cerr << "copySymDepths: " << de->getDepth(Position::LEFT) << ", " << de->getDepth(Position::RIGHT) << endl; #endif DirectedEdge* sym = de->getSym(); sym->setDepth(Position::LEFT, de->getDepth(Position::RIGHT)); sym->setDepth(Position::RIGHT, de->getDepth(Position::LEFT)); } /*public*/ void BufferSubgraph::findResultEdges() { #if GEOS_DEBUG cerr << "BufferSubgraph::findResultEdges got " << dirEdgeList.size() << " edges" << endl; #endif for(size_t i = 0, n = dirEdgeList.size(); i < n; ++i) { DirectedEdge* de = dirEdgeList[i]; /** * Select edges which have an interior depth on the RHS * and an exterior depth on the LHS. * Note that because of weird rounding effects there may be * edges which have negative depths! Negative depths * count as "outside". */ // <FIX> - handle negative depths #if GEOS_DEBUG cerr << " dirEdge " << i << ": " << de->printEdge() << endl << " depth right: " << de->getDepth(Position::RIGHT) << endl << " depth left: " << de->getDepth(Position::LEFT) << endl << " interiorAreaEdge: " << de->isInteriorAreaEdge() << endl; #endif if(de->getDepth(Position::RIGHT) >= 1 && de->getDepth(Position::LEFT) <= 0 && !de->isInteriorAreaEdge()) { de->setInResult(true); #if GEOS_DEBUG cerr << " IN RESULT" << endl; #endif } } } /*public*/ int BufferSubgraph::compareTo(BufferSubgraph* graph) { assert(rightMostCoord); if(rightMostCoord->x < graph->rightMostCoord->x) { return -1; } if(rightMostCoord->x > graph->rightMostCoord->x) { return 1; } return 0; } /*private*/ void BufferSubgraph::computeDepths(DirectedEdge* startEdge) { set<Node*> nodesVisited; list<Node*> nodeQueue; // Used to be a vector Node* startNode = startEdge->getNode(); nodeQueue.push_back(startNode); //nodesVisited.push_back(startNode); nodesVisited.insert(startNode); startEdge->setVisited(true); while(! nodeQueue.empty()) { //System.out.println(nodes.size() + " queue: " + nodeQueue.size()); Node* n = nodeQueue.front(); // [0]; //nodeQueue.erase(nodeQueue.begin()); nodeQueue.pop_front(); nodesVisited.insert(n); // compute depths around node, starting at this edge since it has depths assigned computeNodeDepth(n); // add all adjacent nodes to process queue, // unless the node has been visited already EdgeEndStar* ees = n->getEdges(); EdgeEndStar::iterator endIt = ees->end(); EdgeEndStar::iterator it = ees->begin(); for(; it != endIt; ++it) { assert(dynamic_cast<DirectedEdge*>(*it)); DirectedEdge* de = static_cast<DirectedEdge*>(*it); DirectedEdge* sym = de->getSym(); if(sym->isVisited()) { continue; } Node* adjNode = sym->getNode(); //if (! contains(nodesVisited,adjNode)) if(nodesVisited.insert(adjNode).second) { nodeQueue.push_back(adjNode); //nodesVisited.insert(adjNode); } } } } /*private*/ bool BufferSubgraph::contains(set<Node*>& nodeSet, Node* node) { //bool result=false; if(nodeSet.find(node) != nodeSet.end()) { return true; } return false; } /*public*/ Envelope* BufferSubgraph::getEnvelope() { if(env == nullptr) { env = new Envelope(); std::size_t const size = dirEdgeList.size(); for(std::size_t i = 0; i < size; ++i) { DirectedEdge* dirEdge = dirEdgeList[i]; const CoordinateSequence* pts = dirEdge->getEdge()->getCoordinates(); std::size_t const n = pts->getSize() - 1; for(std::size_t j = 0; j < n; ++j) { env->expandToInclude(pts->getAt(j)); } } } return env; } std::ostream& operator<< (std::ostream& os, const BufferSubgraph& bs) { os << "BufferSubgraph[" << &bs << "] " << bs.nodes.size() << " nodes, " << bs.dirEdgeList.size() << " directed edges" << std::endl; for(size_t i = 0, n = bs.nodes.size(); i < n; i++) { os << " Node " << i << ": " << *(bs.nodes[i]) << std::endl; } for(size_t i = 0, n = bs.dirEdgeList.size(); i < n; i++) { os << " DirEdge " << i << ": " << std::endl << bs.dirEdgeList[i]->printEdge() << std::endl; } return os; } } // namespace geos.operation.buffer } // namespace geos.operation } // namespace geos