Тема: Как найти пересекающиеся объекты?
Господа, не подскажите, возможно ли найти пересекающиеся объекты/примитивы? Они могут лежать на разных слоях.
Заранее спасибо.
Информационный портал для профессионалов в области САПР
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Форумы CADUser → Программирование → ObjectARX → Как найти пересекающиеся объекты?
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Господа, не подскажите, возможно ли найти пересекающиеся объекты/примитивы? Они могут лежать на разных слоях.
Заранее спасибо.
Возможно. Слои в данном случае значения не имеют. Смотри в документации метод AcDbEntity::intersectWith(...)
Такой вопрос, если ищещь объекты пересекающиеся с полилинией нужно проверять её дуги, сегменты и точки? или достаточно искать пересечения с ней самой?
А почитать документацию и проверить самому сложно?
Проверка показала, что всё равно, есть там сегменты полилинии или нет. Но! Точки пересечения программа не находит, а они там есть!!!
> dimsan
Ответ неверный. Смотри пример ObjectARX SDK samples\database\ARXDBG\
В нем файл Tests\ArxDbgCmdTests.cpp, в нем функцию ArxDbgCmdTests::testIntersect()
Посмотрел, ничего сверхмудрого не увидел. Они просто выбирают продолжать(в смысле extend) примитивы до точки пересечения или нет, на свой вопрос: Нужно ли рассматривать сегменты полилинии на пересечения ответа так и не получил
Нашол ашипку в анализе =0
Вывод такой: никаких элементов полилинии пересматривать ненужно, достаточно искать пересечения полилинии с другими entity.
Всем спасибо, все свободны =)
> dimsan
Все правильно. Я как раз и намекал на ошибку в коде, сославшись на пример, который для полилиний нормально работает.
> Александр Ривилис
У меня какая-то проблема не правильно находит пересечение между полилинией и блоком
void CDWGObjects::printCrossingPoints(void) { std::list<CCrossingPoint*>::const_iterator myIter; for ( myIter = DocVars.docData().DWGObjects.DifferentCrossingObjects.begin(); myIter!= DocVars.docData().DWGObjects.DifferentCrossingObjects.end(); myIter++) { acutPrintf(" Пересечение с %d:\n",(*myIter)->Data_Type); acutPrintf(" С (%f,%f,%f) на пикете %f\n", (*myIter)->x_Beg, (*myIter)->y_Beg, (*myIter)->z_Beg, (*myIter)->BegStation); acutPrintf(" По (%f,%f,%f) на пикете %f\n", (*myIter)->x_End, (*myIter)->y_End, (*myIter)->z_End, (*myIter)->EndStation); } } void CDWGObjects::findingCrossing(AcDbEntity* PipeEntity) { //Итератор для примитивов пересекающихся с трубой std::list<CSurfaceObject*>::const_iterator ObjectsIter; AcDbEntity* ObjectEntity; //Ищем пересечения с поверхностными объектами for( ObjectsIter = this->SurfaceObjects.begin(); ObjectsIter != this->SurfaceObjects.end(); ObjectsIter++) { ObjectEntity = this->getEntitybyStrHandler((*ObjectsIter)->Handler); if (ObjectEntity) { AcGePoint3dArray IntersectionPoints; if(PipeEntity->intersectWith(ObjectEntity, AcDb::kOnBothOperands, IntersectionPoints) == Acad::eOk) { if (IntersectionPoints.length()>0) { double x1, y1, z1, x2, y2, z2, piket1, piket2; if ((*ObjectsIter)->Width_Type==1) { int i=0; while (i<IntersectionPoints.length()) { x1=IntersectionPoints[i][0]; y1=IntersectionPoints[i][1]; z1=IntersectionPoints[i][2]; piket1=0; i++; if (i==IntersectionPoints.length()){ CCrossingPoint* newCross=new CCrossingPoint(x1, y1, z1, piket1, x1, y1, z1, piket1, (*ObjectsIter)->BlockRef_ID, (*ObjectsIter)->Data_Type); this->DifferentCrossingObjects.push_back(newCross); acutPrintf("Возможна ошибочная ситуация при пересечении широким блоком %s", (*ObjectsIter)->BlockName); } else { x2=IntersectionPoints[i][0]; y2=IntersectionPoints[i][1]; z2=IntersectionPoints[i][2]; piket2=0; i++; CCrossingPoint* newCross=new CCrossingPoint(x1, y1, z1, piket1, x2, y2, z2, piket2, (*ObjectsIter)->BlockRef_ID, (*ObjectsIter)->Data_Type); this->DifferentCrossingObjects.push_back(newCross); } } } else { acutPrintf("Тонкие пересечения с %s:\n",(*ObjectsIter)->BlockName); for (int i=0; i<IntersectionPoints.length(); i++) { x1=IntersectionPoints[i][0]; y1=IntersectionPoints[i][1]; z1=IntersectionPoints[i][2]; acutPrintf(" (%f,%f,%f)\n", x1, y1, z1); piket1=0; CCrossingPoint* newCross=new CCrossingPoint(x1, y1, z1, piket1, x1, y1, z1, piket1, (*ObjectsIter)->BlockRef_ID, (*ObjectsIter)->Data_Type); this->DifferentCrossingObjects.push_back(newCross); } } } ObjectEntity->close(); } } } }
В элементах this->SurfaceObjects находятся ссылки на references блока
Вот недостающие куски кода
void CDWGObjects::findingCrossings(void) { //Итератор для элементов трубы std::list<CAcPrimitive*>::const_iterator PipeIter; //Наша труба AcDbEntity* PipeEntity; for( PipeIter = DocVars.docData().DWGObjects.MainPipeLine.begin(); PipeIter != DocVars.docData().DWGObjects.MainPipeLine.end(); PipeIter++ ){ if (strcmp((*PipeIter)->HandlerStr,"CAcPolyLineSegment")){ PipeEntity=this->getEntitybyStrHandler((*PipeIter)->HandlerStr); if (PipeEntity) { this->findingCrossing(PipeEntity); PipeEntity->close(); } } } } AcDbEntity* CDWGObjects::getEntitybyStrHandler(char* strHandler) { AcDbHandle Handler=AcDbHandle(strHandler); AcDbObjectId ObjectId; if(acdbHostApplicationServices()->workingDatabase()->getAcDbObjectId(ObjectId, false, Handler, 0) == Acad::eOk) { AcDbEntity* pEntity; if(acdbOpenObject(pEntity, ObjectId, AcDb::kForRead, false) == Acad::eOk) return pEntity; else return NULL; } else return NULL; }
Не вникая в суть приведенного кода скажу сразу, что для получения пересечения с блоком его нужно расчленить (не командой EXPLODE, а методом ..::exlopde(...)) и искать пересечения с полученными примитивами. Возможно это будет рекурсивный процесс, если блоки вложенные. После получения пересечений все примитивы (результат explode) следует удалить: delete pEnt[i];
Т.е. если я точно знаю что у меня в блоке нету других блоков то можно сделать вот так.
void CDWGObjects::getBlockRefCrossings(AcDbEntity* PipeEntity, AcDbEntity* ObjectEntity, AcGePoint3dArray& IntersectionPoints) { AcDbVoidPtrArray pBlockRefContArr; ObjectEntity->explode(pBlockRefContArr); AcDbEntity* BlockRefEntities; for (int i=0;i<pBlockRefContArr.length(); ++i) { BlockRefEntities=static_cast<AcDbEntity*>(pBlockRefContArr[i]); PipeEntity->intersectWith(BlockRefEntities, AcDb::kOnBothOperands, IntersectionPoints); delete BlockRefEntities; } }
Неплохо было бы проверить, что ObjectEntity->explode(pBlockRefContArr); выполнилось нормально и BlockRefEntities=static_cast<AcDbEntity*>(pBlockRefContArr[i]) не NULL
А в остальном IMHO нормально...
> Александр Ривилис
Посмотри пожалуйста на момент грубых ошибок. Тогда если есть вложенные блоки, то код должен выглядеть следующим образом:
void CDWGObjects::getBlockRefCrossings(AcDbEntity* PipeEntity, AcDbEntity* ObjectEntity, AcGePoint3dArray& IntersectionPoints) { AcDbVoidPtrArray pBlockRefContArr; if (ObjectEntity->explode(pBlockRefContArr)==Acad::eOk) { AcDbEntity* BlockRefEntities; for (int i=0;i<pBlockRefContArr.length(); ++i) { if (BlockRefEntities=static_cast<AcDbEntity*>(pBlockRefContArr[i])) { if (!strcmp(BlockRefEntities->isA()->name(), "AcDbBlockReference")) this->getBlockRefCrossings(PipeEntity, BlockRefEntities, IntersectionPoints); else PipeEntity->intersectWith(BlockRefEntities, AcDb::kOnBothOperands, IntersectionPoints); delete BlockRefEntities; } } } }
Заранее спасибо
1) Мне не нравится форма записи: if (!strcmp(BlockRefEntities->isA()->name(), "AcDbBlockReference"))
Переделай ее на AcDbBlockReference::cast(BlockRefEntities) с проверкой на NULL.
2) С рекурсией нужно быть поосторожнее. Без отладки я не пойму насколько корректно все работает.
3) Проверяй результат explode. Обрати внимание, что в нормальном случае эта функция может вернуть не только eOk, но и eExplodeAgain и тогда требуется повторный проход.
Вариант получения точек пересечения двух произвольных примитивов для использования в качестве lisp-функции, которая возвращает список точек пересечения.
Вызов из lisp:
(setq pts (getintersections (car(entsel)) (car(entsel))))
Это могут быть и блоки. К сожалению не для всех примитивов реализован метод intersectWith() (например, для 3DSOLID). :(
//-------------------------------------------------------- // Главная функция. Ей передаются два параметра - имена примитивов. // Она возвращает список точек их пересечения. // Обрабатываются и вложенные в блок примитивы. //-------------------------------------------------------- static int ads_getintersections(void) { struct resbuf *pArgs =acedGetArgs () ; acedRetNil(); // Сразу вернем nil if (pArgs && pArgs->rbnext && pArgs->restype == RTENAME && pArgs->rbnext->restype == RTENAME) { AcDbObjectId oid1, oid2; if (acdbGetObjectId(oid1,pArgs->resval.rlname) == Acad::eOk && acdbGetObjectId(oid2,pArgs->rbnext->resval.rlname) == Acad::eOk) { AcGePoint3dArray pts; GetIntersectionPoints(oid1,oid2,pts); if (pts.length() > 0) { resbuf *rbfirst = acutBuildList(RTLB,RTNONE), *rb=rbfirst; for (int i=0; i < pts.length(); i++) { rb->rbnext = acutBuildList(RT3DPOINT,asDblArray(pts[i]),RTNONE); rb = rb->rbnext; } rb->rbnext = acutBuildList(RTLE,RTNONE); acedRetList(rbfirst); acutRelRb(rbfirst); } } } return (RSRSLT) ; } // // Функция расчленяет примитивы до состояния атомов (т.е. нерасчленимых) // static void GetAllExloadedEntities(AcDbEntity *ent, AcDbVoidPtrArray& entitySet) { int n; AcDbVoidPtrArray pLocArr; Acad::ErrorStatus es = ent->explode(pLocArr); if (es == Acad::eNotApplicable) { // Добавляем если такого примитива еще нет в массиве и это не блок // (если это блок, то точки пересечения будут с BoundingBox) if (!entitySet.find(ent,n) && !AcDbBlockReference::cast(ent)) entitySet.append(ent); } else { for (int i=0; i < pLocArr.length(); i++) { GetAllExloadedEntities(static_cast<AcDbEntity*>(pLocArr[i]),entitySet); } } } // // Функция возвращает для двух примитивов, заданных именами массив, // содержащий все точки пересечения. // static void GetIntersectionPoints(AcDbObjectId oid1, AcDbObjectId oid2, AcGePoint3dArray &pts) { int i,n; AcDbObjectPointer<AcDbEntity> pEnt1(oid1,AcDb::kForRead); AcDbObjectPointer<AcDbEntity> pEnt2(oid2,AcDb::kForRead); if (pEnt1.openStatus() == Acad::eOk && pEnt2.openStatus() == Acad::eOk) { AcDbVoidPtrArray pArr1, pArr2; GetAllExloadedEntities(pEnt1.object(),pArr1); GetAllExloadedEntities(pEnt2.object(),pArr2); int n1 = pArr1.length(), n2 = pArr2.length(); if (n1 > 0 && n2 > 0) { for (int i1=0; i1 < n1; i1++) { for (int i2=0; i2 < n2; i2++) { AcGePoint3dArray pInt; AcDbEntity *pe1 = static_cast<AcDbEntity*>(pArr1[i1]); AcDbEntity *pe2 = static_cast<AcDbEntity*>(pArr2[i2]); if (pe1->intersectWith(pe2,AcDb::Intersect::kOnBothOperands,pInt) == Acad::eOk) { for (i=0; i < pInt.length(); i++) { // Добавим точку пересечения только если ее // не было в массиве if (!pts.find(pInt[i],n)) pts.append(pInt[i]); } } } } // Обязательно удаляем созданные в процессе explode примитивы for (i=0; i < n1; i++) { AcDbEntity *pEnt = static_cast<AcDbEntity*>(pArr1[i]); if (pEnt->objectId().isNull()) delete pEnt; } for (i=0; i < n2; i++){ AcDbEntity *pEnt = static_cast<AcDbEntity*>(pArr2[i]); if (pEnt->objectId().isNull()) delete pEnt; } } } }
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Форумы CADUser → Программирование → ObjectARX → Как найти пересекающиеся объекты?
Форум работает на PunBB, при поддержке Informer Technologies, Inc