public static MultiPolycurve CreateMultiPolycurve([NotNull] IEnumerable <IPath> paths, double tolerance = 0, [CanBeNull] IEnvelope aoi = null) { var result = new MultiPolycurve(new List <Linestring>()); IEnvelope envelope = new EnvelopeClass(); foreach (IPath path in paths) { if (aoi != null && !aoi.IsEmpty) { path.QueryEnvelope(envelope); if (GeometryUtils.Disjoint(aoi, envelope, tolerance)) { continue; } } // linestring without spatial index Linestring linestring = CreateLinestring(path, int.MaxValue); result.AddLinestring(linestring); } return(result); }
public void CanWriteAndReadMultiLinestring() { var points1 = new List <Pnt3D> { new Pnt3D(0, 0, 9), new Pnt3D(0, 100, 8), new Pnt3D(100, 100, 5) }; var points2 = new List <Pnt3D>(); points2.Add(new Pnt3D(140, -10, 0)); points2.Add(new Pnt3D(140, 30, 23)); points2.Add(new Pnt3D(300, 30, 56)); points2.Add(new Pnt3D(300, -10, 0)); MultiPolycurve polycurve = new MultiPolycurve(new[] { new Linestring(points1), new Linestring(points2) }); WkbGeomWriter writer = new WkbGeomWriter(); byte[] bytes = writer.WriteMultiLinestring(polycurve); WkbGeomReader reader = new WkbGeomReader(); MultiPolycurve deserialized = reader.ReadMultiPolycurve(new MemoryStream(bytes)); Assert.IsTrue(deserialized.Equals(polycurve)); }
public byte[] WriteMultipolygon(MultiPolycurve multipolygon, Ordinates ordinates = Ordinates.Xyz) { return(WriteMultipolygon( GeomTopoOpUtils.GetConnectedComponents(multipolygon, double.Epsilon).ToList(), ordinates)); }
private static IList <RingGroup> CutRingGroupPlanar( [NotNull] RingGroup ringGroup, [NotNull] IPolyline cutLine, double tolerance, ChangeAlongZSource zSource, double zTolerance) { cutLine = GeometryFactory.Clone(cutLine); if (GeometryUtils.IsZAware(cutLine) && zSource != ChangeAlongZSource.Target) { ((IZAware)cutLine).DropZs(); } Plane3D plane = null; if (zSource == ChangeAlongZSource.SourcePlane) { plane = ChangeAlongZUtils.GetSourcePlane( ringGroup.ExteriorRing.GetPoints().ToList(), zTolerance); } GeometryUtils.Simplify(cutLine, true, true); MultiPolycurve cutLinestrings = new MultiPolycurve( GeometryUtils.GetPaths(cutLine).Select( cutPath => GeometryConversionUtils.CreateLinestring(cutPath))); IList <RingGroup> resultGroups = GeomTopoOpUtils.CutPlanar(ringGroup, cutLinestrings, tolerance); foreach (RingGroup resultPoly in resultGroups) { resultPoly.Id = ringGroup.Id; if (plane != null) { resultPoly.AssignUndefinedZs(plane); } else { resultPoly.InterpolateUndefinedZs(); } } Marshal.ReleaseComObject(cutLine); if (resultGroups.Count == 0) { // Return uncut original resultGroups.Add(ringGroup); } return(resultGroups); }
public void CanReadWriteSinglePartPolylineXy() { var points = new WKSPointZ[4]; points[0] = new WKSPointZ { X = 2600000, Y = 1200000, Z = double.NaN }; points[1] = new WKSPointZ { X = 2600030, Y = 1200020, Z = double.NaN }; points[2] = new WKSPointZ { X = 2600020, Y = 1200030, Z = double.NaN }; points[3] = new WKSPointZ { X = 2600040, Y = 1200040, Z = double.NaN }; IPolyline polyline = GeometryFactory.CreatePolyline(points, null); GeometryUtils.MakeNonZAware(polyline); GeometryUtils.Simplify(polyline); WkbGeometryWriter writer = new WkbGeometryWriter(); byte[] wkb = writer.WritePolyline(polyline); // ArcObjects byte[] arcObjectsWkb = GeometryUtils.ToWkb(polyline); Assert.AreEqual(wkb, arcObjectsWkb); // Wkx byte[] wkx = ToChristianSchwarzWkb(ToWkxLineString(points, Ordinates.Xy)); Assert.AreEqual(wkx, wkb); // Bonus test: Geom WkbGeomWriter geomWriter = new WkbGeomWriter(); MultiPolycurve multiPlycurve = GeometryConversionUtils.CreateMultiPolycurve(polyline); byte[] wkbGeom = geomWriter.WriteMultiLinestring(multiPlycurve, Ordinates.Xy); Assert.AreEqual(wkb, wkbGeom); WkbGeometryReader reader = new WkbGeometryReader(); IPolyline restored = reader.ReadPolyline(new MemoryStream(wkb)); Assert.IsTrue(GeometryUtils.AreEqual(polyline, restored)); // Geom WkbGeomReader geomReader = new WkbGeomReader(); Assert.IsTrue( multiPlycurve.Equals(geomReader.ReadMultiPolycurve(new MemoryStream(wkbGeom)))); }
private static IList <IGeometry> TryCutXY( IPolygon inputPolygon, IPolyline cutPolyline, ChangeAlongZSource zSource) { // TODO: // In order to avoid the arbitrary grouping of multipart polygons, try to apply left/right logic // provided by GeomTopoOpUtils double tolerance = GeometryUtils.GetXyTolerance(inputPolygon); double zTolerance = GeometryUtils.GetZTolerance(inputPolygon); MultiPolycurve inputMultipoly = GeometryConversionUtils.CreateMultiPolycurve(inputPolygon); var cutLine = GeometryFactory.Clone(cutPolyline); if (GeometryUtils.IsZAware(cutLine) && zSource != ChangeAlongZSource.Target) { ((IZAware)cutLine).DropZs(); } Plane3D plane = null; if (zSource == ChangeAlongZSource.SourcePlane) { plane = ChangeAlongZUtils.GetSourcePlane( inputMultipoly.GetPoints().ToList(), zTolerance); } GeometryUtils.Simplify(cutLine, true, true); MultiPolycurve cutLinestrings = GeometryConversionUtils.CreateMultiPolycurve(cutLine); bool isMultipart = GeometryUtils.GetExteriorRingCount(inputPolygon) > 1; IList <MultiLinestring> resultGeoms = GeomTopoOpUtils.CutXY(inputMultipoly, cutLinestrings, tolerance, !isMultipart); var result = new List <IGeometry>(); foreach (MultiLinestring resultPoly in resultGeoms) { if (plane != null) { resultPoly.AssignUndefinedZs(plane); } else { resultPoly.InterpolateUndefinedZs(); } result.Add(GeometryConversionUtils.CreatePolygon(inputPolygon, resultPoly.GetLinestrings())); } Marshal.ReleaseComObject(cutLine); return(result.Count == 0 ? null : result); }
public void CanNavigateRings() { var multilinestring = new MultiPolycurve( new[] { new Linestring(new[] { new Pnt3D(0, 0, 9), new Pnt3D(0, 100, 9), new Pnt3D(100, 100, 9), new Pnt3D(100, 0, 9), new Pnt3D(0, 0, 9) }), new Linestring(new[] { // interior ring new Pnt3D(40, 40, 123), new Pnt3D(60, 40, 123), new Pnt3D(60, 60, 12), new Pnt3D(40, 60, 12), new Pnt3D(40, 40, 123) }) }); Assert.True(multilinestring.IsClosed); int partIdx; int localSegmentIdx = multilinestring.GetLocalSegmentIndex(5, out partIdx); Assert.AreEqual(6, multilinestring.GetSegmentStartPointIndex(5)); Assert.AreEqual(1, partIdx); Assert.AreEqual(1, localSegmentIdx); Line3D previousSegment = multilinestring.PreviousSegment(5); Assert.AreEqual(multilinestring.GetSegment(4), previousSegment); Assert.AreEqual(multilinestring.GetSegment(1, 0), previousSegment); int?previousSegmentIdx = multilinestring.PreviousSegmentIndex(5); Assert.NotNull(previousSegmentIdx); Assert.AreEqual(4, previousSegmentIdx); previousSegmentIdx = multilinestring.PreviousSegmentIndex(previousSegmentIdx.Value); Assert.NotNull(previousSegmentIdx); Assert.AreEqual(7, previousSegmentIdx); int?nextSegmentIndex = multilinestring.NextSegmentIndex(previousSegmentIdx.Value); Assert.NotNull(nextSegmentIndex); Assert.AreEqual(4, nextSegmentIndex); Line3D nextSegment = multilinestring.NextSegment(previousSegmentIdx.Value); Assert.AreEqual(multilinestring.GetSegment(4), nextSegment); Assert.AreEqual(multilinestring.GetSegment(1, 0), nextSegment); Assert.AreEqual(5, multilinestring.GetSegmentStartPointIndex(4)); // With the exterior ring: localSegmentIdx = multilinestring.GetLocalSegmentIndex(1, out partIdx); Assert.AreEqual(0, partIdx); Assert.AreEqual(1, localSegmentIdx); previousSegment = multilinestring.PreviousSegment(1); Assert.AreEqual(multilinestring.GetSegment(0), previousSegment); Assert.AreEqual(multilinestring.GetSegment(0, 0), previousSegment); previousSegmentIdx = multilinestring.PreviousSegmentIndex(1); Assert.NotNull(previousSegmentIdx); Assert.AreEqual(0, previousSegmentIdx); previousSegmentIdx = multilinestring.PreviousSegmentIndex(previousSegmentIdx.Value); Assert.NotNull(previousSegmentIdx); Assert.AreEqual(3, previousSegmentIdx); nextSegmentIndex = multilinestring.NextSegmentIndex(previousSegmentIdx.Value); Assert.NotNull(nextSegmentIndex); Assert.AreEqual(0, nextSegmentIndex); nextSegment = multilinestring.NextSegment(previousSegmentIdx.Value); Assert.AreEqual(multilinestring.GetSegment(0), nextSegment); Assert.AreEqual(multilinestring.GetSegment(0, 0), nextSegment); }
public void CanUseBasicProperties() { var multilinestring = new MultiPolycurve( new[] { new Linestring(new[] { new Pnt3D(-5, -15, -25), new Pnt3D(0, 0, 0) }), new Linestring(new[] { new Pnt3D(44, 45, 123), new Pnt3D(33, 33, 123), new Pnt3D(22, 22, 12) }) }); Assert.AreEqual(2, multilinestring.Count); Assert.AreEqual(multilinestring.Count, multilinestring.GetLinestrings().Count()); Assert.AreEqual(3, multilinestring.SegmentCount); Assert.AreEqual(multilinestring.SegmentCount, multilinestring.Count()); Assert.AreEqual(5, multilinestring.PointCount); Assert.AreEqual(multilinestring.PointCount, multilinestring.GetPoints().Count()); Assert.False(multilinestring.IsClosed); Assert.False(multilinestring.IsEmpty); int partIndex; Assert.True(multilinestring.IsFirstPointInPart(0, out partIndex)); Assert.AreEqual(0, partIndex); Assert.True(multilinestring.IsFirstPointInPart(2, out partIndex)); Assert.AreEqual(1, partIndex); Assert.True(multilinestring.IsFirstSegmentInPart(0)); Assert.True(multilinestring.IsFirstSegmentInPart(1)); Assert.True(multilinestring.IsLastPointInPart(1, out partIndex)); Assert.AreEqual(0, partIndex); Assert.True(multilinestring.IsLastPointInPart(4, out partIndex)); Assert.AreEqual(1, partIndex); Assert.True(multilinestring.IsLastSegmentInPart(0)); Assert.True(multilinestring.IsLastSegmentInPart(2)); const double xMin = -5; Assert.AreEqual(xMin, multilinestring.GetLinestring(0).XMin); Assert.AreEqual(xMin, multilinestring.XMin); const double xMax = 44; Assert.AreEqual(xMax, multilinestring.GetLinestring(1).XMax); Assert.AreEqual(xMax, multilinestring.XMax); const double yMin = -15; Assert.AreEqual(yMin, multilinestring.GetLinestring(0).YMin); Assert.AreEqual(yMin, multilinestring.YMin); const double yMax = 45; Assert.AreEqual(yMax, multilinestring.GetLinestring(1).YMax); Assert.AreEqual(yMax, multilinestring.YMax); int partIdx; int localSegmentIndex = multilinestring.GetLocalSegmentIndex(2, out partIdx); Assert.AreEqual(1, partIdx); Assert.AreEqual(1, localSegmentIndex); Assert.AreEqual(2, multilinestring.GetGlobalSegmentIndex(partIdx, localSegmentIndex)); localSegmentIndex = multilinestring.GetLocalSegmentIndex(0, out partIdx); Assert.AreEqual(0, partIdx); Assert.AreEqual(0, localSegmentIndex); Assert.AreEqual(0, multilinestring.GetGlobalSegmentIndex(partIdx, localSegmentIndex)); Assert.AreEqual(multilinestring.GetLinestrings().Sum(l => l.GetLength2D()), multilinestring.GetLength2D()); }
public void CanReadWriteMultipartPolygonXyz() { ISpatialReference sr = SpatialReferenceUtils.CreateSpatialReference( WellKnownHorizontalCS.LV95, WellKnownVerticalCS.LHN95); IPolygon outerRing = GeometryFactory.CreatePolygon(2600000, 1200000, 2601000, 1201000, 432); outerRing.SpatialReference = sr; IPolygon innerRing = GeometryFactory.CreatePolygon(2600100, 1200100, 2600200, 1200200, 421); innerRing.SpatialReference = sr; IPolygon polyWithHole = (IPolygon)IntersectionUtils.Difference(outerRing, innerRing); IPolygon poly2 = GeometryFactory.CreatePolygon(2610000, 1200000, 2611000, 1201000, 543); poly2.SpatialReference = sr; IPolygon multiPolygon = (IPolygon)GeometryUtils.Union(polyWithHole, poly2); Assert.IsTrue(GeometryUtils.IsZAware(multiPolygon)); GeometryUtils.Simplify(multiPolygon); WkbGeometryWriter writer = new WkbGeometryWriter(); byte[] wkb = writer.WritePolygon(multiPolygon); // Wkx var ordinates = Ordinates.Xyz; IList <IGeometry> parts = GeometryUtils.GetParts(multiPolygon).ToList(); IGeometry exteriorRing = parts[0]; IGeometry interiorRing = parts[1]; IGeometry secondExteriorRing = parts[2]; LinearRing wkxOuterRing = ToWkxLinearRing(exteriorRing, ordinates); LinearRing wkxInnerRing = ToWkxLinearRing(interiorRing, ordinates); Polygon wkxPolygon1 = ToWkxPolygon(wkxOuterRing, new[] { wkxInnerRing }); Polygon wkxPolygon2 = ToWkxPolygon(ToWkxLinearRing(secondExteriorRing, ordinates)); MultiPolygon wkxMultiPolygon = new MultiPolygon(new[] { wkxPolygon1, wkxPolygon2 }); byte[] wkx = ToChristianSchwarzWkb(wkxMultiPolygon); Assert.AreEqual(wkx, wkb); // Bonus test: Geom WkbGeomWriter geomWriter = new WkbGeomWriter(); MultiPolycurve multiPly = GeometryConversionUtils.CreateMultiPolycurve(multiPolygon); byte[] wkbGeom = geomWriter.WriteMultipolygon(multiPly, ordinates); Assert.AreEqual(wkb, wkbGeom); WkbGeometryReader reader = new WkbGeometryReader(); IPolygon restored = reader.ReadPolygon(new MemoryStream(wkb)); Assert.IsTrue(GeometryUtils.AreEqual(multiPolygon, restored)); // Geom: WkbGeomReader geomReader = new WkbGeomReader(); IList <RingGroup> readMultiPolygon = geomReader.ReadMultiPolygon(new MemoryStream(wkbGeom)); var readMultiPolycurve = new MultiPolycurve( readMultiPolygon.SelectMany(g => g.GetLinestrings())); Assert.IsTrue(multiPly.Equals(readMultiPolycurve)); // As multipatch IMultiPatch multipatch = GeometryFactory.CreateMultiPatch(multiPolygon); wkb = writer.WriteMultipatch(multipatch); IMultiPatch readMultipatch = (IMultiPatch)reader.ReadGeometry(new MemoryStream(wkb)); // TODO: Implement AreEqual for multipatch that is more permissive regarding First/Outer ring type AssertEqual(multipatch, readMultipatch); }
public void CanReadWriteMultiPartPolylineXyz() { // The spatial reference is important to avoid small differences in // coordinates (snap to spatial reference!) ISpatialReference sr = SpatialReferenceUtils.CreateSpatialReference( WellKnownHorizontalCS.LV95, WellKnownVerticalCS.LHN95); var points1 = new WKSPointZ[4]; points1[0] = new WKSPointZ { X = 2600000, Y = 1200000, Z = 456 }; points1[1] = new WKSPointZ { X = 2600030, Y = 1200020, Z = 457 }; points1[2] = new WKSPointZ { X = 2600020, Y = 1200030, Z = 459 }; points1[3] = new WKSPointZ { X = 2600040, Y = 1200040, Z = 416 }; IPolyline polyline1 = GeometryFactory.CreatePolyline(points1, sr); var points2 = new WKSPointZ[4]; points2[0] = new WKSPointZ { X = 2610000, Y = 1200000, Z = 656 }; points2[1] = new WKSPointZ { X = 2610030, Y = 1200020, Z = 657 }; points2[2] = new WKSPointZ { X = 2610020, Y = 1200030, Z = 659 }; points2[3] = new WKSPointZ { X = 2610040, Y = 1200040, Z = 616 }; IPolyline polyline2 = GeometryFactory.CreatePolyline(points2, sr); IPolyline polyline = (IPolyline)GeometryUtils.Union(polyline1, polyline2); GeometryUtils.Simplify(polyline); WkbGeometryWriter writer = new WkbGeometryWriter(); byte[] wkb = writer.WritePolyline(polyline); // Wkx var ordinates = Ordinates.Xyz; MultiLineString multiLineString = new MultiLineString( new List <LineString> { ToWkxLineString(points1, ordinates), ToWkxLineString(points2, ordinates) }); byte[] wkx = ToChristianSchwarzWkb(multiLineString); Assert.AreEqual(wkx, wkb); // Bonus test: Geom WkbGeomWriter geomWriter = new WkbGeomWriter(); MultiPolycurve multiPlycurve = GeometryConversionUtils.CreateMultiPolycurve(polyline); byte[] wkbGeom = geomWriter.WriteMultiLinestring(multiPlycurve, ordinates); Assert.AreEqual(wkb, wkbGeom); WkbGeometryReader reader = new WkbGeometryReader(); IPolyline restored = reader.ReadPolyline(new MemoryStream(wkb)); Assert.IsTrue(GeometryUtils.AreEqual(polyline, restored)); // Geom: WkbGeomReader geomReader = new WkbGeomReader(); Assert.IsTrue( multiPlycurve.Equals(geomReader.ReadMultiPolycurve(new MemoryStream(wkbGeom)))); }
public void CompareSpatialIndexPerformance() { const int pointCount = 100000; Linestring linestring1 = new Linestring(CreateRandomPoints(pointCount, 2600000, 1200000, 400)); Linestring linestring2 = new Linestring(CreateRandomPoints(pointCount, 2600000, 1200000, 400)); Stopwatch watch; int foundCountBoxtree; int foundSpatialHash; int envelopeIntersections; double tolerance = 0.01; MemoryUsageInfo memUsageBox = new MemoryUsageInfo(); watch = Stopwatch.StartNew(); linestring2.SpatialIndex = BoxTreeSearcher <int> .CreateSpatialSearcher(linestring2); watch.Stop(); Console.WriteLine( $"Linestring ({pointCount}) - Box tree created: {watch.ElapsedMilliseconds}ms. PB: {memUsageBox.Refresh().PrivateBytesDelta:N0}"); watch = Stopwatch.StartNew(); foundCountBoxtree = 0; envelopeIntersections = 0; foreach (Line3D line3D in linestring1) { int foundInEnv = linestring2.FindSegments( line3D.XMin, line3D.YMin, line3D.XMax, line3D.YMax, tolerance).Count(); if (foundInEnv > 0) { envelopeIntersections++; } foundCountBoxtree += foundInEnv; } watch.Stop(); Console.WriteLine( $"Linestring ({pointCount}) - Box tree ({foundCountBoxtree} segments found): {watch.ElapsedMilliseconds}ms"); MemoryUsageInfo memUsageHash = new MemoryUsageInfo(); watch = Stopwatch.StartNew(); linestring2.SpatialIndex = CreateSpatialHash(linestring2); watch.Stop(); Console.WriteLine( $"Linestring ({pointCount}) - spatial hash created: {watch.ElapsedMilliseconds}ms. PB: {memUsageHash.Refresh().PrivateBytesDelta:N0}"); watch = Stopwatch.StartNew(); foundSpatialHash = 0; envelopeIntersections = 0; foreach (Line3D line3D in linestring1) { int foundInEnv = linestring2.FindSegments( line3D.XMin, line3D.YMin, line3D.XMax, line3D.YMax, tolerance).Count(); if (foundInEnv > 0) { envelopeIntersections++; } foundSpatialHash += foundInEnv; } watch.Stop(); Console.WriteLine( $"Linestring ({pointCount}) - Spatial hash ({foundSpatialHash} segments found): {watch.ElapsedMilliseconds}ms"); Assert.AreEqual(foundCountBoxtree, foundSpatialHash); MultiPolycurve poly2 = new MultiPolycurve(new List <Linestring> { linestring2 }); memUsageHash.Refresh(); watch = Stopwatch.StartNew(); poly2.SpatialIndex = SpatialHashSearcher <SegmentIndex> .CreateSpatialSearcher(poly2); watch.Stop(); Console.WriteLine( $"Linestring ({pointCount}) - spatial hash (using multi-part index) created: {watch.ElapsedMilliseconds}ms. PB: {memUsageHash.Refresh().PrivateBytesDelta:N0}"); watch = Stopwatch.StartNew(); foundSpatialHash = 0; envelopeIntersections = 0; foreach (Line3D line3D in linestring1) { int foundInEnv = poly2.FindSegments( line3D.XMin, line3D.YMin, line3D.XMax, line3D.YMax, tolerance).Count(); if (foundInEnv > 0) { envelopeIntersections++; } foundSpatialHash += foundInEnv; } watch.Stop(); Console.WriteLine( $"Linestring ({pointCount}) - Spatial hash on poly ({foundSpatialHash} segments found): {watch.ElapsedMilliseconds}ms"); Assert.AreEqual(foundCountBoxtree, foundSpatialHash); }