403 lines
14 KiB
Java
403 lines
14 KiB
Java
package ink.wgink.util.point;
|
||
|
||
import java.math.BigDecimal;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* When you feel like quitting. Think about why you started
|
||
* 当你想要放弃的时候,想想当初你为何开始
|
||
*
|
||
* @ClassName: PointUtil
|
||
* @Description: 点工具类
|
||
* @Author: WangGeng
|
||
* @Date: 2019-08-09 22:43
|
||
* @Version: 1.0
|
||
**/
|
||
public class PointUtil {
|
||
|
||
private static final double EARTH_RADIUS = 637_1393.00D;
|
||
private static final double RADIAN = Math.PI / 180.00D;
|
||
private static final double HALF = 0.5D;
|
||
|
||
public static final double MIN_LAT = -90;
|
||
public static final double MAX_LAT = 90;
|
||
public static final double MIN_LNG = -180;
|
||
public static final double MAX_LNG = 180;
|
||
|
||
/**
|
||
* 点在多边形内
|
||
*
|
||
* @param point
|
||
* @param points
|
||
* @return
|
||
*/
|
||
public static boolean isPointInPoly(Point point, List<Point> points) {
|
||
int N = points.size();
|
||
//如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
|
||
boolean boundOrVertex = true;
|
||
//cross points count of x
|
||
int intersectCount = 0;
|
||
//浮点类型计算时候与0比较时候的容差
|
||
double precision = 2e-10;
|
||
//neighbour bound vertices
|
||
Point p1, p2;
|
||
//当前点
|
||
Point p = point;
|
||
//left vertex
|
||
p1 = points.get(0);
|
||
//check all rays
|
||
for (int i = 1; i <= N; ++i) {
|
||
if (p.equals(p1)) {
|
||
//p is an vertex
|
||
return boundOrVertex;
|
||
}
|
||
//right vertex
|
||
p2 = points.get(i % N);
|
||
//ray is outside of our interests
|
||
if (p.getX() < Math.min(p1.getX(), p2.getX()) || p.getX() > Math.max(p1.getX(), p2.getX())) {
|
||
p1 = p2;
|
||
continue;//next ray left point
|
||
}
|
||
//ray is crossing over by the algorithm (common part of)
|
||
if (p.getX() > Math.min(p1.getX(), p2.getX()) && p.getX() < Math.max(p1.getX(), p2.getX())) {
|
||
//x is before of ray
|
||
if (p.getY() <= Math.max(p1.getY(), p2.getY())) {
|
||
//overlies on a horizontal ray
|
||
if (p1.getX() == p2.getX() && p.getY() >= Math.min(p1.getY(), p2.getY())) {
|
||
return boundOrVertex;
|
||
}
|
||
//ray is vertical
|
||
if (p1.getY() == p2.getY()) {
|
||
//overlies on a vertical ray
|
||
if (p1.getY() == p.getY()) {
|
||
return boundOrVertex;
|
||
} else {
|
||
//before ray
|
||
++intersectCount;
|
||
}
|
||
} else {
|
||
//cross point on the left side
|
||
//cross point of y
|
||
double xinters = (p.getX() - p1.getX()) * (p2.getY() - p1.getY()) / (p2.getX() - p1.getX()) + p1.getY();
|
||
//overlies on a ray
|
||
if (Math.abs(p.getY() - xinters) < precision) {
|
||
return boundOrVertex;
|
||
}
|
||
//before ray
|
||
if (p.getY() < xinters) {
|
||
++intersectCount;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
//special case when ray is crossing through the vertex
|
||
//p crossing over p2
|
||
if (p.getX() == p2.getX() && p.getY() <= p2.getY()) {
|
||
//next vertex
|
||
Point p3 = points.get((i + 1) % N);
|
||
//p.x lies between p1.x & p3.x
|
||
if (p.getX() >= Math.min(p1.getX(), p3.getX()) && p.getX() <= Math.max(p1.getX(), p3.getX())) {
|
||
++intersectCount;
|
||
} else {
|
||
intersectCount += 2;
|
||
}
|
||
}
|
||
}
|
||
//next ray left point
|
||
p1 = p2;
|
||
}
|
||
if (intersectCount % 2 == 0) {
|
||
//偶数在多边形外
|
||
return false;
|
||
} else {
|
||
//奇数在多边形内
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 判断是否在圆形内
|
||
* <p>
|
||
* 判断点与圆心之间的距离和圆半径的关系
|
||
*
|
||
* @param p
|
||
* @param c
|
||
* @return
|
||
*/
|
||
public static int distencePC(Point p, Circle c) {
|
||
int s;
|
||
double d2 = Math.hypot((p.getX() - c.getPoint().getX()), (p.getY() - c.getPoint().getY()));
|
||
double r = c.getR();
|
||
if (d2 > r) {
|
||
// 圆外
|
||
s = -1;
|
||
} else if (d2 < r) {
|
||
// 圆内
|
||
s = 1;
|
||
} else {
|
||
// 圆上
|
||
s = 0;
|
||
}
|
||
return s;
|
||
}
|
||
|
||
/**
|
||
* 计算距离,Point的x为纬度,y为经度
|
||
*
|
||
* @param point1
|
||
* @param point2
|
||
* @return
|
||
*/
|
||
public static double getDistance(Point point1, Point point2) {
|
||
double lat1 = point1.getX();
|
||
double lon1 = point1.getY();
|
||
double lat2 = point2.getX();
|
||
double lon2 = point2.getY();
|
||
double x, y, a, b, distance;
|
||
|
||
lat1 *= RADIAN;
|
||
lat2 *= RADIAN;
|
||
x = lat1 - lat2;
|
||
y = lon1 - lon2;
|
||
y *= RADIAN;
|
||
a = Math.sin(x * HALF);
|
||
b = Math.sin(y * HALF);
|
||
distance = EARTH_RADIUS * Math.asin(Math.sqrt(a * a + Math.cos(lat1) * Math.cos(lat2) * b * b)) / HALF;
|
||
return new BigDecimal(distance).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
|
||
}
|
||
|
||
/**
|
||
* 计算面积
|
||
*
|
||
* @param points
|
||
* @return
|
||
*/
|
||
public static double getSqua(List<Point> points) {
|
||
double area = 0;
|
||
int size = points.size();
|
||
if (size > 2) {
|
||
double LowX = 0.0;
|
||
double LowY = 0.0;
|
||
double MiddleX = 0.0;
|
||
double MiddleY = 0.0;
|
||
double HighX = 0.0;
|
||
double HighY = 0.0;
|
||
|
||
double AM = 0.0;
|
||
double BM = 0.0;
|
||
double CM = 0.0;
|
||
|
||
double AL = 0.0;
|
||
double BL = 0.0;
|
||
double CL = 0.0;
|
||
|
||
double AH = 0.0;
|
||
double BH = 0.0;
|
||
double CH = 0.0;
|
||
|
||
double CoefficientL = 0.0;
|
||
double CoefficientH = 0.0;
|
||
|
||
double ALtangent = 0.0;
|
||
double BLtangent = 0.0;
|
||
double CLtangent = 0.0;
|
||
|
||
double AHtangent = 0.0;
|
||
double BHtangent = 0.0;
|
||
double CHtangent = 0.0;
|
||
|
||
double ANormalLine = 0.0;
|
||
double BNormalLine = 0.0;
|
||
double CNormalLine = 0.0;
|
||
|
||
double OrientationValue = 0.0;
|
||
|
||
double AngleCos = 0.0;
|
||
|
||
double Sum1 = 0.0;
|
||
double Sum2 = 0.0;
|
||
double Count2 = 0;
|
||
double Count1 = 0;
|
||
|
||
double Sum = 0.0;
|
||
double Radius = 6378000;
|
||
|
||
for (int i = 0; i < size; i++) {
|
||
if (i == 0) {
|
||
LowX = points.get(size - 1).getX() * Math.PI / 180;
|
||
LowY = points.get(size - 1).getY() * Math.PI / 180;
|
||
MiddleX = points.get(0).getX() * Math.PI / 180;
|
||
MiddleY = points.get(0).getY() * Math.PI / 180;
|
||
HighX = points.get(1).getX() * Math.PI / 180;
|
||
HighY = points.get(1).getY() * Math.PI / 180;
|
||
} else if (i == size - 1) {
|
||
LowX = points.get(size - 2).getX() * Math.PI / 180;
|
||
LowY = points.get(size - 2).getY() * Math.PI / 180;
|
||
MiddleX = points.get(size - 1).getX() * Math.PI / 180;
|
||
MiddleY = points.get(size - 1).getY() * Math.PI / 180;
|
||
HighX = points.get(0).getX() * Math.PI / 180;
|
||
HighY = points.get(0).getY() * Math.PI / 180;
|
||
} else {
|
||
LowX = points.get(i - 1).getX() * Math.PI / 180;
|
||
LowY = points.get(i - 1).getY() * Math.PI / 180;
|
||
MiddleX = points.get(i).getX() * Math.PI / 180;
|
||
MiddleY = points.get(i).getY() * Math.PI / 180;
|
||
HighX = points.get(i + 1).getX() * Math.PI / 180;
|
||
HighY = points.get(i + 1).getY() * Math.PI / 180;
|
||
}
|
||
|
||
AM = Math.cos(MiddleY) * Math.cos(MiddleX);
|
||
BM = Math.cos(MiddleY) * Math.sin(MiddleX);
|
||
CM = Math.sin(MiddleY);
|
||
AL = Math.cos(LowY) * Math.cos(LowX);
|
||
BL = Math.cos(LowY) * Math.sin(LowX);
|
||
CL = Math.sin(LowY);
|
||
AH = Math.cos(HighY) * Math.cos(HighX);
|
||
BH = Math.cos(HighY) * Math.sin(HighX);
|
||
CH = Math.sin(HighY);
|
||
|
||
CoefficientL = (AM * AM + BM * BM + CM * CM) / (AM * AL + BM * BL + CM * CL);
|
||
CoefficientH = (AM * AM + BM * BM + CM * CM) / (AM * AH + BM * BH + CM * CH);
|
||
|
||
ALtangent = CoefficientL * AL - AM;
|
||
BLtangent = CoefficientL * BL - BM;
|
||
CLtangent = CoefficientL * CL - CM;
|
||
AHtangent = CoefficientH * AH - AM;
|
||
BHtangent = CoefficientH * BH - BM;
|
||
CHtangent = CoefficientH * CH - CM;
|
||
|
||
AngleCos = (AHtangent * ALtangent + BHtangent * BLtangent + CHtangent * CLtangent) / (
|
||
Math.sqrt(AHtangent * AHtangent + BHtangent * BHtangent + CHtangent * CHtangent)
|
||
* Math.sqrt(ALtangent * ALtangent + BLtangent * BLtangent
|
||
+ CLtangent * CLtangent));
|
||
|
||
AngleCos = Math.acos(AngleCos);
|
||
|
||
ANormalLine = BHtangent * CLtangent - CHtangent * BLtangent;
|
||
BNormalLine = 0 - (AHtangent * CLtangent - CHtangent * ALtangent);
|
||
CNormalLine = AHtangent * BLtangent - BHtangent * ALtangent;
|
||
|
||
if (AM != 0) {
|
||
OrientationValue = ANormalLine / AM;
|
||
} else if (BM != 0) {
|
||
OrientationValue = BNormalLine / BM;
|
||
} else {
|
||
OrientationValue = CNormalLine / CM;
|
||
}
|
||
|
||
if (OrientationValue > 0) {
|
||
Sum1 += AngleCos;
|
||
Count1++;
|
||
|
||
} else {
|
||
Sum2 += AngleCos;
|
||
Count2++;
|
||
//Sum +=2*Math.PI-AngleCos;
|
||
}
|
||
}
|
||
if (Sum1 > Sum2) {
|
||
Sum = Sum1 + (2 * Math.PI * Count2 - Sum2);
|
||
} else {
|
||
Sum = (2 * Math.PI * Count1 - Sum1) + Sum2;
|
||
}
|
||
//平方米
|
||
area = (Sum - (size - 2) * Math.PI) * Radius * Radius;
|
||
}
|
||
return Math.abs(area);
|
||
}
|
||
|
||
/**
|
||
* 计算中心点
|
||
*
|
||
* @param mPoints
|
||
* @return
|
||
*/
|
||
public static Point getCenterPoint(List<Point> mPoints) {
|
||
double latitude = (getMinLatitude(mPoints) + getMaxLatitude(mPoints)) / 2;
|
||
double longitude = (getMinLongitude(mPoints) + getMaxLongitude(mPoints)) / 2;
|
||
return new Point(latitude, longitude);
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取不规则多边形重心点
|
||
*
|
||
* @param mPoints
|
||
* @return
|
||
*/
|
||
public static Point getCenterOfGravityPoint(List<Point> mPoints) {
|
||
double area = 0.0;//多边形面积
|
||
double Gx = 0.0, Gy = 0.0;// 重心的x、y
|
||
for (int i = 1; i <= mPoints.size(); i++) {
|
||
double iLat = mPoints.get(i % mPoints.size()).getX();
|
||
double iLng = mPoints.get(i % mPoints.size()).getY();
|
||
double nextLat = mPoints.get(i - 1).getX();
|
||
double nextLng = mPoints.get(i - 1).getY();
|
||
double temp = (iLat * nextLng - iLng * nextLat) / 2.0;
|
||
area += temp;
|
||
Gx += temp * (iLat + nextLat) / 3.0;
|
||
Gy += temp * (iLng + nextLng) / 3.0;
|
||
}
|
||
Gx = Gx / area;
|
||
Gy = Gy / area;
|
||
return new Point(Gx, Gy);
|
||
}
|
||
|
||
// 经度最小值
|
||
public static double getMinLongitude(List<Point> mPoints) {
|
||
double minLongitude = MAX_LNG;
|
||
if (mPoints.size() > 0) {
|
||
minLongitude = mPoints.get(0).getY();
|
||
for (Point latlng : mPoints) {
|
||
// 经度最小值
|
||
if (latlng.getY() < minLongitude)
|
||
minLongitude = latlng.getY();
|
||
}
|
||
}
|
||
return minLongitude;
|
||
}
|
||
|
||
// 经度最大值
|
||
public static double getMaxLongitude(List<Point> mPoints) {
|
||
double maxLongitude = MIN_LNG;
|
||
if (mPoints.size() > 0) {
|
||
maxLongitude = mPoints.get(0).getY();
|
||
for (Point latlng : mPoints) {
|
||
// 经度最大值
|
||
if (latlng.getY() > maxLongitude)
|
||
maxLongitude = latlng.getY();
|
||
}
|
||
}
|
||
return maxLongitude;
|
||
}
|
||
|
||
// 纬度最小值
|
||
public static double getMinLatitude(List<Point> mPoints) {
|
||
double minLatitude = MAX_LAT;
|
||
if (mPoints.size() > 0) {
|
||
minLatitude = mPoints.get(0).getX();
|
||
for (Point latlng : mPoints) {
|
||
// 纬度最小值
|
||
if (latlng.getX() < minLatitude)
|
||
minLatitude = latlng.getX();
|
||
}
|
||
}
|
||
return minLatitude;
|
||
}
|
||
|
||
// 纬度最大值
|
||
public static double getMaxLatitude(List<Point> mPoints) {
|
||
double maxLatitude = MIN_LAT;
|
||
if (mPoints.size() > 0) {
|
||
maxLatitude = mPoints.get(0).getX();
|
||
for (Point latlng : mPoints) {
|
||
// 纬度最大值
|
||
if (latlng.getX() > maxLatitude)
|
||
maxLatitude = latlng.getX();
|
||
}
|
||
}
|
||
return maxLatitude;
|
||
}
|
||
|
||
}
|