我是靠谱客的博主 甜美酒窝,最近开发中收集的这篇文章主要介绍通过经纬度判断两个多边形是否相交或重合,并获取重合面积,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

工具类


/**
* @program:
* @description 获取两条经纬度线段的交点坐标工具类
* @author: wys
* @create: 2020-11-27 09:21
**/
public class GisCheckUtils {
private static Logger log = LoggerFactory.getLogger(GisCheckUtils.class);
/**
* 地球周长
*/
private static double L = 6381372 * Math.PI * 2;
/**
* 平面展开后,x轴等于周长
*/
private static double W = L;
/**
* y轴约等于周长一半
*/
private static double H = L / 2;
/**
* 米勒投影中的一个常数,范围大约在正负2.3之间
*/
private static double mill = 2.3;
/**
* 将经纬度转换成X和Y轴
* 米勒投影算法
*
* @param lat 纬度
* @param lon 经度
* @return
*/
private static Point millierConvertion(double lat, double lon) {
// 将经度从度数转换为弧度
double x = lon * Math.PI / 180;
// 将纬度从度数转换为弧度
double y = lat * Math.PI / 180;
// 米勒投影的转换
y = 1.25 * Math.log(Math.tan(0.25 * Math.PI + 0.4 * y));
// 弧度转为实际距离
x = (W / 2) + (W / (2 * Math.PI)) * x;
y = (H / 2) - (H / (2 * mill)) * y;
return new Point(x, y);
}
/**
* xy轴转坐标
*
* @param x
* @param y
* @return 坐标点
*/
private static Location xyToLocation(double x, double y) {
//实际距离 转为弧度
x = (x - (W / 2)) / (W / (2 * Math.PI));
y = -1 * (y - (H / 2)) / (H / (2 * mill));
// 米勒投影的转换反转
y = (Math.atan(Math.pow(Math.E, y / 1.25)) - 0.25 * Math.PI) / 0.4;
//将经度从弧度转换为度数
double lon = 180 / Math.PI * x;
//将纬度从弧度转换为度数
double lat = 180 / Math.PI * y;
return new Location(lon, lat);
}
/**
* 获取两条直线相交的点
*
* @param LineOne 线段一
* @param LineTwo 线段二
* @return 相交点坐标
为null 不相交
*/
public static Location getIntersectPoint(Line LineOne, Line LineTwo) {
//先判断有没有相交 (延长线不算) 不相交返回null 相交执行获取交点坐标 (如需获取延长线交点注释此方法)----
if (!segIntersect(LineOne, LineTwo)) {
return null;
}
//转换对象
Point[] points = LineToPoint(LineOne, LineTwo);
//获取两条直线相交的点
Point Location = getIntersectPoint(points[0], points[1], points[2], points[3]);
if (Location != null) {
return xyToLocation(Location.x, Location.y);
}
return null;
}
/**
* 获取两条直线list所有相交的点
*
* @param LineOneList 线段集合一
* @param LineTwoList 线段集合二
* @return 相交点坐标
为null 不相交
*/
public static List<Location> getIntersectPointList(List<Line> LineOneList, List<Line> LineTwoList) {
List<Location> locationList = new ArrayList<>();
for (Line line : LineOneList) {
for (Line line1 : LineTwoList) {
Location location = getIntersectPoint(line,line1);
if (Objects.nonNull(location)) {
locationList.add(location);
}
}
}
return locationList;
}
/**
* 获取两条直线相交的点
*
* @param p1 线段一 开始点
* @param p2 线段一 结束点
* @param p3 线段二 开始点
* @param p4 线段二 结束点
* @return
*/
public static Point getIntersectPoint(Point p1, Point p2, Point p3, Point p4) {
double A1 = p1.getY() - p2.getY();
double B1 = p2.getX() - p1.getX();
double C1 = A1 * p1.getX() + B1 * p1.getY();
double A2 = p3.getY() - p4.getY();
double B2 = p4.getX() - p3.getX();
double C2 = A2 * p3.getX() + B2 * p3.getY();
double det_k = A1 * B2 - A2 * B1;
if (Math.abs(det_k) < 0.00001) {
return null;
}
double a = B2 / det_k;
double b = -1 * B1 / det_k;
double c = -1 * A2 / det_k;
double d = A1 / det_k;
double x = a * C1 + b * C2;
double y = c * C1 + d * C2;
return new Point(x, y);
}
/**
* 验证两条线有没有相交
*
* @param LineOne 线段1
* @param LineTwo 线段2
* @return true 相交
*/
public static boolean segIntersect(Line LineOne, Line LineTwo) {
//转换对象
Point[] points = LineToPoint(LineOne, LineTwo);
//验证两条线有没有相交
return segIntersect(points[0], points[1], points[2], points[3]) > 0;
}
/**
* 线段转换为点对象
*
* @param LineOne 线段一
* @param LineTwo 线段二
* @return 点对象数组
*/
private static Point[] LineToPoint(Line LineOne, Line LineTwo) {
//线段1
Double oneStartLat = LineOne.getStartLocation().getLat();
Double oneStartLon = LineOne.getStartLocation().getLon();
Double oneEndLat = LineOne.getEndLocation().getLat();
Double oneEndLon = LineOne.getEndLocation().getLon();
// 线段2
Double twoStartLat = LineTwo.getStartLocation().getLat();
Double twoStartLon = LineTwo.getStartLocation().getLon();
Double twoEndLat = LineTwo.getEndLocation().getLat();
Double twoEndLon = LineTwo.getEndLocation().getLon();
Point[] points = new Point[4];
//将经纬度转换成X和Y轴
points[0] = millierConvertion(oneStartLat, oneStartLon);
points[1] = millierConvertion(oneEndLat, oneEndLon);
points[2] = millierConvertion(twoStartLat, twoStartLon);
points[3] = millierConvertion(twoEndLat, twoEndLon);
return points;
}
/**
* 验证两条线有没有相交
*
* @param A 线段一 开始点
* @param B 线段一 结束点
* @param C 线段二 开始点
* @param D 线段二 结束点
* @return
*/
public static int segIntersect(Point A, Point B, Point C, Point D) {
Point intersection = new Point();
if (Math.abs(B.getY() - A.getY()) + Math.abs(B.getX() - A.getX()) + Math.abs(D.getY() - C.getY())
+ Math.abs(D.getX() - C.getX()) == 0) {
if ((C.getX() - A.getX()) + (C.getY() - A.getY()) == 0) {
log.info("ABCD是同一个点!");
} else {
log.info("AB是一个点,CD是一个点,且AC不同!");
}
return 0;
}
if (Math.abs(B.getY() - A.getY()) + Math.abs(B.getX() - A.getX()) == 0) {
if ((A.getX() - D.getX()) * (C.getY() - D.getY()) - (A.getY() - D.getY()) * (C.getX() - D.getX()) == 0) {
log.info("A、B是一个点,且在CD线段上!");
} else {
log.info("A、B是一个点,且不在CD线段上!");
}
return 0;
}
if (Math.abs(D.getY() - C.getY()) + Math.abs(D.getX() - C.getX()) == 0) {
if ((D.getX() - B.getX()) * (A.getY() - B.getY()) - (D.getY() - B.getY()) * (A.getX() - B.getX()) == 0) {
log.info("C、D是一个点,且在AB线段上!");
} else {
log.info("C、D是一个点,且不在AB线段上!");
}
return 0;
}
if ((B.getY() - A.getY()) * (C.getX() - D.getX()) - (B.getX() - A.getX()) * (C.getY() - D.getY()) == 0) {
log.info("线段平行,无交点!");
return 0;
}
intersection
.setX(((B.getX() - A.getX()) * (C.getX() - D.getX())
* (C.getY() - A.getY()) - C.getX()
* (B.getX() - A.getX()) * (C.getY() - D.getY()) + A
.getX() * (B.getY() - A.getY()) * (C.getX() - D.getX()))
/ ((B.getY() - A.getY()) * (C.getX() - D.getX()) - (B
.getX() - A.getX()) * (C.getY() - D.getY())));
intersection
.setY(((B.getY() - A.getY()) * (C.getY() - D.getY())
* (C.getX() - A.getX()) - C.getY()
* (B.getY() - A.getY()) * (C.getX() - D.getX()) + A
.getY() * (B.getX() - A.getX()) * (C.getY() - D.getY()))
/ ((B.getX() - A.getX()) * (C.getY() - D.getY()) - (B
.getY() - A.getY()) * (C.getX() - D.getX())));
if ((intersection.getX() - A.getX()) * (intersection.getX() - B.getX()) <= 0
&& (intersection.getX() - C.getX())
* (intersection.getX() - D.getX()) <= 0
&& (intersection.getY() - A.getY())
* (intersection.getY() - B.getY()) <= 0
&& (intersection.getY() - C.getY())
* (intersection.getY() - D.getY()) <= 0) {
if ((A.getX() == C.getX() && A.getY() == C.getY()) || (A.getX() == D.getX() && A.getY() == D.getY())
|| (B.getX() == C.getX() && B.getY() == C.getY()) || (B.getX() == D.getX() && B.getY() == D.getY())) {
log.info("线段相交于端点上");
return 2;
} else {
log.info("线段相交于点(" + intersection.getX() + ","
+ intersection.getY() + ")!");
//相交
return 1;
}
} else {
log.info("线段相交于虚交点(" + intersection.getX() + ","
+ intersection.getY() + ")!");
//相交但不在线段上
return -1;
}
}
/**
* 点对象
*/
public static class Point {
private double x;
private double y;
public Point() {
}
public Point(double x, double y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return
x
+ ","+ y ;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
/**
* 球面积计算公式
*
* @param locationList
* @return
*/
public static double calculatePolygonArea(List<Location> locationList) {
double area = 0;
int size = locationList.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 = locationList.get(size - 1).getLon() * Math.PI / 180;
LowY = locationList.get(size - 1).getLat() * Math.PI / 180;
MiddleX = locationList.get(0).getLon() * Math.PI / 180;
MiddleY = locationList.get(0).getLat() * Math.PI / 180;
HighX = locationList.get(1).getLon() * Math.PI / 180;
HighY = locationList.get(1).getLat() * Math.PI / 180;
} else if (i == size - 1) {
LowX = locationList.get(size - 2).getLon() * Math.PI / 180;
LowY = locationList.get(size - 2).getLat() * Math.PI / 180;
MiddleX = locationList.get(size - 1).getLon() * Math.PI / 180;
MiddleY = locationList.get(size - 1).getLat() * Math.PI / 180;
HighX = locationList.get(0).getLon() * Math.PI / 180;
HighY = locationList.get(0).getLat() * Math.PI / 180;
} else {
LowX = locationList.get(i - 1).getLon() * Math.PI / 180;
LowY = locationList.get(i - 1).getLat() * Math.PI / 180;
MiddleX = locationList.get(i).getLon() * Math.PI / 180;
MiddleY = locationList.get(i).getLat() * Math.PI / 180;
HighX = locationList.get(i + 1).getLon() * Math.PI / 180;
HighY = locationList.get(i + 1).getLat() * 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 circleList
* @param locationList
* @return
*/
private static double CoincidentArea(List<Location> circleList, List<Location> locationList) {
List<Location> areaList = new ArrayList<>();
//先处理所有的点,防止顺序不对
circleList = sortLocation(circleList);
locationList = sortLocation(locationList);
//获取圈地线段
List<Line> circleLineList = getLines(circleList);
//获取线段
List<Line> lineList = getLines(locationList);
//判断是否相交
boolean isIntersect = isIntersect(circleLineList, lineList);
if (isIntersect) {
areaList = GisCheckUtils.getIntersectPointList(circleLineList, lineList);
//判断圈地的点是否在范围内
for (Location location : circleList) {
boolean isPointInPolygon = isPointInPolygon(location, locationList);
if (isPointInPolygon){
areaList.add(location);
}
}
//判断是否在圈地的点范围内
for (Location location : locationList) {
boolean isPointInPolygon = isPointInPolygon(location, circleList);
if (isPointInPolygon) {
areaList.add(location);
}
}
double area = GisCheckUtils.calculatePolygonArea(sortLocation(areaList));
log.info("重合区域面积为: " + area + "平方米");
return area;
}
//如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含
//先判断圈地是否被包含
boolean isPointInPolygon = isPolygonInPolygon(circleList,locationList);
if (isPointInPolygon) {
double area = GisCheckUtils.calculatePolygonArea(circleList);
log.info("重合区域面积为: " + area + "平方米");
return area;
}
//如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含
//再判断圈地是否包含
isPointInPolygon = isPolygonInPolygon(locationList,circleList);
if (isPointInPolygon) {
double area = GisCheckUtils.calculatePolygonArea(locationList);
log.info("重合区域面积为: " + area + "平方米");
return area;
}
return
0;
}
/**
* 判断第一个多边形是否存在一个点在第二个多边形内
*
* @param locationList1
* @param locationList2
* @return
*/
private static boolean isPolygonInPolygon(List<Location> locationList1, List<Location> locationList2) {
//判断第一个多边形是否在第二个多边形内
for (Location location : locationList1) {
boolean isPointInPolygon = isPointInPolygon(location, locationList2);
if (isPointInPolygon) return true;
}
return false;
}
/**
* 判断第一个多边形是否全部在第二个多边形内
*
* @param locationList1
* @param locationList2
* @return
*/
private static boolean isPolygonAllInPolygon(List<Location> locationList1, List<Location> locationList2) {
//判断第一个多边形是否在第二个多边形内
for (Location location : locationList1) {
boolean isPointInPolygon = isPointInPolygon(location, locationList2);
if (!isPointInPolygon) return false;
}
return true;
}
/**
* 判断点是否在多边形内
*
* @param location
* @param locationList2
* @return
*/
private static boolean isPointInPolygon(Location location, List<Location> locationList2) {
//点是否在多边形内
GeneralPath path = new GeneralPath();
//设定多边形起始点
path.moveTo(locationList2.get(0).getLon(), locationList2.get(0).getLat());
for (Location l : locationList2) {
path.lineTo(l.getLon(), l.getLat());
}
//图像完成,封闭
path.moveTo(locationList2.get(0).getLon(), locationList2.get(0).getLat());
//多边形结束
path.closePath();
return path.contains(location.getLon(), location.getLat());
}
/**
* 判断线段是否相交
*
* @param lineList
* @param lineList2
* @return
*/
private static boolean isIntersect(List<Line> lineList, List<Line> lineList2) {
for (Line line : lineList) {
for (Line line1 : lineList2) {
//两条线段是否相交
boolean b = Line2D.linesIntersect(line.getStartLocation().getLon(), line.getStartLocation().getLat(), line.getEndLocation().getLon(), line.getEndLocation().getLat(),
line1.getStartLocation().getLon(), line1.getStartLocation().getLat(), line1.getEndLocation().getLon(), line1.getEndLocation().getLat());
if (b) {
return true;
}
}
}
return false;
}
/**
* 根据点获取线段
*
* @param locationList
* @return
*/
private static List<Line> getLines(List<Location> locationList) {
List<Line> lineList = new ArrayList();
for (int i = 0; i < locationList.size(); i++) {
if (i < locationList.size() - 1) {
Location l = locationList.get(i);
Location l2 = locationList.get(i + 1);
Line line = new Line(l, l2);
lineList.add(line);
} else {
Location l = locationList.get(i);
Location l2 = locationList.get(0);
Line line = new Line(l, l2);
lineList.add(line);
}
}
return lineList;
}
/**
* 将多边形的点排序
*
* @param locationList
* @return
*/
private static List<Location> sortLocation(List<Location> locationList) {
double plusX = 0, plusY = 0;
for (Location location : locationList) {
plusX += location.getLon();
plusY += location.getLat();
}
Location location = new Location(plusX / locationList.size(), plusY / locationList.size());
Map<Integer,List> mapAll = new HashMap<>();
for (int i = 0; i < locationList.size(); i++) {
//第一个放经纬度 第二个放角度
List objList = new ArrayList<>();
objList.add(locationList.get(i));
objList.add(getAngle1(location.getLat(), location.getLon(),
locationList.get(i).getLat(), locationList.get(i).getLon()));
mapAll.put(i, objList);
}
List temp = new ArrayList<>();
int size = mapAll.size();
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - 1 - i; j++) {
if (Double.parseDouble(mapAll.get(j).get(1).toString()) >
Double.parseDouble(mapAll.get(j + 1).get(1).toString())) //交换两数位置
{
temp = mapAll.get(j);
mapAll.put(j, mapAll.get(j + 1));
mapAll.put(j + 1, temp);
}
}
}
//生成新的顺时针的坐标点集合
locationList.clear();
for (Integer integer : mapAll.keySet()) {
if (mapAll.get(integer).get(0) instanceof Location) {
locationList.add((Location) mapAll.get(integer).get(0));
}
}
return
locationList;
}
/**
* 将多边形的点排序
*
* @param lat_a 纬度1
* @param lng_a 经度1
* @param lat_b 纬度2
* @param lng_b 经度2
* @return
*/
private static double getAngle1(double lat_a, double lng_a, double lat_b, double lng_b) {
double y = Math.sin(lng_b - lng_a) * Math.cos(lat_b);
double x = Math.cos(lat_a) * Math.sin(lat_b) - Math.sin(lat_a) * Math.cos(lat_b) * Math.cos(lng_b - lng_a);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
if (brng < 0)
brng = brng + 360;
return brng;
}
}

点坐标实体类

/**
* 经纬度坐标实体类
*
*/
public class Location {
private double lon;
private double lat;
public Location() {
}
public Location(double lon, double lat) {
this.lon = lon;
this.lat = lat;
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
}

线段实体类

public class Line {
private Location startLocation;//起点
private Location endLocation;//终点
public Line() {
}
public Line(Location startLocation, Location endLocation) {
this.startLocation = startLocation;
this.endLocation = endLocation;
}
public Location getStartLocation() {
return startLocation;
}
public void setStartLocation(Location startLocation) {
this.startLocation = startLocation;
}
public Location getEndLocation() {
return endLocation;
}
public void setEndLocation(Location endLocation) {
this.endLocation = endLocation;
}
@Override
public String toString() {
return "Line{" +
"startLocation=" + startLocation +
", endLocation=" + endLocation +
'}';
}
}

最后

以上就是甜美酒窝为你收集整理的通过经纬度判断两个多边形是否相交或重合,并获取重合面积的全部内容,希望文章能够帮你解决通过经纬度判断两个多边形是否相交或重合,并获取重合面积所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(88)

评论列表共有 0 条评论

立即
投稿
返回
顶部