/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the LineStrings in the result of the specified overlay operation. /// </returns> public virtual IList Build(SpatialFunction opCode) { FindCoveredLineEdges(); CollectLines(opCode); BuildLines(opCode); return _resultLineList; }
public void MarkResultAreaEdges(SpatialFunction overlayOpCode) { foreach (var edge in _edges) { MarkInResultArea(edge, overlayOpCode); } }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the LineStrings in the result of the specified overlay operation. /// </returns> public IList <Geometry> Build(SpatialFunction opCode) { FindCoveredLineEdges(); CollectLines(opCode); BuildLines(opCode); return(_resultLineList); }
/// <summary> /// Determines nodes which are in the result, and creates <see cref="IPoint"/>s for them. /// </summary> /// <remarks> /// This method determines nodes which are candidates for the result via their /// labelling and their graph topology. /// </remarks> /// <param name="opCode">The overlay operation</param> private void ExtractNonCoveredResultNodes(SpatialFunction opCode) { // testing only //if (true) return resultNodeList; foreach (var n in _op.Graph.Nodes) { // filter out nodes which are known to be in the result if (n.IsInResult) { continue; } // if an incident edge is in the result, then the node coordinate is included already if (n.IsIncidentEdgeInResult()) { continue; } if (n.Edges.Degree == 0 || opCode == SpatialFunction.Intersection) { /** * For nodes on edges, only INTERSECTION can result in edge nodes being included even * if none of their incident edges are included */ Label label = n.Label; if (OverlayOp.IsResultOfOp(label, opCode)) { FilterCoveredNodeToPoint(n); } } } //Console.Writeline("connectedResultNodes collected = " + connectedResultNodes.size()); }
/// <summary> /// Tests if the result can be determined to be empty /// based on simple properties of the input geometries /// (such as whether one or both are empty, /// or their envelopes are disjoint). /// </summary> /// <param name="opCode">The overlay operation</param> /// <param name="a">The A operand geometry</param> /// <param name="b">The B operand geometry</param> /// <param name="pm">The precision model to use</param> /// <returns><c>true</c> if the overlay result is determined to be empty</returns> internal static bool IsEmptyResult(SpatialFunction opCode, Geometry a, Geometry b, PrecisionModel pm) { switch (opCode) { case OverlayNG.INTERSECTION: if (IsEnvDisjoint(a, b, pm)) { return(true); } break; case OverlayNG.DIFFERENCE: if (IsEmpty(a)) { return(true); } break; case OverlayNG.UNION: case OverlayNG.SYMDIFFERENCE: if (IsEmpty(a) && IsEmpty(b)) { return(true); } break; } return(false); }
/// <summary> /// Computes an overlay operation /// for the given geometry arguments. /// </summary> /// <param name="geom0">The first geometry argument</param> /// <param name="geom1">The second geometry argument</param> /// <param name="opCode">The code for the desired overlay operation</param> /// <returns>The result of the overlay operation</returns> /// <exception cref="TopologyException">Thrown if a robustness problem is encountered.</exception> public static Geometry Overlay(Geometry geom0, Geometry geom1, SpatialFunction opCode) { var gov = new OverlayOp(geom0, geom1); var geomOv = gov.GetResultGeometry(opCode); return(geomOv); }
/// <summary> /// Creates an empty result geometry of the appropriate dimension, /// based on the given overlay operation and the dimensions of the inputs. /// The created geometry is always an atomic geometry, /// not a collection. /// <para/> /// The empty result is constructed using the following rules: /// <list type="bullet"> /// <item><description><see cref="SpatialFunction.Intersection"/> - result has the dimension of the lowest input dimension</description></item> /// <item><description><see cref="SpatialFunction.Union"/> - result has the dimension of the highest input dimension</description></item> /// <item><description><see cref="SpatialFunction.Difference"/> - result has the dimension of the left-hand input</description></item> /// <item><description><see cref="SpatialFunction.SymDifference"/> - result has the dimension of the highest input dimension /// (since symDifference is the union of the differences).</description></item> /// </list> /// </summary> /// <param name="overlayOpCode">The overlay operation being performed</param> /// <param name="a">An input geometry</param> /// <param name="b">An input geometry</param> /// <param name="geomFact">The geometry factory being used for the operation</param> /// <returns>An empty atomic geometry of the appropriate dimension</returns> public static Geometry CreateEmptyResult(SpatialFunction overlayOpCode, Geometry a, Geometry b, GeometryFactory geomFact) { var resultDim = ResultDimension(overlayOpCode, a, b); // Handles resultDim == Dimension.False, although it should not happen return(geomFact.CreateEmpty(resultDim)); }
/// <summary> /// Tests whether a point with a given topological <see cref="Label"/> /// relative to two geometries is contained in /// the result of overlaying the geometries using /// a given overlay operation. /// <para/> /// The method handles arguments of <see cref="Location.Null"/> correctly /// </summary> /// <param name="label">The topological label of the point</param> /// <param name="opCode">The code for the overlay operation to test</param> /// <returns><c>true</c> if the label locations correspond to the overlay <paramref name="opCode"/></returns> private static bool IsResultOfOpPoint(OverlayLabel label, SpatialFunction opCode) { var loc0 = label.GetLocation(0); var loc1 = label.GetLocation(1); return(IsResultOfOp(opCode, loc0, loc1)); }
/// <summary> /// Collect edges from Area inputs which should be in the result but /// which have not been included in a result area. /// This happens ONLY: /// during an intersection when the boundaries of two /// areas touch in a line segment /// OR as a result of a dimensional collapse. /// </summary> /// <param name="de"></param> /// <param name="opCode"></param> /// <param name="edges"></param> public void CollectBoundaryTouchEdge(DirectedEdge de, SpatialFunction opCode, IList <Edge> edges) { var label = de.Label; if (de.IsLineEdge) { return; // only interested in area edges } if (de.IsVisited) { return; // already processed } if (de.IsInteriorAreaEdge) { return; // added to handle dimensional collapses } if (de.Edge.IsInResult) { return; // if the edge linework is already included, don't include it again } // sanity check for labelling of result edgerings Assert.IsTrue(!(de.IsInResult || de.Sym.IsInResult) || !de.Edge.IsInResult); // include the linework if it's in the result of the operation if (OverlayOp.IsResultOfOp(label, opCode) && opCode == SpatialFunction.Intersection) { edges.Add(de.Edge); de.VisitedEdge = true; } }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns></returns> public IGeometry GetResultGeometry(SpatialFunction opCode) { IGeometry[] prepGeom = Snap(); IGeometry result = OverlayOp.Overlay(prepGeom[0], prepGeom[1], opCode); return(PrepareResult(result)); }
private static Dimension ResultDimension(SpatialFunction opCode, IGeometry g0, IGeometry g1) { var dim0 = (int)g0.Dimension; var dim1 = (int)g1.Dimension; var resultDimension = -1; switch (opCode) { case SpatialFunction.Intersection: resultDimension = Math.Min(dim0, dim1); break; case SpatialFunction.Union: resultDimension = Math.Max(dim0, dim1); break; case SpatialFunction.Difference: resultDimension = dim0; break; case SpatialFunction.SymDifference: /** * This result is chosen because * <pre> * SymDiff = Union(Diff(A, B), Diff(B, A) * </pre> * and Union has the dimension of the highest-dimension argument. */ resultDimension = Math.Max(dim0, dim1); break; } return((Dimension)resultDimension); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns></returns> public Geometry GetResultGeometry(SpatialFunction opCode) { var prepGeom = Snap(_geom); var result = OverlayOp.Overlay(prepGeom[0], prepGeom[1], opCode); return(PrepareResult(result)); }
/// <summary> /// Attempt overlay using snapping with repeated tries with increasing snap tolerances. /// </summary> /// <param name ="geom0"></param> /// <param name ="geom1"></param> /// <param name ="opCode"></param> /// <returns>The computed overlay result, or null if the overlay fails</returns> private static Geometry OverlaySnapTries(Geometry geom0, Geometry geom1, SpatialFunction opCode) { Geometry result; double snapTol = SnapTolerance(geom0, geom1); for (int i = 0; i < NUM_SNAP_TRIES; i++) { result = OverlaySnapping(geom0, geom1, opCode, snapTol); if (result != null) { return(result); } /* * Now try snapping each input individually, * and then doing the overlay. */ result = OverlaySnapBoth(geom0, geom1, opCode, snapTol); if (result != null) { return(result); } // increase the snap tolerance and try again snapTol = snapTol * 10; } // failed to compute overlay return(null); }
/// <summary> /// /// </summary> /// <param name="geom0"></param> /// <param name="geom1"></param> /// <param name="opCode"></param> /// <returns></returns> public static IGeometry Overlay(IGeometry geom0, IGeometry geom1, SpatialFunction opCode) { OverlayOp gov = new OverlayOp(geom0, geom1); IGeometry geomOv = gov.GetResultGeometry(opCode); return(geomOv); }
static Geometry Overlay(Geometry a, Geometry b, SpatialFunction opCode) { var ov = new NetTopologySuite.Operation.OverlayNG.OverlayNG(a, b, opCode); ov.StrictMode = true; return(ov.GetResult()); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the LineStrings in the result of the specified overlay operation. /// </returns> public virtual IList Build(SpatialFunction opCode) { FindCoveredLineEdges(); CollectLines(opCode); BuildLines(opCode); return(_resultLineList); }
/// <summary> /// /// </summary> /// <param name="label"></param> /// <param name="opCode"></param> /// <returns></returns> public static bool IsResultOfOp(Label label, SpatialFunction opCode) { LocationType loc0 = label.GetLocation(0); LocationType loc1 = label.GetLocation(1); return(IsResultOfOp(loc0, loc1, opCode)); }
/// <summary> /// This method will handle arguments of Location.NULL correctly. /// </summary> /// <returns><c>true</c> if the locations correspond to the opCode.</returns> public static bool IsResultOfOp(LocationType loc0, LocationType loc1, SpatialFunction opCode) { if (loc0 == LocationType.Boundary) { loc0 = LocationType.Interior; } if (loc1 == LocationType.Boundary) { loc1 = LocationType.Interior; } switch (opCode) { case SpatialFunction.Intersection: return(loc0 == LocationType.Interior && loc1 == LocationType.Interior); case SpatialFunction.Union: return(loc0 == LocationType.Interior || loc1 == LocationType.Interior); case SpatialFunction.Difference: return(loc0 == LocationType.Interior && loc1 != LocationType.Interior); case SpatialFunction.SymDifference: return((loc0 == LocationType.Interior && loc1 != LocationType.Interior) || (loc0 != LocationType.Interior && loc1 == LocationType.Interior)); default: return(false); } }
/// <summary> /// Computes the dimension of the result of /// applying the given operation to inputs /// with the given dimensions. /// This assumes that complete collapse does not occur. /// <para/> /// The result dimension is computed using the following rules: /// <list type="bullet"> /// <item><term><see cref="SpatialFunction.Intersection"/></term><description>result has the dimension of the lowest input dimension</description></item> /// <item><term><see cref="SpatialFunction.Union"/></term><description>result has the dimension of the highest input dimension</description></item> /// <item><term><see cref="SpatialFunction.Difference"/></term><description>result has the dimension of the left-hand input</description></item> /// <item><term><see cref="SpatialFunction.SymDifference"/></term><description>result has the dimension of the highest input dimension /// (since the Symmetric Difference is the Union of the Differences).</description></item> /// </list> /// </summary> /// <param name="opCode">The overlay operation</param> /// <param name="dim0">Dimension of the LH input</param> /// <param name="dim1">Dimension of the RH input</param> /// <returns></returns> internal static Dimension ResultDimension(SpatialFunction opCode, Dimension dim0, Dimension dim1) { var resultDimension = Dimension.False; switch (opCode) { case OverlayNG.INTERSECTION: resultDimension = (Dimension)Math.Min((int)dim0, (int)dim1); break; case OverlayNG.UNION: resultDimension = (Dimension)Math.Max((int)dim0, (int)dim1); break; case OverlayNG.DIFFERENCE: resultDimension = dim0; break; case OverlayNG.SYMDIFFERENCE: /* * This result is chosen because * <pre> * SymDiff = Union( Diff(A, B), Diff(B, A) ) * </pre> * and Union has the dimension of the highest-dimension argument. */ resultDimension = (Dimension)Math.Max((int)dim0, (int)dim1); break; } return(resultDimension); }
public IGeometry GetResultGeometry(SpatialFunction opCode) { IGeometry result = null; var isSuccess = false; try { result = OverlayOp.Overlay(geom[0], geom[1], opCode); var isValid = true; // not needed if noding validation is used // boolean isValid = OverlayResultValidator.isValid(geom[0], geom[1], OverlayOp.INTERSECTION, result); // if (isValid) isSuccess = true; } catch (Exception ex) { // Ignore this exception, since the operation will be rerun Debug.WriteLine(ex); } if (!isSuccess) { // This may still throw an exception - just let it go if it does result = SnapOverlayOp.Overlay(geom[0], geom[1], opCode); } return(result); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the LineStrings in the result of the specified overlay operation. /// </returns> public IList<IGeometry> Build(SpatialFunction opCode) { FindCoveredLineEdges(); CollectLines(opCode); BuildLines(opCode); return _resultLineList; }
/// <summary> /// Determines nodes which are in the result, and creates <see cref="IPoint"/>s for them. /// </summary> /// <remarks> /// This method determines nodes which are candidates for the result via their /// labelling and their graph topology. /// </remarks> /// <param name="opCode">The overlay operation</param> private void ExtractNonCoveredResultNodes(SpatialFunction opCode) { // testing only //if (true) return resultNodeList; foreach (var n in _op.Graph.Nodes) { // filter out nodes which are known to be in the result if (n.IsInResult) continue; // if an incident edge is in the result, then the node coordinate is included already if (n.IsIncidentEdgeInResult()) continue; if (n.Edges.Degree == 0 || opCode == SpatialFunction.Intersection) { /** * For nodes on edges, only INTERSECTION can result in edge nodes being included even * if none of their incident edges are included */ Label label = n.Label; if (OverlayOp.IsResultOfOp(label, opCode)) { FilterCoveredNodeToPoint(n); } } } //Console.Writeline("connectedResultNodes collected = " + connectedResultNodes.size()); }
public IGeometry GetResultGeometry(SpatialFunction opCode) { IGeometry result = null; var isSuccess = false; try { result = OverlayOp.Overlay(geom[0], geom[1], opCode); var isValid = true; // not needed if noding validation is used // boolean isValid = OverlayResultValidator.isValid(geom[0], geom[1], OverlayOp.INTERSECTION, result); // if (isValid) isSuccess = true; } catch (Exception ex) { // Ignore this exception, since the operation will be rerun Debug.WriteLine(ex); } if (!isSuccess) { // This may still throw an exception - just let it go if it does result = SnapOverlayOp.Overlay(geom[0], geom[1], opCode); } return result; }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the Points in the result of the specified overlay operation. /// </returns> public IList Build(SpatialFunction opCode) { IList nodeList = CollectNodes(opCode); IList resultPointList = SimplifyPoints(nodeList); return(resultPointList); }
/// <summary> /// Tests whether a point with a given topological <see cref="Label"/> /// relative to two geometries is contained in /// the result of overlaying the geometries using /// a given overlay operation. /// <para/> /// The method handles arguments of <see cref="Location.Null"/> correctly /// </summary> /// <param name="label">The topological label of the point</param> /// <param name="overlayOpCode">The code for the overlay operation to test</param> /// <returns><c>true</c> if the label locations correspond to the overlayOpCode</returns> public static bool IsResultOfOp(Label label, SpatialFunction overlayOpCode) { var loc0 = label.GetLocation(0); var loc1 = label.GetLocation(1); return(IsResultOfOp(loc0, loc1, overlayOpCode)); }
public IGeometry GetResultGeometry(SpatialFunction opCode) { IGeometry result = null; var isSuccess = false; Exception savedException = null; try { // try basic operation with input geometries result = OverlayOp.Overlay(_geom[0], _geom[1], opCode); var isValid = true; // not needed if noding validation is used // boolean isValid = OverlayResultValidator.isValid(geom[0], geom[1], OverlayOp.INTERSECTION, result); // if (isValid) isSuccess = true; } catch (Exception ex) { savedException = ex; // Ignore this exception, since the operation will be rerun } if (!isSuccess) { // this may still throw an exception // if so, throw the original exception since it has the input coordinates try { result = SnapOverlayOp.Overlay(_geom[0], _geom[1], opCode); } catch (Exception) { throw savedException; } } return result; }
/// <summary> /// Tests whether a point with given <see cref="Location"/>s /// relative to two geometries would be contained in /// the result of overlaying the geometries using /// a given overlay operation. /// This is used to determine whether components /// computed during the overlay process should be /// included in the result geometry. /// <para/> /// The method handles arguments of <see cref="Location.Null"/> correctly. /// </summary> /// <param name="overlayOpCode">The code for the overlay operation to test</param> /// <param name="loc0">The code for the location in the first geometry</param> /// <param name="loc1">The code for the location in the second geometry</param> /// <returns><c>true</c> if a point with given locations is in the result of the overlay operation</returns> internal static bool IsResultOfOp(SpatialFunction overlayOpCode, Location loc0, Location loc1) { if (loc0 == Location.Boundary) { loc0 = Location.Interior; } if (loc1 == Location.Boundary) { loc1 = Location.Interior; } switch (overlayOpCode) { case INTERSECTION: return(loc0 == Location.Interior && loc1 == Location.Interior); case UNION: return(loc0 == Location.Interior || loc1 == Location.Interior); case DIFFERENCE: return(loc0 == Location.Interior && loc1 != Location.Interior); case SYMDIFFERENCE: return((loc0 == Location.Interior && loc1 != Location.Interior) || (loc0 != Location.Interior && loc1 == Location.Interior)); } return(false); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the Points in the result of the specified overlay operation. /// </returns> public IList <IGeometry> Build(SpatialFunction opCode) { var nodeList = CollectNodes(opCode); var resultPointList = SimplifyPoints(nodeList); return(resultPointList); }
private void ComputeOverlay(SpatialFunction opCode) { // copy points from input Geometries. // This ensures that any Point geometries // in the input are considered for inclusion in the result set CopyPoints(0); CopyPoints(1); // node the input Geometries arg[0].ComputeSelfNodes(lineIntersector, false); arg[1].ComputeSelfNodes(lineIntersector, false); // compute intersections between edges of the two input geometries arg[0].ComputeEdgeIntersections(arg[1], lineIntersector, true); IList baseSplitEdges = new ArrayList(); arg[0].ComputeSplitEdges(baseSplitEdges); arg[1].ComputeSplitEdges(baseSplitEdges); // add the noded edges to this result graph InsertUniqueEdges(baseSplitEdges); ComputeLabelsFromDepths(); ReplaceCollapsedEdges(); if (!NodingValidatorDisabled) { var nv = new EdgeNodingValidator(edgeList.Edges); nv.checkValid(); } graph.AddEdges(edgeList.Edges); ComputeLabelling(); LabelIncompleteNodes(); /* * The ordering of building the result Geometries is important. * Areas must be built before lines, which must be built before points. * This is so that lines which are covered by areas are not included * explicitly, and similarly for points. */ FindResultAreaEdges(opCode); CancelDuplicateResultEdges(); var polyBuilder = new PolygonBuilder(geomFact); polyBuilder.Add(graph); resultPolyList = polyBuilder.Polygons; var lineBuilder = new LineBuilder(this, geomFact, ptLocator); resultLineList = lineBuilder.Build(opCode); var pointBuilder = new PointBuilder(this, geomFact, ptLocator); resultPointList = pointBuilder.Build(opCode); // gather the results from all calculations into a single Geometry for the result set resultGeom = ComputeGeometry(resultPointList, resultLineList, resultPolyList); }
static Geometry Overlay(Geometry a, Geometry b, double scaleFactor, SpatialFunction opCode) { var pm = new PrecisionModel(scaleFactor); var ov = new NetTopologySuite.Operation.OverlayNG.OverlayNG(a, b, pm, opCode); ov.StrictMode = true; return(ov.GetResult()); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> private void CollectLines(SpatialFunction opCode) { foreach (DirectedEdge de in _op.Graph.EdgeEnds) { CollectLineEdge(de, opCode, _lineEdgesList); CollectBoundaryTouchEdge(de, opCode, _lineEdgesList); } }
/// <summary> /// Creates a builder for linear elements which may be present /// in the overlay result. /// </summary> /// <param name="inputGeom">The input geometries</param> /// <param name="graph">The topology graph</param> /// <param name="hasResultArea"><c>true</c> if an area has been generated for the result</param> /// <param name="opCode">The overlay operation code</param> /// <param name="geomFact">The output geometry factory</param> public LineBuilder(InputGeometry inputGeom, OverlayGraph graph, bool hasResultArea, SpatialFunction opCode, GeometryFactory geomFact) { _graph = graph; _opCode = opCode; _geometryFactory = geomFact; _hasResultArea = hasResultArea; _inputAreaIndex = inputGeom.GetAreaIndex(); }
/// <summary> /// Creates an instance of an overlay operation on inputs which are both point geometries. /// </summary> /// <param name="opCode">The code for the desired overlay operation</param> /// <param name="geom0">The first geometry argument</param> /// <param name="geom1">The second geometry argument</param> /// <param name="pm">The precision model to use</param> public OverlayPoints(SpatialFunction opCode, Geometry geom0, Geometry geom1, PrecisionModel pm) { _opCode = opCode; _geom0 = geom0; _geom1 = geom1; _pm = pm; _geometryFactory = geom0.Factory; }
/// <summary> /// Computes an overlay operation for /// the given geometry operands, with the /// noding strategy determined by the precision model. /// </summary> /// <param name="geom0">The first geometry argument</param> /// <param name="geom1">The second geometry argument</param> /// <param name="opCode">The code for the desired overlay operation</param> /// <param name="pm">The precision model to use</param> /// <returns>The result of the overlay operation</returns> public static Geometry Overlay(Geometry geom0, Geometry geom1, SpatialFunction opCode, PrecisionModel pm) { var ov = new OverlayNG(geom0, geom1, pm, opCode); var geomOv = ov.GetResult(); return(geomOv); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> private void BuildLines(SpatialFunction opCode) { foreach (Edge e in _lineEdgesList) { ILineString line = _geometryFactory.CreateLineString(e.Coordinates); _resultLineList.Add(line); e.InResult = true; } }
/// <summary> /// Computes the Point geometries which will appear in the result, /// given the specified overlay operation. /// </summary> /// <param name="opCode">The spatial function</param> /// <returns> /// A list of the Points in the result. /// </returns> public IList<IGeometry> Build(SpatialFunction opCode) { ExtractNonCoveredResultNodes(opCode); /** * It can happen that connected result nodes are still covered by * result geometries, so must perform this filter. * (For instance, this can happen during topology collapse). */ return _resultPointList; }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns></returns> private IList CollectNodes(SpatialFunction opCode) { IList resultNodeList = new ArrayList(); // add nodes from edge intersections which have not already been included in the result IEnumerator nodeit = _op.Graph.Nodes.GetEnumerator(); while (nodeit.MoveNext()) { Node n = (Node)nodeit.Current; if (n.IsInResult) continue; Label label = n.Label; if (OverlayOp.IsResultOfOp(label, opCode)) resultNodeList.Add(n); } return resultNodeList; }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns></returns> private IList<Node> CollectNodes(SpatialFunction opCode) { IList<Node> resultNodeList = new List<Node>(); // add nodes from edge intersections which have not already been included in the result foreach (Node n in _op.Graph.Nodes) { if (!n.IsInResult) { Label label = n.Label; if (OverlayOp.IsResultOfOp(label, opCode)) resultNodeList.Add(n); } } return resultNodeList; }
public bool IsValid(SpatialFunction overlayOp) { AddTestPts(_geom[0]); AddTestPts(_geom[1]); bool isValid = CheckValid(overlayOp); /* System.out.println("OverlayResultValidator: " + isValid); System.out.println("G0"); System.out.println(geom[0]); System.out.println("G1"); System.out.println(geom[1]); System.out.println("Result"); System.out.println(geom[2]); */ return isValid; }
/// <summary> /// Collect edges from Area inputs which should be in the result but /// which have not been included in a result area. /// This happens ONLY: /// during an intersection when the boundaries of two /// areas touch in a line segment /// OR as a result of a dimensional collapse. /// </summary> /// <param name="de"></param> /// <param name="opCode"></param> /// <param name="edges"></param> public void CollectBoundaryTouchEdge(DirectedEdge de, SpatialFunction opCode, IList<Edge> edges) { Label label = de.Label; if (de.IsLineEdge) return; // only interested in area edges if (de.IsVisited) return; // already processed if (de.IsInteriorAreaEdge) return; // added to handle dimensional collapses if (de.Edge.IsInResult) return; // if the edge linework is already included, don't include it again // sanity check for labelling of result edgerings Assert.IsTrue(!(de.IsInResult || de.Sym.IsInResult) || !de.Edge.IsInResult); // include the linework if it's in the result of the operation if (OverlayOp.IsResultOfOp(label, opCode) && opCode == SpatialFunction.Intersection) { edges.Add(de.Edge); de.VisitedEdge = true; } }
/// <summary> /// This method will handle arguments of Location.NULL correctly. /// </summary> /// <returns><c>true</c> if the locations correspond to the opCode.</returns> public static bool IsResultOfOp(Locations loc0, Locations loc1, SpatialFunction opCode) { if (loc0 == Locations.Boundary) loc0 = Locations.Interior; if (loc1 == Locations.Boundary) loc1 = Locations.Interior; switch (opCode) { case SpatialFunction.Intersection: return loc0 == Locations.Interior && loc1 == Locations.Interior; case SpatialFunction.Union: return loc0 == Locations.Interior || loc1 == Locations.Interior; case SpatialFunction.Difference: return loc0 == Locations.Interior && loc1 != Locations.Interior; case SpatialFunction.SymDifference: return (loc0 == Locations.Interior && loc1 != Locations.Interior) || (loc0 != Locations.Interior && loc1 == Locations.Interior); default: return false; } }
private static void ReportResult(SpatialFunction overlayOp, Location[] location, bool expectedInterior) { #if !PCL // ReSharper disable RedundantStringFormatCall // String.Format needed to build 2.0 release! Debug.WriteLine(String.Format("{0}:" + " A:{1} B:{2} expected:{3} actual:{4}", overlayOp, LocationUtility.ToLocationSymbol(location[0]), LocationUtility.ToLocationSymbol(location[1]), expectedInterior ? 'i' : 'e', LocationUtility.ToLocationSymbol(location[2]))); // ReSharper restore RedundantStringFormatCall #endif }
private static bool IsValidResult(SpatialFunction overlayOp, Location[] location) { bool expectedInterior = OverlayOp.IsResultOfOp(location[0], location[1], overlayOp); bool resultInInterior = (location[2] == Location.Interior); // MD use simpler: boolean isValid = (expectedInterior == resultInInterior); bool isValid = !(expectedInterior ^ resultInInterior); if (!isValid) ReportResult(overlayOp, location, expectedInterior); return isValid; }
private bool CheckValid(SpatialFunction overlayOp, Coordinate pt) { _location[0] = _locFinder[0].GetLocation(pt); _location[1] = _locFinder[1].GetLocation(pt); _location[2] = _locFinder[2].GetLocation(pt); /* * If any location is on the Boundary, can't deduce anything, so just return true */ if (HasLocation(_location, Location.Boundary)) return true; return IsValidResult(overlayOp, _location); }
/// <summary> /// Creates an empty result geometry of the appropriate dimension, /// based on the given overlay operation and the dimensions of the inputs. /// The created geometry is always an atomic geometry, /// not a collection. /// <para/> /// The empty result is constructed using the following rules: /// <list type="Bullet"> /// <item><see cref="SpatialFunction.Intersection"/> - result has the dimension of the lowest input dimension</item> /// <item><see cref="SpatialFunction.Union"/> - result has the dimension of the highest input dimension</item> /// <item><see cref="SpatialFunction.Difference"/> - result has the dimension of the left-hand input</item> /// <item><see cref="SpatialFunction.SymDifference"/> - result has the dimension of the highest input dimension /// (since symDifference is the union of the differences).</item> /// </list> /// </summary> /// <param name="overlayOpCode">The overlay operation being performed</param> /// <param name="a">An input geometry</param> /// <param name="b">An input geometry</param> /// <param name="geomFact">The geometry factory being used for the operation</param> /// <returns>An empty atomic geometry of the appropriate dimension</returns> public static IGeometry CreateEmptyResult(SpatialFunction overlayOpCode, IGeometry a, IGeometry b, IGeometryFactory geomFact) { IGeometry result = null; switch (ResultDimension(overlayOpCode, a, b)) { case Dimension.False: result = geomFact.CreateGeometryCollection(new IGeometry[0]); break; case Dimension.Point: result = geomFact.CreatePoint((Coordinate)null); break; case Dimension.Curve: result = geomFact.CreateLineString((Coordinate[])null); break; case Dimension.Surface: result = geomFact.CreatePolygon(null, null); break; } return result; }
/// <summary> /// Tests whether a point with a given topological <see cref="Label"/> /// relative to two geometries is contained in /// the result of overlaying the geometries using /// a given overlay operation. /// <para/> /// The method handles arguments of <see cref="Location.Null"/> correctly /// </summary> /// <param name="label">The topological label of the point</param> /// <param name="overlayOpCode">The code for the overlay operation to test</param> /// <returns><c>true</c> if the label locations correspond to the overlayOpCode</returns> public static bool IsResultOfOp(Label label, SpatialFunction overlayOpCode) { var loc0 = label.GetLocation(0); var loc1 = label.GetLocation(1); return IsResultOfOp(loc0, loc1, overlayOpCode); }
/// <summary> /// Find all edges whose label indicates that they are in the result area(s), /// according to the operation being performed. Since we want polygon shells to be /// oriented CW, choose dirEdges with the interior of the result on the RHS. /// Mark them as being in the result. /// Interior Area edges are the result of dimensional collapses. /// They do not form part of the result area boundary. /// </summary> private void FindResultAreaEdges(SpatialFunction opCode) { var it = _graph.EdgeEnds.GetEnumerator(); while (it.MoveNext()) { var de = (DirectedEdge) it.Current; // mark all dirEdges with the appropriate label var label = de.Label; if (label.IsArea() && !de.IsInteriorAreaEdge && IsResultOfOp(label.GetLocation(0, Positions.Right), label.GetLocation(1, Positions.Right), opCode)) de.InResult = true; } }
/// <summary> /// Gets the result of the overlay for a given overlay operation. /// <para/> /// Note: this method can be called once only. /// </summary> /// <param name="overlayOpCode">The code of the overlay operation to perform</param> /// <returns>The computed result geometry</returns> /// <exception cref="TopologyException">Thrown if a robustness problem is encountered</exception> public IGeometry GetResultGeometry(SpatialFunction overlayOpCode) { ComputeOverlay(overlayOpCode); return _resultGeom; }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the Points in the result of the specified overlay operation. /// </returns> public virtual IList Build(SpatialFunction opCode) { IList nodeList = CollectNodes(opCode); IList resultPointList = SimplifyPoints(nodeList); return resultPointList; }
private static Dimension ResultDimension(SpatialFunction opCode, IGeometry g0, IGeometry g1) { var dim0 = (int)g0.Dimension; var dim1 = (int)g1.Dimension; var resultDimension = -1; switch (opCode) { case SpatialFunction.Intersection: resultDimension = Math.Min(dim0, dim1); break; case SpatialFunction.Union: resultDimension = Math.Max(dim0, dim1); break; case SpatialFunction.Difference: resultDimension = dim0; break; case SpatialFunction.SymDifference: /** * This result is chosen because * <pre> * SymDiff = Union(Diff(A, B), Diff(B, A) * </pre> * and Union has the dimension of the highest-dimension argument. */ resultDimension = Math.Max(dim0, dim1); break; } return (Dimension)resultDimension; }
private IGeometry ComputeGeometry(IEnumerable<IGeometry> resultPtList, IEnumerable<IGeometry> resultLiList, IEnumerable<IGeometry> resultPlList, SpatialFunction opCode) { var geomList = new List<IGeometry>(); // element geometries of the result are always in the order Point,Curve,A geomList.AddRange(resultPtList); geomList.AddRange(resultLiList); geomList.AddRange(resultPlList); if (geomList.Count == 0) return CreateEmptyResult(opCode, arg[0].Geometry, arg[1].Geometry, _geomFact); // build the most specific point possible return _geomFact.BuildGeometry(geomList); }
private bool CheckValid(SpatialFunction overlayOp) { for (int i = 0; i < _testCoords.Count; i++) { Coordinate pt = _testCoords[i]; if (!CheckValid(overlayOp, pt)) { _invalidLocation = pt; return false; } } return true; }
/** * * and optionally validating the result. * * @param opCode * @param g0 * @param args * @return * @throws Exception */ /// <summary> /// Invokes an overlay op, optionally using snapping, /// and optionally validating the result. /// </summary> public IResult InvokeValidatedOverlayOp(SpatialFunction opCode, IGeometry g0, Object[] args) { var g1 = (IGeometry)args[0]; var result = InvokeGeometryOverlayMethod(opCode, g0, g1); // validate Validate(opCode, g0, g1, result); AreaValidate(g0, g1); /** * Return an empty GeometryCollection as the result. * This allows the test case to avoid specifying an exact result */ if (ReturnEmptyGeometryCollection) { result = result.Factory.CreateGeometryCollection(null); } return new GeometryResult(result); }
public static bool IsValid(IGeometry a, IGeometry b, SpatialFunction overlayOp, IGeometry result) { OverlayResultValidator validator = new OverlayResultValidator(a, b, result); return validator.IsValid(overlayOp); }
/// <summary> /// Computes an overlay operation /// for the given geometry arguments. /// </summary> /// <param name="geom0">The first geometry argument</param> /// <param name="geom1">The second geometry argument</param> /// <param name="opCode">The code for the desired overlay operation</param> /// <returns>The result of the overlay operation</returns> /// <exception cref="TopologyException">Thrown if a robustness problem is encountered.</exception> public static IGeometry Overlay(IGeometry geom0, IGeometry geom1, SpatialFunction opCode) { var gov = new OverlayOp(geom0, geom1); var geomOv = gov.GetResultGeometry(opCode); return geomOv; }
private static void Validate(SpatialFunction opCode, IGeometry g0, IGeometry g1, IGeometry result) { var validator = new OverlayResultValidator(g0, g1, result); // check if computed result is valid if (!validator.IsValid(opCode)) { var invalidLoc = validator.InvalidLocation; String msg = "Operation result is invalid [OverlayResultValidator] ( " + WKTWriter.ToPoint(invalidLoc) + " )"; ReportError(msg); } }
private void ComputeOverlay(SpatialFunction opCode) { // copy points from input Geometries. // This ensures that any Point geometries // in the input are considered for inclusion in the result set CopyPoints(0); CopyPoints(1); // node the input Geometries arg[0].ComputeSelfNodes(lineIntersector, false); arg[1].ComputeSelfNodes(lineIntersector, false); // compute intersections between edges of the two input geometries arg[0].ComputeEdgeIntersections(arg[1], lineIntersector, true); IList<Edge> baseSplitEdges = new List<Edge>(); arg[0].ComputeSplitEdges(baseSplitEdges); arg[1].ComputeSplitEdges(baseSplitEdges); // add the noded edges to this result graph InsertUniqueEdges(baseSplitEdges); ComputeLabelsFromDepths(); ReplaceCollapsedEdges(); if (!NodingValidatorDisabled) { /* * Check that the noding completed correctly. * * This test is slow, but necessary in order to catch robustness failure * situations. * If an exception is thrown because of a noding failure, * then snapping will be performed, which will hopefully avoid the problem. * In the future hopefully a faster check can be developed. * */ var nv = new EdgeNodingValidator(_edgeList.Edges); nv.CheckValid(); } _graph.AddEdges(_edgeList.Edges); ComputeLabelling(); LabelIncompleteNodes(); /* * The ordering of building the result Geometries is important. * Areas must be built before lines, which must be built before points. * This is so that lines which are covered by areas are not included * explicitly, and similarly for points. */ FindResultAreaEdges(opCode); CancelDuplicateResultEdges(); var polyBuilder = new PolygonBuilder(_geomFact); polyBuilder.Add(_graph); _resultPolyList = polyBuilder.Polygons; var lineBuilder = new LineBuilder(this, _geomFact, _ptLocator); _resultLineList = lineBuilder.Build(opCode); var pointBuilder = new PointBuilder(this, _geomFact, _ptLocator); _resultPointList = pointBuilder.Build(opCode); // gather the results from all calculations into a single Geometry for the result set _resultGeom = ComputeGeometry(_resultPointList, _resultLineList, _resultPolyList, opCode); }
/// <summary> /// /// </summary> /// <param name="opCode"></param> /// <returns> /// A list of the Points in the result of the specified overlay operation. /// </returns> public IList<IGeometry> Build(SpatialFunction opCode) { var nodeList = CollectNodes(opCode); var resultPointList = SimplifyPoints(nodeList); return resultPointList; }
public static IGeometry InvokeGeometryOverlayMethod(SpatialFunction opCode, IGeometry g0, IGeometry g1) { switch (opCode) { case SpatialFunction.Intersection: return g0.Intersection(g1); case SpatialFunction.Union: return g0.Union(g1); case SpatialFunction.Difference: return g0.Difference(g1); case SpatialFunction.SymDifference: return g0.SymmetricDifference(g1); } throw new ArgumentException(@"Unknown overlay op code"); }