jjzjj

在Web前端基于CAD图实现等值线在线分析

vjmap 2023-03-28 原文

意义

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

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

实现原理

等值线的原理

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

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

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

     

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

实现

先上效果图

以下的实现代码已开源至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 < 100; i++) {
            let feature={
                "type" : "Feature",
                "properties" : {
                    "value" : vjmap.randInt(dataMinValue, dataMaxValue) // 在最大值最小值范围内随机生成一个测试数据
                },
                "geometry" : {
                    "type" : "Point",
                    "coordinates" : map.toLngLat(mapBounds.randomPoint())
                }
            };
            dataset.features.push(feature);
        }
​
        let contoursSize = 20; // 等值面分级区间数,这里设置为20,可以自行设置
        const createContour = async (dataset, contoursSize, propField, colors, dataMinValue, dataMaxValue, maxHeight, model) => {
            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 < colors.length; i++) {
                interpolateInput.push(i / (colors.length - 1)); // 插值输入值,这里输入0-1之间的比例
                interpolateOutput.push(colors[i]) // 插值输出值,这里输入0-1之间的比例对应的颜色值
            }
​
            // 启动webworker计算函数
            let createContourWorker = vjmap.WorkerProxy(vjmap.vectorContour);
            let { grid, contour } = await createContourWorker(dataset, propField, contours, {
                model: model || 'exponential',
                sigma2:0,
                alpha:100
            });
​
            // 根据比例插值颜色
            const mapProgressToValues = value => 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 < contour.features.length; i++) {
                let prop = contour.features[i].properties;
                let r = (prop.value - dataMinValue) / (dataMaxValue - dataMinValue);
                prop.color = mapProgressToValues(r); // 插值出颜色值
                prop.height = h * r; // 插值出要拉伸的高度值
            }
            return contour;
        }
​
​
        let maxHeight = map.pixelToHeight(100, map.getZoom()); // 设置最大值要拉伸的高度
        let contour = await createContour(dataset, contoursSize, "value" /*geojson的哪个属性值用于计算*/, colors, dataMinValue, dataMaxValue, maxHeight);
​
(3)绘制原始数据和生成好的等值线

let markers = null;
        const addMarkers = ()=> {
            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 => `<h3>值: ${f.properties.value.toFixed(2)}</h3>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 => `<h3>值: ${f.properties.value.toFixed(2)}</h3>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 => `<h3>值: ${f.properties.value.toFixed(2)}</h3>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

有关在Web前端基于CAD图实现等值线在线分析的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  3. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  6. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  7. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  8. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

  9. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

  10. ruby - 如何配置 Ruby Mechanize 代理以通过 Charles Web 代理工作? - 2

    我正在使用Ruby/Mechanize编写一个“自动填写表格”应用程序。它几乎可以工作。我可以使用精彩CharlesWeb代理以查看服务器和我的Firefox浏览器之间的交换。现在我想使用Charles查看服务器和我的应用程序之间的交换。Charles在端口8888上代理。假设服务器位于https://my.host.com。.一件不起作用的事情是:@agent||=Mechanize.newdo|agent|agent.set_proxy("my.host.com",8888)end这会导致Net::HTTP::Persistent::Error:...lib/net/http/pe

随机推荐