GeoUtils.java
7.55 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package com.bsth.util.Geo;
import java.util.ArrayList;
import java.util.List;
public class GeoUtils {
private final static double EARTH_RADIUS = 6378137;
private final static double INLINE_THRESHOLD = Integer.parseInt("120");
private final static double DRIFT_THRESHOLD = Integer.parseInt("2000");
public static boolean isPointInRect(Point point, Bounds bounds) {
Point sw = bounds.getSouthWest(); // 西南脚点
Point ne = bounds.getNorthEast(); // 东北脚点
return (point.getLon() >= sw.getLon() && point.getLon() <= ne.getLon()
&& point.getLat() >= sw.getLat() && point.getLat() <= ne
.getLat());
}
public static boolean isPointInCircle(Point point, Circle circle) {
// point与圆心距离小于圆形半径,则点在圆内,否则在圆外
Point c = circle.getCenter();
double r = circle.getRadius();
double dis = getDistance(point, c);
if (dis <= r) {
return true;
} else {
return false;
}
}
public static boolean isPointInPolygon(Point point, Polygon polygon) {
Bounds polygonBounds = polygon.getBounds();
if (!isPointInRect(point, polygonBounds)) {
return false;
}
List<Point> pts = polygon.getPoints();// 获取多边形点
// 下述代码来源:http://paulbourke.net/geometry/insidepoly/,进行了部分修改
// 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
// 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
int N = pts.size();
boolean boundOrVertex = true; // 如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
int intersectCount = 0;// cross points count of x
double precision = 2e-10; // 浮点类型计算时候与0比较时候的容差
Point p1, p2;// neighbour bound vertices
Point p = point; // 测试点
p1 = pts.get(0);// left vertex
for (int i = 1; i <= N; ++i) {// check all rays
if (p.equals(p1)) {
return boundOrVertex;// p is an vertex
}
p2 = pts.get(i % N);// right vertex
if (p.getLat() < Math.min(p1.getLat(), p2.getLat())
|| p.getLat() > Math.max(p1.getLat(), p2.getLat())) {// ray
// is
// outside
// of
// our
// interests
p1 = p2;
continue;// next ray left point
}
if (p.getLat() > Math.min(p1.getLat(), p2.getLat())
&& p.getLat() < Math.max(p1.getLat(), p2.getLat())) {// ray
// is
// crossing
// over
// by
// the
// algorithm
// (common
// part
// of)
if (p.getLon() <= Math.max(p1.getLon(), p2.getLon())) {// x is
// before
// of
// ray
if (p1.getLat() == p2.getLat()
&& p.getLon() >= Math.min(p1.getLon(), p2.getLon())) {// overlies
// on
// a
// horizontal
// ray
return boundOrVertex;
}
if (p1.getLon() == p2.getLon()) {// ray is vertical
if (p1.getLon() == p.getLon()) {// overlies on a
// vertical ray
return boundOrVertex;
} else {// before ray
++intersectCount;
}
} else {// cross point on the left side
double xinters = (p.getLat() - p1.getLat())
* (p2.getLon() - p1.getLon())
/ (p2.getLat() - p1.getLat()) + p1.getLon();// cross
// point
// of
// lng
if (Math.abs(p.getLon() - xinters) < precision) {// overlies
// on
// a
// ray
return boundOrVertex;
}
if (p.getLon() < xinters) {// before ray
++intersectCount;
}
}
}
} else {// special case when ray is crossing through the vertex
if (p.getLat() == p2.getLat() && p.getLon() <= p2.getLon()) {// p
// crossing
// over
// p2
Point p3 = pts.get((i + 1) % N); // next vertex
if (p.getLat() >= Math.min(p1.getLat(), p3.getLat())
&& p.getLat() <= Math.max(p1.getLat(), p3.getLat())) {// p.lat
// lies
// between
// p1.lat
// &
// p3.lat
++intersectCount;
} else {
intersectCount += 2;
}
}
}
p1 = p2;// next ray left point
}
if (intersectCount % 2 == 0) {// 偶数在多边形外
return false;
} else { // 奇数在多边形内
return true;
}
}
private static double degreeToRad(double degree) {
return Math.PI * degree / 180;
}
private static double radToDegree(double rad) {
return (180 * rad) / Math.PI;
}
private static double getRange(double v, double a, double b) {
v = Math.min(Math.max(v, a), b);
return v;
}
private static double getLoop(double v, double a, double b) {
while (v > b) {
v -= b - a;
}
while (v < a) {
v += b - a;
}
return v;
}
/**
* 判断点是否在某个路段
* @param ps
* @param p
* @return
*/
public static boolean isInSection(List<Point> ps, Point p) {
for (int i = 0, len = ps.size();i < len - 1;i++) {
if (isInSection(ps.get(i), ps.get(i + 1), p)) return true;
}
return false;
}
/**
* 判断点是否在某个线段上
* @param lp1
* @param lp2
* @param p
* @return
*/
private static boolean isInSection(Point lp1, Point lp2, Point p) {
double a = lp1.getLat() - lp2.getLat(), b = lp2.getLon() - lp1.getLon(), c = lp1.getLon()*lp2.getLat() - lp2.getLon()*lp1.getLat();
double lon = (Math.pow(b, 2)*p.getLon() - a*b*p.getLat() - a*c)/(Math.pow(a, 2) + Math.pow(b, 2));
double lat = (Math.pow(a, 2)*p.getLat() - a*b*p.getLon() - b*c)/(Math.pow(a, 2) + Math.pow(b, 2));
Point vp = new Point(lon, lat);
return getDistance(p, vp) < INLINE_THRESHOLD && isBetween(lp1, lp2, vp);
}
private static boolean isBetween(Point lp1, Point lp2, Point p) {
double lon1 = lp1.getLon(), lat1 = lp1.getLat();
double lon2 = lp2.getLon(), lat2 = lp2.getLat();
double lon = p.getLon(), lat = p.getLat();
return (lon > lon1 && lon < lon2 || lon > lon2 && lon < lon1) || (lat > lat1 && lat < lat2 || lat > lat2 && lat < lat1);
}
public static boolean isDrift(Point p1, Point p2) {
return getDistance(p1, p2) > DRIFT_THRESHOLD;
}
public static double getDistance(Point p1, Point p2) {
double lng1 = getLoop(p1.getLon(), -180, 180), lat1 = getRange(
p1.getLat(), -74, 74);
double lng2 = getLoop(p2.getLon(), -180, 180), lat2 = getRange(
p2.getLat(), -74, 74);
double x1, x2, y1, y2;
x1 = degreeToRad(lng1);
y1 = degreeToRad(lat1);
x2 = degreeToRad(lng2);
y2 = degreeToRad(lat2);
return EARTH_RADIUS
* Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1)
* Math.cos(y2) * Math.cos(x2 - x1)));
}
public static void main(String args[]) {
String a = "121.644416 31.195991, 121.643949 31.195928, 121.64364 31.195886";
List<Point> points = new ArrayList<>();
for(String t1 : a.split(", ")){
String[] arr = t1.split(" ");
Point p = new Point(Double.parseDouble(arr[0]), Double.parseDouble(arr[1]));
points.add(p);
}
System.out.println(isInSection(points, new Point(121.644416, 31.195991)));
}
}