private static bool ValidateFlowDirection( [NotNull] IFeature feature, [NotNull] ILinearNetworkFeatureFinder featureFinder, [NotNull] NotificationCollection notifications) { if (((IFeatureClass)feature.Class).ShapeType != esriGeometryType.esriGeometryPolyline) { return(true); } IGeometry newGeometry = feature.Shape; IPolyline polyline = (IPolyline)newGeometry; bool hasCorrectOrientation = false; bool hasWrongOrientation = false; int fromEdgeCount = ValidateConnections(feature, LineEnd.From, featureFinder, ref hasCorrectOrientation, ref hasWrongOrientation); int toEdgeCount = ValidateConnections(feature, LineEnd.To, featureFinder, ref hasCorrectOrientation, ref hasWrongOrientation); if (!hasWrongOrientation) { return(true); } if (!hasCorrectOrientation) { // all other connections are different -> flip polyline.ReverseOrientation(); feature.Shape = polyline; feature.Store(); _msg.InfoFormat("Feature {0} was flipped to enforce flow direction", GdbObjectUtils.ToString(feature)); return(true); } // Mixed situation: if (fromEdgeCount <= 1 && toEdgeCount <= 1) { // No bifurcation or confluence but still incorrect at one end -> error? NotificationUtils.Add(notifications, "Feature {0} does not have a consistent flow direction with respect to its connected edges", GdbObjectUtils.ToString(feature)); return(false); } // Confluence or bifurcation -> probably ok return(true); }
private bool ValidateGeometry([NotNull] IFeature feature, [NotNull] ILinearNetworkFeatureFinder featureFinder, [NotNull] NotificationCollection notifications) { bool result = ValidatePartCount(feature.Shape, GdbObjectUtils.ToString(feature), notifications); if (!AllowLoops) { result &= ValidateNoLoop(feature.Shape, GdbObjectUtils.ToString(feature), notifications); } return(result); }
public LinearNetworkEditAgent( [NotNull] LinearNetworkDef networkDefinition, [NotNull] ILinearNetworkFeatureFinder networkFeatureFinder) { NetworkDefinition = networkDefinition; NetworkFeatureFinder = networkFeatureFinder; // TODO: Use CustomTolerance if larger than tolerance _searchTolerance = SpatialReferenceUtils.GetXyTolerance(NetworkDefinition.GetSpatialReference()); _createdInOperation = new HashSet <IFeature>(); _updatedInOperation = new Dictionary <IFeature, IGeometry>(3); _deletedInOperation = new List <IFeature>(3); }
/// <summary> /// Stores the result of a merge operation by updating the specified survivor feature /// with the merged geometry and deleting the features that are not needed any more. /// In case the features are geometric network edges the network junctions between the /// original features can be deleted, if required by the provided predicate. /// </summary> /// <param name="survivingFeature">The feature that should remain after the merge operation.</param> /// <param name="featuresToDelete">The features that should be deleted by the merge operation.</param> /// <param name="mergedGeometry">The merged geometry.</param> /// <param name="linearNetworkFeatureFinder"></param> /// <param name="deleteIntermediateNetworkJunctions">The predicate that determines /// which intermediate junctions (between the original edges) should be deleted.</param> /// <param name="deletedJunctionIDs">The junctions that were deleted.</param> /// <remarks>Should be called within an edit operation.</remarks> public static void StoreEdgeFeatureMerge( [NotNull] IFeature survivingFeature, [NotNull] IEnumerable <IFeature> featuresToDelete, [NotNull] IPolyline mergedGeometry, [CanBeNull] ILinearNetworkFeatureFinder linearNetworkFeatureFinder, [CanBeNull] Predicate <IFeature> deleteIntermediateNetworkJunctions, out List <int> deletedJunctionIDs) { Assert.ArgumentNotNull(survivingFeature, nameof(survivingFeature)); Assert.ArgumentNotNull(featuresToDelete, nameof(featuresToDelete)); Assert.ArgumentNotNull(mergedGeometry, nameof(mergedGeometry)); deletedJunctionIDs = new List <int>(); foreach (IFeature featureToDelete in featuresToDelete) { if (linearNetworkFeatureFinder != null) { IPolyline edgePolyline = (IPolyline)featureToDelete.Shape; IList <IFeature> fromJunctions = linearNetworkFeatureFinder.FindJunctionFeaturesAt(edgePolyline.FromPoint); deletedJunctionIDs.AddRange( DeleteIntermediateJunctions(fromJunctions, deleteIntermediateNetworkJunctions, linearNetworkFeatureFinder, mergedGeometry)); IList <IFeature> toJunctions = linearNetworkFeatureFinder.FindJunctionFeaturesAt(edgePolyline.ToPoint); deletedJunctionIDs.AddRange( DeleteIntermediateJunctions(toJunctions, deleteIntermediateNetworkJunctions, linearNetworkFeatureFinder, mergedGeometry)); } featureToDelete.Delete(); } GdbObjectUtils.SetFeatureShape(survivingFeature, mergedGeometry); survivingFeature.Store(); }
private static IEnumerable <int> DeleteIntermediateJunctions( [NotNull] IEnumerable <IFeature> junctions, [CanBeNull] Predicate <IFeature> predicate, [NotNull] ILinearNetworkFeatureFinder linearNetworkFeatureFinder, [NotNull] IPolyline mergedLine) { var result = new List <int>(); foreach (IFeature junction in junctions) { if (predicate != null && !predicate(junction)) { continue; } IPoint junctionPoint = (IPoint)junction.Shape; int edgeCount = linearNetworkFeatureFinder.FindEdgeFeaturesAt(junctionPoint).Count; if (edgeCount <= 2) { // Check if it is still needed for the merged geometry IPoint fromPoint = mergedLine.FromPoint; IPoint toPoint = mergedLine.ToPoint; bool neededForMergedLine = GeometryUtils.AreEqualInXY(junctionPoint, fromPoint) || GeometryUtils.AreEqualInXY(junctionPoint, toPoint); if (!neededForMergedLine) { result.Add(junction.OID); junction.Delete(); } } } return(result); }
public void PerformFinalValidation( [NotNull] Dictionary <IFeature, IGeometry> updates, [NotNull] IEnumerable <IFeature> inserts, [NotNull] ILinearNetworkFeatureFinder networkFeatureFinder) { bool valid = true; NotificationCollection notifications = new NotificationCollection(); if (EnforceFlowDirection) { foreach (var update in updates) { valid &= ValidateFlowDirection(update.Key, networkFeatureFinder, notifications); } foreach (IFeature insert in inserts) { valid &= ValidateFlowDirection(insert, networkFeatureFinder, notifications); } } HandleValidationResult(valid, notifications); }
public void ValidateIndividualGeometries( [NotNull] Dictionary <IFeature, IGeometry> updates, [NotNull] IEnumerable <IFeature> inserts, [NotNull] ILinearNetworkFeatureFinder networkFeatureFinder) { bool valid = true; var notifications = new NotificationCollection(); foreach (var keyValuePair in updates) { IFeature feature = keyValuePair.Key; valid &= ValidateGeometry(feature, networkFeatureFinder, notifications); } foreach (IFeature newFeature in inserts) { valid &= ValidateGeometry(newFeature, networkFeatureFinder, notifications); } HandleValidationResult(valid, notifications); }
private static int ValidateConnections([NotNull] IFeature feature, LineEnd atLineEnd, [NotNull] ILinearNetworkFeatureFinder featureFinder, ref bool hasCorrectOrientation, ref bool hasWrongOrientation) { IPolyline polyline = (IPolyline)feature.Shape; IList <IFeature> connectedEdgeFeatures = featureFinder.GetConnectedEdgeFeatures(feature, polyline, atLineEnd); IPoint thisLineEndPoint = atLineEnd == LineEnd.From ? polyline.FromPoint : polyline.ToPoint; foreach (IFeature connectedAtFrom in connectedEdgeFeatures) { IPolyline connectedPolyline = (IPolyline)connectedAtFrom.Shape; IPoint otherLineEndPoint = atLineEnd == LineEnd.From ? connectedPolyline.ToPoint : connectedPolyline.FromPoint; if (GeometryUtils.AreEqual(otherLineEndPoint, thisLineEndPoint)) { // correct orientation hasCorrectOrientation = true; } else { hasWrongOrientation = true; } } return(connectedEdgeFeatures.Count); }
public LinearNetworkNodeUpdater([NotNull] ILinearNetworkFeatureFinder networkFeatureFinder) { Assert.ArgumentNotNull(networkFeatureFinder, nameof(networkFeatureFinder)); NetworkFeatureFinder = networkFeatureFinder; }
public static bool SnapPoint([NotNull] IPoint newEndPoint, [NotNull] IList <IFeature> candidateTargetEdges, [NotNull] ILinearNetworkFeatureFinder networkFeatureFinder) { if (networkFeatureFinder.SearchTolerance <= 0) { return(false); } Pnt2D newEndPnt = new Pnt2D(newEndPoint.X, newEndPoint.Y); IPoint fromPoint = new PointClass() { SpatialReference = newEndPoint.SpatialReference }; IPoint toPoint = new PointClass() { SpatialReference = newEndPoint.SpatialReference }; double searchToleranceSquared = networkFeatureFinder.SearchTolerance * networkFeatureFinder.SearchTolerance; bool snapped = false; foreach (IFeature feature in candidateTargetEdges) { IPolyline otherPolyline = (IPolyline)feature.Shape; otherPolyline.QueryFromPoint(fromPoint); Pnt2D fromPnt = new Pnt2D(fromPoint.X, fromPoint.Y); double fromDistance2 = fromPnt.Dist2(newEndPnt); otherPolyline.QueryToPoint(toPoint); Pnt2D toPnt = new Pnt2D(toPoint.X, toPoint.Y); double toDistance2 = toPnt.Dist2(newEndPnt); if (fromDistance2 > searchToleranceSquared && toDistance2 > searchToleranceSquared) { continue; } if (Math.Min(fromDistance2, toDistance2) < GetXyResolutionSquared(feature)) { // already snapped continue; } IPoint sourcePoint = fromDistance2 < toDistance2 ? fromPoint : toPoint; snapped = true; CopyCoords(sourcePoint, newEndPoint); } if (!snapped) { // Try snapping onto curve interior foreach (IFeature feature in candidateTargetEdges) { IPolyline otherPolyline = (IPolyline)feature.Shape; double distanceFromCurve = GeometryUtils.GetDistanceFromCurve(newEndPoint, otherPolyline, fromPoint); if (distanceFromCurve >= 0 && distanceFromCurve < networkFeatureFinder.SearchTolerance) { snapped = true; CopyCoords(fromPoint, newEndPoint); } } } return(snapped); }