package com.revolsys.geometry.graph.visitor;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import com.revolsys.geometry.filter.EqualFilter;
import com.revolsys.geometry.filter.LinearIntersectionFilter;
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.comparator.EdgeLengthComparator;
import com.revolsys.geometry.graph.filter.EdgeObjectFilter;
import com.revolsys.geometry.graph.filter.EdgeTypeNameFilter;
import com.revolsys.geometry.model.LineString;
import com.revolsys.logging.Logs;
import com.revolsys.record.Record;
import com.revolsys.record.filter.RecordGeometryFilter;
import com.revolsys.util.ObjectProcessor;
import com.revolsys.util.count.LabelCountMap;
import com.revolsys.visitor.AbstractVisitor;
public class LinearIntersectionNotEqualLineEdgeCleanupVisitor extends AbstractVisitor<Edge<Record>>
implements ObjectProcessor<RecordGraph> {
private LabelCountMap duplicateStatistics;
private Set<String> equalExcludeFieldNames = new HashSet<>(
Arrays.asList(Record.EXCLUDE_ID, Record.EXCLUDE_GEOMETRY));
private Comparator<Record> newerComparator;
public LinearIntersectionNotEqualLineEdgeCleanupVisitor() {
super.setComparator(new EdgeLengthComparator<Record>(true));
}
@Override
public void accept(final Edge<Record> edge) {
final String typePath = edge.getTypeName();
final Graph<Record> graph = edge.getGraph();
final LineString line = edge.getLine();
Predicate<Edge<Record>> attributeAndGeometryFilter = new EdgeTypeNameFilter<>(typePath);
final Predicate<Edge<Record>> filter = getPredicate();
if (filter != null) {
attributeAndGeometryFilter = attributeAndGeometryFilter.and(filter);
}
final Predicate<Record> notEqualLineFilter = new RecordGeometryFilter<>(new EqualFilter<>(line))
.negate();
final RecordGeometryFilter<LineString> linearIntersectionFilter = new RecordGeometryFilter<>(
new LinearIntersectionFilter(line));
attributeAndGeometryFilter = attributeAndGeometryFilter
.and(new EdgeObjectFilter<>(notEqualLineFilter.and(linearIntersectionFilter)));
final List<Edge<Record>> intersectingEdges = graph.getEdges(line, attributeAndGeometryFilter);
if (!intersectingEdges.isEmpty()) {
if (intersectingEdges.size() == 1 && line.getLength() > 10) {
if (line.getVertexCount() > 2) {
final Edge<Record> edge2 = intersectingEdges.get(0);
final LineString line2 = edge2.getLine();
if (middleCoordinatesEqual(line, line2)) {
final boolean firstEqual = line.equalsVertex(2, 0, line2, 0);
if (!firstEqual) {
final Node<Record> fromNode1 = edge.getFromNode();
final Node<Record> fromNode2 = edge2.getFromNode();
if (fromNode1.distancePoint(fromNode2) < 2) {
graph.moveNodesToMidpoint(typePath, fromNode1, fromNode2);
return;
}
}
final boolean lastEqual = line.equalsVertex(2, line.getVertexCount() - 1, line2,
line.getVertexCount() - 1);
if (!lastEqual) {
final Node<Record> toNode1 = edge.getToNode();
final Node<Record> toNode2 = edge2.getToNode();
if (toNode1.distancePoint(toNode2) < 2) {
graph.moveNodesToMidpoint(typePath, toNode1, toNode2);
return;
}
}
}
}
}
Logs.error(this, "Has intersecting edges " + line);
}
}
@PreDestroy
public void destroy() {
if (this.duplicateStatistics != null) {
this.duplicateStatistics.disconnect();
}
this.duplicateStatistics = null;
}
public Set<String> getEqualExcludeFieldNames() {
return this.equalExcludeFieldNames;
}
public Comparator<Record> getNewerComparator() {
return this.newerComparator;
}
@PostConstruct
public void init() {
this.duplicateStatistics = new LabelCountMap("Duplicate intersecting lines");
this.duplicateStatistics.connect();
}
private boolean middleCoordinatesEqual(final LineString points1, final LineString points2) {
if (points1.getVertexCount() == points2.getVertexCount()) {
for (int i = 1; i < points2.getVertexCount(); i++) {
if (!points1.equalsVertex(2, i, points1, i)) {
return false;
}
}
return true;
} else {
return false;
}
}
@Override
public void process(final RecordGraph graph) {
graph.forEachEdge(this);
}
@Override
public void setComparator(final Comparator<Edge<Record>> comparator) {
throw new IllegalArgumentException("Cannot override comparator");
}
public void setEqualExcludeFieldNames(final Collection<String> equalExcludeFieldNames) {
setEqualExcludeFieldNames(new HashSet<>(equalExcludeFieldNames));
}
public void setEqualExcludeFieldNames(final Set<String> equalExcludeFieldNames) {
this.equalExcludeFieldNames = new HashSet<>(equalExcludeFieldNames);
this.equalExcludeFieldNames.add(Record.EXCLUDE_ID);
this.equalExcludeFieldNames.add(Record.EXCLUDE_GEOMETRY);
}
public void setNewerComparator(final Comparator<Record> newerComparator) {
this.newerComparator = newerComparator;
}
}