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

07/05/2016

Как средствами ObjectARX получить точки пересечения кривой и плоскости

Вопрос: Имеется кривая (наследник AcDbCurve) и задана плоскость AcGePlane. Каким образом можно получить все точки пересечения кривой и плоскости?

Ответ: Для этой цели мы воспользуемся геометрической библиотекой. Во-первых, при помощи функции acdbConvertAcDbCurveToGelibCurve мы преобразуем AcDbCurve (и любого его наследника) в AcGeCurve3d. Во-вторых, воспользуемся классом AcGeCurveSurfInt для получения точек пересечения кривой и плоскости.

Ниже вы видите исходный код функции, которая запрашивает у пользователя кривую, начальный и конечный уровень для горизонтальных плоскостей и шаг между горизонтальными плоскостями. Результат её работы – желтые точки, отмечающие пересечение плоскостей и кривой.

Код - C++: [Выделить]
  1. static void RivilisCheckInt () {
  2.   Acad::ErrorStatus es;
  3.   ads_name en; ads_point p;
  4.   double level1 = -10.0;
  5.   double level2 = +10.0;
  6.   double step = 1.0;
  7.   if (acedEntSel(_T("\nВыберите произвольную кривую: "), en, p) == RTNORM) {
  8.     TCHAR buf1[32]; acdbRToS(level1,-1,-1, buf1, sizeof(buf1)-1);
  9.     TCHAR buf2[32]; acdbRToS(level2,-1,-1, buf2, sizeof(buf2)-1);
  10.     TCHAR buf3[32]; acdbRToS(step,-1,-1, buf3, sizeof(buf3)-1);
  11.     AcString s1;
  12.    s1.format(_T("\nУкажите начальную отметку уровня для проверки пересечения с плоскостью <%s>: "), buf1);
  13.     AcString s2;
  14.    s2.format(_T("\nУкажите конечную отметку уровня для проверки пересечения с плоскостью <%s>: "), buf2);
  15.     if (acedGetReal(s1,&level1) != RTCAN && acedGetReal(s2,&level2) != RTCAN) {
  16.       AcString s3; s3.format(_T("\nУкажите шаг уровней <%s>: "), buf3);
  17.       acedInitGet(RSG_NOZERO | RSG_NONEG, NULL);
  18.       if (acedGetReal(s3,&step) == RTCAN) return;
  19.       AcDbObjectId eId; acdbGetObjectId(eId, en);
  20.       AcDbObjectPointer<AcDbCurve> pCurve(eId, AcDb::kForRead);
  21.       if (pCurve.openStatus() == Acad::eWrongObjectType) {
  22.         acutPrintf(_T("\nВыбрана не кривая. Допустимы линии, полилинии, дуги, окружности, сплайны, и т.д."));
  23.         return;
  24.       }
  25.       if (pCurve.openStatus() != Acad::eOk) {
  26.         acutPrintf(_T("\nОшибка открытия: %s"), acadErrorStatusText(pCurve.openStatus()));
  27.         return;
  28.       }
  29.       // GE-кривая, полученная из AcDb-кривой
  30.       AcGeCurve3d *pGeCurve = NULL;
  31.       if ((es = acdbConvertAcDbCurveToGelibCurve(pCurve, pGeCurve)) != Acad::eOk) {
  32.         acutPrintf(_T("\nacdbConvertAcDbCurveToGelibCurve: %s"), acadErrorStatusText(es));
  33.         return;
  34.       }
  35.       for (double z = min(level1, level2); z <= max(level1,level2); z += step)
  36.       {
  37.         // Плоскость сечения
  38.         AcGePlane plan(AcGePoint3d(0,0,z), AcGeVector3d::kZAxis);
  39.         AcGeIntersectError err;
  40.         AcGeCurveSurfInt csint(*pGeCurve, plan);
  41.         int n = csint.numIntPoints(err);
  42.         if ((n = csint.numIntPoints(err)) != 0)
  43.         {
  44.           // Задаём форму точки
  45.           acdbCurDwg()->setPdmode(34);
  46.           acutPrintf(_T("\nВсего %d пересечений на уровне %g"), n, z);
  47.           AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForWrite);
  48.           if (pBTR.openStatus() == Acad::eOk) {
  49.             for (int i = 0; i < n; i++) {
  50.               AcDbPoint *pPoint = new AcDbPoint(csint.intPoint(i,err));
  51.               pPoint->setDatabaseDefaults();
  52.               pPoint->setColorIndex(2);
  53.               pBTR->appendAcDbEntity(pPoint);
  54.               pPoint->close();
  55.             }
  56.           }
  57.         }
  58.       }
  59.       delete pGeCurve;
  60.     }
  61.   }
  62. }
  63.  

Полный проект: CurvSurfInter.zip

Результаты работы:

Автор: Александр Ривилис

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

Опубликовано 07.05.2016