当前位置: 首页 > news >正文

vue openlayer 找出直线上的某一个点 , 点距离直线 最短路径的点 WKT坐标转换为GeoJSON坐标

背景:

在项目开发中的航线推荐功能,使用vue+openlayer技术,需要对海面上两点计算出最佳航线,算法组是计算出最佳路径,可能是最短路径【算法组做的,这里不详细介绍】。再然后由于需求,我们进一步做了起点和终点之间的途经点【可以参考电子地图的导航功能】,遇到的问题就是算法返回的结果不包括“途经点”【问题所在】。我们需要把途经点移动到绘制的航线上。

核心代码:

根据项目实际情况,turfjs的官方文档的nearestPointOnLine()可以找出点到直线最短距离的点。

import * as turf from "@turf/turf";
import { parse } from 'wellknown';// 从WKT字符串创建一个GeoJSON点
const wktPoint = 'POINT (-75.343 39.984)';
const geoJsonFromWKT_point = parse(wktPoint);
const geoJsonFromWKT_linString = parse(data.linstring);
const result = nearestPointOnLine(turf.lineString(geoJsonFromWKT_linString.coordinates),turf.point(geoJsonFromWKT_point.coordinates), { units: 'kilometers' }
);//从GeoJSON点转成wkt字符串
const wkt = `POINT (
${result.geometry.coordinates[0]} ${result.geometry.coordinates[1]}
)`;

这个wktPoint,这个'POINT (-75.343 39.984)'字符串是WKT坐标

这个result变量控制台打印是一个GeoJSON坐标,这个result就是我们找出的点到直线最短距离的点。【下面有详细介绍】

在地理信息系统(GIS)开发中,WKT(Well-Known Text)和GeoJSON是两种常用的地理数据格式。WKT是一种文本标记语言,用于表示空间数据,而GeoJSON则是一种基于JSON的格式,用于表示地理空间数据。

行文思路:

行文思路如下:

已知点和直线,求出:点到直线最短距离的点

坐标转换:WKT坐标转换为GeoJSON坐标

坐标转换:GeoJSON坐标为转换WKT坐标

效果展示:

问题解决前,效果展示:

问题后,途经点修正后,效果展示:

 解决思路:

1.算法组修改,把航线绘制的途经点改成必经点。那么航线推荐功能的接口就应该返回“途经点在航线上的”航线。

2.前端修改,进行轨迹修正,即把途经点移动到航线,需要找出点到直线的最短距离的点。

 turfjs官网:点击跳转

实现步骤:

理论知识:

nearestPointOnLine()方法,在trufjs官方文档有详细介绍:

nearestPointOnLine()

turf.nearestPointOnLine 是 TurfJS 中用于计算点到线段的最近投影点的函数,其核心作用是确定某点与线段之间的最短距离,并返回线段上距离该点最近的点。

核心功能

该函数通过计算点与线段所有线段端点的距离,并选择最近的点作为结果。当点位于线段所在直线上时,返回线段端点;若点在线段延长线上,则返回线段上的最近点。

适用场景

  • 轨迹修正‌:用于行车轨迹贴路修正,计算轨迹点与道路网的最短距离。 ‌

  • 空间分析‌:在地理空间计算中确定点与线状地物的最近接触点。 ‌

 官网链接:点击跳转 

示例代码:

const point = turf.point([120.0, 30.0]);
const line = turf.lineString([  [119.0, 30.0],  [121.0, 30.0]  
]);
const nearest = turf.nearestPointOnLine(point, line);

写到这儿。。。你就知道了解决思路,以下是具体项目具体分析。。。

实际项目:

项目背景:航线推荐功能,查询接口返回的一个几何图形LineString(线),这是wkt坐标。

wkt一种用于表示地理空间数据的文本格式

以下是查询接口返回的数据:【以实际项目为主】

页面布局:

途经点是自定义的,地图随意选点:

问题前后对比,效果展示:

解决了问题后的,效果展示:

 

1.代码调用:

//航线推荐接口返回的值
const _linSting 是以下这种形式:
LINESTRING(122.19815694444445 30.120453055555554,122.22144758979722 30.120244897632674,122.22438333 30.12031111,122.2665 30.12075833,122.30419722 30.12058889,122.33525833 30.12011667,122.34729444 30.08787222,122.35019167 30.07115,122.35173889 30.06221111,122.35411389 30.01499167,122.35136944 30.00548056,122.34491944 29.98091944,122.33718889 29.96655,122.33271944 29.96163333,122.32862778 29.95649167,122.32733611 29.95480278,122.32158611 29.946175,122.32047778 29.943575,122.31883611 29.93878611,122.31685556 29.93231111,122.31556667 29.92909444,122.30998611 29.92473611,122.30608056 29.92311667,122.29998889 29.92172778,122.29645278 29.92237778,122.29087222 29.92370556,122.27765278 29.92668056,122.27075556 29.92805278,122.26268889 29.92931667,122.24844167 29.93058333,122.24054444 29.93110278,122.23075833 29.9314,122.19532222 29.93424722,122.17360833 29.93528889,122.15770556 29.93543333,122.11901944 29.93484444,122.12850833 29.92282778,122.15166667 29.88,122.12616667 29.844,122.08134722 29.80005,122.06946389 29.79244444,122.06398611 29.78670278,122.063 29.78200278,122.061 29.7635,122.04783333 29.73433333,122.03792778 29.72096667,122.03033333 29.71,122.02165556 29.67784722,122.01375833 29.627275,122.01494167 29.60646111,122.01555556 29.59050833,122.01425278 29.59444722,122.01343889 29.59620278,122.01113056 29.5998,122.00842778 29.60345556,122.00409167 29.60793333,121.99728056 29.61435556,121.98663889 29.62349722,121.96776389 29.64048333,121.96287222 29.64421389,121.94989722 29.65463611,121.94222222 29.65921389,121.934925 29.66227222,121.92230833 29.66678611,121.91681944 29.66844722,121.91441111 29.66913333,121.90760278 29.67028611,121.90631111 29.66982778,121.82540556 29.63092778,121.80504167 29.62099444,121.79145833 29.61494722,121.78983611 29.61401389,121.74970833 29.57115278,121.74767222 29.56915278,121.70981389 29.54735833,121.70788333 29.54636667,121.63290556 29.51941389,121.62504722 29.51773333,121.58716389 29.51258611,121.53591389 29.50583889,121.517975 29.50305833,121.51772920296226 29.503006324853867,121.51368305555556 29.50080388888889)
amend_tujingPoint({linString:_linString})

2.代码封装,以及封装过程解决的问题

代码:

import { nearestPointOnLine } from "@turf/nearest-point-on-line";
const amend_tujingPoint = (data) => {if (!routeState.tujingPoint) return;let tempArr = [];routeState.tujingPoint.forEach((item, index) => {console.log('item>>>', item,typeof item);const result = nearestPointOnLine(data.linstring, item, { units: 'kilometers' });tempArr.push(result);})console.log('修正途径点>>>', tempArr);
}

 

上面这串代码会报错,控制台报错如下:

 

Uncaught (in promise) Error: coord must be GeoJSON Point or an Array of numbers

Uncaught(在promise中)错误:coord必须是GeoJSON点或数字数组 

那么我们需要了解一个GeoJSON Point是什么?

 百度一下这个问题GeoJSON Point 是什么?

理论知识:

 GeoJSON要求每个要素(Feature)都必须包含 typegeometry 和 properties 字段,其中 geometry 字段定义了地理要素的几何形状和坐标,而 properties 字段则用于存储与该地理要素相关的属性信息。

示例如下:

{

"type": "Feature",

"geometry": {

        "type": "Point",

        "coordinates": [116.3974, 39.9093]

},

"properties": { "name": "北京市", "population": "2154万" }

},

 

geometry 数据示例:【可忽略不看】

//点
{"type": "Point","coordinates": [longitude, latitude]
}
//线
{"type": "LineString","coordinates": [[longitude1, latitude1],[longitude2, latitude2],// 更多点]
}
//面
{"type": "Polygon","coordinates": [[[longitude1, latitude1],[longitude2, latitude2],// 更多点,形成闭合环],// 可选:内部环(洞)]
}
//feature特征,数据示例如下:
// point feature
{"type": "Feature","geometry": {"type": "Point","coordinates": [longitude, latitude]},"properties": {"property1": "value1",// 更多属性}
}
// line feature
{"type": "Feature","geometry": {"type": "LineString","coordinates": [[-122.4194, 47.8584],[-122.4141, 47.8586],[-122.4112, 47.8583]]},"properties": {"name": "LineString Example","description": "This is a line feature."}
}
// polygon feature
{"type": "Feature","geometry": {"type": "Polygon","coordinates": [[[-122.4159, 47.8581],[-122.4159, 47.8595],[-122.4126, 47.8591],[-122.4126, 47.8579],[-122.4159, 47.8581]]]},"properties": {"name": "Polygon Example","description": "This is a polygon feature."}
}
//特征集合数据示例
{"type": "FeatureCollection","features": [{"type": "Feature","geometry": {"type": "Point","coordinates": [longitude, latitude]},"properties": {"property1": "value1",// 更多属性}},{"type": "Feature","geometry": {"type": "LineString","coordinates": [[-122.4194, 47.8584],[-122.4141, 47.8586],[-122.4112, 47.8583]]},"properties": {"name": "LineString Example","description": "This is a line feature."}},{"type": "Feature","geometry": {"type": "Polygon","coordinates": [[[-122.4159, 47.8581],[-122.4159, 47.8595],[-122.4126, 47.8591],[-122.4126, 47.8579],[-122.4159, 47.8581]]]},"properties": {"name": "Polygon Example","description": "This is a polygon feature."}}// 更多特征]
}

问题解决,核心思路:

必须把POINT(122.0272939 29.61940809)字符串转成数组形式[122.0272939,29.61940809]

思路一:对字符串截取,改成数组形式

思路二:把wkt坐标【文本字符串】转成一个GeoJSON点【几何要素】

这里详细介绍思路二。。。

备注:

A Geometry object represents points, curves, and surfaces in

coordinate space. Every Geometry object is a GeoJSON object no matter where it occurs in a GeoJSON text.

The value of a Geometry object's "type" member MUST be one of the seven geometry types (see Section 1.4).

A GeoJSON Geometry object of any type other than

"GeometryCollection" has a member with the name "coordinates".

The value of the "coordinates" member is an array. The structure of the elements in this array is determined by the type of geometry. GeoJSON processors MAY interpret Geometry objects with empty "coordinates" arrays as null objects.

翻译成中文:

几何对象表示中的点、曲线和曲面的坐标。每个几何对象都是一个GeoJSON对象,无论它在GeoJSON文本中出现在哪里。

几何对象的“类型”成员的值必须是七种几何类型之一(见如下:)。

 "Point", "MultiPoint", "LineString","MultiLineString", "Polygon", "MultiPolygon", and
    "GeometryCollection".

任何类型的GeoJSON几何对象“GeometricCollection”有一个包含名为“coordinates”的变量。
“coordinates”的值是一个数组。此阵列中元素的结构由几何形状的类型决定。GeoJSON处理器可以将具有空“coordinates”数组的几何对象解释为空对象。

代码【点到直线最短距离的点】:【结果是得到:GeoJSON 点】

import { nearestPointOnLine } from "@turf/nearest-point-on-line";
import { point, feature } from '@turf/helpers';
import { parse } from 'wellknown';
import * as turf from "@turf/turf";
const amend_tujingPoint = (data) => {if (!routeState.tujingPoint) return;let tempArr = [];routeState.tujingPoint.forEach((item, index) => {// 从WKT字符串创建一个GeoJSON点const wktPoint = item || 'POINT (-75.343 39.984)';const geoJsonFromWKT_point = parse(wktPoint);const geoJsonFromWKT_linString = parse(data.linstring);console.log('item>>>', item, 22, geoJsonFromWKT_point,33, geoJsonFromWKT_linString);const result = nearestPointOnLine(turf.lineString(geoJsonFromWKT_linString.coordinates),turf.point(geoJsonFromWKT_point.coordinates), { units: 'kilometers' });tempArr.push(result);})console.log('修正途径点>>>', tempArr);
}

控制台不报错,打印如下:

 

备注:从这里可以看出,我们已经把wkt字符串转成了GeoJson点

写到这儿,我们已经找到了点到直线最短距离的点 点到直线的最短距离的点。。。

其它理论知识:

 一、wkt坐标转成GeoJson坐标:

理论知识:

import { parse } from 'wellknown';//wellknown是处理地理数据格式的库

wellknown是一个开源JavaScript库,主要用于在浏览器和Node.js环境中解析 WKT (Well-Known Text)格式的地理数据,并将其转换为 GeoJSON 格式,反之亦然。

核心功能

  • 双向转换‌:支持将WKT字符串转换为GeoJSON几何对象,反之亦然。 ‌

  • 几何类型支持‌:涵盖点、线、面、多边形、多线串等2D/3D/4D几何类型。

  • 跨平台使用‌:可在Node.js环境、浏览器(通过browserify)及命令行接口(CLI)中运行。 ‌

应用场景

  • 数据转换‌:适用于Web应用中WKT与GeoJSON格式之间的快速转换。 ‌

  • 地图交互‌:支持将用户地图选择(如点、线、面)转换为WKT并保存或传输。 ‌

  • 数据存储与交换‌:简化不同系统间的地理数据格式转换需求。 ‌

核心代码: 

// 从WKT字符串创建一个GeoJSON点

npm install wellknown 

import { parse } from 'wellknown';
 

const wktPoint = 'POINT(122.02538726 29.61802305)';

const geoJsonFromWKT_point = parse(wktPoint);

console.log(geoJsonFromWKT_point);

控制台打印: 

控制台打印geoJsonFromWKT_point,如下:

{
    "type": "Point",
    "coordinates": [
        122.02538726,
        29.61802305
    ]

控制台打印const geoJsonFromWKT_linString = parse('自定义的一个wkt线');

二、GeoJson坐标转成wkt坐标:

理论知识:

import * as turf from "@turf/turf";//turf 是用于处理地理数据的Turf.js库

在Node.js中,你可以使用@turf/turf库来处理GeoJSON和WKT之间的转换。首先,安装这个库:

核心代码: 

npm install @turf/turf

const turf = require('@turf/turf');//vue2

import * as turf from "@turf/turf";//vue3
 
// GeoJSON对象或字符串
const geojson = {
  "type": "Point",
  "coordinates": [102.0, 0.5]
};
 方法一、
// 将GeoJSON转换为WKT字符串
const wkt = turf.toWkt(geojson);
console.log(wkt);  // 输出:POINT (102 0.5)

控制台打印:

turf.js 本身并不直接提供 toWkt 方法,但你可以使用第三方库如 geojson-to-wkt 来实现这一转换。 

npm install geojson-to-wkt

// 使用 geojson-to-wkt 库进行转换

const wkt = geojsonToWkt(geojson);

方法二:拼接一个wkt坐标

const wkt = `POINT (${result.geometry.coordinates[0]} ${result.geometry.coordinates[1]})`; 

代码【最终版】:

import { parse } from 'wellknown';
import * as turf from "@turf/turf";
const amend_tujingPoint = (data) => {if (!routeState.tujingPoint) return;let tempArr = [];routeState.tujingPoint.forEach((item, index) => {const wktPoint = item || 'POINT (-75.343 39.984)';const geoJsonFromWKT_point = parse(wktPoint);const geoJsonFromWKT_linString = parse(data.linstring);const result = nearestPointOnLine(turf.lineString(geoJsonFromWKT_linString.coordinates), turf.point(geoJsonFromWKT_point.coordinates), { units: 'kilometers' });const wkt = `POINT (${result.geometry.coordinates[0]} ${result.geometry.coordinates[1]})`;tempArr.push(wkt);})console.log('修正途径点>>>', tempArr);
}

http://www.dtcms.com/a/268656.html

相关文章:

  • iOS Widget 开发-1:什么是 iOS Widget?开发前的基本认知
  • 亚马逊运营进阶指南:如何用AI工具赋能广告运营
  • 期待在 VR 森林体验模拟中实现与森林的 “虚拟复现”​
  • 华锐视点 VR 污水处理技术对激发学习兴趣的作用​
  • 北京-4年功能测试2年空窗-报培训班学测开-第四十四天
  • UI + MCP Client + MCP Server实验案例
  • 【机器学习笔记 Ⅱ】11 决策树模型
  • Spring Boot 操作 Redis 时 KeySerializer 和 HashKeySerializer 有什么区别?
  • day16——Java集合进阶(Collection、List、Set)
  • Kafka消息积压的原因分析与解决方案
  • 网络安全之重放攻击:原理、危害与防御之道
  • windows grpcurl
  • 用安卓手机给苹果手机设置使用时长限制,怎样将苹果手机的某些APP设置为禁用?有三种方法
  • 软件工程功能点估算基础
  • QML Row与Column布局
  • YOLOv11 架构优化:提升目标检测性能
  • 国内免代理免费使用Gemini大模型实战
  • Vue的生命周期(Vue2)
  • Maven继承:多模块项目高效管理秘笈
  • 微软重磅开源Magentic-UI!
  • 【Rust CLI项目】Rust CLI命令行处理csv文件项目实战
  • AI Tool Calling 实战——让 LLM 控制 Java 工具
  • java-Milvus 连接池(多key)与自定义端点监听设计
  • C++开源项目—2048.cpp
  • 部署MongoDB
  • 接口漏洞怎么抓?Fiddler 中文版 + Postman + Wireshark 实战指南
  • 记录一个关于Maven配置TSF的报错问题
  • 基于 Three.js 开发三维引擎-02动态圆柱墙体实现
  • Python中50个常用的内置函数(2/2)
  • 剑指offer第2版:动态规划+记忆化搜索