起因:最初采用SDE和pgsql11开发,后因数据库升级到pgsql14,sde因和pgsql版本不般配,无法导入要素数据和显示数据,数据库升级又是必然,所以只能另外找解决方案。
参考资料:Spatial Database for Postgres and ArcGis users: how to choose
附加:zigGis, GDAL。传说中的zigGis相当牛,能直接将postgis中的GIS类型显示到ArcGis的控件中,但是版本又比较复杂,也有可能会设计到版本不般配问题,后期我再看看这方面的知识体系。
Pgsql+postgis使用:PostgreSQL+PostGIS的使用(转载) - 无痕客 - 博客园
PostGIS教程一:PostGIS介绍 - 知乎
实现步骤:
在postgis中提供很多函数将wkb转成它的geometry类型,同样也有将geometry转成binary的函数。当然更兴奋的是ArcGis中有针对标准wkb的转换,这样一来,可想而知,这个方案是行的通的。
第一步:从postgreSQL中通过postgis读取GIS数据显示在AxMapControl中
1. C# 连接数据库pg
注意点: 要注意的是因为ArcEngine中对wkb的支持是byte[]之间的转换,所以在进行数据库取数据时用postgis的这个函数将GIS数据转成byte[],这样写 asbinary(the_geom)
2. 将得到的byte[](也就是wkb数据)通过ArcEngine的接口得到IGeometry,如下所示:
IGeometryFactory3 factory = new GeometryEnvironment() as IGeometryFactory3;
factory.CreateGeometryFromWkbVariant(wkb, out geom, out countin);
3. 将 IGeometry 显示在AxMapControl中。
第二步:将上一步从pg中显示出来的GIS数据进行相应的修改后保存回pg中
1. 修改指定的要素后通过 geometry得到wkb
要对修改操作进行保存,就需要将指定的要素中的geometry再次转回wkb然后通过sql语句修改pg中的指定记录即可,思路很简单,问题在于拼接SQL字符串上面,因为arcengine通过geometry得到的仍然是一个byte[],这个东西是没办法拼到sql语句中的。
2. 用到的ArcEngine接口如下:
IGeometryFactory3 factory = new GeometryEnvironment() as IGeometryFactory3;
byte[] geoBytes = factory.CreateWkbVariantFromGeometry(geometry) as byte[];
3. 拼接SQL时要将上面的byte[]数组转码
其实postgis处理存到pg中的是一长串的16进制字符串,相信大家打开数据库能看到,要想拼接好SQL串就得这样来一下:geomfromwkb(decode('" + geoByteStr + "', 'hex'))其中的geoByteStr是byte[]转成16进制的字串
上面两步已走通,是完全可以实现的,这样做的话,数据表我们也能自行定义,操作GIS数据,属性等,更灵活。
资料
读取pgsql数据库
namespace WHUGIS.Classes
{
class DAO
{
private static string connectionString = "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=GIS_engine;";
public DAO()
{
}
public static Byte[] executeRouteQuery(string sqlstr)
{
NpgsqlConnection sqlConn = new NpgsqlConnection(connectionString);
try
{
sqlConn.Open();
NpgsqlCommand objCommand = new NpgsqlCommand(sqlstr, sqlConn);
Byte[] routeWKB = (byte[])objCommand.ExecuteScalar();
return routeWKB;
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
return null;
}
finally
{
sqlConn.Close();
}
}
}
}
ArcgisEngine Igeometry和WKB转换
using System;
using System.Collections.Generic;
using System.Text;
using GisSharpBlog.NetTopologySuite.IO;
using ESRI.ArcGIS.Geometry;
namespace Utils
{
/// <summary>
/// This class is used to convert a GeoAPI Geometry to ESRI and vice-versa.
/// It can also convert a ESRI Geometry to WKB/WKT and vice-versa.
/// </summary>
public static class Converters
{
public static byte[] ConvertGeometryToWKB(IGeometry geometry)
{
IWkb wkb = geometry as IWkb;
ITopologicalOperator oper = geometry as ITopologicalOperator;
oper.Simplify();
IGeometryFactory3 factory = new GeometryEnvironment() as IGeometryFactory3;
byte[] b = factory.CreateWkbVariantFromGeometry(geometry) as byte[];
return b;
}
public static byte[] ConvertWKTToWKB(string wkt)
{
WKBWriter writer = new WKBWriter();
WKTReader reader = new WKTReader();
return writer.Write(reader.Read(wkt));
}
public static string ConvertWKBToWKT(byte[] wkb)
{
WKTWriter writer = new WKTWriter();
WKBReader reader = new WKBReader();
return writer.Write(reader.Read(wkb));
}
public static string ConvertGeometryToWKT(IGeometry geometry)
{
byte[] b = ConvertGeometryToWKB(geometry);
WKBReader reader = new WKBReader();
GeoAPI.Geometries.IGeometry g = reader.Read(b);
WKTWriter writer = new WKTWriter();
return writer.Write(g);
}
public static IGeometry ConvertWKTToGeometry(string wkt)
{
byte[] wkb = ConvertWKTToWKB(wkt);
return ConvertWKBToGeometry(wkb);
}
public static IGeometry ConvertWKBToGeometry(byte[] wkb)
{
IGeometry geom;
int countin = wkb.GetLength(0);
IGeometryFactory3 factory = new GeometryEnvironment() as IGeometryFactory3;
factory.CreateGeometryFromWkbVariant(wkb, out geom, out countin);
return geom;
}
public static IGeometry ConvertGeoAPIToESRI(GeoAPI.Geometries.IGeometry geometry)
{
WKBWriter writer = new WKBWriter();
byte[] bytes = writer.Write(geometry);
return ConvertWKBToGeometry(bytes);
}
public static GeoAPI.Geometries.IGeometry ConvertESRIToGeoAPI(IGeometry geometry)
{
byte[] wkb = ConvertGeometryToWKB(geometry);
WKBReader reader = new WKBReader();
return reader.Read(wkb);
}
}
}