C++实现常用的平面计算几何问题求解

326 篇文章 2 订阅
36 篇文章 0 订阅

通过封装常用的点、线段类型,并提供点、线间的相互关系运算,为计算几何工具库的编写提供基础框架。

代码如下:(代码正确性仍需测试,谨慎使用)

//参考
//http://dev.gameres.com/Program/Abstract/Geometry.htm
//http://zhan.renren.com/jisuanjihe?from=template&checked=true

/*
toolbox: Geometry algorithm toolbox
author: alaclp
email: alaclp@qq.com
publish date: 2015-1-16
*/
#include <iostream>
#include <stdio.h>
#include <math.h>

using namespace std;

//预定义
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Max(x, y) ((x) > (y) ? (x) : (y))

//点对象
typedef struct Point {
	double x, y;
	//构造函数
	Point(double x, double y) : x(x), y(y) {}
	//无参数时的构造函数
	Point() : x(0), y(0) {}
	//取得到点pt的距离
	double distance(const Point& pt) {
		return sqrt( (x - pt.x) * (x - pt.x) + (y - pt.y) * (y - pt.y));
	}
	//判断两点是否同一个点
	bool equal(const Point& pt) {
		return ((x - pt.x) == 0) && (y - pt.y == 0);
	}
} Point;

//线段对象
typedef struct PartLine {
	Point pa, pb;
	double length;
	
	PartLine() {
		length = 0;
	}
	
	//构造函数
	PartLine(Point pa, Point pb) : pa(pa), pb(pb) {
		length = sqrt((pa.x - pb.x) * (pa.x - pb.x) + (pa.y - pb.y) * (pa.y - pb.y));
	}
	
	void assign(const PartLine& pl) {
		pa = pl.pa;
		pb = pl.pb;
		length = pl.length;
	}
	
	//利用叉积计算点到线段的垂直距离
	//注意:此结果距离有正负之分
	//若pc点在线段的逆时针方向,则距离为正;否则,距离为副值
	double getDistantToPoint(Point pc) {
		double area = crossProd(pc) / 2;
		return area * 2 / length;
		/* 利用海伦公式计算
		PartLine pl1(this->pa, pc), pl2(this->pb, pc);
		double l1 = this->length, l2 = pl1.length, l3 = pl2.length;
		double s = (l1 + l2 + l3) / 2;	 //海伦公式
		double area = sqrt(s * (s - l1) * (s - l2) * (s - l3));
		return area * 2 / l1;
		*/
	}
	
	//向量的叉积 
	/* 计算向量的叉积(ABxAC A(x1,y1) B(x2,y2) C(x3,y3))是计算行列式 
	| x1-x0 y1-y0 | 
	| x2-x0 y2-y0 | 
	的结果(向量的叉积 AB X AC) 
	*/
	//计算AB与AC的叉积---叉积的绝对值是两向量所构成平行四边形的面积
	double crossProd(Point& pc) {
		//计算ab X ac
		return (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
	}
	
	//判断两线段是否相交
	bool isIntersected(PartLine& pl) {
		double d1, d2, d3, d4, d5, d6;
		d1 = pl.crossProd(pb);
		d2 = pl.crossProd(pa);
		d3 = crossProd(pl.pa);
		d4 = crossProd(pl.pb);
		d5 = crossProd(pl.pa);
		d6 = crossProd(pl.pb);
		//printf("%f %f %f %f %f %f\n", d1, d2, d3, d4, d5, d6);
		bool cond1 = d1 * d2 <= 0,	 				//pb和pa在pl的两侧或线段或线段的延长线上
			 cond2 = d3 * d4 <= 0,	 				//pl.pa和pl.pb在this的两侧或线段或线段的延长线上
			 cond3 = d5 != 0,											//pl.pa不在线段和延长线上
			 cond4 = d6 != 0;											//pl.pb不在线段和延长线上
		return cond1 && cond2 && cond3 && cond4;
	}
	
	//判断两线段是否平行
	bool isParallel(PartLine& pl) {
		double v1 = crossProd(pl.pa),
				 v2 = crossProd(pl.pb);
		return (v1 == v2) && (v1 != 0);
	}
	
	//沿pa点旋转theta
	PartLine rotateA(double theta) {
		float nx = pa.x +(pb.x - pa.x) * cos(theta) - (pb.y - pa.y) * sin(theta),
			  ny = pa.y + (pb.x - pa.x) * sin(theta) + (pb.y - pa.y) * cos(theta);
		return PartLine(pa, Point(nx, ny));
	}
	
	//沿pb点旋转theta
	PartLine rotateB(double theta) {
		float nx = pb.x +(pa.x - pb.x) * cos(theta) - (pa.y - pb.y) * sin(theta),
			  ny = pb.y + (pa.x - pb.x) * sin(theta) + (pa.y - pb.y) * cos(theta);
		return PartLine(Point(nx, ny), pb);
	}
	
	//判断两线段是否重叠或共线
	bool inSameLine(PartLine& pl) {
		double v1 = crossProd(pl.pa), v2 = crossProd(pl.pb);
		if (v1 != v2) return false;
		if (v1 != 0) return false;
		return true;
	}
	
	//取得两线段的相交点---如果不相交返回valid=false
	//如果多个交点,给出警告
	Point getCrossPoint(PartLine& pl, bool& valid) {
		valid = false;
		if (!isIntersected(pl)) {  //不相交
			return Point();
		}
		if ( inSameLine(pl) ) {  //有交点且共线
		  if ( pa.equal(pl.pa) ) { valid = true; return pa; }
  		  if ( pa.equal(pl.pb) ) { valid = true; return pa; }
		  if ( pb.equal(pl.pa) ) { valid = true; return pb; }
  		  if ( pb.equal(pl.pb) ) { valid = true; return pb; }
  		  //多个焦点
  		  cout << "错误:计算交点结果数量为无穷" << endl;
  		  valid = false;
  		  return Point();
		}
		//相交
		Point pt1, pt2, pt3, result;
		pt1 = pa;
		pt2 = pb;
		pt3.x = (pt1.x + pt2.x) / 2;
		pt3.y = (pt1.y + pt2.y) / 2;
		double L1 = pl.crossProd(pt1), L2 = pl.crossProd(pt2), L3 = pl.crossProd(pt3);	
		printf("%f %f %f=%f\n", L1, L2, L3, L1 + L2);	
		while(fabs(L1) > 1e-7 || fabs(L2) > 1e-7) {
			valid = true;
			if (fabs(L1) < fabs(L2)) 
				pt2 = pt3;
			else 
				pt1 = pt3;
			pt3.x = (pt1.x + pt2.x) / 2;
			pt3.y = (pt1.y + pt2.y) / 2;
			result = pt3;
			L1 = pl.crossProd(pt1), L2 = pl.crossProd(pt2), L3 = pl.crossProd(pt3);
			printf("%f %f %f=%f\n", L1, L2, L3, L1 - L2);
		}
		return pt3;
	}
	
	//取得线段上离pt最近的点
	Point getNearestPointToPoint(Point& pt) {
		Point pt1, pt2, pt3, result;
		pt1 = pa;
		pt2 = pb;
		pt3.x = (pt1.x + pt2.x) / 2;
		pt3.y = (pt1.y + pt2.y) / 2;
		double L1 = pt1.distance(pt), L2 = pt2.distance(pt), L3 = pt3.distance(pt); 
		if (L1 == L2) return pt3;
		while(fabs(L1 - L2) > 1e-7) {
			if (L1 < L2) 
				pt2 = pt3;
			else 
				pt1 = pt3;
			pt3.x = (pt1.x + pt2.x) / 2;
			pt3.y = (pt1.y + pt2.y) / 2;
			result = pt3;
			L1 = pt1.distance(pt);
			L2 = pt2.distance(pt);
			L3 = pt3.distance(pt); 
			//printf("%f %f %f=%f\n", L1, L2, L3, L1 - L2);
		}
		return result;
	}
	
	//取得一个点在线段上的镜像点
	Point getMirrorPoint(Point& pc) {
	}
	
} PartLine;

int main(void) 
{ 
	Point p1(0, 0), p2(1, 1), p3(0, 1.1), p4(0.5, 0.5+1e-10), p5(0.5, 0.5-1e-10), np;
	PartLine pl1(p1, p2), pl2(p3, p4), pl3(p3, p5);
	cout << pl1.getDistantToPoint(p3) << endl;
	cout << "线段1和2相交?" << pl1.isIntersected(pl2) << endl;
	np = pl1.getNearestPointToPoint(p5);
	cout << "最近点:" << np.x << ", " << np.y << endl;
	bool isvalid;
	np = pl1.getCrossPoint(pl3, isvalid);
	cout << "两线段的相交点:" << (isvalid ? "有效":"无效") << "=" << np.x << ", " << np.y << endl;
	PartLine plx = pl1.rotateA(M_PI / 2);
	printf("旋转90度后:%f %f %f %f\n", plx.pa.x, plx.pa.y, plx.pb.x, plx.pb.y);
	return 0; 
}



㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断圆是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 圆的基本运算 1 .点是否在圆内 20 2 .求不共线的三点所确定的圆 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两圆关系: 24 2.判断圆是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两圆交点: 27 8.两圆公共面积: 28 9. 圆和直线关系: 29 10. 内切圆: 30 11. 求切点: 31 12. 线段的左右旋: 31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值