/// <summary> /// Unions a collection of geometries /// using a given precision model. /// <para/> /// This class is most useful for performing UnaryUnion using /// a fixed-precision model. /// For unary union using floating precision, /// <see cref="OverlayNGRobust.Union(Geometry)"/> should be used. /// </summary> /// <param name="geom">The geometry to union</param> /// <param name="pm">The precision model to use</param> /// <returns>The union of the geometries</returns> /// <seealso cref="OverlayNGRobust"/> public static Geometry Union(Geometry geom, PrecisionModel pm) { if (geom == null) { throw new ArgumentNullException(nameof(geom)); } var unionSRFun = new UnionStrategy((g0, g1) => OverlayNG.Overlay(g0, g1, SpatialFunction.Union, pm), OverlayUtility.IsFloating(pm)); var op = new UnaryUnionOp(geom) { UnionStrategy = unionSRFun }; return(op.Union()); }
//=============================================== /// <summary> /// Attempt Overlay using Snap-Rounding with an automatically-determined /// scale factor. /// </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> public static Geometry OverlaySR(Geometry geom0, Geometry geom1, SpatialFunction opCode) { Geometry result; try { //System.out.println("OverlaySnapIfNeeded: trying snap-rounding"); double scaleSafe = PrecisionUtility.SafeScale(geom0, geom1); var pmSafe = new PrecisionModel(scaleSafe); result = OverlayNG.Overlay(geom0, geom1, opCode, pmSafe); return(result); } catch (TopologyException ex) { //---- ignore exception, return null result to indicate failure } return(null); }
/// <summary> /// Overlay two geometries, using heuristics to ensure /// computation completes correctly. /// In practice the heuristics are observed to be fully correct. /// </summary> /// <param name="geom0">A geometry</param> /// <param name="geom1">A geometry</param> /// <param name="opCode">The overlay operation code</param> /// <returns>The overlay result geometry</returns> public static Geometry Overlay(Geometry geom0, Geometry geom1, SpatialFunction opCode) { if (geom0 == null) { throw new ArgumentNullException(nameof(geom0)); } switch (opCode) { case SpatialFunction.Intersection: case SpatialFunction.Union: case SpatialFunction.Difference: case SpatialFunction.SymDifference: break; default: throw new ArgumentOutOfRangeException(nameof(opCode), opCode, "Only Intersection, Union, Difference, and SymDifference are recognized at this time."); } /* * First try overlay with a PrecisionModels.Floating noder, which is * fast and causes least change to geometry coordinates * By default the noder is validated, which is required in order * to detect certain invalid noding situations which otherwise * cause incorrect overlay output. */ try { return(OverlayNG.Overlay(geom0, geom1, opCode)); } catch (Exception ex) { /* * On failure retry using snapping noding with a "safe" tolerance. * if this throws an exception just let it go, * since it is something that is not a TopologyException */ try { if (OverlaySnapTries(geom0, geom1, opCode) is Geometry result) { return(result); } } catch (Exception ex2) { throw new AggregateException(ex, ex2); } /* * On failure retry using snap-rounding with a heuristic scale factor (grid size). */ try { if (OverlaySR(geom0, geom1, opCode) is Geometry result) { return(result); } } catch (Exception ex2) { throw new AggregateException(ex, ex2); } /* * Just can't get overlay to work, so throw original error. */ throw; } }
private static Geometry OverlaySnapTol(Geometry geom0, Geometry geom1, SpatialFunction opCode, double snapTol) { var snapNoder = new SnappingNoder(snapTol); return(OverlayNG.Overlay(geom0, geom1, opCode, snapNoder)); }