package com.ruoyi.system.utils;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.system.domain.TbRail;
import com.ruoyi.system.domain.TbRailPoint;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class RailUtil {
/**
* 找到多边形边界上一个点,使得这个点与多边形外面的指定点距离最短
* @param railPointList
* @param point
* @return
*/
public static TbRailPoint findClosestPointOnPolygonBoundary(List railPointList, TbRailPoint point){
TbRailPoint rtn = new TbRailPoint();
rtn.setLongitude(BigDecimal.ZERO);
rtn.setLatitude(BigDecimal.ZERO);
Point2D.Double closestPointOnPolygonBoundary = findClosestPointOnPolygonBoundary(railPointList, new Point2D.Double(point.getLongitude().doubleValue(), point.getLatitude().doubleValue()));
if (Objects.isNull(closestPointOnPolygonBoundary)){
return rtn;
}
rtn.setLongitude(BigDecimal.valueOf(closestPointOnPolygonBoundary.x));
rtn.setLatitude(BigDecimal.valueOf(closestPointOnPolygonBoundary.y));
return rtn;
}
public static Point2D.Double findClosestPointOnPolygonBoundary(List polygonVertices, Point2D.Double externalPoint) {
double minDistance = Double.MAX_VALUE;
Point2D.Double closestPoint = null;
// 遍历多边形的每条边
for (int i = 0; i < polygonVertices.size(); i++) {
Point2D.Double p1 = polygonVertices.get(i);
Point2D.Double p2 = polygonVertices.get((i + 1) % polygonVertices.size()); // 循环到下一个顶点
// 计算边与externalPoint的最近点
Point2D.Double nearestOnEdge = findNearestPointOnLineSegment(p1, p2, externalPoint);
// 计算距离
double distance = distance(externalPoint, nearestOnEdge);
// 更新最小距离和对应的点
if (distance < minDistance) {
minDistance = distance;
closestPoint = nearestOnEdge;
}
}
return closestPoint;
}
// 计算两点之间的距离
public static double distance(Point2D.Double p1, Point2D.Double p2) {
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
// 找到线段上与点P最近的点
public static Point2D.Double findNearestPointOnLineSegment(Point2D.Double p, Point2D.Double q, Point2D.Double r) {
double l2 = distance(p, q) * distance(p, q);
if (l2 == 0.0) return p;
double t = ((r.x - p.x) * (q.x - p.x) + (r.y - p.y) * (q.y - p.y)) / l2;
t = Math.max(0, Math.min(1, t));
Point2D.Double projection = new Point2D.Double();
projection.x = p.x + t * (q.x - p.x);
projection.y = p.y + t * (q.y - p.y);
return projection;
}
/**
* 点 p(我们要找到它到线段 ab 的最近点的点),以及线段的两个端点 a 和 end。它首先计算点 p 到线段 ab 的垂足位置,然后根据这个位置是否在线段上来确定最近的点。如果垂足不在线段上,则最近的点将是线段的起点或终点,具体取决于哪个点距离 point 更近。
* @param point
* @return
*/
public static Point2D.Double perpendicularIntersection(Point2D.Double point, Point2D.Double lineStart, Point2D.Double lineEnd) {
// 计算点到线段两个端点的向量
double dx1 = lineEnd.x - lineStart.x;
double dy1 = lineEnd.y - lineStart.y;
double dx2 = point.x - lineStart.x;
double dy2 = point.y - lineStart.y;
// 计算点到线段垂直向量的点积
double dotProduct = dx1 * dx2 + dy1 * dy2;
// 如果点积为0,则点垂直于线段,即点在线段上或其延长线上
if (dotProduct <= 0) {
return lineStart; // 最近点就是线段的起点
}
// 计算线段长度
double lineLengthSquared = dx1 * dx1 + dy1 * dy1;
// 如果点积大于线段长度的平方,则点垂直于线段延长线,最近点是线段的终点
if (dotProduct >= lineLengthSquared) {
return lineEnd; // 最近点就是线段的终点
}
// 计算投影长度
double projLength = dotProduct / lineLengthSquared;
// 计算最近点的坐标
double closestX = lineStart.x + dx1 * projLength;
double closestY = lineStart.y + dy1 * projLength;
// 返回最近点
return new Point2D.Double(closestX,closestY);
}
public static TbRailPoint findClosestPointOnPolygonBoundary2(List polygonVertices, TbRailPoint point) {
TbRailPoint rtn = new TbRailPoint();
rtn.setLongitude(BigDecimal.ZERO);
rtn.setLatitude(BigDecimal.ZERO);
Point2D.Double externalPoint = new Point2D.Double(point.getLongitude().doubleValue(), point.getLatitude().doubleValue());
if (CollUtil.isEmpty(polygonVertices) || polygonVertices.size()!=4){
log.info("【3D围栏维护】边界异常 {} ", JSON.toJSONString(polygonVertices));
return rtn;
}
// 界外的点,对每一条边界做垂线,找到最近的点
Point2D.Double p1 = perpendicularIntersection(externalPoint, polygonVertices.get(0), polygonVertices.get(1));
Point2D.Double p2 = perpendicularIntersection(externalPoint, polygonVertices.get(1), polygonVertices.get(2));
Point2D.Double p3 = perpendicularIntersection(externalPoint, polygonVertices.get(2), polygonVertices.get(3));
Point2D.Double p4 = perpendicularIntersection(externalPoint, polygonVertices.get(3), polygonVertices.get(0));
ArrayList nearPts = CollUtil.newArrayList(p1, p2, p3, p4);
nearPts.addAll(polygonVertices);
double minDis = distance(externalPoint, p1);
Point2D.Double nearest = p1;
for (Point2D.Double nearPt : nearPts) {
double distance = distance(externalPoint, p2);
if (distance
//
// // 定义多边形的坐标
// List
// polygonCoords.add(new Point2D.Double(1, 1));
// polygonCoords.add(new Point2D.Double(3, 1));
// polygonCoords.add(new Point2D.Double(3, 3));
// polygonCoords.add(new Point2D.Double(1, 3));
//
// // 定义外部点的坐标
// Point2D.Double outsidePoint = new Point2D.Double(0, 2);
//
// // 找到外部点到多边形边界最近的点
// Point2D.Double nearestPoint = findClosestPointOnPolygonBoundary(polygonCoords, outsidePoint);
//
// // 输出结果
// System.out.println("Nearest Point to Polygon Boundary: " + nearestPoint);
Point2D.Double point = new Point2D.Double(-1, -1);
Point2D.Double intersection = perpendicularIntersection(point, new Point2D.Double(0.0, 0.0), new Point2D.Double(2.0, 2.0));
System.out.println(“Intersection point: (” + intersection.x + ", " + intersection.y + “)”);
}
}