ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用Shapefile-js读取shp文件并使用WebGL绘制

2022-07-17 00:33:01  阅读:172  来源: 互联网

标签:shp ol const Shapefile WebGL new gl 绘制


1. 引言

坐标数据是空间数据文件的核心,空间数据的数据量往往是很大的。数据可视化是GIS的一个核心应用,绘制海量的坐标数据始终是一个考验设备性能的难题,使用GPU进行绘制可有效减少CPU的负载,提升绘制时的速度

shapefile是空间数据文件常用的格式,Shapefile-js提供了编写简单的JavaScript程序以读取ESRI Shapefile 以及关联的属性文件的功能,它可以在网页端使用,也可在Node.js环境下使用

Shapefile-js的GitHub地址:calvinmetcalf/shapefile-js: Convert a Shapefile to GeoJSON. Not many caveats. (github.com)

本文基于JavaScript语言,使用Shapefile-js库来读取shp文件,并使用WebGL绘制空间数据

2. 数据准备

数据为2015年中国省级行政边界数据(province),来源为:中国科学院资源环境科学与数据中心 (resdc.cn)

下图为数据的主要信息:

image-20220716235607672

3. shp解析

原始的shp文件包含多个文件:

  • shp文件
  • dbf文件
  • prj文件
  • ......

方便起见,笔者把它们打包为一个zip文件,文件名为province.zip,当然,这一步非必须

根据GitHub的示例,很简单就可以解析shp为json:

<script src='https://unpkg.com/shpjs@latest/dist/shp.js'> </script>
<script>
    shp('http://127.0.0.1:5500/province/province.zip').then(function (data) {
        console.log(data)
    }
</script>

进行绘制需要读取shp文件的四至范围和每个Geometry的坐标数据,这里笔者使用OpenLayers进行加载GeoJSON

不妨使用OpenLayers绘制一下地图,读取四至范围:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- openlayers cdn -->
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
    <link rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css">
</head>

<body>
    <div id="map" style="height: 800px;"></div>

    <script src='https://unpkg.com/shpjs@latest/dist/shp.js'> </script>
    <script>
        shp('http://127.0.0.1:5500/province/province.zip').then(function (data) {
            console.log(data)
            const map = new ol.Map({
                target: 'map',
                layers: [
                    new ol.layer.Tile({
                        source: new ol.source.OSM()
                    }),
                    new ol.layer.Vector({
                        source: new ol.source.Vector({
                            features: new ol.format.GeoJSON().readFeatures(data, {
                                featureProjection: 'EPSG:3857'
                            })
                        }),
                        style: new ol.style.Style({
                            stroke: new ol.style.Stroke({
                                color: '#f00',
                                width: 2
                            })
                        })
                    }),

                ],
                view: new ol.View({
                    center: ol.proj.fromLonLat([104.114129, 37.550339]),
                    zoom: 3
                })
            });
            console.log(map.getAllLayers()[1].getSource())
        });

    </script>
</body>

</html>

结果图如下:

image-20220717001353535

4. WebGL绘制

WebGL详细的绘制流程可以参考:基于JavaScript的OpenGL 01 之Hello Triangle - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

使用OpenGL绘制shp文件可以参考:使用Shapefile C Library读取shp文件并使用OpenGL绘制 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

本文所使用的方法是每个Geometry绑定一个VAO和VBO,然后进行绘制

完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src='https://unpkg.com/shpjs@latest/dist/shp.js'> </script>
    <!-- openlayers cdn -->
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
    <link rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css">

    <style>
        html,
        body,
        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <canvas></canvas>
    <script>
        var canvas = document.querySelector('canvas');
        canvas.width = canvas.clientWidth;
        canvas.height = canvas.clientHeight;
        var gl = canvas.getContext('webgl');
        if (!gl) {
            console.log('WebGL not supported, falling back to experimental-webgl');
        }
        gl.clearColor(0.2, 0.3, 0.3, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);


        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, `
        attribute vec3 aPos;

            void main()
            {
                gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
            }
        `);
        gl.compileShader(vertexShader);
        if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
            alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(vertexShader));
            gl.deleteShader(vertexShader);

        }

        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, `
            #version 100
            void main()
            {
                gl_FragColor  = vec4(1.0, 0.5, 0.2, 1.0);
            }
        `);
        gl.compileShader(fragmentShader);
        if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
            alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(fragmentShader));
            gl.deleteShader(fragmentShader);

        }
        const shaderProgram = gl.createProgram();
        gl.attachShader(shaderProgram, vertexShader);
        gl.attachShader(shaderProgram, fragmentShader);
        gl.linkProgram(shaderProgram);
        if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
            alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
        }

        gl.useProgram(shaderProgram);


        shp('http://127.0.0.1:5500/province/province.zip').then(function (data) {
            console.log(data)
            var features = new ol.format.GeoJSON().readFeatures(data, {
                featureProjection: 'EPSG:3857'
            })
            var source = new ol.source.Vector({
                features: features
            })
            console.log(source)
            var minx, miny, maxx, maxy;
            [minx, miny, maxx, maxy] = source.getExtent();
            console.log(minx, miny, maxx, maxy)
            for (let i = 0; i < features.length; i++) {
                const feature = features[i];
                const geometry = feature.getGeometry();
                const coordinate = geometry.getCoordinates()[0];
                let lineString = []
                for (let j = 0; j < coordinate.length; j++) {
                    const point = coordinate[j];
                    let x = (point[0] - minx) / (maxx - minx) * 2 - 1;
                    let y = (point[1] - miny) / (maxy - miny) * 2 - 1;
                    lineString.push(x, y, 0.0);
                }
                const lineStringBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, lineStringBuffer);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lineString), gl.STATIC_DRAW);

                gl.vertexAttribPointer(gl.getAttribLocation(shaderProgram, 'aPos'), 3, gl.FLOAT, false, 0, 0);
                gl.enableVertexAttribArray(0)

                gl.drawArrays(gl.LINE_STRIP, 0, lineString.length / 3);
            }
        })
    </script>
</body>

</html>

绘制结果图如下:

image-20220716234850069

5. 参考资料

[1]calvinmetcalf/shapefile-js: Convert a Shapefile to GeoJSON. Not many caveats. (github.com)

[2]OpenLayers v6.14.1 API - Index

[3]使用Shapefile C Library读取shp文件并使用OpenGL绘制 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

[4]基于JavaScript的OpenGL 01 之Hello Triangle - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

标签:shp,ol,const,Shapefile,WebGL,new,gl,绘制
来源: https://www.cnblogs.com/jiujiubashiyi/p/16485711.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有