📄 geometryfromwkb.cs
字号:
// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// SOURCECODE IS MODIFIED FROM ANOTHER WORK AND IS ORIGINALLY BASED ON GeoTools.NET:
/*
* Copyright (C) 2002 Urban Science Applications, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
using System;
using System.IO;
using System.Collections;
using System.Diagnostics;
using SharpMap.Geometries;
namespace SharpMap.Converters.WellKnownBinary
{
/// <summary>
/// Converts Well-known Binary representations to a <see cref="SharpMap.Geometries.Geometry"/> instance.
/// </summary>
/// <remarks>
/// <para>The Well-known Binary Representation for <see cref="SharpMap.Geometries.Geometry"/> (WKBGeometry) provides a portable
/// representation of a <see cref="SharpMap.Geometries.Geometry"/> value as a contiguous stream of bytes. It permits <see cref="SharpMap.Geometries.Geometry"/>
/// values to be exchanged between an ODBC client and an SQL database in binary form.</para>
/// <para>The Well-known Binary Representation for <see cref="SharpMap.Geometries.Geometry"/> is obtained by serializing a <see cref="SharpMap.Geometries.Geometry"/>
/// instance as a sequence of numeric types drawn from the set {Unsigned Integer, Double} and
/// then serializing each numeric type as a sequence of bytes using one of two well defined,
/// standard, binary representations for numeric types (NDR, XDR). The specific binary encoding
/// (NDR or XDR) used for a geometry byte stream is described by a one byte tag that precedes
/// the serialized bytes. The only difference between the two encodings of geometry is one of
/// byte order, the XDR encoding is Big Endian, the NDR encoding is Little Endian.</para>
/// </remarks>
public class GeometryFromWKB
{
/// <summary>
/// Creates a <see cref="SharpMap.Geometries.Geometry"/> from the supplied byte[] containing the Well-known Binary representation.
/// </summary>
/// <param name="bytes">byte[] containing the Well-known Binary representation.</param>
/// <returns>A <see cref="SharpMap.Geometries.Geometry"/> bases on the supplied Well-known Binary representation.</returns>
public static Geometry Parse(byte[] bytes)
{
// Create a memory stream using the suppiled byte array.
using (MemoryStream ms = new MemoryStream(bytes))
{
// Create a new binary reader using the newly created memorystream.
using (BinaryReader reader = new BinaryReader(ms))
{
// Call the main create function.
return Parse(reader);
}
}
}
/// <summary>
/// Creates a <see cref="SharpMap.Geometries.Geometry"/> based on the Well-known binary representation.
/// </summary>
/// <param name="reader">A <see cref="System.IO.BinaryReader">BinaryReader</see> used to read the Well-known binary representation.</param>
/// <returns>A <see cref="SharpMap.Geometries.Geometry"/> based on the Well-known binary representation.</returns>
public static Geometry Parse(BinaryReader reader)
{
// Get the first byte in the array. This specifies if the WKB is in
// XDR (big-endian) format of NDR (little-endian) format.
byte byteOrder = reader.ReadByte();
if (!Enum.IsDefined(typeof(WkbByteOrder), byteOrder))
{
throw new ArgumentException("Byte order not recognized");
}
// Get the type of this geometry.
uint type = (uint)ReadUInt32(reader, (WkbByteOrder)byteOrder);
if (!Enum.IsDefined(typeof(WKBGeometryType), type))
throw new ArgumentException("Geometry type not recognized");
switch((WKBGeometryType)type)
{
case WKBGeometryType.wkbPoint:
return CreateWKBPoint(reader, (WkbByteOrder)byteOrder);
case WKBGeometryType.wkbLineString:
return CreateWKBLineString(reader, (WkbByteOrder)byteOrder);
case WKBGeometryType.wkbPolygon:
return CreateWKBPolygon(reader, (WkbByteOrder)byteOrder);
case WKBGeometryType.wkbMultiPoint:
return CreateWKBMultiPoint(reader, (WkbByteOrder)byteOrder);
case WKBGeometryType.wkbMultiLineString:
return CreateWKBMultiLineString(reader, (WkbByteOrder)byteOrder);
case WKBGeometryType.wkbMultiPolygon:
return CreateWKBMultiPolygon(reader, (WkbByteOrder)byteOrder);
case WKBGeometryType.wkbGeometryCollection:
return CreateWKBGeometryCollection(reader, (WkbByteOrder)byteOrder);
default:
throw new NotSupportedException("Geometry type '" + type.ToString() + "' not supported");
}
}
private static Point CreateWKBPoint(BinaryReader reader, WkbByteOrder byteOrder)
{
// Create and return the point.
return new Point(ReadDouble(reader, byteOrder), ReadDouble(reader, byteOrder));
}
private static Point[] ReadCoordinates(BinaryReader reader, WkbByteOrder byteOrder)
{
// Get the number of points in this linestring.
int numPoints = (int)ReadUInt32(reader, byteOrder);
// Create a new array of coordinates.
Point[] coords = new Point[numPoints];
// Loop on the number of points in the ring.
for (int i = 0; i < numPoints; i++)
{
// Add the coordinate.
coords[i] = new Point(ReadDouble(reader, byteOrder), ReadDouble(reader, byteOrder));
}
return coords;
}
private static LineString CreateWKBLineString(BinaryReader reader, WkbByteOrder byteOrder)
{
SharpMap.Geometries.LineString l = new SharpMap.Geometries.LineString();
l.Vertices.AddRange(ReadCoordinates(reader, byteOrder));
return l;
}
private static LinearRing CreateWKBLinearRing(BinaryReader reader, WkbByteOrder byteOrder)
{
SharpMap.Geometries.LinearRing l = new SharpMap.Geometries.LinearRing();
l.Vertices.AddRange(ReadCoordinates(reader, byteOrder));
//if polygon isn't closed, add the first point to the end (this shouldn't occur for correct WKB data)
if (l.Vertices[0].X != l.Vertices[l.Vertices.Count - 1].X || l.Vertices[0].Y != l.Vertices[l.Vertices.Count - 1].Y)
l.Vertices.Add(new Point(l.Vertices[0].X, l.Vertices[0].Y));
return l;
}
private static Polygon CreateWKBPolygon(BinaryReader reader, WkbByteOrder byteOrder)
{
// Get the Number of rings in this Polygon.
int numRings = (int)ReadUInt32(reader, byteOrder);
Debug.Assert(numRings >= 1, "Number of rings in polygon must be 1 or more.");
Polygon shell = new Polygon(CreateWKBLinearRing(reader, byteOrder));
// Create a new array of linearrings for the interior rings.
for (int i = 0; i < (numRings - 1); i++)
shell.InteriorRings.Add(CreateWKBLinearRing(reader, byteOrder));
// Create and return the Poylgon.
return shell;
}
private static MultiPoint CreateWKBMultiPoint(BinaryReader reader, WkbByteOrder byteOrder)
{
// Get the number of points in this multipoint.
int numPoints = (int)ReadUInt32(reader, byteOrder);
// Create a new array for the points.
MultiPoint points = new MultiPoint();
// Loop on the number of points.
for (int i = 0; i < numPoints; i++)
{
// Read point header
reader.ReadByte();
ReadUInt32(reader, byteOrder);
// TODO: Validate type
// Create the next point and add it to the point array.
points.Points.Add(CreateWKBPoint(reader, byteOrder));
}
return points;
}
private static MultiLineString CreateWKBMultiLineString(BinaryReader reader, WkbByteOrder byteOrder)
{
// Get the number of linestrings in this multilinestring.
int numLineStrings = (int)ReadUInt32(reader, byteOrder);
// Create a new array for the linestrings .
MultiLineString mline = new MultiLineString();
// Loop on the number of linestrings.
for (int i = 0; i < numLineStrings; i++)
{
// Read linestring header
reader.ReadByte();
ReadUInt32(reader, byteOrder);
// Create the next linestring and add it to the array.
mline.LineStrings.Add(CreateWKBLineString(reader, byteOrder));
}
// Create and return the MultiLineString.
return mline;
}
private static MultiPolygon CreateWKBMultiPolygon(BinaryReader reader, WkbByteOrder byteOrder)
{
// Get the number of Polygons.
int numPolygons = (int)ReadUInt32(reader, byteOrder);
// Create a new array for the Polygons.
MultiPolygon polygons = new MultiPolygon();
// Loop on the number of polygons.
for (int i = 0; i < numPolygons; i++)
{
// read polygon header
reader.ReadByte();
ReadUInt32(reader, byteOrder);
// TODO: Validate type
// Create the next polygon and add it to the array.
polygons.Polygons.Add(CreateWKBPolygon(reader, byteOrder));
}
//Create and return the MultiPolygon.
return polygons;
}
private static Geometry CreateWKBGeometryCollection(BinaryReader reader, WkbByteOrder byteOrder)
{
// The next byte in the array tells the number of geometries in this collection.
int numGeometries = (int)ReadUInt32(reader, byteOrder);
// Create a new array for the geometries.
GeometryCollection geometries = new GeometryCollection();
// Loop on the number of geometries.
for (int i = 0; i < numGeometries; i++)
{
// Call the main create function with the next geometry.
geometries.Collection.Add(Parse(reader));
}
// Create and return the next geometry.
return geometries;
}
//NOT USED
//private static int ReadInt32(BinaryReader reader, WKBByteOrder byteOrder)
//{
// if (byteOrder == WKBByteOrder.Xdr)
// {
// byte[] bytes = BitConverter.GetBytes(reader.ReadInt32());
// Array.Reverse(bytes);
// return BitConverter.ToInt32(bytes, 0);
// }
// else
// return reader.ReadInt32();
//}
private static uint ReadUInt32(BinaryReader reader, WkbByteOrder byteOrder)
{
if (byteOrder == WkbByteOrder.Xdr)
{
byte[] bytes = BitConverter.GetBytes(reader.ReadUInt32());
Array.Reverse(bytes);
return BitConverter.ToUInt32(bytes, 0);
}
else
return reader.ReadUInt32();
}
private static double ReadDouble(BinaryReader reader, WkbByteOrder byteOrder)
{
if (byteOrder == WkbByteOrder.Xdr)
{
byte[] bytes = BitConverter.GetBytes(reader.ReadDouble());
Array.Reverse(bytes);
return BitConverter.ToDouble(bytes, 0);
}
else
return reader.ReadDouble();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -