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");
}
}
}