package com.revolsys.geometry.graph.visitor; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import com.revolsys.geometry.graph.Edge; import com.revolsys.geometry.graph.Graph; import com.revolsys.geometry.graph.Node; import com.revolsys.geometry.graph.RecordGraph; import com.revolsys.geometry.graph.attribute.NodeProperties; import com.revolsys.record.Record; import com.revolsys.util.ObjectProcessor; import com.revolsys.util.count.LabelCountMap; import com.revolsys.visitor.AbstractVisitor; public class ItersectsNodeEdgeCleanupVisitor extends AbstractVisitor<Edge<Record>> implements ObjectProcessor<RecordGraph> { private final Set<String> equalExcludeFieldNames = new HashSet<>( Arrays.asList(Record.EXCLUDE_ID, Record.EXCLUDE_GEOMETRY)); private LabelCountMap splitStatistics; @Override public void accept(final Edge<Record> edge) { final String typePath = edge.getTypeName(); final Node<Record> fromNode = edge.getFromNode(); final Node<Record> toNode = edge.getToNode(); final Graph<Record> graph = edge.getGraph(); final List<Node<Record>> nodes = graph.findNodes(edge, 2); for (final Iterator<Node<Record>> nodeIter = nodes.iterator(); nodeIter.hasNext();) { final Node<Record> node = nodeIter.next(); final List<Edge<Record>> edges = NodeProperties.getEdgesByType(node, typePath); if (edges.isEmpty()) { nodeIter.remove(); } } if (!nodes.isEmpty()) { if (nodes.size() > 1) { for (int i = 0; i < nodes.size(); i++) { Node<Record> node1 = nodes.get(i); for (int j = i + 1; j < nodes.size(); j++) { final Node<Record> node2 = nodes.get(j); if (node1.distancePoint(node2) < 2) { if (edge.distancePoint(node1) <= edge.distancePoint(node2)) { nodes.remove(j); } else { nodes.remove(i); node1 = node2; } } } } } if (nodes.size() == 1) { final Node<Record> node = nodes.get(0); if (node.distancePoint(fromNode) <= 10) { moveEndUndershoots(typePath, fromNode, node); } else if (node.distancePoint(toNode) <= 10) { moveEndUndershoots(typePath, toNode, node); } else { graph.splitEdge(edge, nodes); this.splitStatistics.addCount(typePath); } } else { graph.splitEdge(edge, nodes); } } } @PreDestroy public void destroy() { if (this.splitStatistics != null) { this.splitStatistics.disconnect(); } this.splitStatistics = null; } public Set<String> getEqualExcludeFieldNames() { return this.equalExcludeFieldNames; } @PostConstruct public void init() { this.splitStatistics = new LabelCountMap("Split edges"); this.splitStatistics.connect(); } private boolean moveEndUndershoots(final String typePath, final Node<Record> node1, final Node<Record> node2) { boolean matched = false; if (!node2.hasEdgeTo(node1)) { final Set<Double> angles1 = NodeProperties.getEdgeAnglesByType(node2, typePath); final Set<Double> angles2 = NodeProperties.getEdgeAnglesByType(node1, typePath); if (angles1.size() == 1 && angles2.size() == 1) { matched = node1.getGraph().moveNodesToMidpoint(typePath, node2, node1); } } return matched; } @Override public void process(final RecordGraph graph) { graph.forEachEdge(this); } }