wg-basic/basic-util/src/main/java/ink/wgink/util/point/PointUtil.java

403 lines
14 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}