package com.revolsys.geometry.graph.attribute; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.function.Function; import com.revolsys.comparator.NumericComparator; import com.revolsys.geometry.graph.Edge; 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.schema.RecordDefinition; public class NodeProperties { protected static class Methods { public static Set<Double> edgeAngles(final Node<?> node) { final Set<Double> angles = new TreeSet<>(new NumericComparator<Double>()); for (final Edge<?> edge : node.getInEdges()) { final double toAngle = edge.getToAngle(); angles.add(toAngle); } for (final Edge<?> edge : node.getOutEdges()) { final double fromAngle = edge.getFromAngle(); angles.add(fromAngle); } return angles; } public static Map<String, Set<Double>> edgeAnglesByType(final Node<?> node) { final Map<String, Set<Double>> anglesByType = new HashMap<>(); for (final Edge<?> edge : node.getInEdges()) { final String typePath = edge.getTypeName(); final double toAngle = edge.getToAngle(); final Set<Double> angles = getAnglesForType(anglesByType, typePath); angles.add(toAngle); } for (final Edge<?> edge : node.getOutEdges()) { final String typePath = edge.getTypeName(); final double fromAngle = edge.getFromAngle(); final Set<Double> angles = getAnglesForType(anglesByType, typePath); angles.add(fromAngle); } return anglesByType; } public static Set<RecordDefinition> edgeRecordDefinitions(final Node<?> node) { final Set<RecordDefinition> recordDefinitions = new HashSet<>(); for (final Edge<?> edge : node.getEdges()) { final Object object = edge.getObject(); if (object instanceof Record) { final Record record = (Record)object; final RecordDefinition recordDefinition = record.getRecordDefinition(); recordDefinitions.add(recordDefinition); } } return recordDefinitions; } public static <T> Map<LineString, Map<String, Set<Edge<T>>>> edgesByLineAndTypeName( final Node<T> node) { final List<Edge<T>> edges = node.getEdges(); final Map<LineString, Map<String, Set<Edge<T>>>> lineEdgeMap = new HashMap<>(); for (final Edge<T> edge : new HashSet<>(edges)) { LineString line = edge.getLine(); Map<String, Set<Edge<T>>> edgesByType = edgesByTypeForLine(lineEdgeMap, line); if (edgesByType == null) { edgesByType = new HashMap<>(); if (edge.getEnd(node).isTo()) { line = line.reverse(); } lineEdgeMap.put(line, edgesByType); } Set<Edge<T>> typeEdges = edgesByType.get(edge.getTypeName()); if (typeEdges == null) { typeEdges = new HashSet<>(); final String typePath = edge.getTypeName(); edgesByType.put(typePath, typeEdges); } typeEdges.add(edge); } return lineEdgeMap; } public static <T> Map<String, List<Edge<T>>> edgesByType(final Node<T> node) { final Map<String, List<Edge<T>>> edgesByType = new HashMap<>(); for (final Edge<T> edge : node.getEdges()) { final String typePath = edge.getTypeName(); List<Edge<T>> typeEdges = edgesByType.get(typePath); if (typeEdges == null) { typeEdges = new ArrayList<>(); edgesByType.put(typePath, typeEdges); } typeEdges.add(edge); } return edgesByType; } private static <T> Map<String, Set<Edge<T>>> edgesByTypeForLine( final Map<LineString, Map<String, Set<Edge<T>>>> lineEdgeMap, final LineString line) { for (final Entry<LineString, Map<String, Set<Edge<T>>>> entry : lineEdgeMap.entrySet()) { final LineString keyLine = entry.getKey(); if (LineStringUtil.equalsIgnoreDirection2d(line, keyLine)) { return entry.getValue(); } } return null; } public static <T> Map<String, Map<LineString, Set<Edge<T>>>> edgesByTypeNameAndLine( final Node<T> node) { final List<Edge<T>> edges = node.getEdges(); final Map<String, Map<LineString, Set<Edge<T>>>> typeLineEdgeMap = new HashMap<>(); for (final Edge<T> edge : new HashSet<>(edges)) { final String typePath = edge.getTypeName(); Map<LineString, Set<Edge<T>>> lineEdgeMap = typeLineEdgeMap.get(typePath); if (lineEdgeMap == null) { lineEdgeMap = new HashMap<>(); typeLineEdgeMap.put(typePath, lineEdgeMap); } Edge.addEdgeToEdgesByLine(node, lineEdgeMap, edge); } return typeLineEdgeMap; } public static Set<String> edgeTypeNames(final Node<?> node) { final Set<String> typePaths = new HashSet<>(); for (final Edge<?> edge : node.getEdges()) { final String typePath = edge.getTypeName(); typePaths.add(typePath); } return typePaths; } public static Set<Double> getAnglesForType(final Map<String, Set<Double>> anglesByType, final String typePath) { Set<Double> angles = anglesByType.get(typePath); if (angles == null) { angles = new TreeSet<>(new NumericComparator<Double>()); anglesByType.put(typePath, angles); } return angles; } } public static Set<Double> getEdgeAngles(final Node<?> node) { return getField(node, "edgeAngles", Methods::edgeAngles); } public static Map<String, Set<Double>> getEdgeAnglesByType(final Node<?> node) { return getField(node, "edgeAnglesByType", Methods::edgeAnglesByType); } public static <T> Set<Double> getEdgeAnglesByType(final Node<T> node, final String typePath) { final Map<String, Set<Double>> anglesByType = getEdgeAnglesByType(node); final Set<Double> angles = anglesByType.get(typePath); return angles; } public static Set<RecordDefinition> getEdgeRecordDefinitions(final Node<? extends Object> node) { return getField(node, "edgeRecordDefinitions", Methods::edgeRecordDefinitions); } /** * Get the map of edge angles, which contains a map of type names to the list * of edges with that angle and type name. * * @param <T> * @param node The node. * @return The map. */ public static <T> Map<LineString, Map<String, Set<Edge<T>>>> getEdgesByLineAndTypeName( final Node<T> node) { return getField(node, "edgesByLineAndTypeName", Methods::edgesByLineAndTypeName); } public static <T> Map<String, List<Edge<T>>> getEdgesByType(final Node<T> node) { return getField(node, "edgesByType", Methods::edgesByType); } public static <T> List<Edge<T>> getEdgesByType(final Node<T> node, final String typePath) { final Map<String, List<Edge<T>>> edgesByType = getEdgesByType(node); final List<Edge<T>> edges = edgesByType.get(typePath); if (edges != null) { return new ArrayList<>(edges); } return Collections.emptyList(); } public static <T> Map<String, Map<LineString, Set<Edge<T>>>> getEdgesByTypeNameAndLine( final Node<T> node) { return getField(node, "edgesByTypeNameAndLine", Methods::edgesByTypeNameAndLine); } public static Set<String> getEdgeTypeNames(final Node<? extends Object> node) { return getField(node, "edgeTypeNames", Methods::edgeTypeNames); } @SuppressWarnings("unchecked") private static <T, V> V getField(final Node<T> node, final String name, final Function<Node<T>, V> function) { final String fieldName = NodeProperties.class.getName() + "." + name; if (!node.hasProperty(fieldName)) { final FunctionObjectPropertyProxy<Node<T>, V> proxy = new FunctionObjectPropertyProxy<>( function); node.setProperty(fieldName, proxy); } final V value = (V)node.getProperty(fieldName); return value; } }