Выбор точки на 3DSolid при выборе примитива
Функция acedEntSel даёт возможность пользователю выбрать примитив и также позволяет получить точку, которая была указана при выборе примитива. Когда эту функцию используют с 2D-примитивом, тока возвращаемая acedEntSel очень удобна в случае если нужна информация для таких задач как РАЗОРВАТЬ (Break), ОБРЕЗАТЬ (Trim) и т.д.Однако если acedEntSel используется с 3DSolid, точка возвращается в плоскости XY текущей ПСК вне зависимости от того где указали точку на 3DSolid. Если включена объектная привязка (OSNAP) при выборе примитива, тогда точка будет на поверхности 3DSolid. Если важно получить точку на 3DSolid, которая использовалась при выборе объекта именно при помощи кода, то можно использовать следующий алгоритм:
В следующем коде создаётся луч (Ray) вдоль направления взгляда и находятся все точки пересечения луча с 3DSolid. Код показывает все точки пересечения. Но первая точка пересечения будет именно той точкой, которую выбрал пользователь.
Необходимо отметить, что в AutoCAD 2015 и AutoCAD 2016, метод "AcBrBrep::getLineContainment" возвращает меньшее количество точек пересечения при тесте. Это поведение передано для изучения и исправления команде инженер. AutoCAD 2014 и предыдущие возвращают правильное количество точек.
Ниже записанное видео и пример кода:
- static void SelectOn3dSolid()
- {
- Acad::ErrorStatus es;
- // pt - это точка в ПСК, а точнее в плоскости XY ПСК
- // если не включены привязки при выборе объекта
- // В этом случае у точки есть все три координаты в ПСК
- ads_name ename;
- ads_point pt;
- int ret = acedEntSel(_T("\nУкажите 3DSOLID : " ), ename, pt);
- if (ret != RTNORM)
- return ;
- AcDbObjectId entId = AcDbObjectId::kNull;
- es = acdbGetObjectId(entId, ename);
- AcDbEntity *pEnt = NULL;
- AcDb3dSolid *pSolid = NULL;
- es = acdbOpenAcDbEntity(pEnt, entId, AcDb::kForRead);
- pSolid = AcDb3dSolid::cast(pEnt);
- if (pSolid == NULL)
- {
- acutPrintf(L"\nВыбранный объект не 3DSOLID.\\n" );
- return ;
- }
- // Получаем координату в МСК для выбранной точки
- AcGePoint3d wcsPt = AcGePoint3d::kOrigin;
- acdbUcs2Wcs(pt, pt, 0);
- wcsPt = asPnt3d(pt);
- resbuf viewRb;
- AcGePoint3d target = AcGePoint3d::kOrigin;
- // Получаем Цель (TARGET) в ПСК
- acedGetVar(_T("TARGET" ), &viewRb);
- target = asPnt3d(viewRb.resval.rpoint);
- acdbUcs2Wcs(asDblArray(target), asDblArray(target), 0);
- AcGeVector3d dir = AcGeVector3d::kIdentity;
- // Направление взгляда (VIEWDIR) в ПСК
- acedGetVar( ACRX_T("VIEWDIR" ), &viewRb );
- dir = asVec3d(viewRb.resval.rpoint);
- acdbUcs2Wcs(asDblArray(dir), asDblArray(dir), 1);
- AcGePoint3d position = target + dir;
- dir = dir.normalize().negate();
- AcGeLine3d testRay(
- wcsPt.project(AcGePlane(position, dir), dir.negate()),
- dir);
- AcBrBrep* pBrep = new AcBrBrep();
- pBrep->setSubentPath(AcDbFullSubentPath( pEnt->objectId(), AcDbSubentId()));
- AcBr::ErrorStatus bres;
- AcBrHit *pHits = NULL;
- Adesk::UInt32 nHitsFound = 0;
- // Находим все пересечения
- bres = pBrep->getLineContainment(testRay, 0, nHitsFound, pHits );
- if (bres == AcBr::eOk)
- {
- for ( Adesk::UInt32 i = 0; i < nHitsFound; i++)
- {
- AcBrEntity *pHitEntity = NULL;
- pHits[i].getEntityHit( pHitEntity );
- if ( pHitEntity == NULL )
- continue ;
- if ( ! pHitEntity->isKindOf(AcBrBrep::desc()))
- {
- AcGePoint3d hitPt; pHits[i].getPoint(hitPt);
- AcDbPoint *pDbPt = new AcDbPoint(hitPt);
- PostToDb(pDbPt);
- es = pDbPt->close();
- }
- delete pHitEntity;
- }
- delete [] pHits;
- }
- delete pBrep;
- pEnt->close();
- }
Источник: http://adndevblog.typepad.com/autocad/2015/06/selected-point-on-solid-during-entity-selection.html
Обсуждение: http://adn-cis.org/forum/index.php?topic=2834
Опубликовано 07.07.2015