📄 shapefile.cs
字号:
#region Disposers and finalizers
private bool disposed = false;
/// <summary>
/// Disposes the object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
Close();
_Envelope = null;
tree = null;
}
disposed = true;
}
}
/// <summary>
/// Finalizes the object
/// </summary>
~ShapeFile()
{
this.Dispose();
}
#endregion
/// <summary>
/// Reads and parses the header of the .shx index file
/// </summary>
private void ParseHeader()
{
fsShapeIndex = new FileStream(_Filename.Remove(_Filename.Length - 4, 4) + ".shx", FileMode.Open, FileAccess.Read);
brShapeIndex = new BinaryReader(fsShapeIndex, System.Text.Encoding.Unicode);
brShapeIndex.BaseStream.Seek(0, 0);
//Check file header
if (brShapeIndex.ReadInt32() != 170328064) //File Code is actually 9994, but in Little Endian Byte Order this is '170328064'
throw (new ApplicationException("Invalid Shapefile Index (.shx)"));
brShapeIndex.BaseStream.Seek(24, 0); //seek to File Length
int IndexFileSize = SwapByteOrder(brShapeIndex.ReadInt32()); //Read filelength as big-endian. The length is based on 16bit words
_FeatureCount = (2 * IndexFileSize - 100) / 8; //Calculate FeatureCount. Each feature takes up 8 bytes. The header is 100 bytes
brShapeIndex.BaseStream.Seek(32, 0); //seek to ShapeType
_ShapeType = (ShapeType)brShapeIndex.ReadInt32();
//Read the spatial bounding box of the contents
brShapeIndex.BaseStream.Seek(36, 0); //seek to box
_Envelope = new SharpMap.Geometries.BoundingBox(brShapeIndex.ReadDouble(), brShapeIndex.ReadDouble(), brShapeIndex.ReadDouble(), brShapeIndex.ReadDouble());
brShapeIndex.Close();
fsShapeIndex.Close();
}
/// <summary>
/// Reads and parses the projection if a projection file exists
/// </summary>
private void ParseProjection()
{
string projfile = Path.GetDirectoryName(Filename) + "\\" + Path.GetFileNameWithoutExtension(Filename) + ".prj";
if (System.IO.File.Exists(projfile))
{
try
{
string wkt = System.IO.File.ReadAllText(projfile);
_CoordinateSystem = (SharpMap.CoordinateSystems.ICoordinateSystem)SharpMap.Converters.WellKnownText.CoordinateSystemWktReader.Parse(wkt);
_CoordsysReadFromFile = true;
}
catch(System.Exception ex) {
System.Diagnostics.Trace.TraceWarning("Coordinate system file '" + projfile + "' found, but could not be parsed. WKT parser returned:" + ex.Message);
throw (ex);
}
}
}
/// <summary>
/// Reads the record offsets from the .shx index file and returns the information in an array
/// </summary>
private int[] ReadIndex()
{
int[] OffsetOfRecord = new int[ _FeatureCount ];
brShapeIndex.BaseStream.Seek(100, 0); //skip the header
for (int x=0; x < _FeatureCount; ++x )
{
OffsetOfRecord[x] = 2 * SwapByteOrder(brShapeIndex.ReadInt32()); //Read shape data position // ibuffer);
brShapeIndex.BaseStream.Seek(brShapeIndex.BaseStream.Position + 4, 0); //Skip content length
}
return OffsetOfRecord;
}
/// <summary>
/// Gets the file position of the n'th shape
/// </summary>
/// <param name="n">Shape ID</param>
/// <returns></returns>
private int GetShapeIndex(uint n)
{
brShapeIndex.BaseStream.Seek(100+n*8, 0); //seek to the position of the index
return 2 * SwapByteOrder(brShapeIndex.ReadInt32()); //Read shape data position
}
///<summary>
///Swaps the byte order of an int32
///</summary>
/// <param name="i">Integer to swap</param>
/// <returns>Byte Order swapped int32</returns>
private int SwapByteOrder (int i)
{
byte[] buffer = BitConverter.GetBytes(i);
Array.Reverse(buffer, 0, buffer.Length);
return BitConverter.ToInt32(buffer, 0);
}
/// <summary>
/// Loads a spatial index from a file. If it doesn't exist, one is created and saved
/// </summary>
/// <param name="filename"></param>
/// <returns>QuadTree index</returns>
private Utilities.SpatialIndexing.QuadTree CreateSpatialIndexFromFile(string filename)
{
if (System.IO.File.Exists(filename + ".sidx"))
{
try
{
return Utilities.SpatialIndexing.QuadTree.FromFile(filename + ".sidx");
}
catch(Utilities.SpatialIndexing.QuadTree.ObsoleteFileFormatException)
{
System.IO.File.Delete(filename + ".sidx");
return CreateSpatialIndexFromFile(filename);
}
catch (System.Exception ex) { throw ex; }
}
else
{
Utilities.SpatialIndexing.QuadTree tree = CreateSpatialIndex(_Filename);
tree.SaveIndex(filename + ".sidx");
return tree;
}
}
/// <summary>
/// Generates a spatial index for a specified shape file.
/// </summary>
/// <param name="filename"></param>
private Utilities.SpatialIndexing.QuadTree CreateSpatialIndex(string filename)
{
List<Utilities.SpatialIndexing.QuadTree.BoxObjects> objList = new List<Utilities.SpatialIndexing.QuadTree.BoxObjects>();
//Convert all the geometries to boundingboxes
uint i = 0;
foreach (SharpMap.Geometries.BoundingBox box in GetAllFeatureBoundingBoxes())
{
if (!double.IsNaN(box.Left) && !double.IsNaN(box.Right) && !double.IsNaN(box.Bottom) && !double.IsNaN(box.Top))
{
Utilities.SpatialIndexing.QuadTree.BoxObjects g = new Utilities.SpatialIndexing.QuadTree.BoxObjects();
g.box = box;
g.ID = i;
objList.Add(g);
i++;
}
}
Utilities.SpatialIndexing.Heuristic heur;
heur.maxdepth = (int)Math.Ceiling(Math.Log(this.GetFeatureCount(), 2));
heur.minerror = 10;
heur.tartricnt = 5;
heur.mintricnt = 2;
return new Utilities.SpatialIndexing.QuadTree(objList, 0, heur);
}
private void LoadSpatialIndex() { LoadSpatialIndex(false,false); }
private void LoadSpatialIndex(bool LoadFromFile) { LoadSpatialIndex(false, LoadFromFile); }
private void LoadSpatialIndex(bool ForceRebuild, bool LoadFromFile)
{
//Only load the tree if we haven't already loaded it, or if we want to force a rebuild
if (tree == null || ForceRebuild)
{
// Is this a web application? If so lets store the index in the cache so we don't
// need to rebuild it for each request
if (System.Web.HttpContext.Current != null)
{
//Check if the tree exists in the cache
if (System.Web.HttpContext.Current.Cache[_Filename] != null)
tree = (Utilities.SpatialIndexing.QuadTree)System.Web.HttpContext.Current.Cache[_Filename];
else
{
if (!LoadFromFile)
tree = CreateSpatialIndex(_Filename);
else
tree = CreateSpatialIndexFromFile(_Filename);
//Store the tree in the web cache
//TODO: Remove this when connection pooling is implemented
System.Web.HttpContext.Current.Cache.Insert(_Filename, tree, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1));
}
}
else
if (!LoadFromFile)
tree = CreateSpatialIndex(_Filename);
else
tree = CreateSpatialIndexFromFile(_Filename);
}
}
/// <summary>
/// Forces a rebuild of the spatial index. If the instance of the ShapeFile provider
/// uses a file-based index the file is rewritten to disk.
/// </summary>
public void RebuildSpatialIndex()
{
if (this._FileBasedIndex)
{
if (System.IO.File.Exists(_Filename + ".sidx"))
System.IO.File.Delete(_Filename + ".sidx");
tree = CreateSpatialIndexFromFile(_Filename);
}
else
tree = CreateSpatialIndex(_Filename);
if (System.Web.HttpContext.Current != null)
//TODO: Remove this when connection pooling is implemented:
System.Web.HttpContext.Current.Cache.Insert(_Filename, tree, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1));
}
/// <summary>
/// Reads all boundingboxes of features in the shapefile. This is used for spatial indexing.
/// </summary>
/// <returns></returns>
private List<SharpMap.Geometries.BoundingBox> GetAllFeatureBoundingBoxes()
{
int[] offsetOfRecord = ReadIndex(); //Read the whole .idx file
List<SharpMap.Geometries.BoundingBox> boxes = new List<SharpMap.Geometries.BoundingBox>();
if (_ShapeType == ShapeType.Point)
{
for (int a = 0; a < _FeatureCount; ++a)
{
fsShapeFile.Seek(offsetOfRecord[a]+8, 0); //skip record number and content length
if ((ShapeType)brShapeFile.ReadInt32() != ShapeType.Null)
{
double x = brShapeFile.ReadDouble();
double y = brShapeFile.ReadDouble();
boxes.Add(new SharpMap.Geometries.BoundingBox(x, y, x, y));
}
}
}
else
{
for (int a = 0; a < _FeatureCount; ++a)
{
fsShapeFile.Seek(offsetOfRecord[a] + 8, 0); //skip record number and content length
if ((ShapeType)brShapeFile.ReadInt32() != ShapeType.Null)
boxes.Add(new SharpMap.Geometries.BoundingBox(brShapeFile.ReadDouble(), brShapeFile.ReadDouble(), brShapeFile.ReadDouble(), brShapeFile.ReadDouble()));
}
}
return boxes;
}
#region IProvider Members
/// <summary>
/// Returns geometries whose bounding box intersects 'bbox'
/// </summary>
/// <remarks>
/// <para>Please note that this method doesn't guarantee that the geometries returned actually intersect 'bbox', but only
/// that their boundingbox intersects 'bbox'.</para>
/// <para>This method is much faster than the QueryFeatures method, because intersection tests
/// are performed on objects simplifed by their boundingbox, and using the Spatial Index.</para>
/// </remarks>
/// <param name="bbox"></param>
/// <returns></returns>
public Collection<SharpMap.Geometries.Geometry> GetGeometriesInView(SharpMap.Geometries.BoundingBox bbox)
{
//Use the spatial index to get a list of features whose boundingbox intersects bbox
Collection<uint> objectlist = GetObjectIDsInView(bbox);
if (objectlist.Count == 0) //no features found. Return an empty set
return new Collection<SharpMap.Geometries.Geometry>();
//Collection<SharpMap.Geometries.Geometry> geometries = new Collection<SharpMap.Geometries.Geometry>(objectlist.Count);
Collection<SharpMap.Geometries.Geometry> geometries = new Collection<SharpMap.Geometries.Geometry>();
for (int i = 0; i < objectlist.Count; i++)
{
SharpMap.Geometries.Geometry g = GetGeometryByID(objectlist[i]);
if(g!=null)
geometries.Add(g);
}
return geometries;
}
/// <summary>
/// Returns all objects whose boundingbox intersects bbox.
/// </summary>
/// <remarks>
/// <para>
/// Please note that this method doesn't guarantee that the geometries returned actually intersect 'bbox', but only
/// that their boundingbox intersects 'bbox'.
/// </para>
/// </remarks>
/// <param name="bbox"></param>
/// <param name="ds"></param>
/// <returns></returns>
public void ExecuteIntersectionQuery(SharpMap.Geometries.BoundingBox bbox, SharpMap.Data.FeatureDataSet ds)
{
//Use the spatial index to get a list of features whose boundingbox intersects bbox
Collection<uint> objectlist = GetObjectIDsInView(bbox);
SharpMap.Data.FeatureDataTable dt = dbaseFile.NewTable;
for (int i = 0; i < objectlist.Count; i++)
{
SharpMap.Data.FeatureDataRow fdr = dbaseFile.GetFeature(objectlist[i], dt);
fdr.Geometry = ReadGeometry(objectlist[i]);
if (fdr.Geometry != null)
if (fdr.Geometry.GetBoundingBox().Intersects(bbox))
if (FilterDelegate == null || FilterDelegate(fdr))
dt.AddRow(fdr);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -