直线的正交/平行判定
利用内积的值(cosθ)值来判断。
//判断向量a和b是否正交
bool isOrthogonal(Vector a,Vector b){
return equals(dot(a,b),0.0);
}
bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
return isOrthogonal(a1-a2,b1-b2);
}
bool isOrthogonal(Segment s1,Segment s2){
return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}
利用内积的值(sinθ)值来判断。
//判断向量a和b是否平行
bool isParallel(Vector a,Vector b){
return equals(cross(a,b),0.0);
}
bool isParellel(Point a1,Point a2,Point b1,Point b2){
return isParallel(a1-b1,a2-b2);
}
bool isParallel(Segment s1,Segment s2){
return equals(cross(s1.p1-s1.p2,s2.p1-s2.p2),0.0);
}
投影
从点p向线段(或直线)s=p1p2引一条垂线,交点设为x,这个x就叫作点p的投影(projection)。
//过p点做向量s的投影
Point project(Segment s,Point p){
Vector base=s.p1-s.p2;
//推导如上图
double r=dot(p-s.p1,base)/base.norm();
return s.p1+base*r;
}
映像
作线段或者直线的对称点。利用投影倍长一倍即可。
//过直线做p的对称点
Point reflect(Segment s,Point p){
return p+(project(s,p)-p)*2;
}
两点距离
//两点的距离
double getDistance(Point a,Point b){
Vector v=a-b;
return v.abs();
}
点直线距离
利用外积(cross),面积除以底即可就高。
//点到直线的距离
double getDistanceLP(Line l,Point p){
Vector a=l.p2-l.p1;
Vector b=p-l.p1;
return abs(cross(a,b)/a.abs());
}
点线段距离
考虑点与线段两端点的关系
//点到线段的距离
double getDistanceSP(Segment s,Point p){
Vector v;
if(dot(s.p2-s.p1,p-s.p1)<0){
v=p-s.p1;
return v.abs();
}
if(dot(s.p1-s.p2,p-s.p2)<0){
v=p-s.p2;
return v.abs();
}
return getDistanceLP(s,p);
}
线段与线段的距离
intersec()函数在下面判断线段之间相交可以找到
//线段之间的距离
double getDistance(Segment s1,Segment s2){
if(intersect(s1,s2)) return 0.0;
return min( min(getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2)),
min(getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)));
}
顺时针方向
1.利用外积判断非共线的情况
2.利用内积判断反向共线的情况
3.利用模长的大小判断包含关系
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
//两个向量的位置关系(顺时针or逆时针)
int ccw(Point p0,Point p1,Point p2){
Vector a = p1-p0;
Vector b = p2-p0;
//外积>0
if(cross(a,b)>EPS) return COUNTER_CLOCKWISE;
if(cross(a,b)<-EPS) return CLOCKWISE;
if(dot(a,b)<-EPS) return ONLINE_BACK;
if(a.norm()<b.norm()) return ONLINE_FRONT;
return ON_SEGMENT;
}
判断线段相交
可以利用线段之间顺逆时针的关系
//线段是否相交
bool intersect(Point p1,Point p2,Point p3,Point p4){
//保证p3,p4在p1,p2的顺逆时针不同,同理.
return (ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0&&
ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}
//判断直线是否相交
bool intersect(Segment s1,Segment s2){
return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}
线段的交点
//求线段的交点
Point getCrossPoint(Segment s1,Segment s2){
Vector base = s2.p2-s2.p1;
double d1 = abs(cross(base,s1.p1-s2.p1));
double d2 = abs(cross(base,s1.p2-s2.p2));
double t = d1/(d1+d2);
return s1.p1+(s1.p2-s1.p1)*t;
}
圆与直线的交点
pair<Point,Point>getCrossPoints(Circle c,Line l){
if(getDistance(l,c.c)<=c.r){
Point pr=project(l,c.c);//圆心到直线的垂足
Vector e = l.p1-l.p2;
e = e/e.abs();
double base = sqrt(c.r*c.r-getDistance(c.c,pr)*getDistance(c.c,pr));
return make_pair(pr+e*base,pr-e*base);
}
}
圆与圆相交
//两圆相交的交点值
double arg(Point p){
return atan2(p.y,p.x);
}
Vector polar(double a,double r){
return Point(cos(r)*a,sin(r)*a);
}
pair<Point,Point>getCrossPoints(Circle c1,Circle c2){
double d = getDistance(c1.c,c2.c);
if(d<=(c1.r+c2.r)){
double a = acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
double t = arg(c2.c-c1.c);
return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}
}