예제 #1
0
        /// <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
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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)
        {
            IExtentM mOther = other as IExtentM;
            Extent   result;

            if (HasM && mOther != null && other.HasM)
            {
                ExtentM mResult = new ExtentM
                {
                    MinM = (MinM > mOther.MinM) ? MinM : mOther.MinM,
                    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);
        }
예제 #4
0
        /// <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);
            }
            IExtentM mother = other as IExtentM;

            // If either party claims it has no M values, then w can ignore that part of the equality check.
            if (!HasM || !other.HasM || mother == null)
            {
                return(base.Equals(obj));
            }
            if (MinM != mother.MinM)
            {
                return(false);
            }
            if (MaxM != mother.MaxM)
            {
                return(false);
            }
            return(base.Equals(obj));
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <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);
            IExtentM mvals = extent as IExtentM;

            if (mvals == null || (double.IsNaN(mvals.MinM) || double.IsNaN(mvals.MaxM)))
            {
                MinM = double.MaxValue;
                MaxM = double.MinValue;
            }
        }
예제 #7
0
        /// <summary>
        /// Tests if the specified extent is contained by the this.
        /// </summary>
        /// <param name="ext">The extent to test.</param>
        /// <returns>True, if the extent is contained by this.</returns>
        public override bool Contains(IExtent ext)
        {
            IExtentM mExt = ext as IExtentM;

            if (mExt != null && ext.HasM && HasM)
            {
                if (mExt.MaxM < MinM || mExt.MinM > MaxM)
                {
                    return(false);
                }
            }

            return(base.Contains(ext));
        }
예제 #8
0
        /// <summary>
        /// Tests if this envelope is contained by the specified envelope.  If either party doesn't have
        /// M constraints, they will not be used for this test.
        /// </summary>
        /// <param name="ext">implementation of IExtent to compare to.</param>
        /// <returns></returns>
        public override bool Within(IExtent ext)
        {
            IExtentM mExt = ext as IExtentM;

            if (mExt != null && ext.HasM && HasM)
            {
                if (mExt.MaxM < MaxM)
                {
                    return(false);
                }
                if (mExt.MinM > MinM)
                {
                    return(false);
                }
            }
            return(base.Within(ext));
        }
예제 #9
0
        /// <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 X Y intersect case.</param>
        /// <returns>Boolean, true if they overlap anywhere, or even touch.</returns>
        public override bool Intersects(IExtent ext)
        {
            IExtentM mExt = ext as IExtentM;

            if (mExt != null && ext.HasM && HasM)
            {
                if (mExt.MaxM < MinM)
                {
                    return(false);
                }
                if (mExt.MinM > MaxM)
                {
                    return(false);
                }
            }
            return(base.Intersects(ext));
        }
예제 #10
0
        /// <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 XY case.
        /// </summary>
        /// <param name="ext">The extent to expand to include.</param>
        public override void ExpandToInclude(IExtent ext)
        {
            IExtentM mExt = ext as IExtentM;

            if (mExt != null && ext.HasM && HasM)
            {
                if (mExt.MinM < MinM)
                {
                    MinM = mExt.MinM;
                }
                if (mExt.MaxM > MaxM)
                {
                    MaxM = mExt.MaxM;
                }
            }
            base.ExpandToInclude(ext);
        }
예제 #11
0
        /// <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;
        }
예제 #12
0
        /// <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;
        }
예제 #13
0
        // 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();
        }
예제 #14
0
        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();
        }
예제 #15
0
        // 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();
        }