public void RemoveConnection(GdbObjectReference edge, IEnumerable <IPoint> fromPoints) { foreach (IPoint point in fromPoints) { int index; if (TryGetNodeIndex(point, out index)) { var connectionsToRemove = new List <AdjacentNode>(1); foreach (AdjacentNode adjacentNode in Connections[index]) { if (EdgeReferences[adjacentNode.EdgeIndex].Equals(edge)) { connectionsToRemove.Add(adjacentNode); } } foreach (AdjacentNode adjacentNodeToRemove in connectionsToRemove) { Connections[index].Remove(adjacentNodeToRemove); } } } }
private void AddConnectivity(GdbObjectReference objRef, int fromNodeIndex, int toNodeIndex, float weight, bool respectLineOrientation, ICollection <AdjacentNode> connectedNodesAtFrom, ICollection <AdjacentNode> connectedNodesAtTo) { // adjacency: int edgeIndex = EdgeReferences.Count; EdgeReferences.Add(objRef); // Allow adding the edge, even if its to point is outside the AOI and no connection can // be made. It is still relevant for the node degree count (number of edges at from). if (fromNodeIndex >= 0) { var fromToEdge = new AdjacentNode(toNodeIndex, weight, edgeIndex); connectedNodesAtFrom.Add(fromToEdge); } if (!respectLineOrientation && toNodeIndex >= 0) { var toFromEdge = new AdjacentNode(fromNodeIndex, weight, edgeIndex); connectedNodesAtTo.Add(toFromEdge); } }
public static Overlaps CalculateOverlaps( RemoveOverlapsGrpc.RemoveOverlapsGrpcClient rpcClient, [NotNull] IList <Feature> selectedFeatures, [NotNull] IList <Feature> overlappingFeatures, CancellationToken cancellationToken) { CalculateOverlapsResponse response = CalculateOverlapsRpc(rpcClient, selectedFeatures, overlappingFeatures, cancellationToken); if (response == null || cancellationToken.IsCancellationRequested) { return(null); } var result = new Overlaps(); foreach (OverlapMsg overlapMsg in response.Overlaps) { GdbObjectReference gdbObjRef = new GdbObjectReference( overlapMsg.OriginalFeatureRef.ClassHandle, overlapMsg.OriginalFeatureRef.ObjectId); List <Geometry> overlapGeometries = ProtobufConversionUtils.FromShapeMsgList(overlapMsg.Overlaps); result.AddGeometries(gdbObjRef, overlapGeometries); } result.Notifications.AddRange( response.Notifications.Select(n => new Notification(n))); return(result); }
public static ReshapeResult TryReshape( [NotNull] ReshapeGrpc.ReshapeGrpcClient rpcClient, [NotNull] IList <Feature> selectedFeatures, [NotNull] Polyline reshapeLine, [CanBeNull] IList <Feature> adjacentFeatures, bool allowOpenJawReshape, bool multiReshapeAsUnion, bool tryReshapeNonDefault, CancellationToken cancellationToken) { var allInputFeatures = new Dictionary <GdbObjectReference, Feature>(); AddInputFeatures(selectedFeatures, allInputFeatures); var request = CreateReshapeRequest( selectedFeatures, reshapeLine, adjacentFeatures, allowOpenJawReshape, multiReshapeAsUnion, tryReshapeNonDefault); request.AllowOpenJawReshape = true; // TODO: If the server is overwhelmed by requests, the calls block (and cannot even be cancelled) // Add a task scheduler mode that throws if no free thread is available immediately const int deadline = 2000; AdvancedReshapeResponse reshapeResultMsg = RpcCallUtils.Try( o => rpcClient.AdvancedReshape(request, o), cancellationToken, deadline, true); if (reshapeResultMsg == null) { return(null); } var result = new ReshapeResult { OpenJawReshapeHappened = reshapeResultMsg.OpenJawReshapeHappened, OpenJawIntersectionCount = reshapeResultMsg.OpenJawIntersectionCount, FailureMessage = reshapeResultMsg.WarningMessage }; if (reshapeResultMsg.ResultFeatures.Count == 0) { return(result); } foreach (ResultFeatureMsg resultFeatureMsg in reshapeResultMsg.ResultFeatures) { GdbObjectReference objRef = new GdbObjectReference( resultFeatureMsg.UpdatedFeature.ClassHandle, resultFeatureMsg.UpdatedFeature.ObjectId); Feature inputFeature = allInputFeatures[objRef]; var reshapeResultFeature = new ReshapeResultFeature(inputFeature, resultFeatureMsg); result.ResultFeatures.Add(reshapeResultFeature); } return(result); }
private static ChangeAlongCurves PopulateReshapeAlongCurves( [NotNull] IList <Feature> sourceFeatures, [NotNull] IList <Feature> targetFeatures, IEnumerable <ReshapeLineMsg> reshapeLineMsgs, ReshapeAlongCurveUsability cutSubcurveUsability) { IList <CutSubcurve> resultSubcurves = new List <CutSubcurve>(); foreach (var reshapeLineMsg in reshapeLineMsgs) { CutSubcurve cutSubcurve = FromReshapeLineMsg(reshapeLineMsg); Assert.NotNull(cutSubcurve); if (reshapeLineMsg.Source != null) { var sourceRef = new GdbObjectReference(reshapeLineMsg.Source.ClassHandle, reshapeLineMsg.Source.ObjectId); cutSubcurve.Source = sourceFeatures.First(f => sourceRef.References(f)); } resultSubcurves.Add(cutSubcurve); } return(new ChangeAlongCurves(resultSubcurves, cutSubcurveUsability) { TargetFeatures = targetFeatures }); }
public static GdbObjRefMsg ToGdbObjRefMsg(GdbObjectReference gdbObjectReference) { return(new GdbObjRefMsg { ClassHandle = gdbObjectReference.ClassId, ObjectId = gdbObjectReference.ObjectId }); }
// Additional methods to be considered, once there is a need: //public int GetIncidentEdges(GdbObjectReference nodeFeatureRef, // IList<GdbObjectReference> result){} //public int GetIncidentEdges(IPoint nodeLocation, IList<GdbObjectReference> result){} // Add additional dictionary <EdgeRef,Adjacent> once this is needed //public int GetConnectedEdges(GdbObjectReference edgeFeatureRef, // IList<GdbObjectReference> result, // LineEnd ends = LineEnd.Both) { } private void AddConnectivity(GdbObjectReference objRef, int fromNodeIndex, int toNodeIndex, float weight, bool respectLineOrientation) { List <AdjacentNode> connectedNodesAtFrom = Connections[fromNodeIndex]; List <AdjacentNode> connectedNodesAtTo = Connections[toNodeIndex]; AddConnectivity(objRef, fromNodeIndex, toNodeIndex, weight, respectLineOrientation, connectedNodesAtFrom, connectedNodesAtTo); }
public void AddGeometries(GdbObjectReference sourceFeatureRef, IList <IGeometry> overlapGeometries) { if (overlapGeometries.Count == 0) { return; } OverlapsBySourceRef.Add(sourceFeatureRef, overlapGeometries); }
private IEnumerable <GdbObjectReference> GetIncidentEdges(int nodeIndex) { List <AdjacentNode> connections = Connections[nodeIndex]; foreach (AdjacentNode adjacentNode in connections) { int edgeIndex = adjacentNode.EdgeIndex; GdbObjectReference edgeRef = EdgeReferences[edgeIndex]; yield return(edgeRef); } }
private static GdbObjRefMsg GetGdbObjRefMsg(AllowedError allowedError) { GdbObjectReference objReference = allowedError.GetObjectReference(); var result = new GdbObjRefMsg() { ClassHandle = objReference.ClassId, ObjectId = objReference.ObjectId }; return(result); }
public IEnumerable <GdbObjectReference> GetIncidentEdges(GdbObjectReference nodeFeatureRef) { int nodeIndex; if (!NodeIndexesByNodeReference.TryGetValue(nodeFeatureRef, out nodeIndex)) { yield break; } foreach (GdbObjectReference edgeRef in GetIncidentEdges(nodeIndex)) { yield return(edgeRef); } }
private static void AddRange( [NotNull] IList <Feature> features, [NotNull] IDictionary <GdbObjectReference, Feature> resultDictionary) { foreach (Feature target in features) { var objRef = new GdbObjectReference(target.GetTable().Handle.ToInt64(), target.GetObjectID()); if (!resultDictionary.ContainsKey(objRef)) { resultDictionary.Add(objRef, target); } } }
private static ReshapeResult Reshape( [NotNull] ReshapeGrpc.ReshapeGrpcClient rpcClient, [NotNull] AdvancedReshapeRequest request, [NotNull] IReadOnlyDictionary <GdbObjectReference, Feature> allInputFeatures, CancellationToken cancellationToken) { request.AllowOpenJawReshape = true; const int deadlinePerFeature = 5000; AdvancedReshapeResponse reshapeResultMsg = RpcCallUtils.Try( o => rpcClient.AdvancedReshape(request, o), cancellationToken, deadlinePerFeature * request.Features.Count); if (reshapeResultMsg == null) { return(null); } var result = new ReshapeResult { OpenJawReshapeHappened = reshapeResultMsg.OpenJawReshapeHappened, OpenJawIntersectionCount = reshapeResultMsg.OpenJawIntersectionCount, FailureMessage = reshapeResultMsg.WarningMessage }; if (reshapeResultMsg.ResultFeatures.Count == 0) { return(result); } foreach (ResultFeatureMsg resultFeatureMsg in reshapeResultMsg.ResultFeatures) { GdbObjectReference objRef = new GdbObjectReference( resultFeatureMsg.UpdatedFeature.ClassHandle, resultFeatureMsg.UpdatedFeature.ObjectId); Feature inputFeature = allInputFeatures[objRef]; var reshapeResultFeature = new ReshapeResultFeature(inputFeature, resultFeatureMsg); result.ResultFeatures.Add(reshapeResultFeature); } return(result); }
private static IList <Feature> GetDistinctSelectedFeatures( [NotNull] IEnumerable <KeyValuePair <FeatureClass, List <Feature> > > foundFeaturesByClass, [CanBeNull] IList <Feature> existingSelection, bool xor) { var resultDictionary = new Dictionary <GdbObjectReference, Feature>(); if (existingSelection != null) { AddRange(existingSelection, resultDictionary); } foreach (var keyValuePair in foundFeaturesByClass) { if (xor) { foreach (Feature selected in keyValuePair.Value) { var selectedObjRef = new GdbObjectReference( selected.GetTable().Handle.ToInt64(), selected.GetObjectID()); if (resultDictionary.ContainsKey(selectedObjRef)) { resultDictionary.Remove(selectedObjRef); } else { resultDictionary.Add(selectedObjRef, selected); } } } else { AddRange(keyValuePair.Value, resultDictionary); } } IList <Feature> allTargetFeatures = resultDictionary.Values.ToList(); return(allTargetFeatures); }
/// <summary> /// Adds the connectivity between the provided feature's from/to points/nodes to the /// graph. The from/to nodes are also added if necessary and their respective indexes /// are returned as out parameters. /// </summary> /// <param name="forEdgeFeature">The line feature</param> /// <param name="respectLineOrientation">Whether the connection should only be added /// in one direction (along the line orientation).</param> /// <param name="fromNodeIndex">The from-node index in <see cref="Nodes"/></param> /// <param name="toNodeIndex">The to-node index in <see cref="Nodes"/></param> public void AddConnectivity([NotNull] IFeature forEdgeFeature, bool respectLineOrientation, out int fromNodeIndex, out int toNodeIndex) { var polyline = (IPolyline)forEdgeFeature.Shape; polyline.QueryFromPoint(_queryPointFrom); polyline.QueryToPoint(_queryPointTo); GdbObjectReference objRef = new GdbObjectReference(forEdgeFeature); float weight = (float)polyline.Length; fromNodeIndex = AddNode(_queryPointFrom, out List <AdjacentNode> connectedNodesAtFrom); toNodeIndex = AddNode(_queryPointTo, out List <AdjacentNode> connectedNodesAtTo); AddConnectivity(objRef, fromNodeIndex, toNodeIndex, weight, respectLineOrientation, connectedNodesAtFrom, connectedNodesAtTo); Marshal.ReleaseComObject(polyline); }
public static List <ResultFeature> ApplyCutCurves( [NotNull] ChangeAlongGrpc.ChangeAlongGrpcClient rpcClient, [NotNull] IList <Feature> sourceFeatures, [NotNull] IList <Feature> targetFeatures, [NotNull] IList <CutSubcurve> selectedSubcurves, CancellationToken cancellationToken, out ChangeAlongCurves newChangeAlongCurves) { Dictionary <GdbObjectReference, Feature> featuresByObjRef = CreateFeatureDictionary(sourceFeatures, targetFeatures); ApplyCutLinesRequest request = CreateApplyCutCurvesRequest(sourceFeatures, targetFeatures, selectedSubcurves); ApplyCutLinesResponse response = rpcClient.ApplyCutLines(request, null, null, cancellationToken); List <ResultObjectMsg> responseResultFeatures = response.ResultFeatures.ToList(); var resultFeatures = new List <ResultFeature>(); foreach (ResultObjectMsg resultObjectMsg in responseResultFeatures) { GdbObjectReference originalFeatureRef = GetOriginalGdbObjectReference(resultObjectMsg); Feature originalFeature = featuresByObjRef[originalFeatureRef]; ResultFeature resultFeature = new ResultFeature( originalFeature, resultObjectMsg); resultFeatures.Add(resultFeature); } newChangeAlongCurves = PopulateReshapeAlongCurves( sourceFeatures, targetFeatures, response.NewCutLines, (ReshapeAlongCurveUsability)response.CutLinesUsability); return(resultFeatures); }
private static ReshapeLineMsg ToReshapeLineMsg([NotNull] CutSubcurve cutSubcurve) { var result = new ReshapeLineMsg(); result.Path = ProtobufGeometryUtils.ToShapeMsg(cutSubcurve.Path); result.CanReshape = cutSubcurve.CanReshape; result.IsCandidate = cutSubcurve.IsReshapeMemberCandidate; result.IsFiltered = cutSubcurve.IsFiltered; result.TargetSegmentAtFrom = cutSubcurve.FromPointIsStitchPoint ? ProtobufGeometryUtils.ToShapeMsg(cutSubcurve.TargetSegmentAtFromPoint) : null; result.TargetSegmentAtTo = cutSubcurve.ToPointIsStitchPoint ? ProtobufGeometryUtils.ToShapeMsg(cutSubcurve.TargetSegmentAtToPoint) : null; if (cutSubcurve.ExtraTargetInsertPoints != null) { result.ExtraTargetInsertPoints = ProtobufGeometryUtils.ToShapeMsg( GeometryFactory.CreateMultipoint(cutSubcurve.ExtraTargetInsertPoints)); } if (cutSubcurve.Source != null) { GdbObjectReference sourceObjRef = cutSubcurve.Source.Value; result.Source = new GdbObjRefMsg { ClassHandle = sourceObjRef.ClassId, ObjectId = sourceObjRef.ObjectId }; } return(result); }
/// <summary> /// Calculates the result geometries and adds them to the relevant dictionaries. /// </summary> /// <param name="fromFeatures"></param> /// <param name="overlaps"></param> /// <param name="targetFeaturesForVertexInsertion"></param> /// <param name="trackCancel"></param> public void CalculateResults( [NotNull] IEnumerable <IFeature> fromFeatures, [NotNull] Overlaps overlaps, [CanBeNull] ICollection <IFeature> targetFeaturesForVertexInsertion = null, [CanBeNull] ITrackCancel trackCancel = null) { Assert.ArgumentNotNull(fromFeatures, nameof(fromFeatures)); Assert.ArgumentNotNull(overlaps, nameof(overlaps)); foreach (IFeature feature in fromFeatures) { if (trackCancel != null && !trackCancel.Continue()) { return; } var gdbObjRef = new GdbObjectReference(feature); IList <IGeometry> overlapsForFeature; if (!overlaps.OverlapsBySourceRef.TryGetValue(gdbObjRef, out overlapsForFeature)) { _msg.DebugFormat("No overlaps for feature {0}", gdbObjRef); continue; } IPolycurve overlapGeometry = (IPolycurve)GeometryUtils.Union(overlapsForFeature); ProcessFeature(feature, overlapGeometry); if (targetFeaturesForVertexInsertion != null) { // TODO: Filter target features using spatial index! InsertIntersectingVerticesInTargets(targetFeaturesForVertexInsertion, overlapGeometry); } } }
public int AddEdgeInteriorNode([NotNull] IFeature edgeFeature, [NotNull] IPoint location, bool respectLineOrientation) { if (AreaOfInterest != null && GeometryUtils.Disjoint(AreaOfInterest, location)) { throw new InvalidOperationException( $"The provided location {GeometryUtils.ToString(location)} is outside the AoI. Cannot add edge interior node"); } // TODO: Consider blocking the existing edge (requires the BlockedEdgeIndex list from Dijkstra to be referenced here) // However, an extra path that has the same lenght as the 'split' paths do not harm the resolution. Furthermore // It simplifies removing the edge-interior node later on - the original connection is still valid! // Virtual split, add the two parts var polyline = (IPolyline)edgeFeature.Shape; double distanceAlong = GeometryUtils.GetDistanceAlongCurve(polyline, location); // Edges // The blocking logic works by edge index. Therefore it is ok to add the same GdbObjRef twice. // Alternatively we could create an edge list that can also contain sub-feature edges. var gdbObjRef = new GdbObjectReference(edgeFeature); polyline.QueryFromPoint(_queryPointFrom); polyline.QueryToPoint(_queryPointTo); int fromIndex = AddNode(_queryPointFrom, out List <AdjacentNode> _); int toIndex = AddNode(_queryPointTo, out List <AdjacentNode> _); // split the weight var weightToLocation = (float)distanceAlong; var weightFromLocation = (float)(polyline.Length - distanceAlong); // check other interior nodes on the same edge List <int> interiorNodes; if (!EdgeInteriorNodesByEdge.TryGetValue(gdbObjRef, out interiorNodes)) { interiorNodes = new List <int>(2); EdgeInteriorNodesByEdge.Add(gdbObjRef, interiorNodes); } if (interiorNodes.Count > 1) { throw new NotImplementedException( "More than two nodes in the interior of a single polyline is not supported."); } // special case: there is already an intermediate node on the same edge -> update from-/to- information if (interiorNodes.Count == 1) { int existingNodeIndex = interiorNodes[0]; Node existingNode = Assert.NotNull(Nodes[existingNodeIndex]); _queryPointFrom.PutCoords(existingNode.X, existingNode.Y); double distanceAlongExisting = GeometryUtils.GetDistanceAlongCurve(polyline, _queryPointFrom); if (distanceAlongExisting < distanceAlong) { // the existing interior node is before this node along the line weightToLocation = (float)(distanceAlong - distanceAlongExisting); fromIndex = existingNodeIndex; } else { // the existing interior node is after this node along the line weightFromLocation = (float)(distanceAlongExisting - distanceAlong); toIndex = existingNodeIndex; } } // Add the interior node and the split edges: List <AdjacentNode> connectedNodes; int thisNodeIndex = AddNode(location, out connectedNodes); AddConnectivity(gdbObjRef, fromIndex, thisNodeIndex, weightToLocation, respectLineOrientation); AddConnectivity(gdbObjRef, thisNodeIndex, toIndex, weightFromLocation, respectLineOrientation); // add to interior edges list interiorNodes.Add(thisNodeIndex); return(thisNodeIndex); }
public void CanCalculateOverlaps() { var fClass = new GdbFeatureClass(123, "TestFC", esriGeometryType.esriGeometryPolygon); var sr = SpatialReferenceUtils.CreateSpatialReference( WellKnownHorizontalCS.LV95, WellKnownVerticalCS.LN02); fClass.SpatialReference = sr; IPolygon polygon1 = GeometryFactory.CreatePolygon( GeometryFactory.CreatePoint(2600000, 1200000, sr), GeometryFactory.CreatePoint(2601000, 1201000, sr)); polygon1.SpatialReference = sr; GdbFeature sourceFeature = new GdbFeature(42, fClass) { Shape = polygon1 }; IPolygon polygon2 = GeometryFactory.CreatePolygon( GeometryFactory.CreatePoint(2600500, 1200500, sr), GeometryFactory.CreatePoint(2601500, 1201500, sr)); polygon2.SpatialReference = sr; GdbFeature targetFeature = new GdbFeature(43, fClass) { Shape = polygon2 }; var sourceFeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(sourceFeature); var targetFeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(targetFeature); var objectClassMsg = ProtobufGdbUtils.ToObjectClassMsg(sourceFeature.Class); CalculateOverlapsRequest calculationRequest = new CalculateOverlapsRequest() { ClassDefinitions = { objectClassMsg }, SourceFeatures = { sourceFeatureMsg }, TargetFeatures = { targetFeatureMsg } }; CalculateOverlapsResponse response = RemoveOverlapsServiceUtils.CalculateOverlaps(calculationRequest, null); Assert.AreEqual(1, response.Overlaps.Count); List <ShapeMsg> shapeBufferList = response.Overlaps.SelectMany(kvp => kvp.Overlaps).ToList(); List <IPolygon> resultPolys = ProtobufGeometryUtils.FromShapeMsgList <IPolygon>(shapeBufferList); Assert.AreEqual(1, resultPolys.Count); Assert.AreEqual(1000 * 1000 / 4, ((IArea)resultPolys[0]).Area); // Now the removal: RemoveOverlapsRequest removeRequest = new RemoveOverlapsRequest(); removeRequest.ClassDefinitions.AddRange(calculationRequest.ClassDefinitions); removeRequest.SourceFeatures.AddRange(calculationRequest.SourceFeatures); removeRequest.Overlaps.Add(response.Overlaps); RemoveOverlapsResponse removeResponse = RemoveOverlapsServiceUtils.RemoveOverlaps(removeRequest); Assert.AreEqual(1, removeResponse.ResultsByFeature.Count); ResultGeometriesByFeature resultByFeature = removeResponse.ResultsByFeature[0]; GdbObjectReference originalObjRef = new GdbObjectReference( resultByFeature.OriginalFeatureRef.ClassHandle, resultByFeature.OriginalFeatureRef.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), originalObjRef); var updatedGeometry = ProtobufGeometryUtils.FromShapeMsg(resultByFeature.UpdatedGeometry); Assert.IsNotNull(updatedGeometry); Assert.AreEqual(1000 * 1000 * 3 / 4, ((IArea)updatedGeometry).Area); Assert.AreEqual(0, resultByFeature.NewGeometries.Count); }
public void CanRemoveOverlaps() { var fClass = new GdbFeatureClass(123, "TestFC", esriGeometryType.esriGeometryPolygon); var sr = SpatialReferenceUtils.CreateSpatialReference( WellKnownHorizontalCS.LV95, WellKnownVerticalCS.LN02); IPolygon polygon1 = GeometryFactory.CreatePolygon( GeometryFactory.CreatePoint(2600000, 1200000, sr), GeometryFactory.CreatePoint(2601000, 1201000, sr)); polygon1.SpatialReference = sr; GdbFeature sourceFeature = new GdbFeature(42, fClass) { Shape = polygon1 }; IPolygon polygon2 = GeometryFactory.CreatePolygon( GeometryFactory.CreatePoint(2600500, 1200500, sr), GeometryFactory.CreatePoint(2601500, 1201500, sr)); polygon2.SpatialReference = sr; GdbFeature targetFeature = new GdbFeature(43, fClass) { Shape = polygon2 }; IPolygon overlap = GeometryFactory.CreatePolygon( GeometryFactory.CreatePoint(2600500, 1200500, sr), GeometryFactory.CreatePoint(2601000, 1201000, sr)); overlap.SpatialReference = sr; var sourceFeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(sourceFeature); var targetFeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(targetFeature); var objectClassMsg = ProtobufGdbUtils.ToObjectClassMsg(sourceFeature.Class); var removeRequest = new RemoveOverlapsRequest() { ClassDefinitions = { objectClassMsg }, SourceFeatures = { sourceFeatureMsg }, UpdatableTargetFeatures = { targetFeatureMsg } }; var overlapsMsg = new OverlapMsg(); overlapsMsg.OriginalFeatureRef = new GdbObjRefMsg() { ClassHandle = sourceFeatureMsg.ClassHandle, ObjectId = sourceFeatureMsg.ObjectId }; overlapsMsg.Overlaps.Add(ProtobufGeometryUtils.ToShapeMsg(overlap)); removeRequest.Overlaps.Add(overlapsMsg); RemoveOverlapsResponse removeResponse = RemoveOverlapsServiceUtils.RemoveOverlaps(removeRequest); Assert.AreEqual(1, removeResponse.ResultsByFeature.Count); ResultGeometriesByFeature resultByFeature = removeResponse.ResultsByFeature[0]; GdbObjectReference originalObjRef = new GdbObjectReference( resultByFeature.OriginalFeatureRef.ClassHandle, resultByFeature.OriginalFeatureRef.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), originalObjRef); IGeometry updatedGeometry = ProtobufGeometryUtils.FromShapeMsg(resultByFeature.UpdatedGeometry); Assert.IsNotNull(updatedGeometry); Assert.AreEqual(1000 * 1000 * 3 / 4, ((IArea)updatedGeometry).Area); Assert.AreEqual(0, resultByFeature.NewGeometries.Count); IFeature updatedTarget = ProtobufConversionUtils.FromGdbObjectMsgList(removeResponse.TargetFeaturesToUpdate, removeRequest.ClassDefinitions) .Single(); int pointCount = GeometryUtils.GetPointCount(updatedTarget.Shape); Assert.AreEqual(5 + 2, pointCount); }
public void CanCutMultipleSourcesAlong() { GetOverlappingPolygons(out GdbFeature source1Feature, out GdbFeature source2Feature); IFeatureClass fClass = (IFeatureClass)source1Feature.Class; IFeature cutFeature = fClass.CreateFeature(); cutFeature.Shape = GeometryFactory.CreatePolygon( GeometryFactory.CreatePoint(2600000, 1200750), GeometryFactory.CreatePoint(2602000, 1202000)); cutFeature.Store(); var source1FeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(source1Feature); var source2FeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(source2Feature); var targetFeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg(cutFeature); var objectClassMsg = ProtobufGdbUtils.ToObjectClassMsg(source1Feature.Class); var calculationRequest = new CalculateCutLinesRequest(); calculationRequest.ClassDefinitions.Add(objectClassMsg); calculationRequest.SourceFeatures.Add(source1FeatureMsg); calculationRequest.SourceFeatures.Add(source2FeatureMsg); calculationRequest.TargetFeatures.Add(targetFeatureMsg); calculationRequest.Tolerance = -1; CalculateCutLinesResponse calculateResponse = ChangeAlongServiceUtils.CalculateCutLines(calculationRequest, null); Assert.AreEqual(ReshapeAlongCurveUsability.CanReshape, (ReshapeAlongCurveUsability)calculateResponse.ReshapeLinesUsability); AssertReshapeLineCount(calculateResponse.CutLines, 2, 2); Assert.AreEqual(source1Feature.OID, calculateResponse.CutLines[0].Source.ObjectId); Assert.AreEqual(source2Feature.OID, calculateResponse.CutLines[1].Source.ObjectId); foreach (ReshapeLineMsg cutLineMsg in calculateResponse.CutLines) { IPolyline reshapeLine = (IPolyline)ProtobufGeometryUtils.FromShapeMsg(cutLineMsg.Path); Assert.NotNull(reshapeLine); Assert.AreEqual(1000, reshapeLine.Length); } // // Cutting using just one of the lines: // var applyRequest = new ApplyCutLinesRequest(); applyRequest.CutLines.Add(calculateResponse.CutLines[0]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; ApplyCutLinesResponse applyResponse = ChangeAlongServiceUtils.ApplyCutLines(applyRequest, null); Assert.AreEqual(2, applyResponse.ResultFeatures.Count); GdbObjectMsg updatedFeatureMsg = applyResponse.ResultFeatures.First( r => r.FeatureCase == ResultObjectMsg.FeatureOneofCase.Update).Update; GdbObjectReference updatedObjRef = new GdbObjectReference(updatedFeatureMsg.ClassHandle, updatedFeatureMsg.ObjectId); Assert.AreEqual(new GdbObjectReference(source1Feature), updatedObjRef); // Check the new reshape line: AssertReshapeLineCount(applyResponse.NewCutLines, 1, 1); Assert.AreEqual(ReshapeAlongCurveUsability.CanReshape, (ReshapeAlongCurveUsability)applyResponse.CutLinesUsability); // // Cutting using both lines: // applyRequest = new ApplyCutLinesRequest(); applyRequest.CutLines.AddRange(calculateResponse.CutLines); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyResponse = ChangeAlongServiceUtils.ApplyCutLines(applyRequest, null); Assert.AreEqual(4, applyResponse.ResultFeatures.Count); // Check the new reshape line: AssertReshapeLineCount(applyResponse.NewCutLines, 0, 0); Assert.AreEqual(ReshapeAlongCurveUsability.NoReshapeCurves, (ReshapeAlongCurveUsability)applyResponse.CutLinesUsability); }
public void CanCutAlong() { GetOverlappingPolygons(out GdbFeature sourceFeature, out GdbFeature targetFeature); CalculateCutLinesRequest calculationRequest = CreateCalculateCutLinesRequest(sourceFeature, targetFeature); CalculateCutLinesResponse calculateResponse = ChangeAlongServiceUtils.CalculateCutLines(calculationRequest, null); Assert.AreEqual(ReshapeAlongCurveUsability.CanReshape, (ReshapeAlongCurveUsability)calculateResponse.ReshapeLinesUsability); AssertReshapeLineCount(calculateResponse.CutLines, 1, 1); IPolyline reshapeLine = (IPolyline)ProtobufGeometryUtils.FromShapeMsg(calculateResponse.CutLines[0].Path); Assert.NotNull(reshapeLine); Assert.AreEqual(1000, (reshapeLine).Length); // // Cutting // var applyRequest = new ApplyCutLinesRequest(); applyRequest.CutLines.Add(calculateResponse.CutLines[0]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; ApplyCutLinesResponse applyResponse = ChangeAlongServiceUtils.ApplyCutLines(applyRequest, null); Assert.AreEqual(2, applyResponse.ResultFeatures.Count); List <IGeometry> geometries = applyResponse.ResultFeatures.Select(GetShape).ToList(); Assert.AreEqual(1000 * 1000, geometries.Sum(g => ((IArea)g).Area)); ResultObjectMsg updateResultMsg = applyResponse.ResultFeatures.First( r => r.FeatureCase == ResultObjectMsg.FeatureOneofCase.Update); GdbObjectReference updateObjRef = new GdbObjectReference(updateResultMsg.Update.ClassHandle, updateResultMsg.Update.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), updateObjRef); IGeometry firstGeometry = ProtobufGeometryUtils.FromShapeMsg(updateResultMsg.Update.Shape); Assert.IsNotNull(firstGeometry); Assert.AreEqual(1000 * 1000 * 3 / 4, ((IArea)firstGeometry).Area); // Check the new reshape line: AssertReshapeLineCount(applyResponse.NewCutLines, 0, 0); Assert.AreEqual(ReshapeAlongCurveUsability.NoReshapeCurves, (ReshapeAlongCurveUsability)applyResponse.CutLinesUsability); }
public void CanReshapeAlongFilteredLinesByExtent() { GetOverlappingPolygons(out GdbFeature sourceFeature, out GdbFeature targetFeature); CalculateReshapeLinesRequest calculationRequest = CreateCalculateReshapeLinesRequest(sourceFeature, targetFeature); IEnvelope visibleExtent = sourceFeature.Shape.Envelope; visibleExtent.Expand(10, 10, false); calculationRequest.FilterOptions = new ReshapeLineFilterOptionsMsg(); calculationRequest.FilterOptions.ClipLinesOnVisibleExtent = true; calculationRequest.FilterOptions.VisibleExtents.Add( ProtobufGeometryUtils.ToEnvelopeMsg(visibleExtent)); CalculateReshapeLinesResponse calculateResponse = ChangeAlongServiceUtils.CalculateReshapeLines(calculationRequest, null); Assert.AreEqual((int)ReshapeAlongCurveUsability.CanReshape, calculateResponse.ReshapeLinesUsability); // 1 inside-line and 2 extent-intersecting dangles to the outside within the extent. AssertReshapeLineCount(calculateResponse.ReshapeLines, 3, 1); int insideLineIndex = GetInsideReshapeLineIndex(calculateResponse.ReshapeLines, sourceFeature.Shape); IPolyline insideLine = (IPolyline)ProtobufGeometryUtils.FromShapeMsg( calculateResponse.ReshapeLines[insideLineIndex].Path); Assert.NotNull(insideLine); Assert.AreEqual(1000, insideLine.Length); // // Reshape the non-default side (should be possible): // ApplyReshapeLinesRequest applyRequest = new ApplyReshapeLinesRequest(); applyRequest.ReshapeLines.Add(calculateResponse.ReshapeLines[insideLineIndex]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyRequest.UseNonDefaultReshapeSide = true; ApplyReshapeLinesResponse applyResponse = ChangeAlongServiceUtils.ApplyReshapeLines(applyRequest, null); Assert.AreEqual(1, applyResponse.ResultFeatures.Count); GdbObjectMsg updatedFeatureMsg = applyResponse.ResultFeatures[0].Update; GdbObjectReference resultFeatureObjRef = new GdbObjectReference( updatedFeatureMsg.ClassHandle, updatedFeatureMsg.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), resultFeatureObjRef); IGeometry updatedGeometry = ProtobufGeometryUtils.FromShapeMsg(updatedFeatureMsg.Shape); Assert.IsNotNull(updatedGeometry); Assert.AreEqual(1000 * 1000 * 1 / 4, ((IArea)updatedGeometry).Area); // Check the new reshape line - there should be 2 non-reshapable dangles AssertReshapeLineCount(applyResponse.NewReshapeLines, 2, 0); Assert.AreEqual(ReshapeAlongCurveUsability.InsufficientOrAmbiguousReshapeCurves, (ReshapeAlongCurveUsability)applyResponse.ReshapeLinesUsability); }
public void CanReshapeAlongNonDefaultSide() { GetOverlappingPolygons(out GdbFeature sourceFeature, out GdbFeature targetFeature); CalculateReshapeLinesRequest calculationRequest = CreateCalculateReshapeLinesRequest(sourceFeature, targetFeature); CalculateReshapeLinesResponse calculateResponse = ChangeAlongServiceUtils.CalculateReshapeLines(calculationRequest, null); Assert.AreEqual((int)ReshapeAlongCurveUsability.CanReshape, calculateResponse.ReshapeLinesUsability); AssertReshapeLineCount(calculateResponse.ReshapeLines, 2, 2); List <ShapeMsg> reshapePathMsgs = calculateResponse.ReshapeLines.Select(l => l.Path).ToList(); List <IPolyline> resultLines = ProtobufGeometryUtils.FromShapeMsgList <IPolyline>(reshapePathMsgs); int insideLineIndex = resultLines .Select((reshapePath, index) => (reshapePath, index)) .First(rl => GeometryUtils.InteriorIntersects( rl.reshapePath, sourceFeature.Shape)).index; var insideLines = resultLines.Where(rl => GeometryUtils.InteriorIntersects(rl, sourceFeature.Shape)) .ToList(); Assert.AreEqual(1, insideLines.Count); Assert.AreEqual(1000, (insideLines[0]).Length); // // Reshape the default side: // ApplyReshapeLinesRequest applyRequest = new ApplyReshapeLinesRequest(); applyRequest.ReshapeLines.Add(calculateResponse.ReshapeLines[insideLineIndex]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyRequest.UseNonDefaultReshapeSide = false; ApplyReshapeLinesResponse applyResponse = ChangeAlongServiceUtils.ApplyReshapeLines(applyRequest, null); Assert.AreEqual(1, applyResponse.ResultFeatures.Count); GdbObjectMsg updatedFeatureMsg = applyResponse.ResultFeatures[0].Update; GdbObjectReference resultFeatureObjRef = new GdbObjectReference( updatedFeatureMsg.ClassHandle, updatedFeatureMsg.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), resultFeatureObjRef); IGeometry updatedGeometry = ProtobufGeometryUtils.FromShapeMsg(updatedFeatureMsg.Shape); Assert.IsNotNull(updatedGeometry); Assert.AreEqual(1000 * 1000 * 3 / 4, ((IArea)updatedGeometry).Area); // Check the new reshape line: AssertReshapeLineCount(applyResponse.NewReshapeLines, 1, 1); Assert.AreEqual((int)ReshapeAlongCurveUsability.CanReshape, applyResponse.ReshapeLinesUsability); // // Reshape the non-default side: // applyRequest.UseNonDefaultReshapeSide = true; applyResponse = ChangeAlongServiceUtils.ApplyReshapeLines(applyRequest, null); Assert.AreEqual(1, applyResponse.ResultFeatures.Count); updatedFeatureMsg = applyResponse.ResultFeatures[0].Update; resultFeatureObjRef = new GdbObjectReference( updatedFeatureMsg.ClassHandle, updatedFeatureMsg.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), resultFeatureObjRef); updatedGeometry = ProtobufGeometryUtils.FromShapeMsg(updatedFeatureMsg.Shape); Assert.IsNotNull(updatedGeometry); Assert.AreEqual((double)1000 * 1000 * 1 / 4, ((IArea)updatedGeometry).Area); }
public void CanReshapeAlongBufferedTarget() { GetOverlappingPolygons(out GdbFeature sourceFeature, out GdbFeature targetFeature); CalculateReshapeLinesRequest calculationRequest = CreateCalculateReshapeLinesRequest(sourceFeature, targetFeature); double minSegmentLength = 2; calculationRequest.TargetBufferOptions = new TargetBufferOptionsMsg(); calculationRequest.TargetBufferOptions.BufferDistance = 10; calculationRequest.TargetBufferOptions.BufferMinimumSegmentLength = minSegmentLength; CalculateReshapeLinesResponse calculateResponse = ChangeAlongServiceUtils.CalculateReshapeLines(calculationRequest, null); Assert.AreEqual((int)ReshapeAlongCurveUsability.CanReshape, calculateResponse.ReshapeLinesUsability); AssertReshapeLineCount(calculateResponse.ReshapeLines, 4, 4); List <ShapeMsg> reshapePathMsgs = calculateResponse.ReshapeLines.Select(l => l.Path).ToList(); List <IPolyline> resultLines = ProtobufGeometryUtils.FromShapeMsgList <IPolyline>(reshapePathMsgs); int insideLineIndex = resultLines .Select((reshapePath, index) => (reshapePath, index)) .OrderBy(rl => rl.reshapePath.Length) .First(rl => GeometryUtils.InteriorIntersects( rl.reshapePath, sourceFeature.Shape)).index; var insideLines = resultLines.Where(rl => GeometryUtils.InteriorIntersects(rl, sourceFeature.Shape)) .ToList(); Assert.AreEqual(2, insideLines.Count); foreach (IPolyline resultLine in resultLines) { Assert.AreNotEqual(1000, resultLine.Length); Assert.AreEqual( 0, GeometryUtils.GetShortSegments(resultLine, minSegmentLength).Count); } // // Reshape the default side: // ApplyReshapeLinesRequest applyRequest = new ApplyReshapeLinesRequest(); applyRequest.ReshapeLines.Add(calculateResponse.ReshapeLines[insideLineIndex]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyRequest.UseNonDefaultReshapeSide = false; ApplyReshapeLinesResponse applyResponse = ChangeAlongServiceUtils.ApplyReshapeLines(applyRequest, null); Assert.AreEqual(1, applyResponse.ResultFeatures.Count); GdbObjectMsg updatedFeatureMsg = applyResponse.ResultFeatures[0].Update; GdbObjectReference resultFeatureObjRef = new GdbObjectReference( updatedFeatureMsg.ClassHandle, updatedFeatureMsg.ObjectId); Assert.AreEqual(new GdbObjectReference(sourceFeature), resultFeatureObjRef); IGeometry updatedGeometry = ProtobufGeometryUtils.FromShapeMsg(updatedFeatureMsg.Shape); // The shortest reshape line results in a greater remaining area: Assert.IsNotNull(updatedGeometry); Assert.Greater(((IArea)updatedGeometry).Area, 1000 * 1000 * 3 / (double)4); // Check the new reshape line: AssertReshapeLineCount(applyResponse.NewReshapeLines, 3, 3); Assert.AreEqual((int)ReshapeAlongCurveUsability.CanReshape, applyResponse.ReshapeLinesUsability); }
public static RemoveOverlapsResponse RemoveOverlaps( [NotNull] RemoveOverlapsRequest request, [CanBeNull] ITrackCancel trackCancel = null) { // Unpack request bool explodeMultiparts = request.ExplodeMultipartResults; bool storeOverlapsAsNewFeatures = request.StoreOverlapsAsNewFeatures; GdbTableContainer container = ProtobufConversionUtils.CreateGdbTableContainer( request.ClassDefinitions, null, out _); IList <IFeature> selectedFeatureList = ProtobufConversionUtils.FromGdbObjectMsgList( request.SourceFeatures, container); IList <IFeature> targetFeaturesForVertexInsertion = ProtobufConversionUtils.FromGdbObjectMsgList( request.UpdatableTargetFeatures, container); Overlaps overlaps = new Overlaps(); foreach (OverlapMsg overlapMsg in request.Overlaps) { GdbObjectReference gdbRef = new GdbObjectReference( overlapMsg.OriginalFeatureRef.ClassHandle, overlapMsg.OriginalFeatureRef.ObjectId); IFeatureClass fClass = (IFeatureClass)container.GetByClassId(gdbRef.ClassId); List <IGeometry> overlapGeometries = ProtobufGeometryUtils.FromShapeMsgList <IGeometry>( overlapMsg.Overlaps, DatasetUtils.GetSpatialReference(fClass)); overlaps.AddGeometries(gdbRef, overlapGeometries); } // Remove overlaps OverlapsRemover overlapsRemover = RemoveOverlaps( selectedFeatureList, overlaps, targetFeaturesForVertexInsertion, explodeMultiparts, storeOverlapsAsNewFeatures, trackCancel); // Pack response var result = overlapsRemover.Result; var response = new RemoveOverlapsResponse(); PackResultGeometries(result.ResultsByFeature, response.ResultsByFeature); response.NonStorableMessages.AddRange(result.NonStorableMessages); if (result.TargetFeaturesToUpdate != null) { foreach (var keyValuePair in result.TargetFeaturesToUpdate) { IFeature feature = keyValuePair.Key; IGeometry newGeometry = keyValuePair.Value; GdbObjectMsg targetFeatureMsg = ProtobufGdbUtils.ToGdbObjectMsg( feature, newGeometry, feature.Class.ObjectClassID); response.TargetFeaturesToUpdate.Add(targetFeatureMsg); } } response.ResultHasMultiparts = result.ResultHasMultiparts; return(response); }
public void AddGeometries(GdbObjectReference sourceFeatureRef, [NotNull] IList <Geometry> overlapGeometries) { OverlapGeometries.Add(sourceFeatureRef, overlapGeometries); }