Turf处理等压线

        Turf是一个用于空间分析的JavaScript库。它包括传统的空间操作、用于创建GeoJSON数据的辅助函数以及数据分类和统计工具。Turf可以作为客户端插件添加到您的网站,也可以使用Node.js在服务器端运行Turf。

        Turf是一个模块化的js类库,所有的模块都是在packages下面,每个模块下面都包含一个index.ts的源码文件,这个源码是使用typescript编写.

       

        对于上面这个实例,本章将通过源码的方式进行解析,首先调用的是turf.pointGrid这个函数,

这个模块中的index.ts文件,代码中定义了pointGrid函数,这个函数接受如下几个参数

// 基于box边界,通过细分的方式插入点
function pointGrid<P = GeoJsonProperties>(bbox: BBox,      // 东南西北作为边界cellSide: number,// 细分时的步长options: {        units?: Units; // 单位mask?: Feature<Polygon | MultiPolygon>; // 多边形掩码,插值点在这个范围内才算properties?: P;    // 属性} = {}
): FeatureCollection<Point, P> {// Default parameters// 默认使用千米if (options.mask && !options.units) options.units = "kilometers";// Containers// 结果var results = [];// 东南西北四个边界(经纬度)var west = bbox[0];var south = bbox[1];var east = bbox[2];var north = bbox[3];// 计算两点之间的球面距离// 一个单元占整个距离的百分比var xFraction = cellSide / distance([west, south], [east, south], options);// 一个单元的角度制下的距离var cellWidth = xFraction * (east - west);// 一个单元占整个距离的百分比var yFraction = cellSide / distance([west, south], [west, north], options);// 一个单元的角度制下的距离var cellHeight = yFraction * (north - south);// 宽度(角度)var bboxWidth = east - west;// 高度(角度)var bboxHeight = north - south;// 列数var columns = Math.floor(bboxWidth / cellWidth);// 行数var rows = Math.floor(bboxHeight / cellHeight);// adjust origin of the grid// 多出来的一部分的中间var deltaX = (bboxWidth - columns * cellWidth) / 2;var deltaY = (bboxHeight - rows * cellHeight) / 2;// 当前xvar currentX = west + deltaX;// 计算插值点while (currentX <= east) {// 当前yvar currentY = south + deltaY;while (currentY <= north) {// 封装要素点var cellPt = point([currentX, currentY], options.properties);if (options.mask) {// 点是否在掩码范围被内,只有在这个范围内才添加if (within(cellPt, options.mask)) results.push(cellPt);} else {// 添加到结果中results.push(cellPt);}currentY += cellHeight;}currentX += cellWidth;}// 封装成要素集合return featureCollection(results);
}

 计算distance的类是turf-distance文件夹下的index.ts

// 计算距离
function distance(from: Coord | Point,to: Coord | Point,options: {units?: Units;} = {}
) {// 获取坐标数组var coordinates1 = getCoord(from);// 获取坐标数组var coordinates2 = getCoord(to);// 计算维度var dLat = degreesToRadians(coordinates2[1] - coordinates1[1]);// 计算精度var dLon = degreesToRadians(coordinates2[0] - coordinates1[0]);// 角度转换为弧度var lat1 = degreesToRadians(coordinates1[1]);var lat2 = degreesToRadians(coordinates2[1]);// 计算两点之间的角度var a =Math.pow(Math.sin(dLat / 2), 2) +Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);// 弧长公式Rθreturn radiansToLength(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)),options.units);
}

  计算等值线的类是turf-isolines文件夹下的index.ts

// 生成等值线
function isolines(pointGrid: FeatureCollection<Point>,// 网格点breaks: number[],options?: {zProperty?: string;commonProperties?: GeoJsonProperties;breaksProperties?: GeoJsonProperties[];}
) {// Optional parametersoptions = options || {};if (!isObject(options)) throw new Error("options is invalid");const zProperty = options.zProperty || "elevation";const commonProperties = options.commonProperties || {};const breaksProperties = options.breaksProperties || [];// Input validationcollectionOf(pointGrid, "Point", "Input must contain Points");if (!breaks) throw new Error("breaks is required");if (!Array.isArray(breaks)) throw new Error("breaks must be an Array");if (!isObject(commonProperties))throw new Error("commonProperties must be an Object");if (!Array.isArray(breaksProperties))throw new Error("breaksProperties must be an Array");// Isoline methods// 等值线方法// 将网格点,按照z值构建一个只包含z值的矩阵const matrix = gridToMatrix(pointGrid, { zProperty: zProperty, flip: true });// 创建等值线const createdIsoLines = createIsoLines(matrix,breaks,zProperty,commonProperties,breaksProperties);// 重新缩放等值线const scaledIsolines = rescaleIsolines(createdIsoLines, matrix, pointGrid);// 封装成要素return featureCollection(scaledIsolines);
}

将所有的点构建一个z值的矩阵

export default function gridToMatrix(grid, options) {// Optional parametersoptions = options || {};if (!isObject(options)) throw new Error("options is invalid");var zProperty = options.zProperty || "elevation";var flip = options.flip;var flags = options.flags;// validationcollectionOf(grid, "Point", "input must contain Points");// 按照经纬度排序var pointsMatrix = sortPointsByLatLng(grid, flip);var matrix = [];// create property matrix from sorted points// looping order matters here// 从排序点创建属性矩阵循环此处的顺序问题for (var r = 0; r < pointsMatrix.length; r++) {var pointRow = pointsMatrix[r];var row = [];for (var c = 0; c < pointRow.length; c++) {var point = pointRow[c];// Check if zProperty existif (point.properties[zProperty]) row.push(point.properties[zProperty]);else row.push(0);// add flagsif (flags === true) point.properties.matrixPosition = [r, c];}matrix.push(row);}return matrix;
}

 

// 创建等值线
function createIsoLines(matrix: number[][],breaks: number[],zProperty: string,commonProperties: GeoJsonProperties,breaksProperties: GeoJsonProperties[]
): Feature<MultiLineString>[] {const results = [];// 遍历中断点for (let i = 1; i < breaks.length; i++) {// 作为阈值const threshold = +breaks[i]; // make sure it's a numberconst properties = { ...commonProperties, ...breaksProperties[i] };properties[zProperty] = threshold;// 应该是按照矩阵中的四个点计算是否可以计算出这个阈值的插值点const isoline = multiLineString(isoContours(matrix, threshold), properties);results.push(isoline);}return results;
}
// 等压线
export default function isoContours(data, threshold, options) {/* process options */options = options ? options : {};var optionKeys = Object.keys(defaultSettings);for (var i = 0; i < optionKeys.length; i++) {var key = optionKeys[i];var val = options[key];val =typeof val !== "undefined" && val !== null ? val : defaultSettings[key];settings[key] = val;}if (settings.verbose)console.log("MarchingSquaresJS-isoContours: computing isocontour for " + threshold);// 计算等压线网格var ret = contourGrid2Paths(computeContourGrid(data, threshold));if (typeof settings.successCallback === "function")settings.successCallback(ret);return ret;
}
/* assume that x1 == 1 &&  x0 == 0 */
// 线性插值
function interpolateX(y, y0, y1) {return (y - y0) / (y1 - y0);
}/* compute the isocontour 4-bit grid */
// 计算等压线4为的网格
function computeContourGrid(data, threshold) {// 行数、列数var rows = data.length - 1;var cols = data[0].length - 1;// var ContourGrid = { rows: rows, cols: cols, cells: [] };// 遍历行数for (var j = 0; j < rows; ++j) {ContourGrid.cells[j] = [];// 遍历列数for (var i = 0; i < cols; ++i) {/* compose the 4-bit corner representation */var cval = 0;//取出相邻的四个点var tl = data[j + 1][i];var tr = data[j + 1][i + 1];var br = data[j][i + 1];var bl = data[j][i];if (isNaN(tl) || isNaN(tr) || isNaN(br) || isNaN(bl)) {continue;}// 检索阈值是否在四个高度内部,还是外部,四个值都高于阈值8421=15,或者四个值都低于阈值在外部0cval |= tl >= threshold ? 8 : 0;cval |= tr >= threshold ? 4 : 0;cval |= br >= threshold ? 2 : 0;cval |= bl >= threshold ? 1 : 0;/* resolve ambiguity for cval == 5 || 10 via averaging */var flipped = false;// 在对角线上if (cval === 5 || cval === 10) {// 计算平均值var average = (tl + tr + br + bl) / 4;// 两个对角线上的中点值偏离比较远,if (cval === 5 && average < threshold) {cval = 10; // 取另外一个对角线来确定flipped = true;} else if (cval === 10 && average < threshold) {cval = 5;flipped = true;}}/* add cell to ContourGrid if it contains edges */// 如果单元格包含边,则将其添加到ContourGrid// 阈值在四个点内部if (cval !== 0 && cval !== 15) {var top, bottom, left, right;top = bottom = left = right = 0.5;/* interpolate edges of cell */if (cval === 1) {  // 一个点在上,其他三个点都在下面// 插值左边left = 1 - interpolateX(threshold, tl, bl);// 插值下边bottom = 1 - interpolateX(threshold, br, bl);} else if (cval === 2) {bottom = interpolateX(threshold, bl, br);right = 1 - interpolateX(threshold, tr, br);} else if (cval === 3) {left = 1 - interpolateX(threshold, tl, bl);right = 1 - interpolateX(threshold, tr, br);} else if (cval === 4) {top = interpolateX(threshold, tl, tr);right = interpolateX(threshold, br, tr);} else if (cval === 5) {top = interpolateX(threshold, tl, tr);right = interpolateX(threshold, br, tr);bottom = 1 - interpolateX(threshold, br, bl);left = 1 - interpolateX(threshold, tl, bl);} else if (cval === 6) {bottom = interpolateX(threshold, bl, br);top = interpolateX(threshold, tl, tr);} else if (cval === 7) {left = 1 - interpolateX(threshold, tl, bl);top = interpolateX(threshold, tl, tr);} else if (cval === 8) {left = interpolateX(threshold, bl, tl);top = 1 - interpolateX(threshold, tr, tl);} else if (cval === 9) {bottom = 1 - interpolateX(threshold, br, bl);top = 1 - interpolateX(threshold, tr, tl);} else if (cval === 10) {top = 1 - interpolateX(threshold, tr, tl);right = 1 - interpolateX(threshold, tr, br);bottom = interpolateX(threshold, bl, br);left = interpolateX(threshold, bl, tl);} else if (cval === 11) {top = 1 - interpolateX(threshold, tr, tl);right = 1 - interpolateX(threshold, tr, br);} else if (cval === 12) {left = interpolateX(threshold, bl, tl);right = interpolateX(threshold, br, tr);} else if (cval === 13) {bottom = 1 - interpolateX(threshold, br, bl);right = interpolateX(threshold, br, tr);} else if (cval === 14) {left = interpolateX(threshold, bl, tl);bottom = interpolateX(threshold, bl, br);} else {console.log("MarchingSquaresJS-isoContours: Illegal cval detected: " + cval);}ContourGrid.cells[j][i] = {cval: cval,   // 代表的是top、right、bottom、left中哪两个值有效果flipped: flipped,top: top,right: right,bottom: bottom,left: left,};}}}return ContourGrid;
}
// 计算等值点组成的路径
function contourGrid2Paths(grid) {var paths = [];var path_idx = 0;var epsilon = 1e-7;grid.cells.forEach(function (g, j) {g.forEach(function (gg, i) {if (typeof gg !== "undefined" && !isSaddle(gg) && !isTrivial(gg)) {var p = tracePath(grid.cells, j, i);var merged = false;/* we may try to merge paths at this point */if (p.info === "mergeable") {/*search backwards through the path array to find an entrythat starts with where the current path ends...*/var x = p.path[p.path.length - 1][0],y = p.path[p.path.length - 1][1];for (var k = path_idx - 1; k >= 0; k--) {if (Math.abs(paths[k][0][0] - x) <= epsilon &&Math.abs(paths[k][0][1] - y) <= epsilon) {for (var l = p.path.length - 2; l >= 0; --l) {paths[k].unshift(p.path[l]);}merged = true;break;}}}if (!merged) paths[path_idx++] = p.path;}});});return paths;
}

总结:

具体的做法是按照给定的采样点,插值(例如反距离权重)成矩阵,将高度值构建成矩阵,将矩阵中的四个相邻的值取出来,按照给定的阈值进行线性插值定位,计算z值对应的经纬度,这就构成一个插值后的xyz值,将这些值按照路径拼起来就是等直线了

参考:

等值线 | Turf.js中文网

GitHub - Turfjs/turf: A modular geospatial engine written in JavaScript

等值线 | Turf.js中文网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/143890.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优维产品最佳实践:实例视图

背 景 模型可以定义很多的字段&#xff0c;当这些字段越来越多的时候&#xff0c;直接打开实例页面&#xff0c;会杂乱无章的呈现出来&#xff0c;对于用户来说无法快速的找到想要的信息&#xff0c;也不便于查看数据。而且并不是所有的字段都一定会录入了数据&#xff0c;常常…

路由器和路由到底啥区别?

在Vue中会有路由&#xff08;Route&#xff09;的概念&#xff0c;一些伙伴还不知道嘞&#xff0c;这就给大家讲解一下 我们日常出行都会碰到导航这个概念。 导航系统会给出从当前位置到目标位置的建议路径,这就是路由。 而 GPS 导航仪根据路由提供的路径,告诉我们每个路口是…

文档在线预览word、pdf、excel文件转html以实现文档在线预览

目录 一、前言 1、aspose2 、poi pdfbox3 spire二、将文件转换成html字符串 1、将word文件转成html字符串 1.1 使用aspose1.2 使用poi1.3 使用spire2、将pdf文件转成html字符串 2.1 使用aspose2.2 使用 poi pbfbox2.3 使用spire3、将excel文件转成html字符串 3.1 使用aspose…

Linux常见指令(1)

Linux常见指令[1] 一.前言1.操作系统简述 二.Linux常见指令1.登录Xshell2.Linux下的常见命令1.pwd2.ls1.ls -a2.ls -d3.ls -l 3.cd Linux中的文件系统1.文件的相关知识2.Linux下目录结构的认识1.什么叫做路径?2.Linux的整体目录结构3.为什么要有路径呢?4.绝对路径与相对路径 …

IntelliJ IDEA - Maven 在控制台Maven编译正常,但是在IDEA中不正常,表现不一致

文章目录 现象原因解决验证 现象 一个Maven项目&#xff0c;当导入到IDEA后&#xff0c;无法在IDEA中正常的编译和下载jar依赖&#xff0c;类似下面的截图。 但是在Windows控制台却可以正常编译&#xff0c;类似下面的截图。 CMD执行&#xff1a;mvn clean install -Dmaven.te…

就只说 3 个 Java 面试题

在面试时&#xff0c;即使是经验丰富的开发人员&#xff0c;也可能会发现这是一些很棘手的问题&#xff1a; 1、Java中“transient”关键字的用途是什么&#xff1f;如何才能实现这一目标&#xff1f; 在 Java 中&#xff0c;“transient”关键字用于指示类的特定字段不应包含…

(一)设计模式概述

设计模式是由GoF (Gang of Four&#xff09;首先提出的&#xff0c;它是解决特定问题的解决方案。设计模式本身是一种发现&#xff0c;而不是一种发明。学习设计模式可以让我们从别人的成功经验中获取新的灵感&#xff0c;从而写出更优秀的代码。 设计模式的主要特点如下&…

idea开发Springboot出租车管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 出租车管理系统是一套完善的完整信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c; 系统具有完整的源代码和数据…

Unity 制作登录功能01-创建登录的UI并获取输入内容

1.创建UI面板 导入插件TextMesh Pro 2.编写脚本获取用户输入 这里用的是输入框侦听函数&#xff0c;所有UI都可以使用侦听函数 &#xff0c;需要注意TMP_InputField 这个类是UI中导入的一个插件TextMesh Pro&#xff01;在代码中需要引用using TMPro; 命名空间&#xff01; …

使用自功率谱、互功率谱估计滤波器幅频特性

这段时间终于对工程中的随机信号的一般处理方式有点头绪了&#xff0c;功率谱密度估计是十分重要的方式之一&#xff0c;仍需继续深入细化相关内容。 示例&#xff1a;使用自功率谱、互功率谱估计滤波器幅频特性&#xff0c;自己实现 & Matlab自带函数实现。 clc;clear;cl…

rv1126-rv1109-烧录方法之TFTP

注意&#xff1a;开机按ctrlC既可以进入uboot指令集 因为之前习惯了用RK的烧录工具&#xff0c;为了兼容ssd202d的烧录方法 于是我开始尝试了使用ssd202d的方法烧录 SSD202D的方法是 烧录uboot 然后用TFTP烧录下去&#xff0c;于是我开始尝试 烧录前三个即可&#x…

写给程序员的跳槽攻略

未经作者&#xff08;微信ID&#xff1a;Byte-Flow&#xff09;允许&#xff0c;禁止转载 有读者提问&#xff1a;我在现在这家公司呆了 4 年了&#xff0c;工作上说实话压力不大&#xff0c;每天按部就班做着重复性的工作&#xff0c;基本上没有什么大的挑战&#xff0c;最近有…

分布式锁——什么是看门狗?什么是redlock算法?带你全面了解~

目录 1、什么是分布式锁 2、引入setnx 3、引入过期时间 4、引入检验id 5、引入lua脚本 6、引入看门狗 7、redlock算法 1、什么是分布式锁 我们在前面学习中&#xff0c;都有了解关于线程安全的问题&#xff0c;那引发这个问题的关键就是&#xff0c;多个线程去修改了同一…

MIPI协议介绍-CPHY

MIPI协议概述 MIPI(Mobile Industry Processor Interface): 是MIPI联盟发起为移动应用处理器制定的开放标准.MIPI接口协议层主要包括CSI和DSI两种,其中CSI主要用于图像输出&#xff0c;如图像传感器等&#xff1b; DSI主要用于图像输入&#xff0c;如屏幕显示器等.对于camera而…

vs2019配置libcurl环境

一、libcurl下载地址&#xff1a;curl - Download 二、解压下载的压缩包&#xff0c;进入projects\Windows\VC14目录 三、用vs2019打开curl-all.sln工程&#xff0c;选择LIB Debug&#xff0c;x64进行编译 编译后的文件为&#xff1a;curl-8.2.1\build\Win64\VC14\LIB Debug\li…

【Git】轻松学会 Git(一):掌握 Git 的基本操作

文章目录 前言一、创建 Git 本地仓库1.1 什么是仓库1.2 创建本地仓库1.3 .git 目录结构 二、配置 Git三、认识 Git 的工作区、暂存区和版本库3.1 什么是 Git 的工作区、暂存区和版本库3.2 工作区、暂存区和版本库之间的关系 四、添加文件4.1 添加文件到暂存区和版本库中的命令4…

【python入门篇】列表简介及操作(2)

列表是什么&#xff1f; 列表是由一系列按特定顺序排列的元素组成。你可以创建包含字母表中的所有字母、数字 0~9 或所有家庭成员的列表&#xff1b;也可以将任何东西加入列表中&#xff0c;其中的元素之间可以没有任何关系。列表通常包含多个元素&#xff0c;因此给列表指定一…

太实用了! 20分钟彻底理解【Pointpillars论文】,妥妥的!

PointPillars: Fast Encoders for Object Detection from Point Clouds PointPillars&#xff1a;快就对了 摘要&#xff08;可跳过&#xff09;&#xff1a; 这帮人提出了PointPillars&#xff0c;一种新颖的编码器&#xff0c;它利用PointNets来学习以垂直列组织的点云&am…

标题:探寻电大搜题,广东开放大学的智慧之旅

随着信息技术的快速发展和互联网的普及&#xff0c;越来越多的人开始选择通过电大学习。作为知名的广东开放大学&#xff0c;一直致力于提供高质量的教育资源&#xff0c;让更多人实现自己的梦想。在这个过程中&#xff0c;电大搜题微信公众号成为了学生们的得力助手&#xff0…

Arduino PLC IDE

Arduino PLC IDE MCU单片机进入全新的PLC领域概述需要的硬件和软件下一步操作1. Arduino PLC IDE Tool Setup2. Arduino PLC IDE Setup3. Project Setup4. Download the Runtime5. Connect to the Device6. License Activation with Product Key (Portenta Machine Control) 结…