意义

等值线是GIS制图中常见的功能。在实际中经常需要基于CAD图纸对数据进行等值线分析。等值线的类型主要有:等高线、等深线、等温线(等气温线、等水温线)、等压线(水平面等压线、垂直面等压线)、等降水量线、等太阳辐射量线、等盐度线、等PH值线、等太阳高度线、等潜水位线、等承压水位线等。

通过分析等值线,我们可以判读等高线来判断地形的坡度的陡与缓,确定山脉的走向;通过判读等深线来判断海洋地形的种类如大陆架、海沟、海盆、海岭、海底火山等;通过判读大气等压线来判断气压中心的名称:如气旋、反气旋、高压脊、低压糟、轮廓;判断不同部位的天气特点,风向与风力大小;通过判读大气等温线来判断所在地的南北半球、季节与天气;通过判读等降水量线结合具体的地形轮廓判定山地的迎风坡与背风坡等;通过判读人口密度等值线分析某地区人口分布的规律及其影响的自然、历史、社会、经济诸因素。

实现原理

等值线的原理

  • 等值性或同距性原理 在等值线图中,相邻的两条等值线要么等值,要么同距。

  • 低高低和高低高原理 低值凸向高值,凸处的值变低 高值凸向低值,凸处的值变高

  • 疏差小和密差大原理 等值线越稀疏,单位距离的差值越小 等值线越 密集,单位距离的差值越大

用程序绘制等值线的方法一般有:

  • Delaunay三角剖分(Delaunay Triangulation)相关知识 http://www.cnblogs.com/soroman/archive/2007/05/17/750430.html

  • 矩形网格线法 https://www.baidu.com/link?url=qgnhaBc745ZNHND9Ulu4iFrSyRx2gcpZ2LkCZcx9oFhNp3NQFvf3KnbnFxp4b_NBmb5Z0_sPeqQ2Pqb3gnYMM_&wd=&eqid=d7d7fcd7000643850000000362fcec43

  • 克里金法(Kriging) https://baike.baidu.com/item/%E5%85%8B%E9%87%8C%E9%87%91%E6%B3%95/5129539?fr=aladdin

  • 在著名的开源GIS算法库Turfjs http://turfjs.org/ 中也有等值线的算法 isolines

实现

先上效果图

以下的实现代码已开源至github。 地址: https://github.com/vjmap/vjmap-playground/blob/main/src/11geo_%E5%87%A0%E4%BD%95%E8%AE%A1%E7%AE%97/geoVectorContour.js

实现步骤:

(1) Web端在线打开CAD图

如何在Web网页端展示CAD图形(唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud),这个在前面的博文中已讲过,这里不再重复,有需要的朋友可下载工程源代码研究下。

(2) 利用数据生成等值线

为了防止生成等值线的过程造成页面卡顿,这里把算法放到了webworker中来进行计算

//生成测试数据        let dataMinValue = 10; // 数据最小值        let dataMaxValue = 500; // 数据最大值        let dataset = {            "type" : "FeatureCollection",            "features" : []        };​        // 区间颜色值        let colors = ["#006837", "#1a9850", "#66bd63", "#a6d96a", "#d9ef8b", "#ffffbf","#fee08b",            "#fdae61", "#f46d43", "#d73027", "#a50026"];​        for (let i = 0; i  {            let contours = [];            for(let i = 0; i < contoursSize; i++) {                contours.push(dataMinValue + (dataMaxValue - dataMinValue) * i /  (contoursSize - 1));            }​            let interpolateInput = [], interpolateOutput = [];            for(let i = 0; i  vjmap.interpolate(                interpolateInput,                interpolateOutput,                { ease: vjmap.linear }            )(value)​            // 把原数据的颜色也设置下,绘制marker需要            dataset.features.forEach(f => f.properties.color = mapProgressToValues((f.properties.value - dataMinValue) / (dataMaxValue - dataMinValue)))​            let h = maxHeight; // 设置最大值要拉伸的高度            for(let i = 0; i  {            if (markers) return;            markers = dataset.features.map(f => {                // 再随机生成不同样式的                let _marker = new vjmap.DiffusedApertureMarker({                    lngLat: f.geometry.coordinates,                    text: f.properties.value.toFixed(0)                }, {                    // 可以给不同的属性,如宽度,颜色,字体                    width: 10,                    colors: [f.properties.color, vjmap.randomColor()],                    textFontSize: 14,                    textColor: f.properties.color                }).createMarker();                _marker.addTo(map)                return _marker            })        }        const removeMarkers = ()=> {            if (!markers) return;            for(let i = markers.length - 1; i >= 0; i--) {                markers[i].remove();            }            markers = null;        }​        let polyline = null;        const addPolyline = ()=> {            if (polyline) return;            polyline = new vjmap.Polyline({                data: contour,                lineColor: ['case', ['to-boolean', ['feature-state', 'hover']], '#00ffff', ['get', 'color']],                isHoverPointer: true,                isHoverFeatureState: true            });            polyline.addTo(map);            polyline.clickPopup(f => `

值: ${f.properties.value.toFixed(2)}

Color: ${f.properties.color}`, { anchor: 'bottom' }); } const removePolyline = ()=> { if (!polyline) return; polyline.remove(); polyline = null; }

  

(4)生成等值面

let polygon = null;        const addPolygon = ()=> {            if (polygon) return;            polygon = new vjmap.Polygon({                data: contour,                fillColor: ['case', ['to-boolean', ['feature-state', 'hover']], '#00ffff', ['get', 'color']],                fillOpacity: 0.9,                isHoverPointer: true,                isHoverFeatureState: true            });            polygon.addTo(map);            polygon.clickPopup(f => `

值: ${f.properties.value.toFixed(2)}

Color: ${f.properties.color}`, { anchor: 'bottom' }); } const removePolygon = ()=> { if (!polygon) return; polygon.remove(); polygon = null; }

  

(4)生成等值面拉伸

let fillExtrusions = null;        const addFillExtrusion = ()=> {            if (fillExtrusions) return;            fillExtrusions = new vjmap.FillExtrusion({                data: contour,                fillExtrusionColor: ['case', ['to-boolean', ['feature-state', 'hover']], '#00ffff', ['get', 'color']],                fillExtrusionOpacity: 0.9,                fillExtrusionHeight: ['get', 'height'],                fillExtrusionBase:0,                isHoverPointer: true,                isHoverFeatureState: true            });            fillExtrusions.addTo(map);            fillExtrusions.clickPopup(f => `

值: ${f.properties.value.toFixed(2)}

Color: ${f.properties.color}`, { anchor: 'bottom' }); } const removeFillExtrusion = ()=> { if (!fillExtrusions) return; fillExtrusions.remove(); fillExtrusions = null; }

  

以上的实现代码已开源至github。 地址: https://github.com/vjmap/vjmap-playground/blob/main/src/11geo_%E5%87%A0%E4%BD%95%E8%AE%A1%E7%AE%97/geoVectorContour.js

在线体验地址为:https://vjmap.com/demo/#/demo/map/geo/geoVectorContour