GIS常用算法( 二 )

1.6、点和面关系该方法采用射线法思路实现 。(了解射线法可参考:
https://blog.csdn.net/qq_27161673/article/details/52973866)
这里已经考虑到环状多边形的情况 。
适用场景:判断点是否在面内
/*** 点和面关系* @param point 点;[经度,纬度];例:[116.353455, 40.080173]* @param polygon 面;geojson格式中的coordinates;例:[[[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]]]** @return inside 点和面关系;0:多边形外,1:多边形内,2:多边形边上*/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;}}/*** 点和面关系* @param point 点* @param ring 单个闭合面的坐标** @return inside 点和面关系;0:多边形外,1:多边形内,2:多边形边上*/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) { // 目标点水平射线与当前线段有交点inside = !inside;}}}}return Number(inside);}/*** 判断点与线段的相对位置* @param point 目标点* @param line 线段** @return isLeft,点与线段的相对位置,0为在线段上,>0 p在左侧,<0 p在右侧*/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、线段与线段的关系适用场景:判断线和线的关系
/*** 线段与线段的关系* @param line1 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]* @param line2 线段;[[经度,纬度],[经度,纬度]];例:[[116.33,40.21],[116.36,39.76]]** @return intersect 线段与线段的关系;0:相离,1:相交,2:相切*/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]//快速排斥://两个线段为对角线组成的矩形,如果这两个矩形没有重叠的部分,那么两条线段是不可能出现重叠的//这里的确如此,这一步是判定两矩形是否相交//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}//跨立实验://如果两条线段相交,那么必须跨立,就是以一条线段为标准,另一条线段的两端点一定在这条线段的两段//也就是说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
/*** 线和面关系* @param line 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]* @param polygon 面;geojson格式中的coordinates;例:[[[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]]]** @return intersect 线和面关系;0:相离,1:相交,2:包含,3:内切,4:外切*/function intersectLineAndPolygon(line, polygon) {var isTangent = falsevar isInNum = 0var intersect = 0for (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 // 包含}}}/*** 线和面关系* @param line 线段* @param ring 单面** @return intersect 线和面关系;0:相离,1:相交,2:包含,3:内切,4:外切*/function intersectLineAndRing(line, ring) {var inserset = 0var isTangent = falsevar 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}


推荐阅读