/** * Performs the fuse. * * @return True if the fuse was successful, otherwise false. */ public boolean fuse() { // create walker for first stage // if the walker sees a node of degree 2 it adds it to the current // set of nodes, else it starts a new set m_walker = new GraphWalker() { public int visit(Graphable element, GraphTraversal traversal) { Node node = (Node) element; // if the node is not of degree 2, start a new set if (node.getDegree() != 2) { finish(); } else { // add node to current set m_nodes.add(node); m_ndegree2--; } return (GraphTraversal.CONTINUE); } public void finish() { // no need to recreate if empty if (!m_nodes.isEmpty()) { m_sets.add(m_nodes); m_nodes = new ArrayList(); } } }; // perform a topological depth first traversal m_traversal = new BasicGraphTraversal(m_graph, m_walker, new DepthFirstTopologicalIterator()); // initialise set and node collections m_sets = new ArrayList(); m_nodes = new ArrayList(); m_ndegree2 = m_graph.getNodesOfDegree(2).size(); if (m_ndegree2 == 0) return (true); // nothing to fuse m_traversal.init(); // reset edge visited flags m_graph.visitNodes( new GraphVisitor() { public int visit(Graphable component) { component.setVisited(false); return 0; } }); // perform the traversal m_traversal.traverse(); // if all nodes of degree 2 have been visited, we are finished if (m_ndegree2 > 0) { // if there are still nodes of degree 2 that havent been visited, it means // that the graph has a cycle and that the remaining degree 2 nodes are // internal to the cycle, so the strategy for the second stage is to // find all unvisited nodes of degree 2 that are not visited and start // a no bifurcation traversal from them Iterator sources = m_graph .queryNodes( new GraphVisitor() { public int visit(Graphable component) { Node node = (Node) component; if (!node.isVisited() && node.getDegree() == 2) { // check for adjacent node of degree > 2 for (Iterator itr = node.getRelated(); itr.hasNext(); ) { Node rel = (Node) itr.next(); if (rel.getDegree() > 2) return (Graph.PASS_AND_CONTINUE); } } return (Graph.FAIL_QUERY); } }) .iterator(); // if the query returned no nodes, it means that all the cycle is // disconnected from the rest of graph, so just pick any node of degree 2 if (!sources.hasNext()) { sources = m_graph .queryNodes( new GraphVisitor() { public int visit(Graphable component) { if (!component.isVisited()) return (Graph.PASS_AND_STOP); return (Graph.FAIL_QUERY); } }) .iterator(); } // create stage 2 walker, simple add any nodes visited nodes to the // current node set m_walker = new GraphWalker() { public int visit(Graphable element, GraphTraversal traversal) { m_ndegree2--; m_nodes.add(element); return (GraphTraversal.CONTINUE); } public void finish() { m_sets.add(m_nodes); m_nodes = new ArrayList(); } }; m_traversal.setWalker(m_walker); m_traversal.setIterator(new NoBifurcationIterator()); // clear current node list m_nodes = new ArrayList(); Node source = null; while (sources.hasNext()) { while (sources.hasNext()) { source = (Node) sources.next(); if (source.isVisited()) continue; ((SourceGraphIterator) m_traversal.getIterator()).setSource(source); m_traversal.traverse(); } } } // should be zero, if not something wierd not accounted for if (m_ndegree2 == 0) { // build the fused graph for (Iterator sitr = m_sets.iterator(); sitr.hasNext(); ) { ArrayList nodes = (ArrayList) sitr.next(); ArrayList edges = new ArrayList(); Node first = null; // node of degree != 2 adjacent to first node in set Node last = null; // node of degree != 2 adjacent to last node in set if (nodes.size() == 1) { // set first and last to be related nodes Iterator related = ((Node) nodes.get(0)).getRelated(); first = (Node) related.next(); last = (Node) related.next(); edges.addAll(((Node) nodes.get(0)).getEdges()); } else { // get the node of degree != 2 adjacent to first node in set Node node = (Node) nodes.get(0); Iterator rel = node.getRelated(); first = (Node) rel.next(); if (first.equals(nodes.get(1))) first = (Node) rel.next(); // get the node of degree != 2 adjacent to last node in set node = (Node) nodes.get(nodes.size() - 1); rel = node.getRelated(); last = (Node) rel.next(); if (last.equals(nodes.get(nodes.size() - 2))) last = (Node) rel.next(); // check to see that the first node is not of degree 2, if it is we // have a set of nodes that forms a cycle with no bifurcations // set first to point to node at index 1, and last index x, also // remove node at index 0 from node set so it doesn't get removed if (first.getDegree() == 2) { first = (Node) nodes.get(1); last = (Node) nodes.get(0); first = last = (Node) nodes.get(0); // remove first node from list so that it doesn't get deleted nodes.remove(0); } // add edge between first node in set, and the node of degree != 2 // that is adjacent to it edges.add(first.getEdge((Node) nodes.get(0))); // add middle edges for (int i = 1; i < nodes.size(); i++) { Node curr = (Node) nodes.get(i); Node prev = (Node) nodes.get(i - 1); edges.add(curr.getEdge(prev)); } // add edge between last node in set, and the node of degree != 2 // that is adjacent to it edges.add(last.getEdge((Node) nodes.get(nodes.size() - 1))); } // merge the underlying objects of the edges into a single object Object obj = m_merger.merge(edges); // remove the old nodes from the graph m_builder.removeNodes(nodes); // add merged object to the generator // create the new edge Edge newEdge = m_builder.buildEdge(first, last); // set the underlying object to be the merged object we created m_merger.setMergedObject(newEdge, obj, edges); // add the edge to the builder m_builder.addEdge(newEdge); } return (true); } return (false); }
private static List<SimpleFeature> processEdges( List<String> unvisited, Node startNode, GeometryFactory geometryFactory, SimpleFeatureType featureType, long startTime, int pathID, List<SimpleFeature> featuresList, double stepTime, int maxTime, int intersectionWait, int stepDistance) { LineString line; Node currentNode = startNode; int crossings = 0; int walkDistance = 0; long walkTime = startTime; while ((unvisited.size() > 0) && (walkTime <= maxTime)) { if (currentNode.getEdges().size() > 0) { int crossingWait = 0; if (currentNode.getEdges().size() > 2) { // This is an intersection - therefore delay for crossing crossingWait = intersectionWait; crossings++; } for (Edge edge : (List<Edge>) currentNode.getEdges()) { if (unvisited.contains(String.valueOf(edge.getID()))) { line = (LineString) edge.getObject(); Coordinate pt = ((Point) currentNode.getObject()).getCoordinate(); LengthIndexedLine lil = new LengthIndexedLine(line); if (lil.project(pt) == lil.getStartIndex()) { // start coordinate is at start of line for (int index = 0; index < lil.getEndIndex(); index += stepDistance) { Coordinate coordinate = lil.extractPoint(index); Point point = geometryFactory.createPoint(coordinate); SimpleFeature feature = buildTimeFeatureFromGeometry( featureType, point, walkTime, crossings, walkDistance, String.valueOf(pathID)); walkDistance += stepDistance; walkTime += stepTime + crossingWait; crossingWait = 0; // only perform wait once featuresList.add(feature); } } else if (lil.project(pt) == lil.getEndIndex()) { // start coordinate is at the end of the line for (int index = (int) lil.getEndIndex(); index >= 0; index -= stepDistance) { Coordinate coordinate = lil.extractPoint(index); Point point = geometryFactory.createPoint(coordinate); SimpleFeature feature = buildTimeFeatureFromGeometry( featureType, point, walkTime, crossings, walkDistance, String.valueOf(pathID)); walkDistance += stepDistance; walkTime += stepTime + crossingWait; crossingWait = 0; // only perform wait once featuresList.add(feature); } } else { LOGGER.error("Start coordinate did not match with Index!"); } unvisited.remove(String.valueOf(edge.getID())); Node nextNode = edge.getOtherNode(currentNode); if (nextNode != null) { currentNode = nextNode; } else { break; } } } } } return featuresList; }