湖南省第十届大学生计算机程序设计竞赛(HNCPC2014)CSG - 1123 : 点到圆弧的距离(计算几何)

文章目录

题目链接


题意

:输入一个点 P P P 和一条圆弧(圆周的一部分),你的任务是计算 P P P 到圆弧的最短距离。换句话说,你需要在圆弧上找一个点,到 P P P 点的距离最小。

题解

:呃
先找圆心
显然
假如点跟圆心的连线在那段扇形的圆弧范围内,点到圆弧的最短距离为点到圆心的距离减去半径然后取绝对值;不然,点到圆弧的最短的距离为到这段圆弧的两个端点的最小值。

那怎么判断是不是在圆弧范围内呢?

本来想找PB和OA,OC是否有交点但是wa了好像不是精度问题在这里插入图片描述
两个点是不是在一条线的两端可以用叉积判断
判断 C , D C,D C,D 点是否在 A B AB AB线段两边
向量 A B AB AB和向量 A C AC AC是顺时针,所以他们的叉积 > 0 >0 >0
向量 A B AB AB和向量 A D AD AD是逆时针,所以他们的叉积 < 0 <0 <0
只要 C r o s s ( A B , A C ) ∗ C r o s s ( A B , A D ) < 0 Cross(AB,AC)*Cross(AB,AD)<0 Cross(AB,AC)Cross(AB,AD)<0时,就是在不在同一侧
所以这样看, B B B 就在射线 A C AC AC A D AD AD 中间~就可以判断 P P P是否在圆环范围内
对于这题就可以用来判断 P P P是否在 O C , O A OC,OA OC,OA之间

但是上面只适用劣弧的情况 还要考虑平角和优弧的情况 反正还是用这个叉积判qaq

在这里插入图片描述

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
const double eps = 1e-8;
const double PI = acos(-1.0);
int sgn(double x) {
    if (fabs(x) < eps) {
        return 0;
    }
    return (x < 0) ? -1 : 1;
}
struct Point {
    double x, y;
    Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}
};
typedef Point Vector; //向量
Vector operator + (Vector A, Vector B) { //向量加法
    return Vector(A.x + B.x, A.y + B.y);
}
Vector operator - (Point A, Point B) {
    return Vector(A.x - B.x, A.y - B.y);
}
Vector operator * (Vector A, double p) {
    return Vector(A.x * p, A.y * p);
}
Vector operator / (Vector A, double p) {
    return Vector(A.x / p, A.y / p);
}
bool operator < (const Point A, const Point B) {
    return A.x < B.x || (sgn(A.x - B.x) == 0 && A.y < B.y);
}
bool operator == (const Point A, const Point B) {
    return sgn(A.x - B.x) == 0 && sgn(A.y - B.y) == 0;
}
double Dot(Vector A, Vector B) {//点积
    return A.x * B.x + A.y * B.y;
}
double Cross(Vector A, Vector B) {//向量叉积
    return A.x * B.y - A.y * B.x;
}
double Length(Vector A) {//模
    return sqrt(Dot(A, A));
}
Vector Normal(Vector A) {//单位向量
    double L = Length(A);
    return Vector(-A.y / L, A.x / L);
}
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) {//两直线焦点
    Vector u = P - Q;
    double t = Cross(w, u) / Cross(v, w);
    return P + v * t;
}
double dis(Point a, Point b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
signed main() {
    int t=0;
    double x1, y1, x2, y2, x3, y3, xp, yp;
    while(cin >> x1 >>y1 >> x2 >> y2 >> x3 >> y3 >> xp >> yp) {

        Point A = { x1,y1 };
        Point B = { x2,y2 };
        Point AB = { (x1 + x2) / 2,(y1 + y2) / 2 };
        Point C = { x3,y3 };
        Point BC = { (x3 + x2) / 2,(y3 + y2) / 2 };
        Point P = { xp,yp };
        Point O = GetLineIntersection(AB, Normal(A - B), BC, Normal(B - C));//也可以用三角形外心找圆心

		double ans = min(dis(P, A), dis(P, C));
        double d = dis(O, P);
        double r = dis(O, A);
		if((2*r==dis(A, C))) {
			if(Cross(A-C, A-P)*Cross(A-C,A-B)>=0) {
				ans=min(ans, fabs(d-r));
			}
			cout << "Case " << ++t << ": " <<fixed<< setprecision(3) << ans << endl;
			continue;
		}
        if(Cross(C-A, C-B)*Cross(C-A, C-O)<0) {
			if(Cross(O-A, O-P)*Cross(O-A,O-C)>=0&&Cross(O-C, O-P)*Cross(O-C,O-A)>=0) {
				ans=min(ans, fabs(d-r));
			}
        }else {
			if(!(Cross(O-A, O-P)*Cross(O-A,O-C)>=0&&Cross(O-C, O-P)*Cross(O-C,O-A)>=0)) {
				ans=min(ans, fabs(d-r));
			}
        }
        cout << "Case " << ++t << ": " <<fixed<< setprecision(3) << ans << endl;
    }
    return 0;
}


总结

一道计算几何 暖你一整天

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值