在这里主要说一些在图形应用中多边形相关的判断和操作。
例如求点映射到线上的坐标,计算点到线的距离,以及点是否在多边形内,点到多边形的距离。
最后介绍一个第三方库:jsts。

一些多边形的判断和操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* 点到线的映射坐标
* @param {{x: Number, y: Number}} p 点
* @param {{x: Number, y: Number}} a 线段起始点
* @param {{x: Number, y: Number}} b 线段终止点
* @param {{x: Number, y: Number}} 线上的点
*/
function getFocusPoint(p, a, b) {
let point = {};
// 如果a.x === b.x 说明是条竖着的线
if (a.x - b.x === 0) {
p.x = a.x;
p.y = p.y;
} else {
let k = (a.y - b.y) / (a.x - b.x);
let l = a.y - k * a.x;
let m = p.x + k * p.y;

point.x = (m - k * l) / (k * k + 1);
point.y = k * point.x + l;
}

return point;
}

/**
* 计算点到线段的距离
* @param {{x: Number, y: Number}} p 点
* @param {{x: Number, y: Number}} a 线段起始点
* @param {{x: Number, y: Number}} b 线段终止点
* @return {Number} 距离
*/
function pointToSegmentDist(p, a, b) {
let AB = [b.x - a.x, b.y - a.y]
let AP = [p.x - a.x, p.y - a.y]
let AB_AP = AB.x * AP.x + AB.y * AP.y
let distAB2 = AB.x * AB.x + AB.y * AB.y
let D = [a.x, a.y]
if (distAB2 != 0) {
let t = AB_AP / distAB2
if (t > 1) {
D = [b.x, b.y]
} else if (t > 0) {
D = [a.x + AB.x * t, a.y + AB.y * t]
} else {
D = [a.x, a.y]
}
}
let AD = [p.x - a.x, p.y - a.y]
return Math.sqrt(AD.x * AD.x + AD.y * AD.y)
}

/**
* 判断点是否在多边形内部,一般用射线法
* @param {{x: Number, y: Number}} p 点
* @param {Array} polygon 多边形坐标
* @return {Number} 1: 在内部,0: 在外部
*/
function pointInPolygon(p, polygon) {
// 统计p点右边交点的个数
var count = 0
for (var i = 0; i < ring.length - 1; i++) {
var a = polygon[i]
var b = polygon[i + 1]
if ((a.y > p.y !== b.y > p.y) &&
(p.x < (b.x - a.x) * (p.y - a.y) / (b.y - a.y) + a.x)) count++;
}
return count % 2
}

/**
* 判断点到多边形的最近距离
* @param {{x: Number, y: Number}} p 点
* @param {Array} polygon 多边形坐标
* @return {Number} 最短距离;点在多边形内部,距离为正;在多边形外部,距离为负;在边上,距离为零
*/
function pointToPolygonDist(p, polygon) {
// 统计p点右边交点的个数
var count = 0
var minDist = Infinity
for (var i = 0; i < ring.length - 1; i++) {
var a = polygon[i]
var b = polygon[i + 1]
if ((a.y > p.y !== b.y > p.y) &&
(p.x < (b.x - a.x) * (p.y - a.y) / (b.y - a.y) + a.x)) count++;
minDist = Math.min(minDist, pointToSegmentDist(p, a, b))
}
if (count % 2 === 0) minDist = -minDist
return minDist
}

/**
* 二维坐标围绕某个点旋转特定角度
* @param {Array} pointList 二维坐标集合
* @param {Number} theta 弧度
* @param {Object} point 旋转点
* @return {Array} 结果集合
*/
function rotationByPoint(pointList, theta, point) {
let {x, y} = point;
let sinTheta = Math.sin(theta);
let cosTheta = Math.cos(theta);

let m00 = cosTheta;
let m01 = -sinTheta;
let m02 = x - x * cosTheta + y * sinTheta;
let m10 = sinTheta;
let m11 = cosTheta;
let m12 = y - x * sinTheta - y * cosTheta;

return pointList.map(src => {
let dest = {};
let xp = m00 * src.x + m01 * src.y + m02;
let yp = m10 * src.x + m11 * src.y + m12;
dest.x = xp;
dest.y = yp;
return dest;
});
}

jsts

JSTS是一个Javascript符合OGC规范的简单要素空间位置关系判定和函数的类库,JSTS也是总所周知的java类库JST的一个接口。

下面是一些jsts的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let a_coor = new jsts.geom.Coordinate(0, 0);
let b_coor = new jsts.geom.Coordinate(1, 0);
let c_coor = new jsts.geom.Coordinate(1, 1);
let d_coor = new jsts.geom.Coordinate(0, 1);

let factory = new jsts.geom.GeometryFactory();

let ring = factory.createLinearRing([a_coor, b_coor, c_coor, d_coor, a_coor]);
let line = factory.createLineString([new jsts.geom.Coordinate(0.5, 0), new jsts.geom.Coordinate(1, 0)]);
let polygon = factory.createPolygon([a_coor, b_coor, c_coor, d_coor, a_coor]);

let x = 0.5
let y = 0
let mouse_coor = new jsts.geom.Coordinate(x, y);
let mouse_point = factory.createPoint(mouse_coor);

let distance = new jsts.operation.distance.DistanceOp(mouse_point, ring);

console.log('nearest points', distance.nearestPoints());
console.log('distance', distance.distance())
console.log(ring.contains(mouse_point))

jsts的一些API

  • 两个多边形是否相交:polygon1.intersects(polygon2) => true/false

参考

  1. JSTS demonstration
  2. JTS javadoc
  3. JSTS gh-pages