package com.revolsys.geometry.graph;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import com.revolsys.geometry.graph.filter.EdgeObjectFilter;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.Point;
import com.revolsys.record.Record;
import com.revolsys.record.Records;
import com.revolsys.record.filter.RecordGeometryFilter;
import com.revolsys.record.property.DirectionalFields;
import com.revolsys.record.schema.RecordDefinition;
public class RecordGraph extends Graph<Record> {
public static <T extends Geometry> Predicate<Edge<Record>> getEdgeFilter(
final Predicate<T> geometryFilter) {
final Predicate<Record> recordFilter = new RecordGeometryFilter<>(geometryFilter);
final EdgeObjectFilter<Record> edgeFilter = new EdgeObjectFilter<>(recordFilter);
return edgeFilter;
}
public RecordGraph() {
super(false);
}
public RecordGraph(final Iterable<? extends Record> records) {
addEdges(records);
}
public Edge<Record> addEdge(final Record record) {
final Geometry geometry = record.getGeometry();
if (geometry instanceof LineString) {
final LineString line = (LineString)geometry;
return addEdge(record, line);
} else if (geometry.isGeometryCollection()) {
if (geometry.getGeometryCount() == 1) {
final Geometry part = geometry.getGeometry(0);
if (part instanceof LineString) {
final LineString line = (LineString)part;
return addEdge(record, line);
}
}
}
throw new IllegalArgumentException("Cannot add edge for a " + geometry.getGeometryType());
}
public List<Edge<Record>> addEdges(final Iterable<? extends Record> records) {
final List<Edge<Record>> edges = new ArrayList<>();
for (final Record record : records) {
final Edge<Record> edge = addEdge(record);
edges.add(edge);
}
return edges;
}
/**
* Clone the record, setting the line property to the new value.
*
* @param record The record to clone.
* @param line The line.
* @return The new record.
*/
@Override
protected Record clone(final Record record, final LineString line) {
if (record == null) {
return null;
} else {
return Records.copy(record, line);
}
}
public Edge<Record> getEdge(final Record record) {
if (record != null) {
final LineString line = record.getGeometry();
return getEdge(record, line);
}
return null;
}
@Override
public LineString getEdgeLine(final int edgeId) {
final Record record = getEdgeObject(edgeId);
if (record == null) {
return null;
} else {
final LineString line = record.getGeometry();
return line;
}
}
@Override
public Node<Record> getNode(final Point point) {
return super.getNode(point);
}
public List<Record> getObjects(final Collection<Integer> edgeIds) {
final List<Record> records = new ArrayList<>();
for (final Integer edgeId : edgeIds) {
final Edge<Record> edge = getEdge(edgeId);
final Record record = edge.getObject();
records.add(record);
}
return records;
}
/**
* Get the type name for the edge.
*
* @param edge The edge.
* @return The type name.
*/
@Override
public String getTypeName(final Edge<Record> edge) {
final Record record = edge.getObject();
if (record == null) {
return null;
} else {
final RecordDefinition recordDefinition = record.getRecordDefinition();
final String typePath = recordDefinition.getPath();
return typePath;
}
}
public boolean hasEdge(final Record record) {
final LineString line = record.getGeometry();
final Point fromPoint = line.getPoint(0);
final Point toPoint = line.getToPoint();
final Node<Record> fromNode = findNode(fromPoint);
final Node<Record> toNode = findNode(toPoint);
if (fromNode != null && toNode != null) {
final Collection<Edge<Record>> edges = Node.getEdgesBetween(fromNode, toNode);
for (final Edge<Record> edge : edges) {
final LineString updateLine = edge.getLine();
if (updateLine.equals(line)) {
return true;
}
}
}
return false;
}
@Override
public Edge<Record> merge(final Node<Record> node, final Edge<Record> edge1,
final Edge<Record> edge2) {
final Record record1 = edge1.getObject();
final Record record2 = edge2.getObject();
final Record mergedObject = DirectionalFields.merge(node, record1, record2);
final Edge<Record> mergedEdge = addEdge(mergedObject);
remove(edge1);
remove(edge2);
return mergedEdge;
}
public List<Edge<Record>> splitEdges(final Point point, final double distance) {
final List<Edge<Record>> edges = new ArrayList<>();
for (final Edge<Record> edge : getEdges(point, distance)) {
final LineString line = edge.getLine();
final List<Edge<Record>> splitEdges = edge.splitEdge(point);
DirectionalFields.edgeSplitFieldValues(line, point, splitEdges);
edges.addAll(splitEdges);
}
return edges;
}
}