package com.revolsys.geometry.graph.attribute; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.revolsys.geometry.graph.Edge; import com.revolsys.geometry.graph.EdgePair; import com.revolsys.geometry.graph.Node; import com.revolsys.geometry.model.LineString; import com.revolsys.geometry.util.LineStringUtil; import com.revolsys.record.Record; import com.revolsys.record.property.DirectionalFields; public class PseudoNodeAttribute { private final List<EdgePair<Record>> edgePairs = new ArrayList<>(); private final Set<String> equalExcludeFieldNames = new HashSet<>(); private final List<EdgePair<Record>> reversedEdgePairs = new ArrayList<>(); private final String typePath; public PseudoNodeAttribute(final Node<Record> node, final String typePath, final Collection<String> equalExcludeFieldNames) { this.typePath = typePath; if (equalExcludeFieldNames != null) { this.equalExcludeFieldNames.addAll(equalExcludeFieldNames); } final Map<String, Map<LineString, Set<Edge<Record>>>> edgesByTypeNameAndLine = NodeProperties .getEdgesByTypeNameAndLine(node); final Map<LineString, Set<Edge<Record>>> edgesByLine = edgesByTypeNameAndLine.get(typePath); init(node, edgesByLine); } public List<EdgePair<Record>> getEdgePairs() { return this.edgePairs; } public List<EdgePair<Record>> getReversedEdgePairs() { return this.reversedEdgePairs; } public String getTypeName() { return this.typePath; } private void init(final Node<Record> node, final Map<LineString, Set<Edge<Record>>> edgesByLine) { if (isPseudoNode(node, edgesByLine)) { } } protected boolean isPseudoNode(final Node<Record> node, final Map<LineString, Set<Edge<Record>>> edgesByLine) { final Set<LineString> lines = edgesByLine.keySet(); if (!LineStringUtil.hasLoop(lines)) { if (edgesByLine.size() == 2) { final Iterator<Set<Edge<Record>>> edgeIter = edgesByLine.values().iterator(); final Set<Edge<Record>> edges1 = edgeIter.next(); final Set<Edge<Record>> edges2 = edgeIter.next(); final int size1 = edges1.size(); final int size2 = edges2.size(); if (size1 == size2) { if (size1 == 1) { final Edge<Record> edge1 = edges1.iterator().next(); final Edge<Record> edge2 = edges2.iterator().next(); final EdgePair<Record> edgePair = newEdgePair(node, edge1, edge2); if (edgePair != null) { if (edge1.getEnd(node) == edge2.getEnd(node)) { this.reversedEdgePairs.add(edgePair); } else { this.edgePairs.add(edgePair); } return true; } } else { final List<Edge<Record>> unmatchedEdges1 = new ArrayList<>(edges1); final List<Edge<Record>> unmatchedEdges2 = new ArrayList<>(edges2); // Find non-reversed matches matchEdges(node, unmatchedEdges1, unmatchedEdges2, this.edgePairs, false); if (unmatchedEdges2.isEmpty()) { return true; } else { // Find reversed matches matchEdges(node, unmatchedEdges1, unmatchedEdges2, this.reversedEdgePairs, true); if (unmatchedEdges2.isEmpty()) { return true; } } } } } } return false; } private void matchEdges(final Node<Record> node, final List<Edge<Record>> edges1, final List<Edge<Record>> edges2, final List<EdgePair<Record>> pairedEdges, final boolean reversed) { final Iterator<Edge<Record>> edgeIter1 = edges1.iterator(); while (edgeIter1.hasNext()) { final Edge<Record> edge1 = edgeIter1.next(); boolean matched = false; final Iterator<Edge<Record>> edgeIter2 = edges2.iterator(); while (!matched && edgeIter2.hasNext()) { final Edge<Record> edge2 = edgeIter2.next(); boolean match = false; if (edge1.getEnd(node) == edge2.getEnd(node)) { match = reversed; } else { match = !reversed; } if (match) { final EdgePair<Record> edgePair = newEdgePair(node, edge1, edge2); if (edgePair != null) { matched = true; edgeIter1.remove(); edgeIter2.remove(); pairedEdges.add(edgePair); } } } } } private EdgePair<Record> newEdgePair(final Node<Record> node, final Edge<Record> edge1, final Edge<Record> edge2) { final Record object1 = edge1.getObject(); final Record object2 = edge2.getObject(); if (DirectionalFields.canMergeRecords(node, object1, object2, this.equalExcludeFieldNames)) { return new EdgePair<>(edge1, edge2); } else { return null; } } }