Пересечение между примитивами 3-ГРАНЬ и ОТРЕЗОК при помощи ARX
Вопрос:
Как можно вычислить точку пересечения (если она есть) между AcDbFace и AcDbLine
Ответ:
Существуют два основных пути которыми это можно осуществлено с помощью ARX и оба они далее показаны:
1 – Первый путь – создание бесконечной плоскости и бесконечной прямой, а затем использование луча из точки их пересечения, чтобы понять внутри ли 3-грани эта точка.
2 – Второй путь – использование 3D-тел. Создаём тонкое выдавленное тело из 3-грани, а другое из отрезка. Тогда выполняем для них метод checkInterferences для получения точки пересечения.
Ниже примеры этих функций вместе с тестовой функцией:
- //////////////////////////////////////////////////
- // Использование: Пересечение между 3-гранью
- // и Отрезком с использованием луча
- //////////////////////////////////////////////////
- void FindIntersection(AcDbFace* pFace, AcDbLine* pLine)
- {
- AcGePoint3d vertex1, vertex2, vertex3, vertex4;
- pFace->getVertexAt(0, vertex1);
- pFace->getVertexAt(1, vertex2);
- pFace->getVertexAt(2, vertex3);
- pFace->getVertexAt(3, vertex4);
- AcGeVector3d vecU(vertex2.asVector()-vertex1.asVector());
- AcGeVector3d vecV(vertex3.asVector()-vertex1.asVector());
- // Создаём временную плоскость
- AcGePlane plane(vertex1, vecU, vecV);
- // Создаём временный отрезок
- AcGeLineSeg3d line (pLine->startPoint(), pLine->endPoint());
- // Находим пересечение
- AcGePoint3d resultPoint;
- if (plane.intersectWith(line, resultPoint) == Adesk::kTrue)
- {
- AcGeRay3d ray(resultPoint, vertex1.asVector() - vertex2.asVector());
- int intNum = 0;
- // Проверяем точку пересечения на попадание внутрь 3-грани
- AcGePoint3d intPoint;
- if (ray.intersectWith(AcGeLineSeg3d(vertex1, vertex2), intPoint)
- == Adesk::kTrue) ++intNum;
- if (ray.intersectWith(AcGeLineSeg3d(vertex2, vertex3), intPoint)
- == Adesk::kTrue) ++intNum;
- if (ray.intersectWith(AcGeLineSeg3d(vertex3, vertex4), intPoint)
- == Adesk::kTrue) ++intNum;
- if (ray.intersectWith(AcGeLineSeg3d(vertex4, vertex1), intPoint)
- == Adesk::kTrue) ++intNum;
- // если intNum нечетное – точка внутри
- if((intNum%2) != 0)
- {
- acutPrintf (L"\nТочка пересечения: [%f, %f, %f]",
- resultPoint.x, resultPoint.y, resultPoint.z);
- }
- }
- }
- /////////////////////////////////////////////////////////////////////
- // Использование: Пересечение между 3-гранью
- // и Отрезком с помощью 3D-тел
- /////////////////////////////////////////////////////////////////////
- void FindIntersection2(AcDbFace* pFace, AcDbLine* pLine)
- {
- // Направление отрезка
- AcGeVector3d direction (pLine->endPoint()-pLine->startPoint());
- // Создаём временный круг
- AcDbCircle* pcircle =
- new AcDbCircle(pLine->startPoint(), direction, 0.01);
- // Создаем временное 3D-тело
- AcDb3dSolid* pSolidLine = new AcDb3dSolid ();
- AcDbSweepOptions sweepOptions;
- pSolidLine->createExtrudedSolid(pcircle, direction, sweepOptions);
- // Создаём временное 3D-тело для 3-грани
- AcDb3dSolid *pSolidFace = new AcDb3dSolid ();
- AcGePoint3d vertex1, vertex2, vertex3;
- pFace->getVertexAt(0, vertex1);
- pFace->getVertexAt(1, vertex2);
- pFace->getVertexAt(2, vertex3);
- AcGeVector3d vec1(vertex2.asVector()-vertex1.asVector());
- AcGeVector3d vec2(vertex3.asVector()-vertex1.asVector());
- // Вычисляем перпендикуляр к 3-грани
- AcGeVector3d faceNormal = vec2.crossProduct(vec1);
- faceNormal *= 0.01 / faceNormal.length();
- // Создаём очень тонкое выдавленное 3D-тело
- pSolidFace->createExtrudedSolid(pFace, faceNormal, sweepOptions);
- // Проверяем пересечение между двумя 3D-телами
- Adesk::Boolean IsIntersec;
- AcDb3dSolid* commonVolumeSolid;
- Acad::ErrorStatus es =
- pSolidFace->checkInterference(
- pSolidLine,
- Adesk::kTrue,
- IsIntersec,
- commonVolumeSolid);
- if (IsIntersec == Adesk::kTrue)
- {
- double volume;
- AcGePoint3d centroid;
- double momInertia[3], prodInertia[3], prinMoments[3],
- radiiGyration[3];
- AcGeVector3d prinAxes[3];
- AcDbExtents extents;
- commonVolumeSolid->getMassProp(
- volume,
- centroid,
- momInertia,
- prodInertia,
- prinMoments,
- prinAxes,
- radiiGyration,
- extents);
- acutPrintf (L"\nТочка пересечения: [%f, %f, %f]",
- centroid.x, centroid.y, centroid.z);
- delete commonVolumeSolid;
- }
- delete pcircle;
- delete pSolidLine;
- delete pSolidFace;
- }
- // Тестовая функция
- void FindIntersectionTest(void)
- {
- ads_name ename;
- ads_point pickpt;
- AcDbObjectId objId;
- AcDbObject *pObj;
- int rc;
- rc= acedEntSel(L"\nВыберите 3-грань: ", ename, pickpt);
- if(rc != RTNORM)
- {
- if (rc != RTCAN) acutPrintf(L"\nОшибка выбора примитива ");
- return;
- }
- acdbGetObjectId(objId, ename);
- acdbOpenObject(pObj, objId, AcDb::kForRead);
- AcDbFace* pEntity1 = AcDbFace::cast(pObj);
- if(!pEntity1)
- {
- acutPrintf(L"\nОшибочный выбор ...");
- pObj->close();
- return;
- }
- rc= acedEntSel(L"\nВыберите отрезок: ", ename, pickpt);
- if(rc != RTNORM)
- {
- if (rc != RTCAN) acutPrintf(L"\nОшибка выбора примитива ");
- return;
- }
- acdbGetObjectId(objId, ename);
- acdbOpenObject(pObj, objId, AcDb::kForRead);
- AcDbLine* pEntity2 = AcDbLine::cast(pObj);
- if(!pEntity2)
- {
- acutPrintf(L"\nОшибочный выбор...");
- pObj->close();
- return;
- }
- FindIntersection (pEntity1, pEntity2);
- FindIntersection2(pEntity1, pEntity2);
- pEntity1->close();
- pEntity2->close();
- }
Источник: 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
Отредактировано 06.06.2013 в 13:07:40