Coder Social home page Coder Social logo

gisalgorithm's Introduction

[TOC]

GIS常用算法

作为一个 GISer,在日常 WebGIS 开发中,会常用到的 turf.js,这是一个地理空间分析的 JavaScript 库,经常搭配各种 WebGIS JsAPI 使用,如 LeafletMapboxGLOpenLayers 等;在后台 Java 开发中,也有个比较强大的GIS库,GeoTools,里面包含构建一个完整的地理信息系统所需要的全部工具类;数据库端常用是 postgis 扩展,需要在 PostgreSQL 数据库中引入使用。

然而在开发某一些业务系统的时候,有些需求只需要调用某一个 GIS 算法,简单的几行代码即可完成,没有必要去引用一个 GIS 类库。

而且有些算法在这些常用的GIS类库中没有对应接口,就比如在下文记录的这几种常用算法中,求垂足、判断线和面的关系,在 turf.js 就没有对应接口。

下面文章中是我总结的一些常用 GIS 算法,这里统一用JavaScript 语言实现,因为 JS 代码相对比较简洁,方便理解其中算法逻辑,也方便在浏览器下预览效果。

在具体应用时可以根据具体需求,翻译成 Rust、C/C++、Java、C#.NET、Python 等语言来使用。

文中代码大部分为之前遇到需求时在网上搜索得到,然后自己根据具体需要做了优化修改,通过这篇文章做个总结收集,也方便后续使用时查找。

1 算法介绍与示例代码

以下方法中传参的点、线、面都是对应 GeoJSON 格式中 coordinates,方便统一调用。

GeoJSON 标准参考:https://geojson.org/

简单的类型约定

/**
 * @typedef {[number, number]} LonLat
 * @typedef {LonLat[]} LineString
 * @typedef {LonLat[]} Ring
 * @typedef {LonLat[][]} Polygon
 * @typedef {[LonLat, LonLat]} LineSegment
 */

以下所有算法函数用到三个简单的输入类型,两个数构成的数组称为 LonLat,即经纬度点;LonLat 数组,即一系列的经纬度点,称为折线,特殊情况下,两个点构成的叫线段 LineSegment;多个 LonLat 点除了表示折线外,还可以表示闭合的单一多边形 Ring,但是在 GeoJSON 中, Polygon 是允许有多个简单多边形构成的,即 LonLat[][]

// LonLat 经纬度点
const p1 = [112.5, 41.4]

// LineString 折线
const l1 = [[112.5, 41.4], [112.5, 41.5], [112.5, 41.6]]

// LineSegment 线段
const seg = [[112.5, 41.4], [112.5, 41.5]]

// Ring 单环
const ring = [[112.5, 41.4], [112.9, 41.5], [113.1, 40.6], [112.5, 41.4]]

// Polygon 多边形
const polygon = [[[112.5, 41.4], [112.9, 41.5], [113.1, 40.6], [112.5, 41.4]]]

1.1 经纬度点之间的距离 getDistance

适用场景:测量

const p1 = [112.5, 41.2]
const p2 = [121.3, 22.4]
const distance = getDistance(p1, p2) // 2249255.8

1.2 根据已知线段以及到起点距离,求目标点坐标 getLinePoint

适用场景:封闭管段定位问题点

const l1 = [[116.01,40.01],[116.52,40.01]]
const offset = 8500
getLinePoint(l1, offset) // return [116.1096913821572, 40.01]

1.3 已知点、线段,求垂足 getFootPoint

垂足可能在线段上,也可能在线段延长线上。

适用场景:求垂足

const l1 = [[116.01,40.01],[116.52,40.01]]
const p1 = [116.35, 40.08]
getFootPoint(l1, p1) // return [116.35, 40.01]

1.4 线段上距离目标点最近的点 getShortestPointInLine

不同于上面求垂足方法,该方法求出的点肯定在线段上。

如果垂足在线段上,则最近的点就是垂足,如果垂足在线段延长线上,则最近的点就是线段某一个端点。

适用场景:根据求出最近的点计算点到线段的最短距离

const l = [[116.01,40.01],[116.52,40.01]]
const p = [116.72, 40.18]
getShortestPointInLine(l, p) // return [116.52, 40.01]

1.5 点缓冲 bufferPoint

这里缓冲属于测地线方法,由于这里并没有严格的投影转换体系,所以与标准的测地线缓冲还有些许误差,不过经测试,半径 100km 内,误差基本可以忽略。

具体缓冲类型可看下之前的文章 你真的会用PostGIS中的buffer缓冲吗?

适用场景:根据点和半径画圆

const p = [116.72, 40.18]
bufferPoint(p, 50000, 64) // 返回一个数组,有 64 个 LonLat

1.6 点和面关系 pointInPolygon

该方法采用射线法思路实现。

了解射线法可参考:https://blog.csdn.net/qq_27161673/article/details/52973866

这里已经考虑到环状多边形的情况。

适用场景:判断点是否在面内

const polygon = [
  [
    [116.1, 39.5],
    [116.1, 40.5],
    [116.9, 40.5],
    [116.9, 39.5],
  ],
  [
    [116.3, 39.7],
    [116.3, 40.3],
    [116.7, 40.3],
    [116.7, 39.7],
  ], 
  [
    [116.4, 39.8],
    [116.4, 40.2],
    [116.6, 40.2],
    [116.6, 39.8],
  ]
]

pointInPolygon([116.35, 40.08], polygon) // return 0
pointInPolygon([116.35, 40.08], polygon) // return 1
pointInPolygon([116.35, 40.08], polygon) // return 2

1.7 线段与线段的关系 intersectLineAndLine

适用场景:判断线和线的关系

const l1 = [[116.01,40.01],[116.52,40.01]]
const l2 = [[116.33,40.21],[116.36,39.76]]
intersectLineAndLine(l1, l2) // return 1

1.8 线和面关系 intersectLineAndPolygon & intersectLineAndRing

适用场景:判断线与面的关系

该方法考虑到环状多边形的情况,且把相切情况分为了内切和外切。

参考链接:https://www.cnblogs.com/xiaozhi_5638/p/4165353.html

const l1 = [[116.01,40.01],[116.52,40.01]]
const l2 = [[116.33,40.21],[116.36,39.76]]
const l3 = [[116.3,39.7],[116.4,40.1]]
const polygon = [
  [
    [116.1, 39.5],
    [116.1, 40.5],
    [116.9, 40.5],
    [116.9, 39.5],
  ],
  [
    [116.3, 39.7],
    [116.3, 40.3],
    [116.7, 40.3],
    [116.7, 39.7],
  ],
  [
    [116.4, 39.8],
    [116.4, 40.2],
    [116.6, 40.2],
    [116.6, 39.8],
  ]
]

intersectLineAndPolygon(l1, polygon) // return 1
intersectLineAndPolygon(l2, polygon) // return 0
intersectLineAndPolygon(l3, polygon) // return 4

1.9 GeoJSON 面转线 convertPolygonToPolyline

适用场景:只有 GeoJSON 面数据,获取线的边界

const polygon = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              112.34344482421875,
              22.172144917381736
            ],
            [
              114.74395751953125,
              22.172144917381736
            ],
            [
              113.51348876953124,
              23.274150156028483
            ],
            [
              112.34344482421875,
              22.172144917381736
            ]
          ]
        ]
      }
    }
  ]
}
convertPolygonToPolyline(polygon)

// 输出
/*
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              112.34344482421875,
              22.172144917381736
            ],
            [
              114.74395751953125,
              22.172144917381736
            ],
            [
              113.51348876953124,
              23.274150156028483
            ],
            [
              112.34344482421875,
              22.172144917381736
            ]
          ]
        ]
      }
    }
  ]
}
*/

2 在线示例

在线示例:GISAlgorithm Demo

代码地址:GISAlgorithm Code


原文地址:http://gisarmory.xyz/blog/index.html?blog=GISAlgorithm

关注《GIS兵器库》, 只给你网上搜不到的GIS知识技能。

本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名《GIS兵器库》(包含链接:  http://gisarmory.xyz/blog/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

贡献者

gisalgorithm's People

Contributors

eternity-xyf avatar gisarmory avatar onsummer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

gisalgorithm's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.