UVA - 12304 2D Geometry 110 in 1! (几何板子)

题目链接

用来测几何板子真好。

1、已知三角形的三个顶点坐标,求三角形的外接圆圆心坐标和半径

证明:

https://blog.csdn.net/MallowFlower/article/details/79919797

结论:

x = ((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2.0*((x3-x1)*(y2-y1)-(x2-x1)*(y3-y1)));

y = ((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2.0*((y3-y1)*(x2-x1)-(y2-y1)*(x3-x1)));

r = (x1-x)*(x1-x)+(y1-y)*(y1-y);

如果只求半径的话:

2 * r * sinA = a

s = 1 / 2 * b * c * sinA

联立两式

r = ( a * b * c ) / ( 4 * s ) ;

2、已知三角形的三个顶点坐标,求三角形的内切圆圆心坐标和半径

不知道怎么证明。。。

结论:

p1,p2,p3为点,a,b,c为边长

圆心 p : point p = (p1*a + p2 * b + p3 * c) / (a + b + c);

半径 r : r = distosegment(p, p1, p2); (圆心 p 到任意一条边的距离)

如果只求半径的话:

s = sqrt ( p * (p - a) * (p - b) * (p - c)); (p是半周长)

s = r * (a + b + c) / 2;

联立两式

r = 2 * s / (a + b + c) ;

3、求过定点的与圆相切的直线的极角

首先判断op与半径的大小

如果op<r,那么没有切线

如果op==r,那么只有一条切线

先求出∠P,将点 o 绕点 p 逆时针(顺时针)旋转 90° 得到点 o‘ ,那么直线 po' 的极角就是切线的极角。

如果op>r,那么有两条切线

先求出∠P,将点 o 绕点 p 逆时针旋转 ∠P 得到点 o‘ ,那么直线 po' 的极角就是切线的极角。

将点 o 绕点 p 顺时针旋转 ∠P 得到点 o‘’ ,那么直线 po'‘ 的极角就是切线的极角。

4、求经过定点且与给定直线相切的半径为r的圆的圆心坐标

直线为L,L1、L2为平行于L的,距离L的距离为R的两条直线

1、由于所求圆与直线L相切,所以所求圆的圆心一定在直线L1或者直线L2上

2、由于所求圆经过点P,所以所求圆的圆心一定在圆P上。

综上,所求圆的圆心就是圆P与两条直线L1、L2的交点。

5、求与两条给定不平行直线相切的半径为r的圆的圆心坐标

已知直线为L1、L2

L1’、L1’’为平行于L1的,距离L的距离为R的两条直线。L2’、L2’’为平行于L2的,距离L的距离为R的两条直线。

1、由于所求圆与直线L1相切,所以所求圆的圆心一定在直线L1’或者直线L1’’上

2、由于所求圆与直线L2相切,所以所求圆的圆心一定在直线L2’或者直线L2’’上

综上,所求圆的圆心就是两条直线L1’、L1’’与两条直线L2’、L2’’的交点。

6、求与两个相离圆都相切的半径为r的圆的圆心坐标

显然,圆1与圆3相切,圆2与圆3相切,所以可以圆1的半径可以看成r1+r3,圆2的半径可以看成r2+r3

所以,整个题目就变成求半径为r1+r3的圆1和半径为r2+r3的圆2的交点

用余弦求得∠O,然后再计算直线 OO' 的极角记作∠angle

然后 OP' 的极角就是∠angle+∠O,同理,OP''的极角就是∠angle-∠O

然后利用 P',P'' 在圆上,半径为 r1 ,即可求得点 P,P' 的坐标。

待更新,晚上接着写完

ACcode:

#include <bits/stdc++.h>
const double eps = 1e-6;
const double PI = acos(-1.0);
using namespace std;
//判断符号
int sign(double x)
{
	if (fabs(x) < eps)
		return 0;
	return x > 0 ? 1 : -1;
}
struct point
{
	double x;
	double y;
	point operator + (const point &other) { return point{ x + other.x, y + other.y }; }
	point operator - (const point &other) { return point{ x - other.x, y - other.y }; }
	point operator * (double k) { return point{ x * k, y * k }; }
	point operator / (double k) { return point{ x / k, y / k }; }
	bool operator == (const point &other)
	{
		return sign(x - other.x) == 0 && sign(y - other.y) == 0;
	}
	bool operator < (const point &other)
	{
		if (fabs(x - other.x) < eps)
			return y < other.y;
		return x < other.x;
	}
};
//极角
double getangle(point o)
{
	return atan2(o.y, o.x);
}
//点积
double dot(point a, point b)
{
	return a.x*b.x + a.y*b.y;
}
//叉积
double cross(point a, point b)
{
	return a.x*b.y - b.x*a.y;
}
//三角形角度 (a是远离要求的角的边长
double getangle(double a, double b, double c)
{
	return acos((b*b + c * c - a * a) / (2 * b*c));
}
//向量的长度 (可以计算两点距离
double getlen(point a)
{
	return sqrt(a.x*a.x + a.y*a.y);
}
//点P 绕 点O 逆时针旋转angle角度(弧度制)
point rotate(point p, point o, double angle)
{
	point t = point{ p.x - o.x,p.y - o.y };
	double c = cos(angle), s = sin(angle);
	return point{ o.x + t.x*c - t.y*s,o.y + t.x*s + t.y*c };
}
//向量a 绕原点逆时针旋转angle角度
point rots(point a, double rad)
{
	return point{ a.x*cos(rad) - a.y*sin(rad),a.x*sin(rad) + a.y*cos(rad) };
}

//判断线段a1- a2, 线段 b1 - b2是否相交 
bool judge_segment(point a1, point a2, point b1, point b2)
{
	double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1);
	double c3 = cross(b2 - b1, a1 - b1), c4 = cross(b2 - b1, a2 - b1);
	return sign(c1)*sign(c2) < 0 && sign(c3)*sign(c4) < 0;
}
//判断点o是否在线段 a-b 上,不包括端点  (叉积=0[在直线a-b上],点积<0[在ab两点之间] 
bool Onsegment(point o, point a, point b)
{
	return sign(cross(a - o, b - o)) == 0 && sign(dot(a - o, b - o)) < 0;
}
//直线 p-p1 与 q-q1 的交点  (调用前保证两直线有唯一交点且不垂直 
point getllpoint(point p, point p1, point q, point q1)
{
	point v = p1 - p;
	point w = q1 - q;
	point u = p - q;
	double t = cross(w, u) / cross(v, w);
	return p + v * t;
}
//直线 k1-k2 与 k3-k4 的交点  (调用前保证两直线有唯一交点且不垂直 
point getLL(point k1, point k2, point k3, point k4) {
	double w1 = cross(k1 - k3, k4 - k3), w2 = cross(k4 - k3, k2 - k3);
	return (k1*w2 + k2 * w1) / (w1 + w2);
}

//点 P 到直线 A-B 的距离
double distoline(point p, point a, point b)
{
	point v1 = b - a, v2 = p - a;
	return fabs(cross(v1, v2))*getlen(v1);
}
//点 P 在直线 A-B 上的投影
point getlineproject(point p, point a, point b)
{
	point v = b - a;
	return a + v * (dot(v, p - a) / dot(v, v));
}
//点 P 到线段 A-B 的最短距离
double distosegment(point p, point a, point b)
{
	if (a == b)
		return getlen(p - a);
	point v1 = b - a, v2 = p - a, v3 = p - b;
	if (sign(dot(v1, v2)) < 0)
		return getlen(v2);
	if (sign(dot(v1, v3)) > 0)
		return getlen(v3);
	return fabs(cross(v1, v2)) / getlen(v1);
}

struct circle
{
	point o;
	double r;
};
//直线和圆的交点坐标,返回值为个数,sol中存交点坐标(极坐标直线方程代入求解)
int getlinecircle(circle oo, point p, point p1, vector<point>& sol)
{
	point line = p1 - p;
	double a = line.x, b = p.x - oo.o.x, c = line.y, d = p.y - oo.o.y;
	double e = a * a + c * c, f = 2 * (a*b + c * d), g = b * b + d * d - oo.r*oo.r;
	double delta = f * f - 4 * e*g;
	if (sign(delta) < 0)//相离
		return 0;
	if (sign(delta) == 0)//相切
	{
		sol.push_back(p + line * (-f / (2 * e)));
		return 1;
	}
	sol.push_back(p + line * ((-f + sqrt(delta)) / (2 * e)));
	sol.push_back(p + line * ((-f - sqrt(delta)) / (2 * e)));
	return 2;
}
//圆和圆的交点,返回值为个数,sol中存交点坐标
int getclrclecircle(circle o1, circle o2, vector<point>&sol)
{
	double dis = getlen(o1.o - o2.o);
	if (sign(dis) == 0)
	{
		if (sign(o1.r - o2.r) == 0) 
			return -1;
		return 0;
	}
	if (sign(o1.r + o2.r - dis) < 0 || sign(fabs(o1.r - o2.r) - dis) > 0)
		return 0;
	double angle1 = getangle(o2.o - o1.o);
	double angle2 = acos((o1.r*o1.r + dis * dis - o2.r*o2.r) / (2 * o1.r*dis));
	double a1 = angle1 - angle2;
	double a2 = angle1 + angle2;
	point p1 = point{ o1.o.x + cos(a1) * o1.r,o1.o.y + sin(a1) * o1.r };
	point p2 = point{ o1.o.x + cos(a2) * o1.r,o1.o.y + sin(a2) * o1.r };
	sol.push_back(p1);
	if (p1 == p2)
		return 1;
	sol.push_back(p2);
	return 2;
}
//已知三点坐标,求外接圆
circle waijiecircle(point p1, point p2, point p3)
{
	point b = point{ p2.x - p1.x,p2.y - p1.y };
	point c = point{ p3.x - p1.x,p3.y - p1.y };
	double temp = 2 * cross(b, c);
	double ox = (c.y*(b.x*b.x + b.y*b.y) - b.y*(c.x*c.x + c.y*c.y)) / temp + p1.x;
	double oy = (b.x*(c.x*c.x + c.y*c.y) - c.x*(b.x*b.x + b.y*b.y)) / temp + p1.y;
	point o = point{ ox,oy };
	return circle{ o,getlen(p1 - o) };
}
//已知三点坐标,求内接圆
circle neiqiecircle(point p1, point p2, point p3)
{
	double a = getlen(p2 - p3);
	double b = getlen(p1 - p3);
	double c = getlen(p1 - p2);
	point o = (p1*a + p2 * b + p3 * c) / (a + b + c);
	return circle{ o,distosegment(o,p1,p2) };
}
//经过点p,作圆o的切线,sol是切点数组,返回值为切点数
int gettangents(point p, circle oo, vector<point>& sol)
{
	double dis = getlen(p - oo.o);
	if (dis < oo.r)
		return 0;
	else if (sign(dis - oo.r) == 0)
	{
		sol.push_back(rotate(oo.o, p, PI / 2));
		return 1;
	}
	else
	{
		double angle = asin(oo.r / dis);
		sol.push_back(rotate(oo.o, p, angle));
		sol.push_back(rotate(oo.o, p, -angle)); 
		return 2;
	}
}
int fifth(point p1, point p2, point p3, point p4, double r, vector<point>& sol)
{
	double angle1 = getangle(point{ p2 - p1 });
	if (sign(angle1 - PI) >= 0)
		angle1 -= PI;
	double angle2 = getangle(point{ p4 - p3 });
	if (sign(angle2 - PI) >= 0)
		angle2 -= PI;
	double l1 = r / cos(angle1);
	double l2 = r / cos(angle2);
	sol.push_back(getLL(point{ p1.x,p1.y - l1 }, point{ p2.x,p2.y - l1 }, point{ p3.x,p3.y - l2 }, point{ p4.x,p4.y - l2 }));
	sol.push_back(getLL(point{ p1.x,p1.y - l1 }, point{ p2.x,p2.y - l1 }, point{ p3.x,p3.y + l2 }, point{ p4.x,p4.y + l2 }));
	sol.push_back(getLL(point{ p1.x,p1.y + l1 }, point{ p2.x,p2.y + l1 }, point{ p3.x,p3.y - l2 }, point{ p4.x,p4.y - l2 }));
	sol.push_back(getLL(point{ p1.x,p1.y + l1 }, point{ p2.x,p2.y + l1 }, point{ p3.x,p3.y + l2 }, point{ p4.x,p4.y + l2 }));
	return 4;
}
int main()
{
	char s[50];
	while (scanf("%s", s) > 0)
	{
		if (s[4] == 'u')
		{
			point p1, p2, p3;
			scanf("%lf%lf%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y, &p3.x, &p3.y);
			circle ans = waijiecircle(p1, p2, p3);
			printf("(%.6lf,%.6lf,%.6lf)\n", ans.o.x, ans.o.y, ans.r);
		}
		else if (s[0] == 'I')
		{
			point p1, p2, p3;
			scanf("%lf%lf%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y, &p3.x, &p3.y);
			circle ans = neiqiecircle(p1, p2, p3);
			printf("(%.6lf,%.6lf,%.6lf)\n", ans.o.x, ans.o.y, ans.r);
		}
		else if (s[0] == 'T')
		{
			circle oo;
			point p;
			vector<point>sol;
			scanf("%lf%lf%lf%lf%lf", &oo.o.x, &oo.o.y, &oo.r, &p.x, &p.y);
			int x = gettangents(p, oo, sol);
			vector<double>ans;
			for (int i = 0; i < x; i++)
			{
				double angle = getangle(point{ sol[i] - p }) / PI * 180;
				if (sign(angle) < 0)
					angle += 180;
				if (sign(angle - 180) >= 0)
					angle -= 180;
				ans.push_back(angle);
			}
			sort(ans.begin(), ans.end());
			printf("[");
			if (!ans.empty())
				printf("%.6lf", ans[0]);
			for (int i = 1; i < x; i++)
				printf(",%.6lf", ans[i]);
			printf("]\n");
		}
		else if (s[7] == 'h')
		{
			circle oo;
			point p1, p2;
			vector<point>sol;
			int x = 0;
			scanf("%lf%lf%lf%lf%lf%lf%lf", &oo.o.x, &oo.o.y, &p1.x, &p1.y, &p2.x, &p2.y, &oo.r);
			double angle = getangle(p2 - p1);
			x += getlinecircle(oo, point{ p1.x,p1.y - oo.r / cos(angle) }, point{ p2.x,p2.y - oo.r / cos(angle) }, sol);
			x += getlinecircle(oo, point{ p1.x,p1.y + oo.r / cos(angle) }, point{ p2.x,p2.y + oo.r / cos(angle) }, sol);
			sort(sol.begin(), sol.end());
			printf("[");
			if (!sol.empty())
				printf("(%.6lf,%.6lf)", sol[0].x, sol[0].y);
			for (int i = 1; i < x; i++)
				printf(",(%.6lf,%.6lf)", sol[i].x, sol[i].y);
			printf("]\n");
		}
		else if (s[18] == 'L')
		{
			point p1, p2, p3, p4;
			double r;
			vector<point>sol;
			scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y, &p3.x, &p3.y, &p4.x, &p4.y, &r);
			int x = fifth(p1, p2, p3, p4, r, sol);
			sort(sol.begin(), sol.end());
			printf("[");
			if (!sol.empty())
				printf("(%.6lf,%.6lf)", sol[0].x, sol[0].y);
			for (int i = 1; i < x; i++)
				printf(",(%.6lf,%.6lf)", sol[i].x, sol[i].y);
			printf("]\n");
		}
		else
		{
			circle oo1, oo2;
			double r;
			vector<point>sol;
			scanf("%lf%lf%lf%lf%lf%lf%lf", &oo1.o.x, &oo1.o.y, &oo1.r, &oo2.o.x, &oo2.o.y, &oo2.r, &r);
			oo1.r += r;
			oo2.r += r;
			int x = getclrclecircle(oo1, oo2, sol);
			sort(sol.begin(), sol.end());
			printf("[");
			if (!sol.empty())
				printf("(%.6lf,%.6lf)", sol[0].x, sol[0].y);
			for (int i = 1; i < x; i++)
				printf(",(%.6lf,%.6lf)", sol[i].x, sol[i].y);
			printf("]\n");
		}
	}
}

 

全部评论

相关推荐

牛客868257804号:九个中铁八个中建
点赞 评论 收藏
分享
10-30 22:18
已编辑
毛坦厂中学 C++
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
今天 12:19
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务