文件目录
1、常用算法
1.1、测算两地理坐标点中间的间距
1.2、依据已经知道线条及其到起始点间距,求总体目标点座标
1.3、已经知道点、线条,求垂足
1.4、线条上间距总体目标点近期的点
1.5、点缓存
1.6、点揉面关联
1.7、线条与线条的关联
1.8、线揉面关联
1.9、geojson 面转线
2、线上实例
做为一个GISer,在日常WebGIS开发设计中,会常见到的turf.js,这是一个自然地理数据挖掘技术的Javascript库,常常配搭各种各样GIS JS API应用,如leaflet、mapboxgl、openlayers等;在后台管理Java开发设计中,也还有一个较为强劲的GIS库,geotools,里边包括搭建一个完全的大数据技术所须要的所有java工具;数据库查询端常见是postgis拓展,必须在postgres库文件引进应用。
殊不知在开发设计某一些信息化系统的情况下,有一些要求只必须读取某一个GIS优化算法,简易的几行编码就可以进行,沒有必需去引入一个GIS类库。
并且有一些优化算法在这常见的GIS类库中沒有相匹配插口,就例如在下文纪录的这几类常用算法中,求垂足、分辨线揉面的关联,在turf.js就沒有相匹配插口。
下边文章内容中就是我汇总的一些常见GIS优化算法,这儿统一用Javascript语言表达完成,由于JS编码相对性较为简洁明了,便捷了解在其中优化算法逻辑性,也便捷在浏览器下浏览实际效果。在实际运用时可以按照实际要求,译成Java、C#、Python等语言表达来应用。
原文中编码绝大多数为以前碰到要求时在网络上检索获得,随后自身依据实际必须干了提升改动,根据这篇文章做一个汇总搜集,也便捷后面应用时搜索。
1、常用算法
下列方式中国传媒大学参的点、线、面全是相匹配geojson文件格式中coordinates,便捷统一读取。geojson规范参照:https://www.oschina.net/translate/geojson-spec
1.1、测算两地理坐标点中间的间距
可用情景:精确测量
function getDistance(p1, p2) { var rlat1 = p1[1] * Math.PI / 180.0; var rlat2 = p2[1] * Math.PI / 180.0; var a = rlat1 - rlat2; var b = p1[0] * Math.PI / 180.0 - p2[0] * Math.PI / 180.0; var d = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) Math.cos(rlat1) * Math.cos(rlat2) * Math.pow(Math.sin(b / 2), 2))); d = d * 6378.137; d = Math.round(d * 10000) / 10; return d}
1.2、依据已经知道线条及其到起始点间距,求总体目标点座标
可用情景:封闭式管段精准定位点
function getLinePoint(line, dis) { var p1 = line[0] var p2 = line[1] var d = getDistance(p1, p2) // 测算两地理坐标点中间的间距(企业:米) var dx = p2[0] - p1[0] var dy = p2[1] - p1[1] return [p1[0] dx * (dis / d), p1[1] dy * (dis / d)]}
1.3、已经知道点、线条,求垂足
垂足很有可能在线条上,也很有可能在线条延伸线上。
可用情景:求垂足
function getFootPoint(line, p) { var p1 = line[0] var p2 = line[1] var dx = p2[0] - p1[0]; var dy = p2[1] - p1[1]; var cross = dx * (p[0] - p1[0]) dy * (p[1] - p1[1]) var d2 = dx * dx dy * dy var u = cross / d2 return [(p1[0] u * dx), (p1[1] u * dy)]}
1.4、线条上间距总体目标点近期的点
有别于上边求垂足方式,该方式算出的点毫无疑问在线条上。
假如垂足在线条上,则近期的点便是垂足,假如垂足在线条延伸线上,则近期的点便是线条某一个节点。
可用情景:依据求出近期的点测算点至线条的最短路线
function getShortestPointInLine(line, p) { var p1 = line[0] var p2 = line[1] var dx = p2[0] - p1[0]; var dy = p2[1] - p1[1]; var cross = dx * (p[0] - p1[0]) dy * (p[1] - p1[1]) if (cross <= 0) { return p1 } var d2 = dx * dx dy * dy if (cross >= d2) { return p2 } // 垂足 var u = cross / d2 return [(p1[0] u * dx), (p1[1] u * dy)]}
1.5、点缓存
这儿缓存归属于测地线方式,因为这儿并沒有严谨的投射变换管理体系,因此与标的测地线缓存也有些许偏差,但是经检测,半经100KM内,偏差基本上可以忽视。实际缓存种类可以看下以前的文章内容你真得用到PostGIS中的buffer缓存吗?
可用情景:依据点和半经画弧
function bufferPoint(center, radius, vertices) { if (!vertices) vertices = 64; var coords = [] // 111319.55:在赤道上1经纬度差相匹配的间距,111133.33:在经线上1层面差相匹配的间距 var distanceX = radius / (111319.55 * Math.cos(center[1] * Math.PI / 180)); var distanceY = radius / 111133.33; var theta, x, y; for (var i = 0; i < vertices; i ) { theta = (i / vertices) * (2 * Math.PI); x = distanceX * Math.cos(theta); y = distanceY * Math.sin(theta); coords.push([center[0] x, center[1] y]); } return [coords]}
1.6、点揉面关联
该方式选用X射线法构思完成。(掌握X射线法可参照:https://blog.csdn.net/qq_27161673/article/details/52973866)
这儿早已充分考虑环形不规则图形的状况。
可用情景:分辨点是不是在平行面
function pointInPolygon(point, polygon) { var isInNum = 0; for (var i = 0; i < polygon.length; i ) { var inside = pointInRing(point, polygon[i]) if (inside === 2) { return 2; } else if (inside === 1) { isInNum ; } } if (isInNum % 2 == 0) { return 0; } else if (isInNum % 2 == 1) { return 1; }}function pointInRing(point, ring) { var inside = false, x = point[0], y = point[1], intersects, i, j; for (i = 0, j = ring.length - 1; i < ring.length; j = i ) { var xi = ring[i][0], yi = ring[i][1], xj = ring[j][0], yj = ring[j][1]; if (xi == xj && yi == yj) { continue } // 分辨点与线段的相对位置,0为在线条上,>0 点在左边,<0 点在右边 if (isLeft(point, [ring[i], ring[j]]) === 0) { return 2; // 点在不规则图形旁边 } else { if ((yi > y) !== (yj > y)) { // 竖直方位总体目标点在yi、yj中间 // 求总体目标点在当今线条上的x座标。 因为JS小数计算后会变换为精准15位的float,因而必须去一下精密度 var xx = Number(((xj - xi) * (y - yi) / (yj - yi) xi).toFixed(10)) if (x <= xx) { // 总体目标点水准X射线与当今线条有相交点 inside = !inside; } } } } return Number(inside);}function isLeft(point, line) { var isLeft = ((line[0][0] - point[0]) * (line[1][1] - point[1]) - (line[1][0] - point[0]) * (line[0][1] - point[1])) // 因为JS小数计算后会变换为精准15位的float,因而必须去一下精密度 return Number(isLeft.toFixed(10))}
1.7、线条与线条的关联
可用情景:分辨线和线的关联
function intersectLineAndLine(line1, line2) { var x1 = line1[0][0], y1 = line1[0][1], x2 = line1[1][0], y2 = line1[1][1], x3 = line2[0][0], y3 = line2[0][1], x4 = line2[1][0], y4 = line2[1][1] //迅速抵触: //2个线条为对角构成的矩形框,假如这两个矩形框沒有重合的一部分,那样两根线条是不太可能发生重合的 //这儿确实如此,这一步是判断两矩形框是不是交点 //1.线条ab的底点小于cd的最高处(很有可能重叠) //2.cd的最左方低于ab的最右边(很有可能重叠) //3.cd的最低值小于ab的最高处(再加上标准1,两条线段在垂直方位上重叠) //4.ab的最左方低于cd的最右边(再加上标准2,两平行线在水平方向上重叠) //综上所述4个标准,两根线条构成的矩形框是重叠的 //尤其要留意一个矩形框含于另一个矩形框以内的状况 if (!(Math.min(x1, x2) <= Math.max(x3, x4) && Math.min(y3, y4) <= Math.max(y1, y2) && Math.min(x3, x4) <= Math.max(x1, x2) && Math.min(y1, y2) <= Math.max(y3, y4))) { return 0 } // 分辨点与线段的相对位置,0为在线条上,>0 点在左边,<0 点在右边 if (isLeft(line1[0], line2) === 0 || isLeft(line1[1], line2) === 0) { return 2 } //跨立试验: //假如两根线条交点,那样务必跨立,便是以一条线条为规范,另一条线条的两边点一定在这里条线条的2段 //换句话说a b二点在线条cd的两边,c d二点在线条ab的两边 var kuaili1 = ((x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1)) * ((x4 - x1) * (y2 - y1) - (x2 - x1) * (y4 - y1)) var kuaili2 = ((x1 - x3) * (y4 - y3) - (x4 - x3) * (y1 - y3)) * ((x2 - x3) * (y4 - y3) - (x4 - x3) * (y2 - y3)) return Number(Number(kuaili1.toFixed(10)) <= 0 && Number(kuaili2.toFixed(10)) <= 0)}
1.8、线揉面关联
可用情景:分辨线与面的关联
该方式充分考虑环形不规则图形的状况,且把相切状况分成了内切圆和外切。
参照连接:https://www.cnblogs.com/xiaozhi_5638/p/4165353.html
function intersectLineAndPolygon(line, polygon) { var isTangent = false var isInNum = 0 var intersect = 0 for (var i = 0; i < polygon.length; i ) { // 线揉面关联;0:相离,1:交点,2:包括,3:内切圆,4:外切 intersect = intersectLineAndRing(line, polygon[i]) if (intersect === 1) { return 1 } else if (intersect === 2) { isInNum } else if (intersect === 3) { isInNum isTangent = true } else if (intersect === 4) { isTangent = true } } if (isInNum % 2 == 0) { if (isTangent) { return 4 // 外切 } else { return 0 // 相离 } } else if (isInNum % 2 == 1) { if (isTangent) { return 3 // 内切圆 } else { return 2 // 包括 } }}function intersectLineAndRing(line, ring) { var inserset = 0 var isTangent = false var inserset1 = pointInRing(line[0], ring) // 点揉面关联;0:不规则图形外,1:不规则图形内,2:不规则图形旁边 var inserset2 = pointInRing(line[1], ring) // 点揉面关联;0:不规则图形外,1:不规则图形内,2:不规则图形旁边 if (inserset1 === inserset2 === 0) { inserset = 0 } else if ((inserset1 * inserset2) === 1) { inserset = 2 } else if ((inserset1 * inserset2) === 2) { inserset = 3 } else if ((inserset1 === 2 || inserset2 === 2) && (inserset1 === 0 || inserset2 === 0)) { inserset = 4 } else if ((inserset1 === 1 || inserset2 === 1) && (inserset1 === 0 || inserset2 === 0)) { return 1 // 交点 } for (var i = 0, j = ring.length - 1; i < ring.length; j = i ) { var line2 = [ring[j], ring[i]] // 总体目标线条与当今线条的关联;0:相离,1:交点,2:相切 var intersectLine = intersectLineAndLine(line, line2) if (intersectLine == 1) { return 1 // 交点 } } return inserset}
1.9、geojson 面转线
可用情景:仅有geojson面数据信息,获得线的界限
function convertPolygonToPolyline(polygonGeoJson) { var polylineGeoJson = JSON.parse(JSON.stringify(polygonGeoJson)) for (var i = 0; i < polylineGeoJson.features.length; i ) { var MultiLineString = [] if (polylineGeoJson.features[i].geometry.type === ‘Polygon’) { var Polygon = polylineGeoJson.features[i].geometry.coordinates Polygon.forEach(LinearRing => { var LineString = LinearRing MultiLineString.push(LineString) }) } else if (polylineGeoJson.features[i].geometry.type === ‘MultiPolygon’) { var MultiPolygon = polylineGeoJson.features[i].geometry.coordinates MultiPolygon.forEach(Polygon => { Polygon.forEach(LinearRing => { var LineString = LinearRing MultiLineString.push(LineString) }) }) } else { console.error(‘请确定键入主要参数为geojson文件格式面数据信息!’) return null } polylineGeoJson.features[i].geometry.type = ‘MultiLineString’ //面转线 polylineGeoJson.features[i].geometry.coordinates = MultiLineString } return polylineGeoJson}
2、线上实例
线上实例:http://gisarmory.xyz/blog/index.html?demo=GISAlgorithm
编码详细地址:http://gisarmory.xyz/blog/index.html?source=GISAlgorithm
全文详细地址:http://gisarmory.xyz/blog/index.html?blog=GISAlgorithm
关心《GIS兵器库》, 只让你在网上找不到的GIS专业知识招式。
本文章内容选用 知识共享落款-非商业应用-同样方法分享 4.0 国际性授权文件 开展批准。热烈欢迎转截、应用、再次公布,但尽量保存文章内容落款《GIS兵器库》(包括连接: http://gisarmory.xyz/blog/),不可用以商业服务目地,根据文中改动后的佳作尽量以同样的批准公布。



