代码一
原文地址:http://blog.sina.com.cn/s/blog_4c8bb86b0100k2lc.html
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
/// <summary>
/// 点是否点中了线
/// </summary>
class ClickOnLine
{
/// <summary>
/// 点是否在直线上
/// </summary>
/// <param name="ptCurr"></param>
/// <param name="pStart">线的起点</param>
/// <param name="pEnd"></param>
/// <param name="allowErr">容许误差</param>
/// <returns>在线上返回true</returns>
public static bool IsPtInLine(Point ptCurr, Point pStart, Point pEnd, int allowErr)
{
CCADCoord pt = new CCADCoord(ptCurr.X, ptCurr.Y);
CCADCoord p1 = new CCADCoord(pStart.X, pStart.Y);
CCADCoord p2 = new CCADCoord(pEnd.X, pEnd.Y);
int n = PtInPolyLine(pt, p1, p2, allowErr);
if (n == 1)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 判断给定点 pt 是否在折线上: 1:在折线上;0:不在折线上
/// </summary>
/// <param name="pt">待判断的点</param>
/// <param name="polyline">折线坐标列表</param>
/// <param name="allowError">容差值(该值应包括线的宽度,如为零则表示精确匹配)</param>
/// <returns>1:在折线上;0:不在折线上</returns>
public static int PtInPolyLine(CCADCoord pt, CCADCoord l1, CCADCoord l2, double allowError)
{
//如果选择的点与当前点重合
if (Math.Abs(l2.X - pt.X) <= allowError && Math.Abs(l2.Y - pt.Y) <= allowError)
return 1;
if (Math.Min(l1.X, l2.X) <= pt.X && Math.Min(l1.Y, l2.Y) <= pt.Y &&
Math.Max(l1.X, l2.X) >= pt.X && Math.Max(l1.Y, l2.Y) >= pt.Y)
{
//精确匹配判断的话
if (Math.Abs(allowError - 0.0) <= 0.0001)
{
#region 该方法理论上是100%可行的,但是在实际过程中,用户的点击往往是模糊的,大概的,所以该方法就会出现问题
CCADCoord tp1 = new CCADCoord(l2.X - pt.X, l2.Y - pt.Y); //矢量减法
CCADCoord tp2 = new CCADCoord(pt.X - l1.X, pt.Y - l1.Y); //矢量减法
if (Math.Abs(Math.Abs(tp1.X * tp2.Y - tp2.X * tp1.Y) - 0.0) <= 0.00000001) //矢量叉乘,平行四边形的面积
return 1;
#endregion
}
else
{
if (Math.Abs(l2.X - l1.X) <= allowError && Math.Abs(l2.X - pt.X) <= allowError)
return 1;
if (Math.Abs(l2.Y - l1.Y) <= allowError && Math.Abs(l2.Y - pt.Y) <= allowError)
return 1;
if (DistancePointToSegment(pt, l1, l2) <= allowError)
return 1;
//如果点到线段的距离在容差范围内,则选取成功
if (DistancePointToSegment(pt, l1, l2) <= allowError)
return 1;
}
}
return 0;
}
/// <summary>
/// 点到线段的距离公式(利用平行四边形的面积算法,非常牛叉)
/// </summary>
/// <param name="P">目标点</param>
/// <param name="A">线段端点A</param>
/// <param name="B">线段端点B</param>
/// <returns></returns>
public static double DistancePointToSegment(CCADCoord P, CCADCoord A, CCADCoord B)
{
//计算点到线段(a,b)的距离
double l = 0.0;
double s = 0.0;
l = DistancePointToPoint(A, B);
s = ((A.Y - P.Y) * (B.X - A.X) - (A.X - P.X) * (B.Y - A.Y)) / (l * l);
return (Math.Abs(s * l));
}
/// <summary>
/// 点到点的距离
/// </summary>
/// <param name="ptA"></param>
/// <param name="ptB"></param>
/// <returns></returns>
private static double DistancePointToPoint(CCADCoord ptA, CCADCoord ptB)
{
return Math.Sqrt(Math.Pow(ptA.X - ptB.X, 2) + Math.Pow(ptA.Y - ptB.Y, 2));
}
/// <summary>
/// 坐标
/// </summary>
public struct CCADCoord
{
public double X;
public double Y;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public CCADCoord(double x, double y)
{
X = x;
Y = y;
}
}
}
代码二:
原文地址:http://www.cnblogs.com/dxp498688071/archive/2011/03/03/1970217.html
/*
判断点是否在线段上:
设点为Q,线段为P1P2 ,判断点Q在该线段上的依据是:( Q - P1 ) × ( P2 - P1 ) = 0 且 Q 在以 P1,P2为对角顶点的矩形内。前者保证Q点在直线P1P2上,后者是保证Q点不在线段P1P2的延长线或反向延长线上,对于这一步骤的判断可以用以下过程实现:
ON-SEGMENT(pi,pj,pk)
if min(xi,xj) <= xk <= max(xi,xj) and min(yi,yj) <= yk <= max(yi,yj)
then return true;
else return false;
特别要注意的是,由于需要考虑水平线段和垂直线段两种特殊情况,min(xi,xj)<=xk<=max(xi,xj)和min(yi,yj)<=yk<=max(yi,yj)两个条件必须同时满足才能返回真值。
*/
#include<stdio.h>
struct point
{
double x,y;
};
double direction( point p1,point p2,point p )
{
return ( p1.x -p.x )*( p2.y-p.y) - ( p2.x -p.x )*( p1.y-p.y) ;
}
int on_segment( point p1,point p2 ,point p )
{
double max=p1.x > p2.x ? p1.x : p2.x ;
double min =p1.x < p2.x ? p1.x : p2.x ;
double max1=p1.y > p2.y ? p1.y : p2.y ;
double min1=p1.y < p2.y ? p1.y : p2.y ;
if( p.x >=min && p.x <=max &&
p.y >=min1 && p.y <=max1 )
return 1;
else
return 0;
}
int main()
{
point p1,p2,q;
while( 1 )
{
scanf("%lf %lf %lf %lf %lf %lf",&q.x ,&q.y ,&p1.x ,&p1.y ,
&p2.x ,&p2.y ) ;
if( !on_segment( p1,p2,q ) )
{
printf("no\n");
continue;
}
if( direction( q,p1,p2 )==0 )
printf("yes\n");
else
printf("no\n");
}
return 0;
}
代码三
原文地址:http://blog.csdn.net/lishiming0308/article/details/5537441
// 判断一点是否在指定线段中
//线段ab,a(ax,ay),b(bx,by),p(x,y);判断点p是否在线段ab上
public static bool PtInSegment(double x, double y, double ax, double ay, double bx, double by)
{
#region
/*利用斜率是否相同进行判断
if (((x <= ax && x >= bx) || (x <= bx && x >= ax)) && ((y <= ay && y >= by) || (y <= by && y >= ay)))
{
if (ax == bx || ay==by)
return true;
double result = (by - ay) / (bx - ax) - (y - ay) / (x - ax);
return Math.Abs(result) < 0.1;
}
return false;
* */
#endregion
#region
//利用三角形定理判断 两边之和大于第三边
//线段ap的长度
double a_p = Math.Sqrt(Math.Pow(Math.Abs(ax - x), 2) + Math.Pow(Math.Abs(ay - y), 2));
//线段b_p的长度
double b_p = Math.Sqrt(Math.Pow(Math.Abs(bx - x), 2) + Math.Pow(Math.Abs(by - y), 2));
//线段ab的长度
double a_b = Math.Sqrt(Math.Pow(Math.Abs(ax - bx), 2) + Math.Pow(Math.Abs(ay - by), 2));
//线段a_p和线段b_p的和
double a_p_b = a_p + b_p;
if (a_p_b - a_b < 0.5)
{
return true;
}
else
{
return false;
}
/*
#endregion
//利用向量的叉积进行判断,确定不可以进行模糊匹配
//p(x,y),a(ax,ay),b(bx,by)
//线段ab的向量表示(bx-ax,by-ay)
//线段ap的向量表示(x-ax,y-ay)
//向量ab和向量ap的叉积abp=(bx-ax)*(y-ay)+(by-ay)*(x-ax)
double abp = (bx - ax) * (y - ay) -(by - ay) * (x - ax);
double MaxX = Math.Max(ax, bx);
double MinX = Math.Min(ax, bx);
double MaxY = Math.Max(ay, by);
double MinY = Math.Min(ay, by);
ax = MinX; bx = MaxX; ay = MinY; by = MaxY;
if (ax <= x &&x<= bx && ay <= y &&y<= by )
{
if(Math .Abs (abp )==0)
return true;
}
return false ;
*/
}