UVaOJ 12304 2D Geometry 110 in 1!

题意: 有6个小题...

(1)给定三角形, 求外接圆

(2)给定三角形, 求内切圆

(3)给定一个点和一个圆, 求所有切线的极角(0 ~180)

(4)给定点P, 直线L和一个半径值r, 求所有过P, 与L相切的半径为r的圆心位置

(5)给定两条不平行直线和半径r, 求与两条线都相切的半径为r的圆心位置

(6)给定两个相离的圆和半径r, 求与两圆都外切的半径为r的圆心位置

 

         解题思路不想说了, 反正我也是东拼西凑才过了的...一开始(3)对atan2不熟悉, 把取值范围搞错了(以为和atan一样), 结果挂了. 以及(2)内切圆也有问题, 如果用角平分线的方法, 求出角度之后还需要判断旋转方向(可以用叉乘), 然而起初没有注意, 结果又挂了. 不过在网上找答案时看到了不错的求法(坐标公式)(其实《训练指南》上面也有), 以后求内切圆就省事多了~

以及这个解决负0的方法也不太令人满意...然而我在别人的正解里也木有看到好的方法(我看的别人的版本似乎只对(3)做了处理, 然后也过了...)

         这题也没啥意思, 主要是当作一个代码仓库吧


#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <iomanip>
#include <algorithm>
#define eps 1e-8

using namespace std;

struct Point
{
	double x,y;
	Point(double _x, double _y):x(_x), y(_y)
	{}
};

struct Circle
{
	Point c;
	double r;
	Circle(Point _c, double _r):c(_c), r(_r)
	{}
	
	Point getPoint(double ang)
	{
		return Point(c.x + r * cos(ang), c.y + r * sin(ang));
	}
};

typedef Point Vector;

/* operators */
Vector operator+(Vector a, Vector b)
{
	return Vector(a.x + b.x, a.y + b.y);
}
Vector operator-(Vector a, Vector b)
{
	return Vector(a.x - b.x, a.y - b.y);
}
Vector operator*(Vector a, double k)
{
	return Vector(a.x * k, a.y * k);
}
Vector operator*(double k, Vector a)
{
	return Vector(a.x * k, a.y * k);
}
Vector operator/(Vector a, double k)
{
	return Vector(a.x / k, a.y / k);
}
bool operator<(Point a, Point b)
{
	if(fabs(a.x - b.x) > eps)	return a.x < b.x;
	return a.y < b.y;
}

ostream& operator<<(ostream& o, Point p)
{
	o <<'(' <<p.x <<',' <<p.y <<')';
	return o;
}

double norm(double d)
{
	if(fabs(d) < eps)	return 0.0;
	else	return d;
}

Point norm(Point p)
{
	return Point(norm(p.x), norm(p.y));
}

template <class T>
void printList(vector<T> vec)
{
	cout <<'[';
	if(vec.size() > 0)
	{
		cout <<norm(vec[0]);
		for(int i = 1; i < vec.size(); i++)
			cout <<',' <<norm(vec[i]);
	}
	cout <<']' <<endl;
}

/* common operations */
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));
}

double Angle(Vector A, Vector B)
{
	return acos(Dot(A, B) / Length(A) / Length(B));
}

Vector Rotate(Vector A, double t)
{
	double nx = A.x * cos(t) - A.y * sin(t);
	double ny = A.x * sin(t) + A.y * cos(t);
	return Vector(nx, ny);
}

double PolarAngle(Vector A)
{
	return atan2(A.y, A.x);
}

Point Intersect(Point A, Vector v, Point B, Vector w)
{
	Vector u = A - B;
	double t = Cross(w, u) / Cross(v, w);
	return A + v*t;
}

double Distance(Point P, Point A, Vector v)
{
	return fabs(Cross(P - A, v) / Length(v));
}

double ArcToAngle(double arg)
{
	return arg / M_PI * 180;
}


int CLIntersect(Circle C, Point A, Vector v, vector<Point>& ans)
{
	double dist = Distance(C.c, A, v);
	if(fabs(dist - C.r) < eps)	//tangent
	{
		Vector c(v.y, -v.x);
		Point H = Intersect(C.c, c, A, v);
		ans.push_back(H);
		return 1;
	}
	else if(dist > C.r)		//disjoint
	{
		return 0;
	}
	else				//cross
	{
		Vector c(v.y, -v.x);
		Point H = Intersect(C.c, c, A, v);
		double l = sqrt(C.r * C.r - dist * dist);
		Point p1 = H + v / Length(v) * l;
		Point p2 = H - v / Length(v) * l;
		ans.push_back(p1);
		ans.push_back(p2);
		return 2;
	}
}

/* end of geometry headers */

Circle CsCircle(Point A, Point B, Point C)
{
	Point D = (A + B) / 2;
	Vector AB = B - A;
	Vector d(AB.y, -AB.x);
	Point E = (A + C) / 2;
	Vector AC = C - A;
	Vector e(AC.y, -AC.x);
	
	Point M = Intersect(D, d, E, e);
	double r = Length(M - A);
	return Circle(M, r);
}

Circle IsCircle(Point A, Point B, Point C)
{
	double a = Length(C-B);
	double b = Length(A-C);
	double c = Length(B-A);
	
	Point M = (A * a + B * b + C * c) / (a + b + c);
	double r = Distance(M, A, B-A);
	return Circle(M, r);
}

int TangentThroughP(Circle C, Point P, vector<double>& ans)
{
	Vector PC = C.c - P;
	double dist = Length(PC);
	
	if(fabs(dist - C.r) < eps)	//on the circle
	{
		double ang = PolarAngle(Vector(PC.y, -PC.x));
		ans.push_back(ang);
		return 1;
	}
	else if(dist < C.r)			//in the circle
	{
		return 0;
	}
	else					//outside the circle
	{
		double t = asin(C.r / dist);
		double ang = PolarAngle(PC);
		double t1 = ArcToAngle(ang + t);
		while(t1 > 180 - eps)	t1 -= 180;
		while(t1 < eps)		t1 += 180;
		double t2 = ArcToAngle(ang - t);
		while(t2 > 180 - eps)	t2 -= 180;
		while(t2 < eps)		t2 += 180;
		ans.push_back(t1);
		ans.push_back(t2);
		return 2;
	}
}

int CirclePL(Point P, Point A, Vector v, double r, vector<Point>& ans)
{
	double dist = Distance(P, A, v);
	Vector p(v.y, -v.x);
	if(fabs(dist - 2*r) < eps)		//dist == 2r, 1 ans
	{
		Point H = Intersect(P, p, A, v);
		ans.push_back((P + H) / 2);
		return 1;
	}
	else if(fabs(dist) < eps)		//on line, 2 ans
	{
		p = p / Length(p) * r;
		ans.push_back(P + p);
		ans.push_back(P - p);
		return 2;
	}
	else
	{
		int cnt = 0;
		p = p / Length(p) * r;
		cnt += CLIntersect(Circle(P, r), A + p, v, ans);
		cnt += CLIntersect(Circle(P, r), A - p, v, ans);
		return cnt;
	}
}

int CircleLL(Point A, Vector v, Point B, Vector w, double r, vector<Point>& ans)
{
	Vector ha = Vector(v.y, -v.x) / Length(v) * r;
	Vector hb = Vector(w.y, -w.x) / Length(w) * r;
	ans.push_back(Intersect(A + ha, v, B + hb, w));
	ans.push_back(Intersect(A - ha, v, B + hb, w));
	ans.push_back(Intersect(A + ha, v, B - hb, w));
	ans.push_back(Intersect(A - ha, v, B - hb, w));
	return 4;
}

int CircleCC(Circle C1, Circle C2, double r, vector<Point>& ans)
{
	double dist = Length(C1.c - C2.c);
	if(fabs(dist - C1.r - C2.r - 2*r) < eps)	//1 ans
	{
		Vector c = C2.c - C1.c;
		c = c / Length(c);
		Point nC = C1.c + c * (C1.r + r);
		ans.push_back(nC);
		return 1;
	}
	else if(dist > C1.r + C2.r + 2*r)			//no ans
	{
		return 0;
	}
	else			//2 ans
	{
		Vector c = C2.c - C1.c;
		double ang = PolarAngle(c);
		double t = acos( ((C1.r + r)*(C1.r + r) + dist * dist - (C2.r + r)*(C2.r + r)) / (2 * (C1.r + r) * dist) );
		double a1 = ang + t;
		double a2 = ang - t;
		Point p1 = C1.c + Vector(cos(a1), sin(a1)) * (C1.r + r);
		Point p2 = C1.c + Vector(cos(a2), sin(a2)) * (C1.r + r);
		ans.push_back(p1);
		ans.push_back(p2);
		return 2;
	}
}


int main()
{
	cout <<setprecision(6) <<fixed;
	string comd;
	while(cin >>comd)
	{
		if(comd == "CircumscribedCircle")
		{
			double x1,y1,x2,y2,x3,y3;
			cin >>x1 >>y1 >>x2 >>y2 >>x3 >>y3;
			Point A(x1, y1), B(x2, y2), C(x3, y3);
			Circle ansC = CsCircle(A, B, C);
			cout <<'(' <<norm(ansC.c.x) <<',' <<norm(ansC.c.y) <<',' <<ansC.r <<')' <<endl;
		}
		if(comd == "InscribedCircle")
		{
			double x1,y1,x2,y2,x3,y3;
			cin >>x1 >>y1 >>x2 >>y2 >>x3 >>y3;
			Point A(x1, y1), B(x2, y2), C(x3, y3);
			Circle ansC = IsCircle(A, B, C);
			cout <<'(' <<norm(ansC.c.x) <<',' <<norm(ansC.c.y) <<',' <<ansC.r <<')' <<endl;
		}
		if(comd == "TangentLineThroughPoint")
		{
			double xc,yc,r,xp,yp;
			cin >>xc >>yc >>r >>xp >>yp;
			Point P(xp, yp);
			Circle C(Point(xc, yc), r);
			vector<double> ans;
			TangentThroughP(C, P, ans);
			sort(ans.begin(), ans.end());
			printList(ans);
		}
		if(comd == "CircleThroughAPointAndTangentToALineWithRadius")
		{
			double xp,yp,x1,y1,x2,y2,r;
			cin >>xp >>yp >>x1 >>y1 >>x2 >>y2 >>r;
			Point P(xp, yp);
			Point A(x1, y1);
			Vector v(x2 - x1, y2 - y1);
			vector<Point> ans;
			CirclePL(P, A, v, r, ans);
			sort(ans.begin(), ans.end());
			printList(ans);
		}
		if(comd == "CircleTangentToTwoLinesWithRadius")
		{
			double x1,y1,x2,y2,x3,y3,x4,y4,r;
			cin >>x1 >>y1 >>x2 >>y2 >>x3 >>y3 >>x4 >>y4 >>r;
			Point A(x1, y1);
			Vector v(x2 - x1, y2 - y1);
			Point B(x3, y3);
			Vector w(x4 - x3, y4 - y3);
			vector<Point> ans;
			CircleLL(A, v, B, w, r, ans);
			sort(ans.begin(), ans.end());
			printList(ans);
		}
		if(comd == "CircleTangentToTwoDisjointCirclesWithRadius")
		{
			double x1,y1,r1,x2,y2,r2,r;
			cin >>x1 >>y1 >>r1 >>x2 >>y2 >>r2 >>r;
			Circle C1(Point(x1, y1), r1);
			Circle C2(Point(x2, y2), r2);
			vector<Point> ans;
			CircleCC(C1, C2, r, ans);
			sort(ans.begin(), ans.end());
			printList(ans);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值