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

20/03/2018

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

Это можно сделать при помощи B-Rep API. Следующий код иллюстрирует как получить пересечение линейного примитива (ОТРЕЗОК, ЛУЧ, ПРЯМАЯ) с примитивом, который представляется в виде ACIS (т.е. твердое тело - SOLID, область - REGION, или тело - BODY).

Код - C++: [Выделить]
  1. //-----------------------------------------------------------------------------
  2. //----- acrxEntryPoint.cpp
  3. //-----------------------------------------------------------------------------
  4. #include "StdAfx.h"
  5. #include "resource.h"
  6.  
  7. //-----------------------------------------------------------------------------
  8. #define szRDS _RXST("")
  9.  
  10. //-----------------------------------------------------------------------------
  11. //----- ObjectARX EntryPoint
  12. class CIntSolid3DApp : public AcRxArxApp {
  13.  
  14. public:
  15.        CIntSolid3DApp () : AcRxArxApp () {}
  16.  
  17.        virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
  18.               AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg (pkt) ;
  19.              return (retCode) ;
  20.        }
  21.  
  22.        virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
  23.              AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg (pkt) ;
  24.              return (retCode) ;
  25.        }
  26.  
  27.        virtual void RegisterServerComponents () {}
  28.       
  29.   // Команда INTSOLID
  30.   static void Asdkintsolid()
  31.   {
  32.     AcDbObjectId lineId;
  33.     AcDbObjectId solidId;
  34.     AcDbEntity * pEnt;
  35.     AcDbEntity * pLinearEnt;
  36.     AcGePoint3dArray hitPoints;
  37.     int nHitsWanted;
  38.     ads_name en;
  39.     ads_point pt;
  40.     // Просим пользоваля выбрать линию
  41.  
  42.     if (acedEntSel(_T("\nВыберите линию: "), en, pt) != RTNORM)
  43.       return;
  44.  
  45.     // Получаем указатель на неё
  46.     if (acdbGetObjectId(lineId, en) != Acad::eOk)
  47.     {
  48.       return;
  49.     }
  50.  
  51.     acdbOpenAcDbEntity(pLinearEnt, lineId, AcDb::kForRead);
  52.     if (pLinearEnt == NULL)
  53.     {
  54.       acutPrintf(_T("\nНе смогли открыть линию"));
  55.       return;
  56.     }
  57.  
  58.     // Просим пользователя выбрать твердое тело
  59.     if (acedEntSel(_T("\nВыберите твердое тело: "), en, pt) != RTNORM)
  60.       return;
  61.  
  62.     // Получаем указатель на него
  63.     if (acdbGetObjectId(solidId, en) != Acad::eOk)
  64.     {
  65.       return;
  66.     }
  67.  
  68.     acdbOpenAcDbEntity(pEnt, solidId, AcDb::kForRead);
  69.     if (pEnt == NULL)
  70.     {
  71.       acutPrintf(_T("\nНе смогли открыть твердое тело"));
  72.       pLinearEnt->close();
  73.       return;
  74.     }
  75.  
  76.     // Спрашиваем количество пересечений, которые должны быть возвращены.
  77.     // Если введено значение 0, то возвращаются все пересечения.
  78.     if (RTNORM != acedGetInt(_T("\nУкажите количество требуемых пересечений : "),
  79.       &nHitsWanted))
  80.     {
  81.       acutPrintf(_T("\nЭто должно быть целое число"));
  82.       pEnt->close();
  83.       pLinearEnt->close();
  84.       return;
  85.     }
  86.  
  87.     // Находим количество пересечений
  88.     if (Acad::eOk != getHits(pLinearEnt, pEnt,
  89.       nHitsWanted, hitPoints))
  90.     {
  91.       pEnt->close();
  92.       pLinearEnt->close();
  93.       return;
  94.     }
  95.  
  96.     // Примитивы нам больше не нужны - закрываем
  97.     pEnt->close();
  98.     pLinearEnt->close();
  99.  
  100.     // Печатаем пересечения
  101.     int len = hitPoints.length();
  102.     if (len == 0)
  103.     {
  104.       acutPrintf(_T("\nПересечения не найдены."));
  105.     }
  106.     else
  107.     {
  108.       acutPrintf(_T("\nНайдено %d пересечений."), len);
  109.  
  110.       for (int i = 0; i < len; i++)
  111.       {
  112.         AcGePoint3d pt = hitPoints[i];
  113.         acutPrintf(_T("\nПересечение %d: (%f, %f, %f)"),
  114.           i + 1, pt[X], pt[Y], pt[Z]);
  115.       }
  116.     }
  117.     return;
  118.   }
  119.  
  120.   static Acad::ErrorStatus getHits(
  121.     AcDbEntity * pLinearEnt,
  122.     AcDbEntity * pEnt,
  123.     int nHitsWanted,
  124.     AcGePoint3dArray &hitPoints)
  125.  
  126.     // Parameters:
  127.     //  AcDbEntity * pLinearEnt - указатель на линию (отрезок, луч, прямая)
  128.     //  AcDbEntity * pEnt - указатель на твердое тело
  129.     //  int nHitsWanted - количество запрашиваемых пересечений
  130.     //  (0 означает все)
  131.     //  AcGePoint3dArray hitPoints - массив точек пересечений
  132.     // Returns:
  133.     //  Acad::eOk - если всё хорошо
  134.     //  Acad::eInvalidInput - если возникли проблемы
  135.   {
  136.  
  137.     // Проверяем, что примитив правильного типа
  138.     if (!(pEnt->isKindOf(AcDb3dSolid::desc()) ||
  139.       pEnt->isKindOf(AcDbRegion::desc()) ||
  140.       pEnt->isKindOf(AcDbBody::desc())))
  141.     {
  142.       acutPrintf(_T("\nВторой аргумент должен быть твердым телом, а не %s"),
  143.         pEnt->isA()->name());
  144.       return Acad::eInvalidInput;
  145.     }
  146.  
  147.     // Проверяем, что указатель на линию соответствующего типа и
  148.     // создаём соотвествующий AcGe-объект.
  149.  
  150.     AcGeLinearEnt3d * pGeLine;
  151.     if (pLinearEnt->isKindOf(AcDbLine::desc()))
  152.     {
  153.       AcDbLine * pLine = (AcDbLine*)pLinearEnt;
  154.       pGeLine = new AcGeLineSeg3d(pLine->startPoint(), pLine->endPoint());
  155.     }
  156.     else if (pLinearEnt->isKindOf(AcDbRay::desc()))
  157.     {
  158.       AcDbRay * pRay = (AcDbRay*)pLinearEnt;
  159.       pGeLine = new AcGeRay3d(pRay->basePoint(), pRay->unitDir());
  160.     }
  161.     else if (pLinearEnt->isKindOf(AcDbXline::desc()))
  162.     {
  163.       AcDbXline * pXline = (AcDbXline *)pLinearEnt;
  164.       pGeLine = new AcGeLine3d(pXline->basePoint(), pXline->unitDir());
  165.     }
  166.     else
  167.     {
  168.       acutPrintf(_T("\nПервый агрумент должен быть линией, а не %s"),
  169.         pLinearEnt->isA()->name());
  170.       return Acad::eInvalidInput;
  171.     }
  172.  
  173.     // Находим количество пересечений при помощи B-Rep API
  174.     AcBrBrep*pBrep = new AcBrBrep;
  175.     AcDbObjectId solidId = pEnt->objectId();
  176.     pBrep->setSubentPath(AcDbFullSubentPath(solidId,
  177.       AcDbSubentId()));
  178.  
  179.     AcBrHit*pHits = NULL;
  180.     Adesk::UInt32 nHitsFound;
  181.     pBrep->getLineContainment(*pGeLine, nHitsWanted, nHitsFound, pHits);
  182.  
  183.     // Добавляем допустимые точки пересечения в hitPoints
  184.  
  185.     for (Adesk::UInt32 i = 0; i < nHitsFound; i++)
  186.     {
  187.  
  188.       AcBrEntity*pHitEntity = NULL;
  189.       pHits[i].getEntityHit(pHitEntity);
  190.  
  191.       if (pHitEntity == NULL)
  192.         continue;
  193.  
  194.       AcGePoint3d hitPt;
  195.       pHits[i].getPoint(hitPt);
  196.  
  197.       if (!pHitEntity->isKindOf(AcBrBrep::desc()))
  198.       {
  199.         hitPoints.append(hitPt);
  200.       }
  201.       else
  202.       {
  203.         acutPrintf(
  204.           _T("\nИгнорируемая точка (%f, %f, %f) в %s"),
  205.           hitPt.x, hitPt.y, hitPt.z, pHitEntity->isA()->name());
  206.       }
  207.  
  208.       delete pHitEntity;
  209.  
  210.     }
  211.  
  212.     // Конвертируем точки из МСК в ПСК
  213.  
  214.     int nPts = hitPoints.length();
  215.     for (int i = 0; i<nPts;i++)
  216.     {
  217.       ads_point pt;
  218.       asPnt3d(pt) = hitPoints[i];
  219.       acdbWcs2Ucs(pt, pt, 0);
  220.       hitPoints[i] = asPnt3d(pt);
  221.     }
  222.  
  223.     // Чистим всё ненужное
  224.     delete[] pHits;
  225.     delete pBrep;
  226.     delete pGeLine;
  227.     return Acad::eOk;
  228.   }
  229.       
  230. } ;
  231.  
  232. //-----------------------------------------------------------------------------
  233. IMPLEMENT_ARX_ENTRYPOINT(CIntSolid3DApp)
  234.  
  235. ACED_ARXCOMMAND_ENTRY_AUTO(CIntSolid3DApp, Asdk, intsolid, intSolid, ACRX_CMD_MODAL, NULL)

 

Источник: http://adndevblog.typepad.com/autocad/2013/02/how-to-intersect-a-line-with-a-solid.html

 

 

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

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

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