计算几何学(2)

直线的正交/平行判定

利用内积的值(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),面积除以底即可就高。d=\frac{|a\times b|}{|a|}=\frac{|(p2-p1)\times(p-p1)|}{|p2-p1|}

//点到直线的距离
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));	
	}	
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值