/// <summary> /// Considers the ShapeType and upgrades the extent class to accommodate M and Z. /// This is automatically called form the setter of ShapeType. /// </summary> public void UpgradeExtent() { if (_shapeType == ShapeType.MultiPointZ || _shapeType == ShapeType.PointZ || _shapeType == ShapeType.PolygonZ || _shapeType == ShapeType.PolyLineZ) { IExtentZ zTest = Extent as IExtentZ; if (zTest == null) { Extent ext = new ExtentMz(); if (_extent != null) { ext.CopyFrom(_extent); } _extent = ext; } // Already implements M and Z } else if (_shapeType == ShapeType.MultiPointM || _shapeType == ShapeType.PointM || _shapeType == ShapeType.PolygonM || _shapeType == ShapeType.PolyLineM) { IExtentM mTest = Extent as IExtentM; if (mTest == null) { Extent ext = new ExtentMz(); if (_extent != null) { ext.CopyFrom(_extent); } _extent = ext; } // already at least implements M } // No upgrade necessary }
/// <summary> /// Allows equality testing for extents that is derived on the extent itself. /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { IExtent other = obj as IExtent; if (other == null) { return(false); } IExtentZ zother = other as IExtentZ; // If either party claims it has no Z values, then ignore that part of the equality check. if (!HasZ || !other.HasM || zother == null) { return(base.Equals(obj)); } if (MinZ != zother.MinZ) { return(false); } if (MaxZ != zother.MaxZ) { return(false); } return(base.Equals(obj)); }
/// <summary> /// Calculates the intersection of this extent and the other extent. A result /// with a min greater than the max in either direction is considered invalid /// and represents no intersection. /// </summary> /// <param name="other">The other extent to intersect with.</param> public override Extent Intersection(Extent other) { IExtentZ zOther = other as IExtentZ; IExtentM mOther = other as IExtentM; Extent result = null; if (HasZ && zOther != null && other.HasZ) { ExtentMZ zResult = new ExtentMZ { MinZ = (MinZ > zOther.MinZ) ? MinZ : zOther.MinZ, MaxZ = (MaxZ < zOther.MaxZ) ? MaxZ : zOther.MaxZ }; result = zResult; } if (HasM && mOther != null && other.HasM) { ExtentM mResult = result as ExtentM ?? new ExtentM(); mResult.MinM = (MinM > mOther.MinM) ? MinM : mOther.MinM; mResult.MaxM = (MaxM < mOther.MaxM) ? MaxM : mOther.MaxM; result = mResult; } else { result = new Extent(); } result.MinX = (MinX > other.MinX) ? MinX : other.MinX; result.MaxX = (MaxX < other.MaxX) ? MaxX : other.MaxX; result.MinY = (MinY > other.MinY) ? MinY : other.MinY; result.MaxY = (MaxY < other.MaxY) ? MaxY : other.MaxY; return(result); }
/// <summary> /// Calculates the intersection of this extent and the other extent. A result /// with a min greater than the max in either direction is considered invalid /// and represents no intersection. /// </summary> /// <param name="other">The other extent to intersect with.</param> /// <returns>The resulting intersection.</returns> public override Extent Intersection(Extent other) { IExtentZ zOther = other as IExtentZ; IExtentM mOther = other as IExtentM; Extent result = null; if (HasZ && zOther != null && other.HasZ) { ExtentMz zResult = new ExtentMz { MinZ = MinZ > zOther.MinZ ? MinZ : zOther.MinZ, MaxZ = MaxZ < zOther.MaxZ ? MaxZ : zOther.MaxZ }; result = zResult; } if (HasM && mOther != null && other.HasM) { ExtentM mResult = (ExtentM)result ?? new ExtentM(); mResult.MinM = MinM > mOther.MinM ? MinM : mOther.MinM; mResult.MaxM = MaxM < mOther.MaxM ? MaxM : mOther.MaxM; result = mResult; } else { result = new Extent(); } result.MinX = MinX > other.MinX ? MinX : other.MinX; result.MaxX = MaxX < other.MaxX ? MaxX : other.MaxX; result.MinY = MinY > other.MinY ? MinY : other.MinY; result.MaxY = MaxY < other.MaxY ? MaxY : other.MaxY; return(result); }
/// <summary> /// Tests for an intersection with the specified extent. Both this extent and the /// other must implement IExtentM and HasM must be true for both, or else just /// the X and Y are compared. /// </summary> /// <param name="ext">The other extent. If the extent doesn't implement IExtentM, then /// this comparison simply defaults to the M, X and Y intersect case.</param> /// <returns>Boolean, true if they overlap anywhere, or even touch.</returns> public override bool Intersects(IExtent ext) { IExtentZ mExt = ext as IExtentZ; if (mExt != null && ext.HasZ && HasZ && (mExt.MaxZ < MinZ || mExt.MinZ > MaxZ)) { return(false); } return(base.Intersects(ext)); }
/// <summary> /// Copies from the implementation of IExtent. This checks to see if IExtentM is implemented /// and if not, this only sets the X and Y bounds. /// </summary> /// <param name="extent"></param> public override void CopyFrom(IExtent extent) { base.CopyFrom(extent); IExtentZ mvals = extent as IExtentZ; if (mvals == null || (double.IsNaN(mvals.MinZ) || double.IsNaN(mvals.MaxZ))) { MinZ = double.MaxValue; MaxZ = double.MinValue; } }
/// <summary> /// Tests if this envelope is contained by the specified envelope /// </summary> /// <param name="ext">The extent to test.</param> /// <returns>Boolean.</returns> public override bool Contains(IExtent ext) { IExtentZ mExt = ext as IExtentZ; if (mExt != null && ext.HasZ && HasZ) { if (mExt.MaxZ > MaxZ || mExt.MinZ < MinZ) { return(false); } } return(base.Within(ext)); }
/// <summary> /// Expands this extent to include the domain of the specified extent. If the specified case /// doesn't support IExtentM or HasM is false for that extent, then this test will default /// to the M, X and Y case. /// </summary> /// <param name="ext">The extent to expand to include</param> public override void ExpandToInclude(IExtent ext) { IExtentZ mExt = ext as IExtentZ; if (mExt != null && ext.HasZ && HasZ) { if (mExt.MinZ < MinZ) { MinZ = mExt.MinZ; } if (mExt.MaxZ > MaxZ) { MaxZ = mExt.MaxZ; } } base.ExpandToInclude(ext); }
/// <summary> /// The shape type is assumed to be fixed, and will control how the input extent is treated as far /// as M and Z values, rather than updating the shape type based on the extent. /// </summary> public void SetExtent(IExtent extent) { IExtentZ zExt = extent as ExtentMZ; IExtentM mExt = extent as ExtentM; if ((ShapeType == ShapeType.MultiPointZ || ShapeType == ShapeType.PointZ || ShapeType == ShapeType.PolygonZ || ShapeType == ShapeType.PolyLineZ)) { if (zExt == null || extent.HasZ == false) { _zMin = double.MaxValue; _zMax = double.MinValue; } else { _zMin = zExt.MinZ; _zMax = zExt.MaxZ; } } if (ShapeType == ShapeType.MultiPointM || ShapeType == ShapeType.PointM || ShapeType == ShapeType.PolygonM || ShapeType == ShapeType.PolyLineM) { if (mExt == null || extent.HasM == false) { _mMin = double.MaxValue; _mMax = double.MinValue; } else { _mMin = mExt.MinM; _mMax = mExt.MaxM; } } _xMin = extent.MinX; _xMax = extent.MaxX; _yMin = extent.MinY; _yMax = extent.MaxY; }
/// <summary> /// The shape type is assumed to be fixed, and will control how the input extent is treated as far /// as M and Z values, rather than updating the shape type based on the extent. /// </summary> /// <param name="extent">The extent.</param> public void SetExtent(IExtent extent) { IExtentZ zExt = extent as ExtentMz; IExtentM mExt = extent as ExtentM; if (ShapeType == ShapeType.MultiPointZ || ShapeType == ShapeType.PointZ || ShapeType == ShapeType.PolygonZ || ShapeType == ShapeType.PolyLineZ) { if (zExt == null || extent.HasZ == false) { Zmin = double.MaxValue; Zmax = double.MinValue; } else { Zmin = zExt.MinZ; Zmax = zExt.MaxZ; } } if (ShapeType == ShapeType.MultiPointM || ShapeType == ShapeType.PointM || ShapeType == ShapeType.PolygonM || ShapeType == ShapeType.PolyLineM) { if (mExt == null || extent.HasM == false) { Mmin = double.MaxValue; Mmax = double.MinValue; } else { Mmin = mExt.MinM; Mmax = mExt.MaxM; } } Xmin = extent.MinX; Xmax = extent.MaxX; Ymin = extent.MinY; Ymax = extent.MaxY; }
// 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(DataStrings.ArgumentNull_S.Replace("%S", fileName)); } if (File.Exists(fileName) == false) { throw new FileNotFoundException(DataStrings.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 != ShapeType.Polygon && header.ShapeType != ShapeType.PolygonM && header.ShapeType != ShapeType.PolygonZ) { throw new ArgumentException(DataStrings.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); // TO DO: replace with a normal reader. We no longer need Buffered Binary reader as // the buffer can be set on the underlying file stream. BufferedBinaryReader bbReader = new 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[] allBounds = new byte[numShapes * 32]; // probably all will be in one block, but use a byteBlock just in case. ByteBlock allParts = new ByteBlock(BLOCKSIZE); ByteBlock allCoords = new ByteBlock(BLOCKSIZE); bool isM = (header.ShapeType == ShapeType.PolygonM || header.ShapeType == ShapeType.PolygonZ); bool isZ = (header.ShapeType == ShapeType.PolygonZ); 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(FeatureType.Polygon); //------------------------------------ shape.RecordNumber = bbReader.ReadInt32(false); // Byte 0 Record Integer 1 Big shape.ContentLength = bbReader.ReadInt32(false); // Byte 4 Length Integer 1 Big // Setting shape type also controls extent class type. shape.ShapeType = (ShapeType)bbReader.ReadInt32(); // Byte 8 Type Integer 1 Little shape.StartIndex = pointOffset; if (shape.ShapeType == ShapeType.NullShape) { continue; } shape.Extent.MinX = bbReader.ReadDouble(); shape.Extent.MinY = bbReader.ReadDouble(); shape.Extent.MaxX = bbReader.ReadDouble(); shape.Extent.MaxY = bbReader.ReadDouble(); shape.NumParts = bbReader.ReadInt32(); // Byte 44 #Parts Integer 1 Little shape.NumPoints = bbReader.ReadInt32(); // Byte 48 #Points Integer 1 Little partOffsets[shp] = allParts.IntOffset(); allParts.Read(shape.NumParts * 4, bbReader); allCoords.Read(shape.NumPoints * 16, bbReader); pointOffset += shape.NumPoints; if (header.ShapeType == ShapeType.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) { IExtentM mExt = (IExtentM)shape.Extent; mExt.MinM = bbReader.ReadDouble(); mExt.MaxM = bbReader.ReadDouble(); if (allM != null) { allM.Read(shape.NumPoints * 8, bbReader); } } } if (header.ShapeType == ShapeType.PolygonZ) { bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints; IExtentZ zExt = (IExtentZ)shape.Extent; zExt.MinZ = bbReader.ReadDouble(); zExt.MaxZ = 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) { IExtentM mExt = (IExtentM)shape.Extent; mExt.MinM = bbReader.ReadDouble(); mExt.MaxM = 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", shapes.Count); for (int shp = 0; shp < shapes.Count; 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], FeatureType.Polygon); partR.NumVertices = count; shape.Parts.Add(partR); } ProgressMeter.CurrentValue = shp; } ProgressMeter.Reset(); }
private void FillLines(string fileName, IProgressHandler progressHandler) { // Check to ensure the fileName is not null if (fileName == null) { throw new NullReferenceException(DataStrings.ArgumentNull_S.Replace("%S", "fileName")); } if (File.Exists(fileName) == false) { throw new FileNotFoundException(DataStrings.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 != ShapeType.PolyLine && header.ShapeType != ShapeType.PolyLineM && header.ShapeType != ShapeType.PolyLineZ) { throw new ArgumentException(DataStrings.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. BufferedBinaryReader bbReader = new BufferedBinaryReader(fileName, progressHandler); if (bbReader.FileLength == 100) { // We have reached the end of the file so we can close the file 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[] allBounds = new byte[numShapes * 32]; // probably all will be in one block, but use a byteBlock just in case. ByteBlock allParts = new ByteBlock(BLOCKSIZE); ByteBlock allCoords = new ByteBlock(BLOCKSIZE); bool isM = (header.ShapeType == ShapeType.PolyLineM || header.ShapeType == ShapeType.PolyLineZ); bool isZ = (header.ShapeType == ShapeType.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); ShapeRange shape = new ShapeRange(FeatureType.Line) { RecordNumber = bbReader.ReadInt32(false), ContentLength = bbReader.ReadInt32(false), ShapeType = (ShapeType)bbReader.ReadInt32(), StartIndex = pointOffset }; if (shape.ShapeType == ShapeType.NullShape) { goto fin; } bbReader.Read(allBounds, shp * 32, 32); shape.NumParts = bbReader.ReadInt32(); // Byte 44 NumParts Integer 1 Little shape.NumPoints = bbReader.ReadInt32(); // Byte 48 NumPoints Integer 1 Little partOffsets[shp] = allParts.IntOffset(); allParts.Read(shape.NumParts * 4, bbReader); allCoords.Read(shape.NumPoints * 16, bbReader); pointOffset += shape.NumPoints; if (header.ShapeType == ShapeType.PolyLineM) { // 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) { //mMin = bbReader.ReadDouble(); //mMax = bbReader.ReadDouble(); bbReader.Seek(16, SeekOrigin.Current); if (allM != null) { allM.Read(shape.NumPoints * 8, bbReader); } } } if (header.ShapeType == ShapeType.PolyLineZ) { bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints; IExtentZ zExt = (IExtentZ)shape.Extent; zExt.MinZ = bbReader.ReadDouble(); zExt.MaxZ = bbReader.ReadDouble(); 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. IExtentM mExt = (IExtentM)shape.Extent; if (hasM) { mExt.MinM = bbReader.ReadDouble(); mExt.MaxM = 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. fin: 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(); 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) { int prt = parts[offset + part + 1]; endIndex = prt + shape.StartIndex; } int count = endIndex - startIndex; PartRange partR = new PartRange(vert, shape.StartIndex, parts[offset + part], FeatureType.Line) { NumVertices = count }; shape.Parts.Add(partR); } } bbReader.Dispose(); }
// 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(DataStrings.ArgumentNull_S.Replace("%S", "fileName")); } if (File.Exists(fileName) == false) { throw new FileNotFoundException(DataStrings.FileNotFound_S.Replace("%S", fileName)); } // Get the basic header information. ShapefileHeader header = new ShapefileHeader(fileName); Extent = header.ToExtent(); // Check to ensure that the fileName is the correct shape type if (header.ShapeType != ShapeType.MultiPoint && header.ShapeType != ShapeType.MultiPointM && header.ShapeType != ShapeType.MultiPointZ) { throw new ArgumentException(DataStrings.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. BufferedBinaryReader bbReader = new 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 == ShapeType.MultiPointZ || header.ShapeType == ShapeType.MultiPointM); bool isZ = (header.ShapeType == ShapeType.MultiPointZ); 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(FeatureType.MultiPoint) { RecordNumber = bbReader.ReadInt32(false), ContentLength = bbReader.ReadInt32(false), ShapeType = (ShapeType)bbReader.ReadInt32(), StartIndex = pointOffset }; //bbReader.Read(bigEndians, shp * 8, 8); if (shape.ShapeType == ShapeType.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 == ShapeType.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) { IExtentM mExt = (IExtentM)MyExtent; mExt.MinM = bbReader.ReadDouble(); mExt.MaxM = bbReader.ReadDouble(); if (allM != null) { allM.Read(shape.NumPoints * 8, bbReader); } } } if (header.ShapeType == ShapeType.MultiPointZ) { bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints; IExtentZ zExt = (IExtentZ)MyExtent; zExt.MinZ = bbReader.ReadDouble(); zExt.MaxZ = 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) { IExtentM mExt = (IExtentM)MyExtent; mExt.MinM = bbReader.ReadDouble(); mExt.MaxM = 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, FeatureType.MultiPoint) { NumVertices = count }; shape.Parts.Add(partR); } bbReader.Dispose(); }