Тема: Как найти пересекающиеся объекты?

Господа, не подскажите, возможно ли найти пересекающиеся объекты/примитивы? Они могут лежать на разных слоях.
Заранее спасибо.

Re: Как найти пересекающиеся объекты?

Возможно. Слои в данном случае значения не имеют. Смотри в документации метод AcDbEntity::intersectWith(...)

Re: Как найти пересекающиеся объекты?

Такой вопрос, если ищещь объекты пересекающиеся с полилинией нужно проверять её дуги, сегменты и точки? или достаточно искать пересечения с ней самой?

Re: Как найти пересекающиеся объекты?

А почитать документацию и проверить самому сложно? smile

Re: Как найти пересекающиеся объекты?

Проверка показала, что всё равно, есть там сегменты полилинии или нет. Но! Точки пересечения программа не находит, а они там есть!!!

Re: Как найти пересекающиеся объекты?

> dimsan
Ответ неверный. Смотри пример ObjectARX SDK samples\database\ARXDBG\
В нем файл Tests\ArxDbgCmdTests.cpp, в нем функцию ArxDbgCmdTests::testIntersect()

Re: Как найти пересекающиеся объекты?

Посмотрел, ничего сверхмудрого не увидел. Они просто выбирают продолжать(в смысле extend) примитивы до точки пересечения или нет, на свой вопрос: Нужно ли рассматривать сегменты полилинии на пересечения ответа так и не получил

Re: Как найти пересекающиеся объекты?

Нашол ашипку в анализе =0
Вывод такой: никаких элементов полилинии пересматривать ненужно, достаточно искать пересечения полилинии с другими entity.
Всем спасибо, все свободны =)

Re: Как найти пересекающиеся объекты?

> dimsan
Все правильно. Я как раз и намекал на ошибку в коде, сославшись на пример, который для полилиний нормально работает.

Re: Как найти пересекающиеся объекты?

> Александр Ривилис
У меня какая-то проблема не правильно находит пересечение между полилинией и блоком

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 блока

Re: Как найти пересекающиеся объекты?

Вот недостающие куски кода

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;
}

Re: Как найти пересекающиеся объекты?

Не вникая в суть приведенного кода скажу сразу, что для получения пересечения с блоком его нужно расчленить (не командой EXPLODE, а методом ..::exlopde(...)) и искать пересечения с полученными примитивами. Возможно это будет рекурсивный процесс, если блоки вложенные. После получения пересечений все примитивы (результат explode) следует удалить: delete pEnt[i];

Re: Как найти пересекающиеся объекты?

Т.е. если я точно знаю что у меня в блоке нету других блоков то можно сделать вот так.

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;
    }
}

Re: Как найти пересекающиеся объекты?

Неплохо было бы проверить, что ObjectEntity->explode(pBlockRefContArr); выполнилось нормально и BlockRefEntities=static_cast<AcDbEntity*>(pBlockRefContArr[i]) не NULL
А в остальном IMHO нормально...

Re: Как найти пересекающиеся объекты?

> Александр Ривилис
Посмотри пожалуйста на момент грубых ошибок. Тогда если есть вложенные блоки, то код должен выглядеть следующим образом:

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;
            }
        }
    }
}

Заранее спасибо

Re: Как найти пересекающиеся объекты?

1) Мне не нравится форма записи: if (!strcmp(BlockRefEntities->isA()->name(), "AcDbBlockReference"))
Переделай ее на AcDbBlockReference::cast(BlockRefEntities) с проверкой на NULL.
2) С рекурсией нужно быть поосторожнее. Без отладки я не пойму насколько корректно все работает.
3) Проверяй результат explode. Обрати внимание, что в нормальном случае эта функция может вернуть не только eOk, но и eExplodeAgain и тогда требуется повторный проход.

Re: Как найти пересекающиеся объекты?

Вариант получения точек пересечения двух произвольных примитивов для использования в качестве 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;
        }
      }
    }
  }