有一个盒马鲜生送货员有一个送货的多边形(四边形)区域,(x,y)为小广所在的位置,判断小广是否在送货区域内,如果不在,计算小广到送货区域的最短距离?二维空间,忽略地球曲率。
输入:x,y
表示小广的位置坐标
输入:x1,y1,x2,y2,x3,y3,x4,y4
表示多边形区域的顶点坐标
输出:如果小广在区域内返回 yes,0
如果小广不在区域内,返回 no,小广到送货区域的最短距离
测试用例:
输入:
1,1
0,0,0,2,2,2,2,0
输出yes,0
输入:
3,0
0,0,0,2,2,2,2,0
输出no,1
输入:
3,0
1,1,2,3,4,1,2,0
输出no,0.4472135954999576
代码如下:
import java.util.*;
import java.util.List;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String line = in.nextLine();
//(x,y)为小广所在的位置
double x = Double.parseDouble(line.split(",")[0]);
double y = Double.parseDouble(line.split(",")[1]);
line = in.nextLine();
//xList记录了多边形n个点的x坐标,yList记录了多边形n个点的y坐标
List<Double> xList = new ArrayList<>();
List<Double> yList = new ArrayList<>();
String[] array = line.split(",");
for (int i = 0; i < array.length; i++) {
xList.add(Double.parseDouble(array[i]));
yList.add(Double.parseDouble(array[i + 1]));
i++;
}
in.close();
System.out.println(measureDistance(xList, yList, x, y));
}
public static String measureDistance(List<Double> xList, List<Double> yList, double x, double y) {
//初始化多边形4个坐标
Point A = new Point(xList.get(0), yList.get(0));
Point B = new Point(xList.get(1), yList.get(1));
Point C = new Point(xList.get(2), yList.get(2));
Point D = new Point(xList.get(3), yList.get(3));
boolean pointInRect = isPointInRect(A, B, C, D, x, y);
if (pointInRect) {
return "yes,0";
} else {
//说明x,y没在范围内,则算出该点与范围的最近距离
String distance = getDistance(xList, yList, x, y);
return "no," + distance;
}
}
private static String getDistance(List<Double> xList1, List<Double> yList1, double x, double y) {
double h1 = pointToLine(xList1.get(0), yList1.get(0), xList1.get(1), yList1.get(1), x, y);
double h2 = pointToLine(xList1.get(1), yList1.get(1), xList1.get(2), yList1.get(2), x, y);
double h3 = pointToLine(xList1.get(2), yList1.get(2), xList1.get(3), yList1.get(3), x, y);
double h4 = pointToLine(xList1.get(3), yList1.get(3), xList1.get(0), yList1.get(0), x, y);
double[] doubles = {h1, h2, h3, h4};
Arrays.sort(doubles);
//排序后找出最小距离
return "" + doubles[0];
}
// 点到直线的最短距离的判断 点(x0,y0) 到由两点组成的线段(x1,y1) ,( x2,y2 )
private static double pointToLine(double x1, double y1, double x2, double y2, double x0, double y0) {
double space = 0;
double a, b, c;
a = lineSpace(x1, y1, x2, y2);// 线段的长度
b = lineSpace(x1, y1, x0, y0);// (x1,y1)到点的距离
c = lineSpace(x2, y2, x0, y0);// (x2,y2)到点的距离
//点与线段两端的之一重合
if (c <= 0.000001 || b <= 0.000001) {
space = 0;
return space;
}
//线段长度为0,点与线的长度变为点与点的
if (a <= 0.000001) {
space = b;
return space;
}
//根据直角三角形的定理,判断哪个边长
if (c * c >= a * a + b * b) {
space = b;
return space;
}
if (b * b >= a * a + c * c) {
space = c;
return space;
}
//锐角三角形时,用面积求高
double p = (a + b + c) / 2;// 半周长
double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
return space;
}
// 计算两点之间的距离
private static double lineSpace(double x1, double y1, double x2, double y2) {
double lineLength = 0;
lineLength = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2)
* (y1 - y2));
return lineLength;
}
//根据向量积正负判断点在图形内部
private static boolean isPointInRect(Point A,Point B,Point C,Point D,double x, double y) {
double a = (B.x - A.x) * (y - A.y) - (B.y - A.y) * (x - A.x);
double b = (C.x - B.x) * (y - B.y) - (C.y - B.y) * (x - B.x);
double c = (D.x - C.x) * (y - C.y) - (D.y - C.y) * (x - C.x);
double d = (A.x - D.x) * (y - D.y) - (A.y - D.y) * (x - D.x);
if ((a > 0 && b > 0 && c > 0 && d > 0) || (a < 0 && b < 0 && c < 0 && d < 0)) {
return true;
}
// 向量积(矢量)(x1,y1)X(x2,y2)=x1y2-x2y1
// AB X AP = (b.x - a.x, b.y - a.y) x (p.x - a.x, p.y - a.y) = (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);
// BC X BP = (c.x - b.x, c.y - b.y) x (p.x - b.x, p.y - b.y) = (c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x);
return false;
}
}
class Point {
//坐标类
public double x;
public double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
}