關於幾何(CAD二次開發實現判斷點與多邊形相對關係)

 一、本節課程
 

C++ ARX二次開發點和閉合多段線的位置關係

二、本節要講解的知識點

結合自己的業務場景,想想自己開發中可能碰到的點和閉合多段線相對關係的需求:統計多段線內部的所有圖塊;還可以拓展判斷任意曲線跟多段線的相對關係。

三、具體內容

  1. 計算機圖形學、計算幾何。判斷點是否在多邊形內部,一般有以下方法:
  1. 叉乘判斷(適合凸多邊形):如果將多邊形的所有頂點按逆時針排序,那麼判斷點和每一條邊的位置關係,如果點在多邊形每一條邊的左側,那麼點就在我們的多邊形內部。
  2. 射線法:從給定點出發,沿着X軸正方向者負方向做一條射線(射線可能跟多邊形沒有交點),計算射線跟多邊形的交點數量,如果是奇數個交點,在內部偶數個交點在外部。處理下點就在多邊形的頂點上的特例。
  1. 本節提供的算法的思路是:
  1. 計算點到多段線的最近點,如果兩點之間的距離少於容差,則認爲點就在多段線上。
  2. 從給定點(要判斷的點)出發,沿最近點到給定點(要判斷的點)的方向 做一個射線(之所以這麼來做射線,是爲了儘可能早可能早判斷出點不在多邊形內部的情況),計算射線和多段線的交點。如果交點中包含了多段線的頂點,就將射線旋轉2度繼續進行判斷;如果不包含多段線的頂點,則根據交點個數來判斷點和多段線的位置關係。

工具函數的添加:

  1. MathUtil.h頭文件中添加:

static bool IsEqual(double a,double b,double tol=1.0*10E-7);

static int GetRand(int minValue,int maxValue);

static double Round(double a,int precision);

static int Round(double a);

  1. MathUtil.cpp文件中添加:

bool CMathUtil::IsEqual(double a,double b,double tol/*=1.0*10E-7*/)

{

return  (fabs(a-b)<tol);

}

//對一個數按照指定的小數位數進行四捨五入

double CMathUtil::Round(double a,int precision)

{

return (floor(a*pow(10.0,precision)+0.5))/pow(10.0,precision);

}

 int CMathUtil::Round(double a)

{

return (int)(a+0.5);

}

int CMathUtil::GetRand(int minValue,int maxValue) 

{

assert(maxValue-minValue>0);

int value=rand();

int rc=minValue+(int)CMathUtil::Round(((double)value)/RAND_MAX*(maxValue-minValue));//將生成的隨機數映射到區間上。

return rc;

}

 

  1. GePointUtil.h頭文件中添加:

static bool IsEqual(const AcGePoint3d &firstPoint,const AcGePoint3d &secondPoint,double tol=1.0E-7);

static bool IsEqual(const AcGePoint2d &firstPoint,const AcGePoint2d &secondPoint,double tol=1.0E-7);

static int FindPoint(const AcGePoint3dArray &points,const AcGePoint3d &point,double tol=1.0E-7);

static int FindPoint(const AcGePoint2dArray &points,const AcGePoint2d &point,double tol=1.0E-7);

static void FilterEqualPoints(AcGePoint3dArray &points,double tol=1.0E-7);

static void FilterEqualPoints(AcGePoint3dArray &points,const AcGePoint2d &pt,double tol=1.0E-7);

 

  1. GePointUtil.cpp頭文件中添加:

 bool CGePointUtil::IsEqual(const AcGePoint3d &firstPoint,const AcGePoint3d &secondPoint,double tol/*=1.0E-7*/)

{

return (fabs(firstPoint.x-secondPoint.x)<tol &&

fabs(firstPoint.y-secondPoint.y)<tol &&

fabs(firstPoint.z-secondPoint.z)<tol);

}

 

 bool CGePointUtil::IsEqual(const AcGePoint2d &firstPoint,const AcGePoint2d &secondPoint,double tol/*=1.0E-7*/)

 {

 return (fabs(firstPoint.x-secondPoint.x)<tol &&

 fabs(firstPoint.y-secondPoint.y)<tol );

 }

 //在數組中查找點,返回點在數組中的索引,如果沒有找到點就返回-1

 int CGePointUtil::FindPoint(const AcGePoint3dArray &points,const AcGePoint3d &point,double tol/*=1.0E-7*/)

 {

 for (int i=0;i<points.length();i++)

 {

 if (IsEqual(points[i],point,tol))

 {

 return i;

 }

 }

 return -1;

 }

 

 //在數組中查找點,返回點在數組中的索引,如果沒有找到點就返回-1

 int CGePointUtil::FindPoint(const AcGePoint2dArray &points,const AcGePoint2d &point,double tol/*=1.0E-7*/)

 {

 for (int i=0;i<points.length();i++)

 {

 if (IsEqual(points[i],point,tol))

 {

 return i;

 }

 }

 return -1;

 }

 

 //點數組本身去重複點

 void CGePointUtil::FilterEqualPoints( AcGePoint3dArray &points,double tol/*=1.0E-7*/)

 {

 for (int i=points.length()-1;i>0;i--)

 {

for (int j=0;j<i;j++)

{

if (CMathUtil::IsEqual(points[i].x,points[j].x,tol)&&

CMathUtil::IsEqual(points[i].y,points[j].y,tol)&&

CMathUtil::IsEqual(points[i].z,points[j].z,tol))

{

points.removeAt(i);

break;

}

}

 }

 }

 void CGePointUtil::FilterEqualPoints( AcGePoint3dArray &points,const AcGePoint2d &pt,double tol/*=1.0E-7*/)

 {

 AcGePoint3dArray tempPoints;

 for (int i=0;i<points.length();i++)

 {

 if (CConvertUtil::ToPoint2d(points[i]).distanceTo(pt)>tol)

 {

 tempPoints.append(points[i]);

 }

 }

 points=tempPoints;

 }

 

  1. 在PolylineUtil.h中添加:

static bool PointIsPolyVert(AcDbPolyline* pPoly,const AcGePoint2d &pt,double tol=1.0E-7);

static void IntersectWithGeRay(AcDbPolyline *pPoly,const AcGeRay2d &geRay,AcGePoint3dArray &intPoints,double tol=1.0E-7);

static int PtRelationToPoly(AcDbPolyline *pPoly,const AcGePoint2d &pt,double tol=1.0E-7);

  1. 在PolylineUtil.cpp中添加:

void CPolylineUtil::IntersectWithGeRay(AcDbPolyline *pPoly,const AcGeRay2d &geRay,AcGePoint3dArray &intPoints,double tol/*=1.0E-7*/)

{

intPoints.setLogicalLength(0);

AcGePoint2dArray intPoints2d;

 

AcGeTol geTol;

geTol.setEqualPoint(tol);

for (int i=0;i<(int)(pPoly->numVerts());i++)

{

if (i<(int)(pPoly->numVerts())-1||pPoly->isClosed()==Adesk::kTrue)

{

double bugle=0;

pPoly->getBulgeAt(i,bugle);

if (fabs(bugle)<1.0E-7)

{

AcGeLineSeg2d geLine;

Acad::ErrorStatus es=pPoly->getLineSegAt(i,geLine);

AcGePoint2d intPoint;

if (geLine.intersectWith(geRay,intPoint,geTol)==Adesk::kTrue)

{

if (CGePointUtil::FindPoint(intPoints2d,intPoint,tol)<0)

{

intPoints2d.append(intPoint);

}

}

}

else

{

AcGeCircArc2d geArc;

pPoly->getArcSegAt(i,geArc);

AcGePoint2d pt1,pt2;

int count=0;

if (geArc.intersectWith(geRay,count,pt1,pt2,geTol)==Adesk::kTrue)

{

if (CGePointUtil::FindPoint(intPoints2d,pt1,tol)<0)

{

intPoints2d.append(pt1);

}

if (count>1 && CGePointUtil::FindPoint(intPoints2d,pt2,tol)<0)

{

intPoints2d.append(pt2);

}

}

}

}

}

double z=pPoly->elevation();

for (int i=0;i<intPoints2d.length();i++)

{

intPoints.append(AcGePoint3d(intPoints2d[i].x,intPoints2d[i].y,z));

}

}

 

 int CPolylineUtil::PtRelationToPoly(AcDbPolyline *pPoly,const AcGePoint2d &pt,double tol/*=1.0E-7*/)

{

assert (pPoly);

//1.如果點在多段線的最近點和給定的點重合,表示點在多段線上

AcGePoint3d closestPoint;

pPoly->getClosestPointTo(CConvertUtil::ToPoint3d(pt,pPoly->elevation()),closestPoint);

 

if (fabs(closestPoint.x-pt.x)<tol && fabs(closestPoint.y-pt.y)<tol)

{

return 0;

}

//2 第一個射線的方向是從最近點到當前點,起點是當前點

//射線的起點是pt,方向從最近點到pt,如果反向做判斷,則最近點距離pt太近的時候,最近點也會被作爲一個交點(這個交點不太容易被排除掉)

//此外,這樣的射線方向很容易判斷出點不在內部的情況

AcGeVector3d vec(-(closestPoint[X]-pt[X]),-(closestPoint[Y]-pt[Y]),0);

AcGeRay2d geRay(AcGePoint2d(pt.x,pt.y),AcGePoint2d(pt.x+vec.x,pt.y+vec.y));

 

//3、射線與多段線計算交點

AcGePoint3dArray intPoints;

IntersectWithGeRay(pPoly,geRay,intPoints,1.0E-4);

 

//

CGePointUtil::FilterEqualPoints(intPoints,1.0E-4);

 

 

RETRY:

if(intPoints.length()==0)

{

return -1;

}

else

{

CGePointUtil::FilterEqualPoints(intPoints,CConvertUtil::ToPoint2d(closestPoint));

 

for (int i=intPoints.length()-1;i>=0;i--)

{

if (  (intPoints[i][X]-pt[X])*(closestPoint[X]-pt[X])>=0 &&

(intPoints[i][Y]-pt[Y])*(closestPoint[Y]-pt[Y])>=0   )

{

intPoints.removeAt(i);

}

}

 

int count=intPoints.length();

for (int i=0;i<intPoints.length();i++)

{

if (PointIsPolyVert(pPoly,CConvertUtil::ToPoint2d(intPoints[i]),1.0E-4))

{

if (PointIsPolyVert(pPoly,AcGePoint2d(pt.x,pt.y),1.0E-4))

{

return 0;

}

 

vec=vec.rotateBy(0.035,AcGeVector3d::kZAxis);

geRay.set(AcGePoint2d(pt.x,pt.y),AcGePoint2d(pt.x+vec.x,pt.y+vec.y));

intPoints.setLogicalLength(0);

IntersectWithGeRay(pPoly,geRay,intPoints,1.0E-4);

goto RETRY;

}

}

if (count%2==0)

{

return -1;

}

else

{

return 1;

}

}

}

詳細筆記細節請關注  yunyou.ke.qq.com 報名免費課後加老師微信後獲取。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章