求点到线段交点个数的公式_两线段交点的魔术公式

求点到线段交点个数的公式

Image 1

介绍 (Introduction)

The people working around with some graphics code, very often run into the problem of clipping line segments. It is a well-known problem and there have been a lot of algorithms provided. However, it is still a boring procedure and I've searched around for some feasible algorithms and finally, I found out the compact ant simply vector formula. In this article, the sample of the completed codes of anyhow segments clipping in MFC have been provided.

人们在处理一些图形代码时,经常会遇到裁剪线段的问题。 这是一个众所周知的问题,并且提供了很多算法。 但是,这仍然是一个无聊的过程,我一直在寻找一些可行的算法,最后,我找到了简单的紧凑型蚁向量公式。 本文中提供了MFC中片段剪辑的完整代码示例。

背景 (Background)

The calculation of the intersection point of two line segments is based on the so-called wedge product of the two vectors; there are three performances of the wedge product of the two vectors completely interchanging:

两个线段的交点的计算是基于两个向量的所谓楔积。 完全互换的两个向量的楔积的三个性能:

Image 2

The vector formula for the calculation of the intersection point of the two lines defined by the line segments:

用于计算由线段定义的两条线的交点的向量公式:

Image 3

The formula (1) is valid just in condition r1^r0≠0. Also, it is clear that in computer calculations, no “pure zero” maybe not obtained while working with the float and double values. Therefore, for programming codes, this condition should be performed as:

公式(1)仅在条件r1 ^ r0 ≠0时有效。 同样,很明显,在计算机计算中,使用floatdouble float值可能不会获得“纯零”。 因此,对于编程代码,此条件应按以下方式执行:

Image 4

If the condition (2) is valid, the coordinates of the intersection point R of the two lines is defined by the line segments to be obtained by the formula (1). It is not clear yet if the segments intersected themselves. The intersection of the segments to be established with the scalar product of the vectors. Intersection condition of the segments has been demonstrated in figure 2:

如果条件(2)成立,则两条线的交点R的坐标由要通过公式(1)获得的线段定义。 目前尚不清楚这些片段是否相交。 要建立的线段与向量的标量积的交集。 段的相交条件已在图2中进行了演示:

Image 5

If the condition (3) is not valid, the segments are not intersected. Nevertheless, the scalar product of the vectors may provide valuable information on the relative positions of the segments concerned:

如果条件(3)无效,则不相交。 然而,向量的标量积可能会提供有关段的相对位置的有价值的信息:

Image 6

The same for another segment:

对于其他细分市场也是如此:

Image 7

And the condition when the lines defined by the segments do not intersect the segments themselves:

线段定义的线不与线段本身相交的情况:

Image 8

If condition (2) is not valid, the segments and the lines defined by them are collinear and there is nothing of the point of intersection if the segments lay not in one line. The condition of the collinear vectors not to be in one line is defined by wedge product in the formula (7) and represented in figure 6:

如果条件(2)无效,则线段和由它们定义的线是共线的,如果线段不在一条线上,则没有任何交点。 共线矢量不在一条直线上的条件由公式(7)中的楔乘积定义,如图6所示:

Image 9

If conditions (2) and (7) are not valid, the segments are placed in one line and maybe overlapped in some areas. The conditions of overlapping may also be established by means of the scalar product and it is worth distinguishing different cases as the segments are collinear in the same direction(r1∙r0>0), or the contrary one(r1∙r0<0), figure 7 and figure 8:

如果条件(2)和(7)无效,则将这些段放在一行中,并且在某些区域可能重叠。 重叠的条件也可以通过标量积来确定,因此值得区分不同的情况,因为线段在同一方向( r1∙r0 > 0)或相反( r1∙r0 <0)是共线的,图7和图8:

Image 10

图片10

Conditions of the collinear segments not overlapping have been provided in figure 9:

共线段不重叠的条件已在图9中提供:

Image 12

The above is a complete set to provide valuable information about the relative positions of the segments. Needless to say, this technology may be applied to any programming language. The main advantage of the formula (1) provided is that it can be used in the graphics programming almost in the same form as performed in this article. In order to check all the technology above, the author developed a computer program in Visual C++ MFC (Microsoft Foundation Classes) with anyhow segments randomly created, randomly rotating and randomly moving and clipping at arbitrary point of time, just press “Enter” button. The vectors' behavior has to be defined regarding edge product, scalar product, and some other special routine mathematical properties.

上面是一个完整的集合,可提供有关段的相对位置的有价值的信息。 不用说,该技术可以应用于任何编程语言。 所提供的公式(1)的主要优点是,它几乎可以以与本文所用的相同形式用于图形编程。 为了检查上述所有技术,作者在Visual C ++ MFC(Microsoft基础类)中开发了一个计算机程序,该程序具有任意创建的段,在任意时间点随机旋转,随机移动和剪切,只需按“ Enter ”按钮。 必须针对边积,标量积和一些其他特殊的常规数学属性定义矢量的行为。

The demo project Segment2D has been created with the standard MFC App wizard. Vector performance is the same as class Polygon_2D and class Vector_2D in my former CodeProject article "Weiler-Atherton algorithm in MFC". The segments are randomly created and randomly moving and randomly rotating.

演示项目Segment2D已使用标准MFC App向导创建 矢量性能与我以前的CodeProject文章“ MFC中的Weiler-Atherton算法 ”中的class Vector_2D class Polygon_2Dclass Vector_2D class Polygon_2D相同。 这些段是随机创建的,随机移动和随机旋转的。

Before you start building the project provided, it is highly recommended to have a look at the demo presentation enclosed to get an idea of the output expected.

在开始构建提供的项目之前,强烈建议您看一下随附的演示演示,以了解预期的输出。

演示说明 (Demo Explanations)

The executable Segment2D.exe has been built with MSVS-2015 pro using the instruments of MSVS-2010. Therefore the Segment2D.exe is valid even for Windows-XP (as opposed to my former CodeProject articles, no special *.dll files are required because of the RAM used only).

可执行文件Segment2D.exe已使用MSVS-2010的工具与MSVS-2015 pro一起构建。 因此, Segment2D.exe甚至对于Windows-XP也有效(与我以前的CodeProject文章相反,由于仅使用了RAM,因此不需要特殊的* .dll文件)。

Some menu and some special Accelerator keys have been arranged in order to demonstrate the Segment2D project implementation:

为了演示Segment2D项目的实现,已经安排了一些菜单和一些特殊的Accelerator键:

Image 13
  • Menu File->Play - play/stop object rotation (also Ctrl+P click)

    菜单文件 -> 播放 -播放/停止对象旋转(也按Ctrl + P 点击)

  • Menu Edit->Reset Scene->Random - two somehow segments with the random rotation and moving rates created (also Space Bar click)

    菜单编辑 -> 重置场景 -> 随机 -创建了两个具有随机旋转和移动速率的段(也可以单击空格键)

  • Menu Edit->Reset Scene->Collinear - two somehow collinear segments with the random moving rates created (also Ctrl+Space Bar click)

    菜单编辑 -> 重置场景 -> 共线 -创建具有随机移动速率的两个共线段(也按Ctrl +空格键单击)

  • Menu Edit->Reset Scene->Overlapping - two somehow segments in line with the random moving rates created (also Alt+Space Bar click)

    菜单编辑 -> 重置场景 -> 重叠 -与创建的随机移动速度一致的两个分段(也可以单击Alt +空格键)

  • Menu Edit->Start Clipping - stop segments rotation and moving and start clipping (also Enter click)

    菜单编辑 -> 开始剪切 -停止线段的旋转和移动,并开始剪切(也请输入 click)

  • Menu Edit->Next Scene - next scene of performance (if play stopped; also Right Arrow click)

    菜单编辑 -> 下一个场景 -表演的下一个场景(如果播放停止;也请单击向右箭头 )

  • Menu Help->Help - show Help Dialog (also F1 click)

    菜单帮助 -> 帮助 -显示帮助对话框 (也可以按F1键)

The Help Dialog is non-modal therefore you can use as menu and accelerator commands directly or press an OK button in the Help Dialog (or double click the item correspondence):

帮助”对话框是非模式的,因此您可以直接用作菜单和加速器命令,也可以在“ 帮助”对话框中按“ 确定”按钮(或双击项目对应项):

Image 14

建筑笔记 (Building Notes)

Solution configuration must be installed as Release and the platform to be x86.

解决方案配置必须安装为Release ,平台必须安装为x86

The project provided has been developed with MSVS-2015 pro using the instruments of MSVS-2010. Therefore the EXE files are valid even for Windows-XP. If you do not need to run the application in Windows-XP, just change the instruments to MSVS-2015.

提供的项目已使用MSVS-2010的工具与MSVS-2015 pro一起开发。 因此, EXE文件即使对于Windows-XP也是有效的。 如果不需要在Windows-XP中运行该应用程序,只需将仪器更改为MSVS-2015即可

The default coding property is UNICODE; nevertheless MBCS coding is also available, just change the property.

默认的编码属性是UNICODE ; 但是,也可以使用MBCS编码,只需更改属性即可。

Even if you are working for the first time with MSVS, just select menu Debug->Start without debugging and the program Segment2D.exe should start building and working.

即使你正在为第一次与MSVS,只要选择菜单调试 - > 启动 而不调试和程序Segment2D.exe应当建立和工作。

项目源和数据存储 (Project Source and Data Storage)

Standard source codes in Segment2Dproj path have been created with the standard MFC Application Wizard:

Segment2Dproj路径中的标准源代码已使用标准MFC应用程序向导创建:

  • Segment2D.cpp - defines the standard class behaviors for the application

    Segment2D.cpp-定义应用程序的标准类行为

  • MainFrm.cpp - implementation of the standard CMainFrame class

    MainFrm.cpp-标准CMainFrame class

  • CChildView.cpp - implementation of the standard CWnd class; messages handling procedures created by the author using standard MFC Application Wizard procedures

    CChildView.cpp-标准CWnd class ; 作者使用标准MFC应用程序向导过程创建的消息处理过程

  • DlgHelp.cpp - non-modal implementation of the standard CDialogEx class; messages handling procedures created by the author using standard MFC Application Wizard procedures

    DlgHelp.cpp-标准CDialogEx class非模式实现; 作者使用标准MFC应用程序向导过程创建的消息处理过程

  • Segment2D.rc and resource.h - menu, dialog, accelerator resources created by the author using the standard Resource Wizard procedures

    Segment2D.rcresource.h-作者使用标准资源向导过程创建的菜单,对话框,加速器资源

Special source codes in Segment2DProj\GlobUse path have been developed by the author based on the standard graphics and geometry routine procedures:

作者根据标准的图形和几何例程程序开发了Segment2DProj \ GlobUse路径中的特殊源代码:

  • Vector_2D.cpp, Poligon_2D.cpp - 2D object handling

    Vector_2D.cppPoligon_2D.cpp -2D对象处理

代码说明 (Code Explanation)

All the Menu and Accelerator Commands have been done with standard MFC AppWizard technologies. And this article has no purpose to explain Segment2D demo project. If required, you may refer to my former article "Weiler-Atherton algorithm in MFC" where the InitApplication and DrawScene Procedure has been described. The main idea of this article is to explain the use of the Magic Formula of the intersection point of two line segments.

所有菜单加速器命令均已使用标准MFC AppWizard技术完成。 并且本文无意解释Segment2D演示项目。 如果需要,可以参考我以前的文章“ MFC中的Weiler-Atherton算法 ”,其中描述了InitApplicationDrawScene Procedure 。 本文的主要思想是解释两个线段交点的魔术公式的用法。

While declaring class Vector_2D, the main operations with the vectors are to be predetermined:

在声明class Vector_2D ,要预先确定向量的主要操作:

class Vector_2D : public CObject
{ 
public:
double x,y;
Vector_2D ( const Vector_2D& v ){ x = v.x; y = v.y;};
Vector_2D(double vx, double vy) { x = vx; y = vy; };
friend Vector_2D operator + ( const Vector_2D&,  const Vector_2D& ); 
friend Vector_2D operator - ( const Vector_2D&,  const Vector_2D& ); 
friend double operator * ( const Vector_2D&,  const Vector_2D& ); 
friend Vector_2D operator * ( double,  const Vector_2D& ); 
friend Vector_2D operator * ( const Vector_2D&, double  ); 
friend Vector_2D operator / ( const Vector_2D&, double  ); 
friend Vector_2D operator / ( const Vector_2D&, const Vector_2D&  );
friend Vector_2D operator & ( const Vector_2D& u, const Vector_2D& v  )
                            { return (u.x + v.x, u.y + v.y);};
friend double operator ^ ( const Vector_2D& u, const Vector_2D& v  )
                         {return (u.x*v.y - u.y*v.x);}; 
friend double operator | ( const Vector_2D &u, const Vector_2D &v  )
                         { return (u.x * v.x + u.y * v.y );};
};
inline Vector_2D Normalize ( Vector_2D& v ) 
     { double vv = !v;  return vv > GeomTreshold ? v /vv : Vector_2D(0); };     
inline Vector_2D  operator + ( const Vector_2D& u,  const Vector_2D& v )
     { return Vector_2D( u.x + v.x, u.y + v.y );}
inline Vector_2D  operator - ( const Vector_2D& u,  const Vector_2D& v )
     { return Vector_2D( u.x - v.x, u.y - v.y );}
inline double  operator *  ( const Vector_2D& u,  const Vector_2D& v )
     {  return  u.x * v.x + u.y * v.y;}
inline Vector_2D  operator *  ( const Vector_2D& u,  double f )
     {  return Vector_2D( u.x * f, u.y * f);}
inline Vector_2D  operator *  ( double f, const Vector_2D& u )
     {return Vector_2D( f * u.x , f * u.y  );}
inline Vector_2D  operator /  ( const Vector_2D& u,  double f )
     {  return Vector_2D( u.x / f, u.y / f );}
inline Vector_2D&    Vector_2D::operator += ( const Vector_2D& v )
     {  x += v.x;  y += v.y;   return * this;}
inline Vector_2D&    Vector_2D::operator -= ( const Vector_2D& v )
     {  x -= v.x;  y -= v.y;  return * this;}
inline Vector_2D&    Vector_2D::operator *= ( double  v ){  x *= v;  y *= v;  return * this;}
inline Vector_2D&    Vector_2D::operator *= ( const Vector_2D& v )
     {  x *= v.x;  y *= v.y;  return * this;}
inline Vector_2D&    Vector_2D::operator /= ( double  v ){  x /= v;  y /= v;  return * this;}

The intersection point of two lines is determined by segments to be calculated in one line:

两条线的交点由要在一条线中计算的线段确定:

Vector_2D R = (r0 * (R11^R10) - r1 *(R01^R00)) / (r1^r0);


And once the intersection point of two lines has been determined by the segments received, it is easy to estimate if the point belongs to the segments with the scalar product calculation as in the Background part of this article prescribed.

而且,一旦根据接收到的线段确定了两条线的交点,就可以通过标量乘积计算轻松估算出该点是否属于线段,如本文背景部分所述。

The overlapping conditions of the collinear segments in line calculated by the function followed:

该函数计算的直线上的共线段的重叠条件如下:

BOOL isOverlapping(Vector_2D R00, Vector_2D R01, Vector_2D R10, 
      Vector_2D R11, Vector_2D * Q0, Vector_2D * Q1)
{
	Vector_2D r0 = R01 - R00;
	Vector_2D r1 = R11 - R10;
	if (fabs(r1^r0 / (!r1 * !r0)) > GeomTreshold)
		return FALSE;
	if (fabs((R10 - R00) ^ r0 / (!(R10 - R00) * !r0)) > GeomTreshold)
		return FALSE;
	if(r0*r1 >0)                            //if segments in same direction
	if ((R00 - R10)* (R00 - R11) <= 0)      //if R00 is inside the segment(R10, R11)
	{
		*Q0 = R00;
		if ((R01 - R10)* (R01 - R11) <= 0)  //if R01 is inside the segment(R10, R11)
			*Q1 = R01;
		else
	      *Q1 = R11;
	}
	else
		if ((R10 - R00)* (R10 - R01) < 0)   //if R10 is inside the segment(R00, R01)
		{
			*Q0 = R10;
			if ((R01 - R10)* (R01 - R11) <= 0) //if R01 is inside the segment(R10, R11)
				*Q1 = R01;
			else
				*Q1 = R11;
		}
		else;
	else                      //if segments in contrary direction
		if ((R00 - R10)* (R00 - R11) <= 0)  //if R00 is inside the segment(R10, R11)
		{
			*Q0 = R00;
			if ((R01 - R10)* (R01 - R11) <= 0) //if R01 is inside the segment(R10, R11)
				*Q1 = R01;
			else
				*Q1 = R10;
		}
		else
			if ((R11 - R00)* (R11 - R01) < 0)  //if R11 is inside the segment(R00, R01)
			{
				*Q0 = R11;
				if ((R01 - R10)* (R01 - R11) <= 0) //if R01 is inside the segment(R10, R11)
					*Q1 = R01;
				else
					*Q1 = R10;
			}
			else
				return FALSE;
	return TRUE;
}
}

使用提供的项目进行自己的应用程序开发 (Your Own Application Development Using the Project Provided)

I hope that my explanations in the Background part of this article are quite clear so everybody can use this technology in any programming language.

我希望我在本文的背景技术部分的解释很清楚,以便每个人都可以在任何编程语言中使用该技术。

You may pick up this entire project, rename it with the project of my former CodeProject article "MFC Project from Existing Code in One Click" and combine and improve the code as you like.

您可以选择整个项目,并用我以前的CodeProject文章“ 一键来自现有代码的MFC项目 ”中的项目将其重命名,然后根据需要组合和改进代码。

Or you may pick up the GlobUse directory from this project and include the special procedures contained in any of your own graphics projects with menu Project->Existing Item.

否则您可能会拿起GlobUse 该项目的目录,并通过菜单Project-> Existing Item包含任何您自己的图形项目中包含的特殊过程

Your references to my code if any, should be highly appreciated.

您对我的代码的引用(如果有的话)应受到高度赞赏。

兴趣点 (Points of Interest)

The main interest point is why I've not found this magic formula in any authoritative sources. It is easy to use even in the school level of geometry. Sure if we unpack this formula using the standard coordinate performance finally should be obtained as an enormous algorithm as provided a lot of on the internet. But I'm sure a few people should come back to the boring procedures after they use this formula.

主要的兴趣点是为什么我在任何权威资料中都没有找到这个神奇的公式。 即使在学校的几何学水平上也很容易使用。 可以肯定的是,如果我们使用标准坐标性能来解开该公式,最终应该作为互联网上大量提供的巨大算法来获得。 但是我敢肯定,使用此公式后,有些人应该回到无聊的过程中。

I believe that this demo and code should be helpful for software people for segments clipping.

我认为,此演示和代码对于软件人进行片段裁剪应该会有所帮助。

The project has been developed in the MFC platform. Nevertheless, everything developed in MFC may be converted to Win32 and vice versa.

该项目已在MFC平台中开发。 但是,用MFC开发的所有内容都可以转换为Win32 ,反之亦然。

The gif in the title of this article has been created with the program of my former CodeProject article "Your Own Avishop".

本文标题中的gif已使用我以前的CodeProject文章“ Your Own Avishop ”的程序创建。

翻译自: https://www.codeproject.com/Articles/5252711/Magic-Formula-of-the-Intersection-Point-of-Two-Lin

求点到线段交点个数的公式

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值