ADN Open CIS
Сообщество программистов Autodesk в СНГ

29/05/2013

Пересечение между примитивами 3-ГРАНЬ и ОТРЕЗОК при помощи ARX

Вопрос:
Как можно вычислить точку пересечения (если она есть) между AcDbFace и AcDbLine

Ответ:
Существуют два основных пути которыми это можно осуществлено с помощью ARX и оба они далее показаны:

1 – Первый путь – создание бесконечной плоскости и бесконечной прямой, а затем использование луча из точки их пересечения, чтобы понять внутри ли 3-грани эта точка.

2 – Второй путь – использование 3D-тел. Создаём тонкое выдавленное тело из 3-грани, а другое из отрезка. Тогда выполняем для них метод checkInterferences для получения точки пересечения.

Ниже примеры этих функций вместе с тестовой функцией:

Код - C++: [Выделить]
  1. //////////////////////////////////////////////////
  2. // Использование: Пересечение между 3-гранью
  3. // и Отрезком с использованием луча
  4. //////////////////////////////////////////////////
  5. void FindIntersection(AcDbFace* pFace, AcDbLine* pLine)
  6. {
  7.  AcGePoint3d vertex1, vertex2, vertex3, vertex4;
  8.  
  9.  pFace->getVertexAt(0, vertex1);
  10.  pFace->getVertexAt(1, vertex2);
  11.  pFace->getVertexAt(2, vertex3);
  12.  pFace->getVertexAt(3, vertex4);
  13.  
  14.  AcGeVector3d vecU(vertex2.asVector()-vertex1.asVector());
  15.  AcGeVector3d vecV(vertex3.asVector()-vertex1.asVector());
  16.  
  17.  // Создаём временную плоскость
  18.  AcGePlane plane(vertex1, vecU, vecV);
  19.  
  20.  // Создаём временный отрезок
  21.  AcGeLineSeg3d line (pLine->startPoint(), pLine->endPoint());
  22.  
  23.  // Находим пересечение
  24.  AcGePoint3d resultPoint;
  25.  
  26.  if (plane.intersectWith(line, resultPoint) == Adesk::kTrue)
  27.  {
  28.   AcGeRay3d ray(resultPoint, vertex1.asVector() - vertex2.asVector());
  29.  
  30.   int intNum = 0;
  31.  
  32.   // Проверяем точку пересечения на попадание внутрь 3-грани
  33.   AcGePoint3d intPoint;
  34.  
  35.   if (ray.intersectWith(AcGeLineSeg3d(vertex1, vertex2), intPoint)
  36.        == Adesk::kTrue) ++intNum;
  37.   if (ray.intersectWith(AcGeLineSeg3d(vertex2, vertex3), intPoint)
  38.        == Adesk::kTrue) ++intNum;
  39.   if (ray.intersectWith(AcGeLineSeg3d(vertex3, vertex4), intPoint)
  40.       == Adesk::kTrue) ++intNum;
  41.   if (ray.intersectWith(AcGeLineSeg3d(vertex4, vertex1), intPoint)
  42.       == Adesk::kTrue) ++intNum;
  43.  
  44.   // если intNum нечетное – точка внутри
  45.   if((intNum%2) != 0)
  46.   {
  47.    acutPrintf (L"\nТочка пересечения: [%f, %f, %f]",
  48.        resultPoint.x, resultPoint.y, resultPoint.z);
  49.   }
  50.  }
  51. }
  52.  
  53. /////////////////////////////////////////////////////////////////////
  54. // Использование: Пересечение между 3-гранью
  55. // и Отрезком с помощью 3D-тел
  56. /////////////////////////////////////////////////////////////////////
  57. void FindIntersection2(AcDbFace* pFace, AcDbLine* pLine)
  58. {
  59.  // Направление отрезка
  60.  AcGeVector3d direction (pLine->endPoint()-pLine->startPoint());
  61.  
  62.  // Создаём временный круг
  63.  AcDbCircle* pcircle =
  64.      new AcDbCircle(pLine->startPoint(), direction, 0.01);
  65.  
  66.  // Создаем временное 3D-тело
  67.  AcDb3dSolid* pSolidLine = new AcDb3dSolid ();
  68.  
  69.  AcDbSweepOptions sweepOptions;
  70.  
  71.  pSolidLine->createExtrudedSolid(pcircle, direction, sweepOptions);
  72.  
  73.  // Создаём временное 3D-тело для 3-грани
  74.  AcDb3dSolid  *pSolidFace = new AcDb3dSolid ();
  75.  
  76.  AcGePoint3d vertex1, vertex2, vertex3;
  77.  
  78.  pFace->getVertexAt(0, vertex1);
  79.  pFace->getVertexAt(1, vertex2);
  80.  pFace->getVertexAt(2, vertex3);
  81.  
  82.  AcGeVector3d vec1(vertex2.asVector()-vertex1.asVector());
  83.  AcGeVector3d vec2(vertex3.asVector()-vertex1.asVector());
  84.  
  85.  // Вычисляем перпендикуляр к 3-грани
  86.  AcGeVector3d faceNormal = vec2.crossProduct(vec1);
  87.  
  88.  faceNormal *= 0.01 / faceNormal.length();
  89.  
  90.  // Создаём очень тонкое выдавленное 3D-тело
  91.  pSolidFace->createExtrudedSolid(pFace, faceNormal, sweepOptions);
  92.  
  93.  // Проверяем пересечение между двумя 3D-телами
  94.  Adesk::Boolean IsIntersec;
  95.  AcDb3dSolid* commonVolumeSolid;
  96.  
  97.  Acad::ErrorStatus es =
  98.       pSolidFace->checkInterference(
  99.            pSolidLine,
  100.            Adesk::kTrue,
  101.            IsIntersec,
  102.            commonVolumeSolid); 
  103.  
  104.  if (IsIntersec == Adesk::kTrue)
  105.  {
  106.   double volume;
  107.   AcGePoint3d centroid;
  108.  
  109.   double momInertia[3], prodInertia[3], prinMoments[3],
  110.       radiiGyration[3];
  111.  
  112.   AcGeVector3d prinAxes[3];
  113.  
  114.   AcDbExtents extents;
  115.  
  116.   commonVolumeSolid->getMassProp(
  117.        volume,
  118.        centroid,
  119.        momInertia,
  120.        prodInertia,
  121.        prinMoments,
  122.        prinAxes,
  123.        radiiGyration,
  124.        extents);
  125.  
  126.   acutPrintf (L"\nТочка пересечения: [%f, %f, %f]",
  127.        centroid.x, centroid.y, centroid.z);
  128.  
  129.   delete commonVolumeSolid;
  130.  }
  131.  
  132.  delete pcircle;
  133.  delete pSolidLine;
  134.  delete pSolidFace;
  135. }
  136.  
  137. // Тестовая функция
  138. void FindIntersectionTest(void)
  139. {
  140.  ads_name ename; 
  141.  ads_point pickpt; 
  142.  
  143.  AcDbObjectId objId;
  144.  AcDbObject *pObj;
  145.  
  146.  int rc;
  147.  
  148.  rc= acedEntSel(L"\nВыберите 3-грань: ", ename, pickpt);
  149.  
  150.  if(rc != RTNORM)
  151.  {
  152.   if (rc != RTCAN) acutPrintf(L"\nОшибка выбора примитива ");
  153.   return;
  154.  }
  155.  
  156.  acdbGetObjectId(objId, ename);
  157.  acdbOpenObject(pObj, objId, AcDb::kForRead);
  158.  
  159.  AcDbFace* pEntity1 = AcDbFace::cast(pObj);
  160.  
  161.  if(!pEntity1)
  162.  {
  163.   acutPrintf(L"\nОшибочный выбор ...");
  164.   pObj->close();
  165.   return;
  166.  }
  167.  
  168.  rc= acedEntSel(L"\nВыберите отрезок: ", ename, pickpt);
  169.  
  170.  if(rc != RTNORM)
  171.  {
  172.   if (rc != RTCAN) acutPrintf(L"\nОшибка выбора примитива ");
  173.   return;
  174.  }
  175.  
  176.  acdbGetObjectId(objId, ename);
  177.  acdbOpenObject(pObj, objId, AcDb::kForRead);
  178.  
  179.  AcDbLine* pEntity2 = AcDbLine::cast(pObj);
  180.  
  181.  if(!pEntity2)
  182.  {
  183.   acutPrintf(L"\nОшибочный выбор...");
  184.   pObj->close();
  185.   return;
  186.  }
  187.  
  188.  FindIntersection (pEntity1, pEntity2);
  189.  FindIntersection2(pEntity1, pEntity2);
  190.  
  191.  pEntity1->close();
  192.  pEntity2->close();
  193. }

 

Источник: http://adndevblog.typepad.com/autocad/2012/05/intersection-between-a-face-and-a-line-using-arx.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=58.0

Опубликовано 29.05.2013
Отредактировано 06.06.2013 в 13:07:40