GIS矢量切片算法(转载)


转自: https://www.giserdqy.com/database/postgresql/25838/


对于大范围矢量数据,由于类型众多范围广泛往往数据量极大,加载渲染会造成平台卡顿。因此对矢量数据进行四叉树索引切片可以高效加载当前区域矢量,提高效率。

image

常见的矢量数据为shapefile,可以通过GDAL读取shp范围进行四叉树划分,构建某一层级瓦块。

以下为C#调用GDAL进行矢量四叉树切片算法:

struct TileStructure
{
    public int level;
    public int x;
    public int y;
    public OSGeo.OGR.Geometry extentPolygon;
    public string path;
    public OSGeo.OGR.DataSource ds;
    public OSGeo.OGR.Layer layer;
 
}


public class VectorTileTool
{
    List<TileStructure> tiles;
    public VectorTileTool()
    {
    }
    public bool SeprateShpLayer(string sourcePath, string resultFolder, int level)
    {
        OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "");
        OSGeo.OGR.Ogr.RegisterAll();
        OSGeo.OGR.Driver dr = OSGeo.OGR.Ogr.GetDriverByName("ESRI shapefile");
        if (dr == null)
        {
            return false;
        }
        OSGeo.OGR.DataSource ds = dr.Open(sourcePath, 0);
        int layerCount = ds.GetLayerCount();
        OSGeo.OGR.Layer layer = ds.GetLayerByIndex(0);
        //投影信息
        OSGeo.OSR.SpatialReference coord = layer.GetSpatialRef();
        string coordString;
        coord.ExportToWkt(out coordString);
        //地理范围
        Envelope layerEx = new Envelope();
        layer.GetExtent(layerEx, 0);
        ////如果瓦块数据存在,全部删除
        //if (Directory.Exists(resultFolder))
        //{
        //    Directory.Delete(resultFolder,true);
        //}
        //创建文件夹
        Directory.CreateDirectory(resultFolder + "\\JSON\\");
        //针对本项目,划分第16级,根据地理范围求出瓦片
        int y0 = Convert.ToInt32((90 - layerEx.MaxY) * Math.Pow(2, level)/180.0);
        int x0 = Convert.ToInt32((180 + layerEx.MinX) * Math.Pow(2, level)/180.0);
        int y1 = Convert.ToInt32((90 - layerEx.MinY) * Math.Pow(2, level) / 180.0);
        int x1 = Convert.ToInt32((180 + layerEx.MaxX) * Math.Pow(2, level) / 180.0);
        //20160621 ZXQ 创建层行列配置文件
        string filePath = resultFolder + "\\JSON\\" + "\\tile.txt";
        FileStream fs = new FileStream(filePath, FileMode.CreateNew);
        StreamWriter sw = new StreamWriter(fs);
        //写入层行列
        sw.Write(level.ToString());
        sw.Write(",");
        sw.Write(x0.ToString());
        sw.Write(",");
        sw.Write(x1.ToString());
        sw.Write(",");
        sw.Write(y0.ToString());
        sw.Write(",");
        sw.Write(y1.ToString());
        sw.Write(",");
        sw.Write("json");
        sw.Flush();
        sw.Close();
        fs.Close();
        tiles = new List<TileStructure>();
        for (int x =x0;x<=x1;x++)
        {
            for (int y=y0;y<=y1;y++)
            {
                TileStructure tile;
                tile.level = level;
                tile.x = x;
                tile.y = y;
                double lonMin = -180 + 180 / (Math.Pow(2, level)) * x;
                double lonMax = -180 + 180 / (Math.Pow(2, level)) * (x + 1);
                double latMax = 90 - 180 / (Math.Pow(2, level)) * y;
                double latMin = 90 - 180 / (Math.Pow(2, level)) * (y + 1);
                tile.extentPolygon = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbPolygon);
                OSGeo.OGR.Geometry geo = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbLinearRing);
                geo.AddPoint(lonMin,latMax,0);
                geo.AddPoint(lonMax, latMax, 0);
                geo.AddPoint(lonMin, latMin, 0);
                geo.AddPoint(lonMax, latMin, 0);
                tile.extentPolygon.AddGeometryDirectly(geo);
                tile.extentPolygon.CloseRings();
                //创建空shp文件
                string tileFolder = resultFolder + "\\SHP\\" + level.ToString() + "\\" + x.ToString();
                string fileName = y.ToString() + ".shp";
                string tilePath = tileFolder + "\\" + fileName;
                if (!Directory.Exists(tileFolder))
                {
                    Directory.CreateDirectory(tileFolder);
                }
                tile.path = tilePath;
                
                tile.ds = dr.CreateDataSource(tilePath, null);
                tile.layer = tile.ds.CreateLayer("house", coord, OSGeo.OGR.wkbGeometryType.wkbPolygon, null);
                FieldDefn fd = new FieldDefn("HEIGHT", FieldType.OFTReal);
                tile.layer.CreateField(fd,1);
                tiles.Add(tile);
                Console.WriteLine("创建第{0}层第{1}行第{2}列瓦块空shapefile数据", level, x, y);
            }
        }
        OSGeo.OGR.Feature feat;
        //读取shp文件
        while ((feat = layer.GetNextFeature()) != null)
        {
            int id = feat.GetFID();
            OSGeo.OGR.Geometry geometry = feat.GetGeometryRef();
            OSGeo.OGR.wkbGeometryType goetype = geometry.GetGeometryType();
            if (goetype != wkbGeometryType.wkbPolygon)
            {
                continue;
            }
            geometry.CloseRings();
            //随机楼层3-15层
            Random random = new Random();
            double height = random.Next(3,15)*3;// feat.GetFieldAsDouble("房屋层数") * 3;
            for (int i = 0; i < tiles.Count;i++ )
            {
                TileStructure tile = tiles[i];
                //如果瓦片与要素相交,则将要素放入该瓦片
                if (tile.extentPolygon.Intersect(geometry))
                {
                    OSGeo.OGR.Feature poFeature = new Feature(tile.layer.GetLayerDefn());
                 
                    poFeature.SetField(0, height.ToString());
                    poFeature.SetGeometry(geometry);
                    tile.layer.CreateFeature(poFeature);
                    Console.WriteLine("写入第{0}个要素入shp", id);
                }
            }
        }
        return true;
    }
}


----------------------完-------------------------------

posted @ 2020-08-12 11:35  ParamousGIS  阅读(1382)  评论(0编辑  收藏  举报