/// <summary> /// /// </summary> /// <param name="ring"></param> /// <param name="clockwise"></param> private static void Normalize(ILinearRing ring, bool clockwise) { if (ring.IsEmpty) { return; } Coordinate[] uniqueCoordinates = new Coordinate[ring.Coordinates.Count - 1]; for (int i = 0; i < uniqueCoordinates.Length; i++) { uniqueCoordinates[i] = ring.Coordinates[i]; } Coordinate minCoordinate = CoordinateArrays.MinCoordinate(uniqueCoordinates); CoordinateArrays.Scroll(uniqueCoordinates, minCoordinate); List <Coordinate> result = new List <Coordinate>(); for (int i = 0; i < uniqueCoordinates.Length; i++) { result.Add(ring.Coordinates[i]); } result.Add(uniqueCoordinates[0].Copy()); ring.Coordinates = result; if (CgAlgorithms.IsCounterClockwise(ring.Coordinates) == clockwise) { ring.Coordinates.Reverse(); } }
private double GetArea(List <Coordinate> tempPolygon) { double area = Math.Abs(CgAlgorithms.SignedArea(tempPolygon)); if (_previousParts == null || _previousParts.Count == 0) { _firstPartIsCounterClockwise = CgAlgorithms.IsCounterClockwise(tempPolygon); } else { if (CgAlgorithms.IsCounterClockwise(tempPolygon) != _firstPartIsCounterClockwise) { area = -area; } } if (Map.Projection != null) { if (Map.Projection.IsLatLon) { // this code really assumes the location is near the equator const double RadiusOfEarth = 111319.5; area *= RadiusOfEarth * RadiusOfEarth; } else { area *= Map.Projection.Unit.Meters * Map.Projection.Unit.Meters; } } return(area); }
/// <summary> /// The left and right topological location arguments assume that the ring is oriented CW. /// If the ring is in the opposite orientation, /// the left and right locations must be interchanged. /// </summary> /// <param name="lr"></param> /// <param name="cwLeft"></param> /// <param name="cwRight"></param> private void AddPolygonRing(IBasicGeometry lr, LocationType cwLeft, LocationType cwRight) { IList <Coordinate> coord = CoordinateArrays.RemoveRepeatedPoints(lr.Coordinates); if (coord.Count < 4) { _hasTooFewPoints = true; _invalidPoint = coord[0]; return; } LocationType left = cwLeft; LocationType right = cwRight; if (CgAlgorithms.IsCounterClockwise(coord)) { left = cwRight; right = cwLeft; } Edge e = new Edge(coord, new Label(_argIndex, LocationType.Boundary, left, right)); _lineEdgeMap.Add(lr, e); InsertEdge(e); // insert the endpoint as a node, to mark that it is on the boundary InsertPoint(_argIndex, coord[0], LocationType.Boundary); }
/// <summary> /// Compute a LinearRing from the point list previously collected. /// Test if the ring is a hole (i.e. if it is CCW) and set the hole flag /// accordingly. /// </summary> public void ComputeRing() { if (_ring != null) { return; // don't compute more than once } Coordinate[] coord = new Coordinate[_pts.Count]; for (int i = 0; i < _pts.Count; i++) { coord[i] = (Coordinate)_pts[i]; } _ring = InnerGeometryFactory.CreateLinearRing(coord); _isHole = CgAlgorithms.IsCounterClockwise(_ring.Coordinates); }
/// <summary> /// Add an offset curve for a ring. /// The side and left and right topological location arguments /// assume that the ring is oriented CW. /// If the ring is in the opposite orientation, /// the left and right locations must be interchanged and the side flipped. /// </summary> /// <param name="coord">The coordinates of the ring (must not contain repeated points).</param> /// <param name="offsetDistance">The distance at which to create the buffer.</param> /// <param name="side">The side of the ring on which to construct the buffer line.</param> /// <param name="cwLeftLoc">The location on the L side of the ring (if it is CW).</param> /// <param name="cwRightLoc">The location on the R side of the ring (if it is CW).</param> private void AddPolygonRing(IList <Coordinate> coord, double offsetDistance, PositionType side, LocationType cwLeftLoc, LocationType cwRightLoc) { LocationType leftLoc = cwLeftLoc; LocationType rightLoc = cwRightLoc; if (CgAlgorithms.IsCounterClockwise(coord)) { leftLoc = cwRightLoc; rightLoc = cwLeftLoc; side = Position.Opposite(side); } IList lineList = _curveBuilder.GetRingCurve(coord, side, offsetDistance); AddCurves(lineList, leftLoc, rightLoc); }
/// <inheritdoc/> protected override void AppendBasicGeometry(ShapefileHeader header, IBasicGeometry feature, int numFeatures) { FileInfo fi = new FileInfo(Filename); int offset = Convert.ToInt32(fi.Length / 2); FileStream shpStream = new FileStream(Filename, FileMode.Append, FileAccess.Write, FileShare.None, 10000); FileStream shxStream = new FileStream(header.ShxFilename, FileMode.Append, FileAccess.Write, FileShare.None, 100); List <int> parts = new List <int>(); List <Coordinate> points = new List <Coordinate>(); int contentLength = 22; for (int iPart = 0; iPart < feature.NumGeometries; iPart++) { parts.Add(points.Count); IBasicPolygon pg = feature.GetBasicGeometryN(iPart) as IBasicPolygon; if (pg == null) { continue; } var bl = pg.Shell; var coords = bl.Coordinates; if (CgAlgorithms.IsCounterClockwise(coords)) { // Exterior rings need to be clockwise coords.Reverse(); } points.AddRange(coords); foreach (IBasicLineString hole in pg.Holes) { parts.Add(points.Count); var holeCoords = hole.Coordinates; if (CgAlgorithms.IsCounterClockwise(holeCoords) == false) { // Interior rings need to be counter-clockwise holeCoords.Reverse(); } points.AddRange(holeCoords); } } contentLength += 2 * parts.Count; if (header.ShapeType == ShapeType.Polygon) { contentLength += points.Count * 8; } if (header.ShapeType == ShapeType.PolygonM) { contentLength += 8; // mmin mmax contentLength += points.Count * 12; // x, y, m } if (header.ShapeType == ShapeType.PolygonZ) { contentLength += 16; // mmin, mmax, zmin, zmax contentLength += points.Count * 16; // x, y, m, z } // Index File // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- shxStream.WriteBe(offset); // Byte 0 Offset Integer 1 Big shxStream.WriteBe(contentLength); // Byte 4 Content Length Integer 1 Big shxStream.Flush(); shxStream.Close(); // X Y Poly Lines // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- shpStream.WriteBe(numFeatures); // Byte 0 Record Number Integer 1 Big shpStream.WriteBe(contentLength); // Byte 4 Content Length Integer 1 Big shpStream.WriteLe((int)header.ShapeType); // Byte 8 Shape Type 3 Integer 1 Little if (header.ShapeType == ShapeType.NullShape) { return; } shpStream.WriteLe(feature.Envelope.Minimum.X); // Byte 12 Xmin Double 1 Little shpStream.WriteLe(feature.Envelope.Minimum.Y); // Byte 20 Ymin Double 1 Little shpStream.WriteLe(feature.Envelope.Maximum.X); // Byte 28 Xmax Double 1 Little shpStream.WriteLe(feature.Envelope.Maximum.Y); // Byte 36 Ymax Double 1 Little shpStream.WriteLe(parts.Count); // Byte 44 NumParts Integer 1 Little shpStream.WriteLe(points.Count); // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little foreach (int iPart in parts) { shpStream.WriteLe(iPart); } double[] xyVals = new double[points.Count * 2]; int i = 0; foreach (Coordinate coord in points) { xyVals[i * 2] = coord.X; xyVals[i * 2 + 1] = coord.Y; i++; } shpStream.WriteLe(xyVals, 0, 2 * points.Count); if (header.ShapeType == ShapeType.PolygonZ) { shpStream.WriteLe(feature.Envelope.Minimum.Z); shpStream.WriteLe(feature.Envelope.Maximum.Z); double[] zVals = new double[points.Count]; for (int ipoint = 0; ipoint < points.Count; ipoint++) { zVals[ipoint] = points[ipoint].Z; } shpStream.WriteLe(zVals, 0, points.Count); } if (header.ShapeType == ShapeType.PolygonM || header.ShapeType == ShapeType.PolygonZ) { if (feature.Envelope == null) { shpStream.WriteLe(0.0); shpStream.WriteLe(0.0); } else { shpStream.WriteLe(feature.Envelope.Minimum.M); shpStream.WriteLe(feature.Envelope.Maximum.M); } double[] mVals = new double[points.Count]; for (int ipoint = 0; ipoint < points.Count; i++) { mVals[ipoint] = points[ipoint].M; ipoint++; } shpStream.WriteLe(mVals, 0, points.Count); } shpStream.Flush(); shpStream.Close(); offset += contentLength; Shapefile.WriteFileLength(Filename, offset); Shapefile.WriteFileLength(header.ShxFilename, 50 + numFeatures * 4); }
private void ReadPolygonShape(Shape shape) { _envelope = shape.Range.Extent.ToEnvelope(); List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); foreach (PartRange part in shape.Range.Parts) { List <Coordinate> coords = new List <Coordinate>(); int i = part.StartIndex; foreach (Vertex d in part) { Coordinate c = new Coordinate(d.X, d.Y); if (shape.M != null && shape.M.Length > 0) { c.M = shape.M[i]; } if (shape.Z != null && shape.Z.Length > 0) { c.Z = shape.Z[i]; } i++; coords.Add(c); } LinearRing ring = new LinearRing(coords); if (shape.Range.Parts.Count == 1) { shells.Add(ring); } else { if (CgAlgorithms.IsCounterClockwise(ring.Coordinates)) { holes.Add(ring); } else { shells.Add(ring); } //if (part.IsHole()) //{ // holes.Add(ring); //} //else //{ // shells.Add(ring); //} } } if (shells.Count == 0 && holes.Count > 0) { shells = holes; holes = new List <ILinearRing>(); } //// Now we have a list of all shells and all holes List <ILinearRing>[] holesForShells = new List <ILinearRing> [shells.Count]; for (int i = 0; i < shells.Count; i++) { holesForShells[i] = new List <ILinearRing>(); } // Find holes for (int i = 0; i < holes.Count; i++) { ILinearRing testRing = holes[i]; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; Coordinate testPt = testRing.Coordinates[0]; ILinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } bool isContained = false; if (tryEnv.Contains(testEnv) && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates) || (PointInList(testPt, tryRing.Coordinates)))) { isContained = true; } // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } holesForShells[j].Add(holes[i]); } } } var polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = new Polygon(shells[i], holesForShells[i].ToArray()); } if (polygons.Length == 1) { _basicGeometry = polygons[0]; } else { // It's a multi part _basicGeometry = new MultiPolygon(polygons); } }
/// <summary> /// Saves the file to a new location /// </summary> /// <param name="fileName">The fileName to save</param> /// <param name="overwrite">Boolean that specifies whether or not to overwrite the existing file</param> public override void SaveAs(string fileName, bool overwrite) { if (IndexMode) { SaveAsIndexed(fileName, overwrite); return; } Filename = fileName; string dir = Path.GetDirectoryName(Path.GetFullPath(fileName)); if (dir != null && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (File.Exists(fileName)) { if (fileName != Filename && overwrite == false) { throw new IOException("File exists."); } File.Delete(fileName); string shx = Path.ChangeExtension(fileName, ".shx"); if (File.Exists(shx)) { File.Delete(shx); } } InvalidateEnvelope(); if (CoordinateType == CoordinateType.Regular) { Header.ShapeType = ShapeType.Polygon; } if (CoordinateType == CoordinateType.M) { Header.ShapeType = ShapeType.PolygonM; } if (CoordinateType == CoordinateType.Z) { Header.ShapeType = ShapeType.PolygonZ; } // Set ShapeType before setting extent. Header.SetExtent(Extent); Header.ShxLength = Features.Count * 4 + 50; Header.SaveAs(fileName); BufferedBinaryWriter bbWriter = new BufferedBinaryWriter(fileName); BufferedBinaryWriter indexWriter = new BufferedBinaryWriter(Header.ShxFilename); int fid = 0; int offset = 50; // the shapefile header starts at 100 bytes, so the initial offset is 50 words int contentLength = 0; foreach (IFeature f in Features) { List <int> parts = new List <int>(); offset += contentLength; // adding the previous content length from each loop calculates the word offset List <Coordinate> points = new List <Coordinate>(); contentLength = 22; for (int iPart = 0; iPart < f.NumGeometries; iPart++) { parts.Add(points.Count); IBasicPolygon pg = f.GetBasicGeometryN(iPart) as IBasicPolygon; if (pg == null) { continue; } IBasicLineString bl = pg.Shell; IList <Coordinate> coords = bl.Coordinates; if (CgAlgorithms.IsCounterClockwise(coords)) { // Exterior rings need to be clockwise coords.Reverse(); } foreach (Coordinate coord in coords) { points.Add(coord); } foreach (IBasicLineString hole in pg.Holes) { parts.Add(points.Count); IList <Coordinate> holeCoords = hole.Coordinates; if (CgAlgorithms.IsCounterClockwise(holeCoords) == false) { // Interior rings need to be counter-clockwise holeCoords.Reverse(); } foreach (Coordinate coord in holeCoords) { points.Add(coord); } } } contentLength += 2 * parts.Count; if (Header.ShapeType == ShapeType.Polygon) { contentLength += points.Count * 8; } if (Header.ShapeType == ShapeType.PolygonM) { contentLength += 8; // mmin mmax contentLength += points.Count * 12; // x, y, m } if (Header.ShapeType == ShapeType.PolygonZ) { contentLength += 16; // mmin, mmax, zmin, zmax contentLength += points.Count * 16; // x, y, m, z } // Index File // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- indexWriter.Write(offset, false); // Byte 0 Offset Integer 1 Big indexWriter.Write(contentLength, false); // Byte 4 Content Length Integer 1 Big // X Y Poly Lines // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- bbWriter.Write(fid + 1, false); // Byte 0 Record Number Integer 1 Big bbWriter.Write(contentLength, false); // Byte 4 Content Length Integer 1 Big bbWriter.Write((int)Header.ShapeType); // Byte 8 Shape Type 3 Integer 1 Little if (Header.ShapeType == ShapeType.NullShape) { continue; } bbWriter.Write(f.Envelope.Minimum.X); // Byte 12 Xmin Double 1 Little bbWriter.Write(f.Envelope.Minimum.Y); // Byte 20 Ymin Double 1 Little bbWriter.Write(f.Envelope.Maximum.X); // Byte 28 Xmax Double 1 Little bbWriter.Write(f.Envelope.Maximum.Y); // Byte 36 Ymax Double 1 Little bbWriter.Write(parts.Count); // Byte 44 NumParts Integer 1 Little bbWriter.Write(points.Count); // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little foreach (int iPart in parts) { bbWriter.Write(iPart); } double[] xyVals = new double[points.Count * 2]; int i = 0; // Byte X Points Point NumPoints Little foreach (Coordinate coord in points) { xyVals[i * 2] = coord.X; xyVals[i * 2 + 1] = coord.Y; i++; } bbWriter.Write(xyVals); if (Header.ShapeType == ShapeType.PolygonZ) { bbWriter.Write(f.Envelope.Minimum.Z); bbWriter.Write(f.Envelope.Maximum.Z); double[] zVals = new double[points.Count]; for (int ipoint = 0; ipoint < points.Count; i++) { zVals[ipoint] = points[ipoint].Z; ipoint++; } bbWriter.Write(zVals); } if (Header.ShapeType == ShapeType.PolygonM || Header.ShapeType == ShapeType.PolygonZ) { if (f.Envelope == null) { bbWriter.Write(0.0); bbWriter.Write(0.0); } else { bbWriter.Write(f.Envelope.Minimum.M); bbWriter.Write(f.Envelope.Maximum.M); } double[] mVals = new double[points.Count]; for (int ipoint = 0; ipoint < points.Count; i++) { mVals[ipoint] = points[ipoint].M; ipoint++; } bbWriter.Write(mVals); } fid++; offset += 4; // header bytes } bbWriter.Close(); indexWriter.Close(); offset += contentLength; //offset += 4; WriteFileLength(fileName, offset); WriteFileLength(Header.ShxFilename, 50 + fid * 4); UpdateAttributes(); SaveProjection(); }
private IGeometry ReadPolygon() { ShapefileGeometryType type = (ShapefileGeometryType)_reader.ReadInt32(); if (type == ShapefileGeometryType.NullShape) { return(_gf.CreatePolygon(null, null)); } if (type != ShapefileGeometryType.Polygon && type != ShapefileGeometryType.PolygonZ) { throw new Exception("Attempting to load a non-polygon as polygon."); } // Read the box double xMin = _reader.ReadDouble(), yMin = _reader.ReadDouble(); ShapeEnvelope.Init(xMin, _reader.ReadDouble(), yMin, _reader.ReadDouble()); // Read poly header int numParts = _reader.ReadInt32(); int numPoints = _reader.ReadInt32(); // Read parts array int[] partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) { partOffsets[i] = _reader.ReadInt32(); } // Read the parts and their points List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); Coordinate[] allCoords = new Coordinate[numPoints]; for (int part = 0, last = numParts - 1, x = 0; part < numParts; part++) { int start = partOffsets[part], stop = (part == last ? numPoints : partOffsets[part + 1]); Coordinate[] coords = new Coordinate[stop - start]; for (int i = 0; i < coords.Length; i++) { coords[i] = allCoords[x++] = new Coordinate( _reader.ReadDouble(), _reader.ReadDouble()); } ILinearRing ring = _gf.CreateLinearRing(coords); // Check for hole. if (CgAlgorithms.IsCounterClockwise(coords)) { holes.Add(ring); } else { shells.Add(ring); } } if (type == ShapefileGeometryType.PolygonZ) { // z min/max _reader.ReadDouble(); _reader.ReadDouble(); for (int i = 0; i < allCoords.Length; i++) { allCoords[i].Z = _reader.ReadDouble(); } // m min/max _reader.ReadDouble(); _reader.ReadDouble(); for (int i = 0; i < allCoords.Length; i++) { allCoords[i].M = _reader.ReadDouble(); } } // Create the polygon if (shells.Count == 1) { return(_gf.CreatePolygon(shells[0], holes.ToArray())); } else // Create a multipolygon { List <IPolygon> polys = new List <IPolygon>(shells.Count); foreach (ILinearRing shell in shells) { IEnvelope shellEnv = shell.EnvelopeInternal; List <ILinearRing> shellHoles = new List <ILinearRing>(); for (int i = holes.Count - 1; i >= 0; i--) { ILinearRing hole = holes[i]; if (shellEnv.Contains(hole.EnvelopeInternal)) { shellHoles.Add(hole); holes.RemoveAt(i); } } polys.Add(_gf.CreatePolygon(shell, shellHoles.ToArray())); } // Add the holes that weren't contains as shells foreach (ILinearRing hole in holes) { LinearRing ring = new LinearRing(hole.Reverse()); polys.Add(_gf.CreatePolygon(ring, null)); } return(_gf.CreateMultiPolygon(polys.ToArray())); } }
/// <summary> /// Creates a Polygon or MultiPolygon from this Polygon shape. /// </summary> /// <param name="factory">The IGeometryFactory to use to create the new IGeometry.</param> /// <returns>The IPolygon or IMultiPolygon created from this shape.</returns> protected IGeometry FromPolygon(IGeometryFactory factory) { if (factory == null) { factory = Geometry.DefaultFactory; } List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); foreach (PartRange part in _shapeRange.Parts) { List <Coordinate> coords = new List <Coordinate>(); int i = part.StartIndex; foreach (Vertex d in part) { Coordinate c = new Coordinate(d.X, d.Y); if (M != null && M.Length > 0) { c.M = M[i]; } if (Z != null && Z.Length > 0) { c.Z = Z[i]; } i++; coords.Add(c); } ILinearRing ring = factory.CreateLinearRing(coords); if (_shapeRange.Parts.Count == 1) { shells.Add(ring); } else { if (CgAlgorithms.IsCounterClockwise(ring.Coordinates)) { holes.Add(ring); } else { shells.Add(ring); } } } //// Now we have a list of all shells and all holes List <ILinearRing>[] holesForShells = new List <ILinearRing> [shells.Count]; for (int i = 0; i < shells.Count; i++) { holesForShells[i] = new List <ILinearRing>(); } // Find holes foreach (ILinearRing t in holes) { ILinearRing testRing = t; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; Coordinate testPt = testRing.Coordinates[0]; ILinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } bool isContained = false; if (tryEnv.Contains(testEnv) && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates) || (PointInList(testPt, tryRing.Coordinates)))) { isContained = true; } // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } holesForShells[j].Add(t); } } } IPolygon[] polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); } if (polygons.Length == 1) { return(polygons[0]); } // It's a multi part return(factory.CreateMultiPolygon(polygons)); }
/// <summary> /// Creates a Polygon or MultiPolygon from this Polygon shape. /// </summary> /// <param name="factory">The IGeometryFactory to use to create the new IGeometry.</param> /// <returns>The IPolygon or IMultiPolygon created from this shape.</returns> protected IGeometry FromPolygon(IGeometryFactory factory) { if (factory == null) { factory = Geometry.DefaultFactory; } List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); foreach (var part in _shapeRange.Parts) { var coords = GetCoordinates(part); var ring = factory.CreateLinearRing(coords); if (_shapeRange.Parts.Count == 1) { shells.Add(ring); } else { if (CgAlgorithms.IsCounterClockwise(ring.Coordinates)) { holes.Add(ring); } else { shells.Add(ring); } } } //// Now we have a list of all shells and all holes List <ILinearRing>[] holesForShells = new List <ILinearRing> [shells.Count]; for (int i = 0; i < shells.Count; i++) { holesForShells[i] = new List <ILinearRing>(); } // Find holes foreach (ILinearRing t in holes) { ILinearRing testRing = t; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; Coordinate testPt = testRing.Coordinates[0]; for (int j = 0; j < shells.Count; j++) { ILinearRing tryRing = shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } var isContained = tryEnv.Contains(testEnv) && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates) || (PointInList(testPt, tryRing.Coordinates))); // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } holesForShells[j].Add(t); } } } var polygons = new IPolygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); } if (polygons.Length == 1) { return(polygons[0]); } // It's a multi part return(factory.CreateMultiPolygon(polygons)); }