LoveArx 发表于 2017-8-12 00:23:48

射线法判断点是否在曲线内

判断点是否在曲线内,可以用REGION的方法,但是更快的是用射线法,下面是实现代码

enum IncidenceType
{
         kIncidenceToLeft = 0,
         kIncidenceToRight,
         kIncidenceToFront,
         kIncidenceUnknown
};

IncidenceType CurveIncidence(const AcDbCurve* pCurve,
                                       const double& param,
                                       const AcGeVector3d& dir,
                                       const AcGeVector3d& normal)
{
         AcGeVector3d deriv1;
         pCurve->getFirstDeriv(param, deriv1);

         if(deriv1.isParallelTo(dir))
         {
                      // need second degree analysis
                      AcGeVector3d deriv2;
                      pCurve->getSecondDeriv(param, deriv2);

                      if(deriv2.isZeroLength() || deriv2.isParallelTo(dir))
                                  return kIncidenceToFront;
                      else
                      {
                                  if(deriv2.crossProduct(dir).dotProduct(normal) < 0)
                                             return kIncidenceToRight;
                                 
                                  else
                                             return kIncidenceToLeft;
                      }
         }

         if(deriv1.crossProduct(dir).dotProduct(normal) < 0)
                      return kIncidenceToLeft;
         else
                      return kIncidenceToRight;
}

Acad::ErrorStatus IsInsideCurve(const AcDbCurve* pCurve,
                                             const AcGePoint3d& testPt,
                                             bool& result)
{
         result = false;

         if(!pCurve->isClosed() || !pCurve)
         {
                      //Curve needs to be closed
                      return Acad::eInvalidInput;
         }

         Acad::ErrorStatus es;
         AcDb2dPolyline*p2dPoly = AcDb2dPolyline::cast(pCurve);

         if(p2dPoly != NULL && p2dPoly->polyType() != AcDb::k2dSimplePoly)
         {
                      // Not supported
                      return Acad::eInvalidInput;
         }

         AcGePoint3d ptOnCurve;
         es = pCurve->getClosestPointTo(testPt, ptOnCurve);
         
         if(testPt.isEqualTo(ptOnCurve))
         {
                      result = true;
                      return es;
         }

         // check its planar
         AcGePlane plane;
         AcDb::Planarity planarity;
         if((es = pCurve->getPlane(plane, planarity)) != Acad::eOk)
         {
                      return es;
         }

         if(planarity != AcDb::kPlanar)
         {
                      return Acad::eInvalidInput;
         }

         // make the test ray from the plane
         double epsilon = 2e-6; // ( trust me on this )

         AcGePoint3dArray IntersectionPoints;
         AcGeVector3d normal = plane.normal();
         AcGeVector3d testVector = normal.perpVector();

         AcDbRay ray;
         ray.setBasePoint(testPt);

         int nGlancingHits=0, numberOfInters=0;
         bool bRetryWithOtherRayDirection;

         do
         {
                      IntersectionPoints.removeAll();
                      bRetryWithOtherRayDirection = false;
                      ray.setUnitDir(testVector);

                      // fire the ray at the curve
                      if((es = pCurve->intersectWith(&ray, AcDb::kOnBothOperands, IntersectionPoints)) != Acad::eOk)
                                  return es;

                      numberOfInters = IntersectionPoints.length();

                      nGlancingHits = 0;

                      for(int i=0; i < numberOfInters; ++i)
                      {
                              // get the first point, and get its parameter
                              AcGePoint3d hitPt = IntersectionPoints;

                              double hitParam;

                                  //Circumvents an issue with AcDbCurve::getParamAtPoint API
                                  if((es = pCurve->getParamAtPoint(hitPt, hitParam )) != Acad::eOk)
                                  {
                                             bRetryWithOtherRayDirection = true;
                                             testVector.rotateBy(5.0 * 3.141592653/180.0, normal);
                                             break;
                                  }

                                  double inParam = hitParam - epsilon;
                                  double outParam = hitParam + epsilon;

                                  double startParam, endParam;

                                  pCurve->getStartParam(startParam);
                                  pCurve->getEndParam(endParam);

                                  //Loop back inside the curve if param is falling outside of range
                                  if (inParam < startParam)
                                             inParam = endParam - epsilon + (startParam - inParam);

                                  if (outParam > endParam)
                                             outParam = startParam + epsilon + (endParam - outParam);

                                  IncidenceType inIncidence = CurveIncidence(pCurve, inParam, testVector, normal);
                                  IncidenceType outIncidence = CurveIncidence(pCurve, outParam, testVector, normal);

                                  if (inIncidence == kIncidenceToFront || outIncidence == kIncidenceToFront)
                                  {
                                             bRetryWithOtherRayDirection = true;
                                             testVector.rotateBy(5.0 * 3.141592653/180.0, normal);
                                             break;
                                  }

                                  if( (inIncidence == kIncidenceToRight && outIncidence == kIncidenceToLeft) ||
                                  (inIncidence == kIncidenceToLeft && outIncidence == kIncidenceToRight))
                                  {
                                             ++nGlancingHits;
                                  }
                      }
         }
         while (bRetryWithOtherRayDirection);

         result = (( numberOfInters + nGlancingHits) % 2 == 1);

         return es;
}


**** Hidden Message *****


zjy2999 发表于 2017-8-18 17:37:33

学习!!!!!

ymd 发表于 2017-8-19 09:34:21

学习!!!!!

819534890 发表于 2017-8-29 14:22:54

学习,谢谢分享

革天明 发表于 2017-10-12 19:42:44

谢谢楼主分享

aeo 发表于 2017-10-21 15:46:18

{:1_12:}{:1_12:}{:1_12:}{:1_12:}{:1_12:}{:1_12:}

tcdod 发表于 2017-11-6 16:51:00

学习,谢谢分享

qq509103902 发表于 2018-7-20 12:45:40

学习!!!!!

viritue 发表于 2019-4-12 01:55:02

正在学习中,谢谢。

king2012 发表于 2019-7-24 09:13:32

学习!!!!!

yujishatan 发表于 2019-9-4 11:19:06

学习下,谢谢

开箱剁手 发表于 2019-10-10 16:01:22

学习学习

再回首haha 发表于 2020-1-23 21:37:11


学习,谢谢分享

老仓测绘上班记 发表于 2020-5-10 20:18:44

谢谢老大分享!学习学习

phi03c 发表于 2020-9-23 00:20:32

thanks for code
页: [1] 2
查看完整版本: 射线法判断点是否在曲线内