package com.revolsys.geometry.graph.visitor; import java.util.List; import java.util.function.Predicate; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import com.revolsys.geometry.graph.Edge; import com.revolsys.geometry.graph.EdgePair; import com.revolsys.geometry.graph.Node; import com.revolsys.geometry.graph.RecordGraph; import com.revolsys.geometry.graph.attribute.NodeProperties; import com.revolsys.geometry.graph.attribute.PseudoNodeAttribute; import com.revolsys.geometry.graph.attribute.PseudoNodeProperty; import com.revolsys.predicate.PredicateProxy; import com.revolsys.record.Record; import com.revolsys.record.property.DirectionalFields; import com.revolsys.record.schema.RecordDefinition; import com.revolsys.util.count.LabelCountMap; /** * Find and remove nodes that have exactly two edges for each feature type with * the same attribution and have the same geometry across all feature types. * * @author Paul Austin */ public class RecordPseudoNodeRemovalVisitor extends AbstractNodeListenerVisitor<Record> implements PredicateProxy<Node<Record>> { private LabelCountMap mergedStatistics; private Predicate<Node<Record>> predicate; public RecordPseudoNodeRemovalVisitor() { } @Override public void accept(final Node<Record> node) { if (node.getEdges().size() > 1) { processPseudoNodes(node); } } @PreDestroy public void destroy() { if (this.mergedStatistics != null) { this.mergedStatistics.disconnect(); } this.mergedStatistics = null; } @Override public Predicate<Node<Record>> getPredicate() { return this.predicate; } @PostConstruct public void init() { this.mergedStatistics = new LabelCountMap("Merged at psuedo node"); this.mergedStatistics.connect(); } private void mergeEdgePairs(final Node<Record> node, final List<EdgePair<Record>> edgePairs) { if (edgePairs != null) { for (final EdgePair<Record> edgePair : edgePairs) { final Edge<Record> edge1 = edgePair.getEdge1(); final Edge<Record> edge2 = edgePair.getEdge2(); final Record object = edge1.getObject(); if (mergeEdges(node, edge1, edge2) != null) { this.mergedStatistics.addCount(object); } } } } protected Edge<Record> mergeEdges(final Node<Record> node, final Edge<Record> edge1, final Edge<Record> edge2) { final Record object1 = edge1.getObject(); final Record object2 = edge2.getObject(); final Record newObject = mergeObjects(node, object1, object2); // newObject.setIdValue(null); final RecordGraph graph = (RecordGraph)edge1.getGraph(); final Edge<Record> newEdge = graph.addEdge(newObject); graph.remove(edge1); graph.remove(edge2); return newEdge; } protected Record mergeObjects(final Node<Record> node, final Record object1, final Record object2) { return DirectionalFields.merge(node, object1, object2); } private void processPseudoNodes(final Node<Record> node) { for (final RecordDefinition recordDefinition : NodeProperties.getEdgeRecordDefinitions(node)) { final PseudoNodeProperty property = PseudoNodeProperty.getProperty(recordDefinition); final PseudoNodeAttribute pseudoNodeAttribute = property.getProperty(node); processPseudoNodesForType(node, pseudoNodeAttribute); } } private void processPseudoNodesForType(final Node<Record> node, final PseudoNodeAttribute pseudoNodeAttribute) { final List<EdgePair<Record>> reversedEdgePairs = pseudoNodeAttribute.getReversedEdgePairs(); mergeEdgePairs(node, reversedEdgePairs); final List<EdgePair<Record>> edgePairs = pseudoNodeAttribute.getEdgePairs(); mergeEdgePairs(node, edgePairs); } public void setFilter(final Predicate<Node<Record>> filter) { this.predicate = filter; } }