/// <summary> /// Creates a new instance of a PolygonShapefile for in-ram handling only. /// </summary> public PolygonShapefile():base(FeatureTypes.Polygon) { Attributes = new AttributeTable(); Header = new ShapefileHeader(); Header.FileLength = 100; Header.ShapeType = ShapeTypes.Polygon; FeatureType = FeatureTypes.Polygon; }
/// <summary> /// Creates a new instance of a PointShapefile for in-ram handling only. /// </summary> public PointShapefile() : base(FeatureTypes.Point) { Attributes = new AttributeTable(); Header = new ShapefileHeader(); Header.FileLength = 100; Header.ShapeType = ShapeTypes.Point; }
/// <summary> /// Creates a new instance of a LineShapefile for in-ram handling only. /// </summary> public LineShapefile() { Attributes = new AttributeTable(); Header = new ShapefileHeader(); Header.FileLength = 100; Header.ShapeType = ShapeTypes.PolyLine; FeatureType = FeatureTypes.Line; }
/// <summary> /// Creates a new instance of a MultiPointShapefile for in-ram handling only. /// </summary> public MultiPointShapefile():base(FeatureTypes.MultiPoint) { _geometryFactory = new GeometryFactory(); Attributes = new AttributeTable(); Header = new ShapefileHeader(); Header.FileLength = 100; Header.ShapeType = ShapeTypes.MultiPoint; }
/// <summary> /// Opens a shapefile /// </summary> /// <param name="filename">The string filename of the point shapefile to load</param> /// <param name="progressHandler">Any valid implementation of the MapWindow.Main.IProgressHandler</param> public void Open(string filename, IProgressHandler progressHandler) { IndexMode = true; Filename = filename; Header = new ShapefileHeader(filename); CoordinateType = CoordinateTypes.Regular; if (Header.ShapeType == ShapeTypes.PointM) { CoordinateType = CoordinateTypes.M; } if (Header.ShapeType == ShapeTypes.PointZ) { CoordinateType = CoordinateTypes.Z; } base.Envelope = Header.ToEnvelope(); Name = Path.GetFileNameWithoutExtension(filename); Attributes.Open(filename); FillPoints(filename, progressHandler); ReadProjection(); }
/// <summary> /// This tests the specified file in order to determine what type of vector the file contains. /// This returns unspecified if the file format is not supported by this provider. /// </summary> /// <param name="filename">The string filename to test</param> /// <returns>A FeatureType clarifying what sort of features are stored on the data type.</returns> public virtual FeatureTypes GetFeatureType(string filename) { ShapefileHeader sh = new ShapefileHeader(filename); if (sh.ShapeType == ShapeTypes.Polygon || sh.ShapeType == ShapeTypes.PolygonM || sh.ShapeType == ShapeTypes.PolygonZ) { return FeatureTypes.Polygon; } if (sh.ShapeType == ShapeTypes.PolyLine || sh.ShapeType == ShapeTypes.PolyLineM || sh.ShapeType == ShapeTypes.PolyLineZ) { return FeatureTypes.Line; } if (sh.ShapeType == ShapeTypes.Point || sh.ShapeType == ShapeTypes.PointM || sh.ShapeType == ShapeTypes.PointZ) { return FeatureTypes.Point; } if(sh.ShapeType == ShapeTypes.MultiPoint || sh.ShapeType == ShapeTypes.MultiPointM || sh.ShapeType == ShapeTypes.MultiPointZ) { return FeatureTypes.MultiPoint; } return FeatureTypes.Unspecified; }
/// <summary> /// Obtains a typed list of ShapefilePoint structures with double values associated with the various coordinates. /// </summary> /// <param name="filename">A string filename</param> /// <param name="progressHandler">A progress indicator</param> private void FillPoints(string filename, IProgressHandler progressHandler) { // Check to ensure the filename is not null if (filename == null) { throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S",filename)); } if (File.Exists(filename) == false) { throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename)); } // Reading the headers gives us an easier way to track the number of shapes and their overall length etc. List<ShapeHeader> shapeHeaders = ReadIndexFile(filename); // Get the basic header information. ShapefileHeader header = new ShapefileHeader(filename); Extent = new Extent(new[] { header.Xmin, header.Ymin, header.Xmax, header.Ymax }); Envelope = Extent.ToEnvelope(); // Check to ensure that the filename is the correct shape type if (header.ShapeType != ShapeTypes.Point && header.ShapeType != ShapeTypes.PointM && header.ShapeType != ShapeTypes.PointZ) { throw new ApplicationException(MessageStrings.FileNotPoints_S.Replace("%S", filename)); } // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time. IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler); if (bbReader.FileLength == 100) { bbReader.Close(); // the file is empty so we are done reading return; } // Skip the shapefile header by skipping the first 100 bytes in the shapefile bbReader.Seek(100, SeekOrigin.Begin); int numShapes = shapeHeaders.Count; byte[] bigEndian = new byte[numShapes * 8]; byte[] allCoords = new byte[numShapes * 16]; bool isM = false; bool isZ = false; if(header.ShapeType == ShapeTypes.PointM || header.ShapeType == ShapeTypes.PointZ) { isM = true; } if (header.ShapeType == ShapeTypes.PointZ) { isZ = true; } byte[] allM = new byte[8]; if(isM) allM = new byte[numShapes * 8]; byte[] allZ = new byte[8]; if(isZ) allZ = new byte[numShapes * 8]; for (int shp = 0; shp < numShapes; shp++) { // Read from the index file because some deleted records // might still exist in the .shp file. long offset = (shapeHeaders[shp].ByteOffset); bbReader.Seek(offset, SeekOrigin.Begin); bbReader.Read(bigEndian, shp * 8, 8); ShapeTypes type = (ShapeTypes)bbReader.ReadInt32(); //bbReader.Seek(4, SeekOrigin.Current); bbReader.Read(allCoords, shp * 16, 16); if(isZ) { bbReader.Read(allZ, shp*8, 8); } if (isM) { bbReader.Read(allM, shp*8, 8); } ShapeRange shape = new ShapeRange(FeatureTypes.Point); shape.StartIndex = shp; shape.ContentLength = 8; shape.NumPoints = 1; shape.NumParts = 1; ShapeIndices.Add(shape); } double[] vert = new double[2 * numShapes]; Buffer.BlockCopy(allCoords, 0, vert, 0, numShapes*16); Vertex = vert; if(isM) { double[] m = new double[numShapes]; Buffer.BlockCopy(allM, 0, m, 0, numShapes * 8); M = m; } if(isZ) { double[] z = new double[numShapes]; Buffer.BlockCopy(allZ, 0, z, 0, numShapes * 8); Z = z; } for (int shp = 0; shp < numShapes; shp++) { PartRange part = new PartRange(vert, shp, 0, FeatureTypes.Point); part.NumVertices = 1; ShapeRange shape = ShapeIndices[shp]; shape.Parts.Add(part); shape.Extent = new Extent(new[] {vert[shp*2], vert[shp*2 + 1], vert[shp*2], vert[shp*2 + 1]}); } bbReader.Dispose(); }
private void Configure() { Attributes = new AttributeTable(); _header = new ShapefileHeader(); IndexMode = true; }
/// <summary> /// This will return the correct shapefile type by reading the filename. /// </summary> /// <param name="filename">A string specifying the file with the extension .shp to open.</param> /// <param name="progressHandler">recieves progress messages and overrides the ProgressHandler on the DataManager.DefaultDataManager</param> /// <returns>A correct shapefile object which is exclusively for reading the .shp data</returns> public new static Shapefile OpenFile(string filename, IProgressHandler progressHandler) { ShapefileHeader head = new ShapefileHeader(); head.Open(filename); PointShapefile psf; LineShapefile lsf; PolygonShapefile pgsf; MultiPointShapefile mpsf; switch (head.ShapeType) { case ShapeTypes.MultiPatch: throw new NotImplementedException("This shape type is not yet supported."); // break; case ShapeTypes.MultiPoint: mpsf = new MultiPointShapefile(); mpsf.Open(filename, progressHandler); return mpsf; case ShapeTypes.MultiPointM: mpsf = new MultiPointShapefile(); mpsf.Open(filename, progressHandler); return mpsf; case ShapeTypes.MultiPointZ: mpsf = new MultiPointShapefile(); mpsf.Open(filename, progressHandler); return mpsf; case ShapeTypes.NullShape: throw new NotImplementedException("This shape type is not yet supported."); // break; case ShapeTypes.Point: // Instantiate a new object to handle the point shapefile psf = new PointShapefile(); // Open the geometric components of the data (but not the dbf components) psf.Open(filename, progressHandler); return psf; case ShapeTypes.PointM: // Instantiate a new object to handle the point shapefile psf = new PointShapefile(); // Open the geometric components of the data (but not the dbf components) psf.Open(filename, progressHandler); return psf; case ShapeTypes.PointZ: // Instantiate a new object to handle the point shapefile psf = new PointShapefile(); // Open the geometric components of the data (but not the dbf components) psf.Open(filename, progressHandler); return psf; case ShapeTypes.Polygon: pgsf = new PolygonShapefile(); pgsf.Open(filename, progressHandler); return pgsf; case ShapeTypes.PolygonM: pgsf = new PolygonShapefile(); pgsf.Open(filename, progressHandler); return pgsf; case ShapeTypes.PolygonZ: pgsf = new PolygonShapefile(); pgsf.Open(filename, progressHandler); return pgsf; case ShapeTypes.PolyLine: lsf = new LineShapefile(); lsf.Open(filename, progressHandler); return lsf; case ShapeTypes.PolyLineM: lsf = new LineShapefile(); lsf.Open(filename, progressHandler); return lsf; case ShapeTypes.PolyLineZ: lsf = new LineShapefile(); lsf.Open(filename, progressHandler); return lsf; } return null; }
// X Y MultiPoints: Total Length = 28 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 8 Integer 1 Little // Byte 12 Xmin Double 1 Little // Byte 20 Ymin Double 1 Little // Byte 28 Xmax Double 1 Little // Byte 36 Ymax Double 1 Little // Byte 48 NumPoints Integer 1 Little // Byte X Points Point NumPoints Little // X Y M MultiPoints: Total Length = 34 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 28 Integer 1 Little // Byte 12 Box Double 4 Little // Byte 44 NumPoints Integer 1 Little // Byte X Points Point NumPoints Little // Byte Y* Mmin Double 1 Little // Byte Y + 8* Mmax Double 1 Little // Byte Y + 16* Marray Double NumPoints Little // X Y Z M MultiPoints: Total Length = 44 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 18 Integer 1 Little // Byte 12 Box Double 4 Little // Byte 44 NumPoints Integer 1 Little // Byte X Points Point NumPoints Little // Byte Y Zmin Double 1 Little // Byte Y + 8 Zmax Double 1 Little // Byte Y + 16 Zarray Double NumPoints Little // Byte Z* Mmin Double 1 Little // Byte Z+8* Mmax Double 1 Little // Byte Z+16* Marray Double NumPoints Little private void FillPoints(string filename, IProgressHandler progressHandler) { // Check to ensure the filename is not null if (filename == null) { throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S", filename)); } if (File.Exists(filename) == false) { throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename)); } // Get the basic header information. ShapefileHeader header = new ShapefileHeader(filename); Extent = new Extent(new[] { header.Xmin, header.Ymin, header.Xmax, header.Ymax }); // Check to ensure that the filename is the correct shape type if (header.ShapeType != ShapeTypes.MultiPoint && header.ShapeType != ShapeTypes.MultiPointM && header.ShapeType != ShapeTypes.MultiPointZ) { throw new ArgumentException(MessageStrings.FileNotLines_S.Replace("%S", filename)); } // Reading the headers gives us an easier way to track the number of shapes and their overall length etc. List<ShapeHeader> shapeHeaders = ReadIndexFile(filename); // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time. IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler); if (bbReader.FileLength == 100) { // The shapefile is empty so we can simply return here bbReader.Close(); return; } // Skip the shapefile header by skipping the first 100 bytes in the shapefile bbReader.Seek(100, SeekOrigin.Begin); int numShapes = shapeHeaders.Count; byte[] bigEndians = new byte[numShapes * 8]; byte[] allBounds = new byte[numShapes * 32]; ByteBlock allCoords = new ByteBlock(BLOCKSIZE); bool isM = (header.ShapeType == ShapeTypes.MultiPointZ || header.ShapeType == ShapeTypes.MultiPointM); bool isZ = (header.ShapeType == ShapeTypes.PolyLineZ); ByteBlock allZ = null; ByteBlock allM = null; if (isZ) { allZ = new ByteBlock(BLOCKSIZE); } if (isM) { allM = new ByteBlock(BLOCKSIZE); } int pointOffset = 0; for (int shp = 0; shp < numShapes; shp++) { // Read from the index file because some deleted records // might still exist in the .shp file. long offset = (shapeHeaders[shp].ByteOffset); bbReader.Seek(offset, SeekOrigin.Begin); // time: 200 ms ShapeRange shape = new ShapeRange(FeatureTypes.MultiPoint); shape.RecordNumber = bbReader.ReadInt32(false); // Byte 0 Record Number Integer 1 Big shape.ContentLength = bbReader.ReadInt32(false); // Byte 4 Content Length Integer 1 Big //bbReader.Read(bigEndians, shp * 8, 8); shape.ShapeType = (ShapeTypes)bbReader.ReadInt32(); shape.StartIndex = pointOffset; if (shape.ShapeType == ShapeTypes.NullShape) { continue; } bbReader.Read(allBounds, shp * 32, 32); shape.NumParts = 1; shape.NumPoints = bbReader.ReadInt32(); allCoords.Read(shape.NumPoints * 16, bbReader); pointOffset += shape.NumPoints; if (header.ShapeType == ShapeTypes.MultiPointM) { // These are listed as "optional" but there isn't a good indicator of how to determine if they were added. // To handle the "optional" M values, check the contentLength for the feature. // The content length does not include the 8-byte record header and is listed in 16-bit words. if (shape.ContentLength * 2 > 44 + 4 * shape.NumParts + 16 * shape.NumPoints) { double mMin = bbReader.ReadDouble(); double mMax = bbReader.ReadDouble(); //bbReader.Seek(16, SeekOrigin.Current); if (allM != null) allM.Read(shape.NumPoints * 8, bbReader); } } if (header.ShapeType == ShapeTypes.MultiPointZ) { bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints; double zMin = bbReader.ReadDouble(); double zMax = bbReader.ReadDouble(); // For Z shapefiles, the Z part is not optional. if (allZ != null) allZ.Read(shape.NumPoints * 8, bbReader); // These are listed as "optional" but there isn't a good indicator of how to determine if they were added. // To handle the "optional" M values, check the contentLength for the feature. // The content length does not include the 8-byte record header and is listed in 16-bit words. if (hasM) { double mMin = bbReader.ReadDouble(); double mMax = bbReader.ReadDouble(); if (allM != null) allM.Read(shape.NumPoints * 8, bbReader); } } // Now that we have read all the values, create the geometries from the points and parts arrays. ShapeIndices.Add(shape); } double[] vert = allCoords.ToDoubleArray(); Vertex = vert; if (isM) M = allM.ToDoubleArray(); if (isZ) Z = allZ.ToDoubleArray(); Array.Reverse(bigEndians); List<ShapeRange> shapes = ShapeIndices; double[] bounds = new double[numShapes * 4]; Buffer.BlockCopy(allBounds, 0, bounds, 0, allBounds.Length); for (int shp = 0; shp < numShapes; shp++) { ShapeRange shape = shapes[shp]; shape.Extent = new Extent(bounds, shp * 4); int endIndex = shape.NumPoints + shape.StartIndex; int startIndex = shape.StartIndex; int count = endIndex - startIndex; PartRange partR = new PartRange(vert, shape.StartIndex, 0, FeatureTypes.MultiPoint); partR.NumVertices = count; shape.Parts.Add(partR); } GC.Collect(); bbReader.Dispose(); }
// X Y Poly Lines: Total Length = 28 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 3 Integer 1 Little // Byte 12 Xmin Double 1 Little // Byte 20 Ymin Double 1 Little // Byte 28 Xmax Double 1 Little // Byte 36 Ymax Double 1 Little // Byte 44 NumParts Integer 1 Little // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little // Byte X Points Point NumPoints Little // X Y M Poly Lines: Total Length = 34 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 23 Integer 1 Little // Byte 12 Box Double 4 Little // Byte 44 NumParts Integer 1 Little // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little // Byte X Points Point NumPoints Little // Byte Y* Mmin Double 1 Little // Byte Y + 8* Mmax Double 1 Little // Byte Y + 16* Marray Double NumPoints Little // X Y Z M Poly Lines: Total Length = 44 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 13 Integer 1 Little // Byte 12 Box Double 4 Little // Byte 44 NumParts Integer 1 Little // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little // Byte X Points Point NumPoints Little // Byte Y Zmin Double 1 Little // Byte Y + 8 Zmax Double 1 Little // Byte Y + 16 Zarray Double NumPoints Little // Byte Z* Mmin Double 1 Little // Byte Z+8* Mmax Double 1 Little // Byte Z+16* Marray Double NumPoints Little private void FillPolygons(string filename, IProgressHandler progressHandler) { // Check to ensure the filename is not null if (filename == null) { throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S", filename)); } if (File.Exists(filename) == false) { throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename)); } // Get the basic header information. ShapefileHeader header = new ShapefileHeader(filename); Extent = new Extent(new[]{header.Xmin, header.Ymin, header.Xmax, header.Ymax}); // Check to ensure that the filename is the correct shape type if (header.ShapeType != ShapeTypes.Polygon && header.ShapeType != ShapeTypes.PolygonM && header.ShapeType != ShapeTypes.PolygonZ) { throw new ArgumentException(MessageStrings.FileNotLines_S.Replace("%S", filename)); } // Reading the headers gives us an easier way to track the number of shapes and their overall length etc. List<ShapeHeader> shapeHeaders = ReadIndexFile(filename); // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time. IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler); if (bbReader.FileLength == 100) { // The shapefile is empty so we can simply return here bbReader.Close(); return; } // Skip the shapefile header by skipping the first 100 bytes in the shapefile bbReader.Seek(100, SeekOrigin.Begin); int numShapes = shapeHeaders.Count; int [] partOffsets = new int[numShapes]; byte[] bigEndians = new byte[numShapes * 8]; byte[] allBounds = new byte[numShapes * 32]; ByteBlock allParts = new ByteBlock(BLOCKSIZE); // probably all will be in one block, but use a byteBlock just in case. ByteBlock allCoords = new ByteBlock(BLOCKSIZE); bool isM = (header.ShapeType == ShapeTypes.PolyLineM || header.ShapeType == ShapeTypes.PolyLineZ); bool isZ = (header.ShapeType == ShapeTypes.PolyLineZ); ByteBlock allZ = null; ByteBlock allM = null; if (isZ) { allZ = new ByteBlock(BLOCKSIZE); } if (isM) { allM = new ByteBlock(BLOCKSIZE); } int pointOffset = 0; for (int shp = 0; shp < numShapes; shp++) { // Read from the index file because some deleted records // might still exist in the .shp file. long offset = (shapeHeaders[shp].ByteOffset); bbReader.Seek(offset, SeekOrigin.Begin); // Position Value Type Number Byte Order ShapeRange shape = new ShapeRange(FeatureTypes.Polygon); //-------------------------------------------------------------------- shape.RecordNumber = bbReader.ReadInt32(false); // Byte 0 Record Number Integer 1 Big shape.ContentLength = bbReader.ReadInt32(false); // Byte 4 Content Length Integer 1 Big shape.ShapeType = (ShapeTypes)bbReader.ReadInt32(); // Byte 8 Shape Type Integer 1 Little shape.StartIndex = pointOffset; if (shape.ShapeType == ShapeTypes.NullShape) { continue; } bbReader.Read(allBounds, shp*32, 32); //double xMin = bbReader.ReadDouble(); // Byte 12 Xmin Double 1 Little // double yMin = bbReader.ReadDouble(); // Byte 20 Ymin Double 1 Little //double xMax = bbReader.ReadDouble(); // Byte 28 Xmax Double 1 Little //double yMax = bbReader.ReadDouble(); // Byte 36 Ymax Double 1 Little shape.NumParts = bbReader.ReadInt32(); // Byte 44 NumParts Integer 1 Little //feature.NumPoints = bbReader.ReadInt32(); // Byte 48 NumPoints Integer 1 Little shape.NumPoints = bbReader.ReadInt32(); // Create an envelope from the extents box in the file. //feature.Envelope = new Envelope(xMin, xMax, yMin, yMax); partOffsets[shp] = allParts.IntOffset(); allParts.Read(shape.NumParts * 4, bbReader); allCoords.Read(shape.NumPoints * 16, bbReader); pointOffset += shape.NumPoints; if (header.ShapeType == ShapeTypes.PolygonM) { // These are listed as "optional" but there isn't a good indicator of how to determine if they were added. // To handle the "optional" M values, check the contentLength for the feature. // The content length does not include the 8-byte record header and is listed in 16-bit words. if (shape.ContentLength * 2 > 44 + 4 * shape.NumParts + 16 * shape.NumPoints) { double mMin = bbReader.ReadDouble(); double mMax = bbReader.ReadDouble(); if(allM != null)allM.Read(shape.NumPoints * 8, bbReader); } } if (header.ShapeType == ShapeTypes.PolygonZ) { bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints; double zMin = bbReader.ReadDouble(); double zMax = bbReader.ReadDouble(); // For Z shapefiles, the Z part is not optional. if (allZ != null) allZ.Read(shape.NumPoints * 8, bbReader); // These are listed as "optional" but there isn't a good indicator of how to determine if they were added. // To handle the "optional" M values, check the contentLength for the feature. // The content length does not include the 8-byte record header and is listed in 16-bit words. if (hasM) { double mMin = bbReader.ReadDouble(); double mMax = bbReader.ReadDouble(); if (allM != null) allM.Read(shape.NumPoints * 8, bbReader); } } ShapeIndices.Add(shape); } double[] vert = allCoords.ToDoubleArray(); Vertex = vert; if (isM) M = allM.ToDoubleArray(); if (isZ) Z = allZ.ToDoubleArray(); List<ShapeRange> shapes = ShapeIndices; double[] bounds = new double[numShapes * 4]; Buffer.BlockCopy(allBounds, 0, bounds, 0, allBounds.Length); int[] parts = allParts.ToIntArray(); ProgressMeter = new ProgressMeter(ProgressHandler, "Testing Parts and Holes", numShapes); for (int shp = 0; shp < numShapes; shp++) { ShapeRange shape = shapes[shp]; shape.Extent = new Extent(bounds, shp * 4); for (int part = 0; part < shape.NumParts; part++) { int offset = partOffsets[shp]; int endIndex = shape.NumPoints + shape.StartIndex; int startIndex = parts[offset + part] + shape.StartIndex; if (part < shape.NumParts - 1) endIndex = parts[offset + part + 1] + shape.StartIndex; int count = endIndex - startIndex; PartRange partR = new PartRange(vert, shape.StartIndex, parts[offset + part], FeatureTypes.Polygon); partR.NumVertices = count; shape.Parts.Add(partR); } ProgressMeter.CurrentValue = shp; } ProgressMeter.Reset(); GC.Collect(); }