fisher_jiang 发表于 2006-10-18 01:33

计算几何算法(含源代码)

<p>㈠ 点的基本运算 <br/>1. 平面上两点之间距离 1 <br/>2. 判断两点是否重合 1 <br/>3. 矢量叉乘 1 <br/>4. 矢量点乘 2 <br/>5. 判断点是否在线段上 2 <br/>6. 求一点饶某点旋转后的坐标 2 <br/>7. 求矢量夹角 2 </p><p>㈡ 线段及直线的基本运算 <br/>1. 点与线段的关系 3 <br/>2. 求点到线段所在直线垂线的垂足 4 <br/>3. 点到线段的最近点 4 <br/>4. 点到线段所在直线的距离 4 <br/>5. 点到折线集的最近距离 4 <br/>6. 判断圆是否在多边形内 5 <br/>7. 求矢量夹角余弦 5 <br/>8. 求线段之间的夹角 5 <br/>9. 判断线段是否相交 6 <br/>10.判断线段是否相交但不交在端点处 6 <br/>11.求线段所在直线的方程 6 <br/>12.求直线的斜率 7 <br/>13.求直线的倾斜角 7 <br/>14.求点关于某直线的对称点 7 <br/>15.判断两条直线是否相交及求直线交点 7 <br/>16.判断线段是否相交,如果相交返回交点 7 </p><p>㈢ 多边形常用算法模块 <br/>1. 判断多边形是否简单多边形 8 <br/>2. 检查多边形顶点的凸凹性 9 <br/>3. 判断多边形是否凸多边形 9 <br/>4. 求多边形面积 9 <br/>5. 判断多边形顶点的排列方向,方法一 10 <br/>6. 判断多边形顶点的排列方向,方法二 10 <br/>7. 射线法判断点是否在多边形内 10 <br/>8. 判断点是否在凸多边形内 11 <br/>9. 寻找点集的graham算法 12 <br/>10.寻找点集凸包的卷包裹法 13 <br/>11.判断线段是否在多边形内 14 <br/>12.求简单多边形的重心 15 <br/>13.求凸多边形的重心 17 <br/>14.求肯定在给定多边形内的一个点 17 <br/>15.求从多边形外一点出发到该多边形的切线 18 <br/>16.判断多边形的核是否存在 19 </p><p>㈣ 圆的基本运算 <br/>1 .点是否在圆内 20 <br/>2 .求不共线的三点所确定的圆 21 </p><p>㈤ 矩形的基本运算 <br/>1.已知矩形三点坐标,求第4点坐标 22 </p><p>㈥ 常用算法的描述 22 </p><p>㈦ 补充 <br/>1.两圆关系: 24 <br/>2.判断圆是否在矩形内: 24 <br/>3.点到平面的距离: 25 <br/>4.点是否在直线同侧: 25 <br/>5.镜面反射线: 25 <br/>6.矩形包含: 26 <br/>7.两圆交点: 27 <br/>8.两圆公共面积: 28 <br/>9. 圆和直线关系: 29 <br/>10. 内切圆: 30 <br/>11. 求切点: 31 <br/>12. 线段的左右旋: 31 <br/>13.公式: 32 </p><p><br/>/* 需要包含的头文件 */ <br/>#include </p><p>/* 常用的常量定义 */ <br/>const double INF = 1E200 <br/>const double EP = 1E-10 <br/>const int MAXV = 300 <br/>const double PI = 3.14159265 </p><p>/* 基本几何结构 */ <br/>struct POINT <br/>{ <br/>double x; <br/>double y; POINT(double a=0, double b=0) { x=a; y=b;} <a href="file://constructor/">file://constructor</a> <br/>}; <br/>struct LINESEG <br/>{ <br/>POINT s; <br/>POINT e; LINESEG(POINT a, POINT b) { s=a; e=b;} <br/>LINESEG() { } <br/>}; <br/>struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a &gt;= 0 <br/>{ <br/>double a; <br/>double b; <br/>double c; LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} <br/>}; </p><p>/********************\ <br/>* * <br/>* 点的基本运算 * <br/>* * <br/>\********************/ </p><p>double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离 <br/>{ <br/>return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) ); <br/>} <br/>bool equal_point(POINT p1,POINT p2) // 判断两个点是否重合 <br/>{ <br/>return ( (abs(p1.x-p2.x)} </p><p>/*****************************************************************************<br/>* <br/>r=multiply(sp,ep,op),得到(sp-op)*(ep-op)的叉积 <br/>r&gt;0:ep在矢量opsp的逆时针方向; <br/>r=0:opspep三点共线; <br/>r&lt;0:ep在矢量opsp的顺时针方向 <br/>******************************************************************************<br/>*/ </p><p>double multiply(POINT sp,POINT ep,POINT op) <br/>{ <br/>return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y)); <br/>} </p><p>/*****************************************************************************<br/>** <br/>r=dotmultiply(p1,p2,op),得到矢量(p1-op)和(p2-op)的点积,如果两个矢量都非零矢量<br/>&nbsp;<br/>r&lt;0:两矢量夹角为锐角;r=0:两矢量夹角为直角;r&gt;0:两矢量夹角为钝角 <br/>******************************************************************************<br/>*/ <br/>double dotmultiply(POINT p1,POINT p2,POINT p0) <br/>{ <br/>return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y)); <br/>} </p><p>/* 判断点p是否在线段l上,条件:(p在线段l所在的直线上)&amp;&amp; (点p在以线段l为对角线的<br/>矩形内) */ <br/>bool online(LINESEG l,POINT p) <br/>{ <br/>return((multiply(l.e,p,l.s)==0) <br/>&amp;&amp;( ( (p.x-l.s.x)*(p.x-l.e.x)&lt;=0 )&amp;&amp;( (p.y-l.s.y)*(p.y-l.e.y)&lt;=0 ) ) ); <br/>} </p><p>// 返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置 <br/>POINT rotate(POINT o,double alpha,POINT p) <br/>{ <br/>POINT tp; <br/>p.x-=o.x; <br/>p.y-=o.y; <br/>tp.x=p.x*cos(alpha)-p.y*sin(alpha)+o.x; <br/>tp.y=p.y*cos(alpha)+p.x*sin(alpha)+o.y; <br/>return tp; <br/>} </p><p>/* 返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度) <br/>角度小于pi,返回正值 <br/>角度大于pi,返回负值 <br/>可以用于求线段之间的夹角 <br/>*/ <br/>double angle(POINT o,POINT s,POINT e) <br/>{ <br/>double cosfi,fi,norm; <br/>double dsx = s.x - o.x; <br/>double dsy = s.y - o.y; <br/>double dex = e.x - o.x; <br/>double dey = e.y - o.y; </p><p>cosfi=dsx*dex+dsy*dey; <br/>norm=(dsx*dsx+dey*dey)*(dex*dex+dey*dey); <br/>cosfi /= sqrt( norm ); </p><p>if (cosfi &gt;= 1.0 ) return 0; <br/>if (cosfi &lt;= -1.0 ) return -3.1415926; </p><p>fi=acos(cosfi); <br/>if (dsx*dey-dsy*dex&gt;0) return fi; // 说明矢量os 在矢量 oe的顺时针方向 <br/>return -fi; <br/>} </p><p><br/>/*****************************\ <br/>* * <br/>* 线段及直线的基本运算 * <br/>* * <br/>\*****************************/ </p><p>/* 判断点与线段的关系,用途很广泛 <br/>本函数是根据下面的公式写的,P是点C到线段AB所在直线的垂足 </p><p>AC dot AB <br/>r = --------- <br/>||AB||^2 <br/>(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay) <br/>= ------------------------------- <br/>L^2 </p><p>r has the following meaning: </p><p>r=0 P = A <br/>r=1 P = B <br/>r&lt;0 P is on the backward extension of AB <br/>r&gt;1 P is on the forward extension of AB <br/>0*/ <br/>double relation(POINT p,LINESEG l) <br/>{ <br/>LINESEG tl; <br/>tl.s=l.s; <br/>tl.e=p; <br/>return dotmultiply(tl.e,l.e,l.s)/(dist(l.s,l.e)*dist(l.s,l.e)); <br/>} </p><p>// 求点C到线段AB所在直线的垂足 P <br/>POINT perpendicular(POINT p,LINESEG l) <br/>{ <br/>double r=relation(p,l); <br/>POINT tp; <br/>tp.x=l.s.x+r*(l.e.x-l.s.x); <br/>tp.y=l.s.y+r*(l.e.y-l.s.y); <br/>return tp; <br/>} <br/>/* 求点p到线段l的最短距离,并返回线段上距该点最近的点np <br/>注意:np是线段l上到点p最近的点,不一定是垂足 */ <br/>double ptolinesegdist(POINT p,LINESEG l,POINT &amp;np) <br/>{ <br/>double r=relation(p,l); <br/>if(r&lt;0) <br/>{ <br/>np=l.s; <br/>return dist(p,l.s); <br/>} <br/>if(r&gt;1) <br/>{ <br/>np=l.e; <br/>return dist(p,l.e); <br/>} <br/>np=perpendicular(p,l); <br/>return dist(p,np); <br/>} </p><p>// 求点p到线段l所在直线的距离,请注意本函数与上个函数的区别 <br/>double ptoldist(POINT p,LINESEG l) <br/>{ <br/>return abs(multiply(p,l.e,l.s))/dist(l.s,l.e); <br/>} </p><p>/* 计算点到折线集的最近距离,并返回最近点. <br/>注意:调用的是ptolineseg()函数 */ <br/>double ptopointset(int vcount,POINT pointset[],POINT p,POINT &amp;q) <br/>{ <br/>int i; <br/>double cd=double(INF),td; <br/>LINESEG l; <br/>POINT tq,cq; </p><p>for(i=0;i{ <br/>l.s=pointset; <br/>l.e=pointset; <br/>td=ptolinesegdist(p,l,tq); <br/>if(td{ <br/>cd=td; <br/>cq=tq; <br/>} <br/>} <br/>q=cq; <br/>return cd; <br/>} <br/>/* 判断圆是否在多边形内.ptolineseg()函数的应用2 */ <br/>bool CircleInsidePolygon(int vcount,POINT center,double radius,POINT polygon[]<br/>) <br/>{ <br/>POINT q; <br/>double d; <br/>q.x=0; <br/>q.y=0; <br/>d=ptopointset(vcount,polygon,center,q); <br/>if(dreturn true; <br/>else <br/>return false; <br/>} </p><p>/* 返回两个矢量l1和l2的夹角的余弦(-1 --- 1)注意:如果想从余弦求夹角的话,注意反<br/>余弦函数的定义域是从 0到pi */ <br/>double cosine(LINESEG l1,LINESEG l2) <br/>{ <br/>return (((l1.e.x-l1.s.x)*(l2.e.x-l2.s.x) + <br/>(l1.e.y-l1.s.y)*(l2.e.y-l2.s.y))/(dist(l1.e,l1.s)*dist(l2.e,l2.s))) ); <br/>} <br/>// 返回线段l1与l2之间的夹角 单位:弧度 范围(-pi,pi) <br/>double lsangle(LINESEG l1,LINESEG l2) <br/>{ <br/>POINT o,s,e; <br/>o.x=o.y=0; <br/>s.x=l1.e.x-l1.s.x; <br/>s.y=l1.e.y-l1.s.y; <br/>e.x=l2.e.x-l2.s.x; <br/>e.y=l2.e.y-l2.s.y; <br/>return angle(o,s,e); <br/>} <br/>// 如果线段u和v相交(包括相交在端点处)时,返回true <br/>bool intersect(LINESEG u,LINESEG v) <br/>{ <br/>return( (max(u.s.x,u.e.x)&gt;=min(v.s.x,v.e.x))&amp;&amp; file://排斥实验 <br/>(max(v.s.x,v.e.x)&gt;=min(u.s.x,u.e.x))&amp;&amp; <br/>(max(u.s.y,u.e.y)&gt;=min(v.s.y,v.e.y))&amp;&amp; <br/>(max(v.s.y,v.e.y)&gt;=min(u.s.y,u.e.y))&amp;&amp; <br/>(multiply(v.s,u.e,u.s)*multiply(u.e,v.e,u.s)&gt;=0)&amp;&amp; file://跨立实验 <br/>(multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)&gt;=0)); <br/>} </p><p><br/>// (线段u和v相交)&amp;&amp;(交点不是双方的端点) 时返回true <br/>bool intersect_A(LINESEG u,LINESEG v) <br/>{ <br/>return((intersect(u,v))&amp;&amp; <br/>(!online(u,v.s))&amp;&amp; <br/>(!online(u,v.e))&amp;&amp; <br/>(!online(v,u.e))&amp;&amp; <br/>(!online(v,u.s))); <br/>} </p><p><br/>// 线段v所在直线与线段u相交时返回true;方法:判断线段u是否跨立线段v <br/>bool intersect_l(LINESEG u,LINESEG v) <br/>{ <br/>return multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)&gt;=0; <br/>} </p><p><br/>&nbsp;</p>

柠檬 发表于 2006-11-6 18:54

哈哈 现在还没钱 不能下

tianpuke 发表于 2006-10-18 14:20

gao

zhegexiao 发表于 2006-10-29 09:19

up!!!

zhaoyunfei1126 发表于 2007-4-7 11:29

佩服!!!!

mathlmx 发表于 2007-5-27 08:43

<p>感谢!</p>

jacklam200 发表于 2007-6-20 22:54

好啊,支持

西马 发表于 2007-7-2 23:39

hao

52352 发表于 2007-7-12 21:02

特斯塔 发表于 2007-8-5 13:49

<p>期待下面的代码</p>
页: [1] 2 3
查看完整版本: 计算几何算法(含源代码)