Тема: Как организовать итерацию по базе?

Как организовать итерацию по базе с целью выборки определенных примитивов, например всех полилиний?

Re: Как организовать итерацию по базе?

> Draft_men
Есть несколько способов. Если стоит такая конкретная задача, то проще всего:

ads_name ss;
resbuf *rb = acutBuildList(RTDXF0,"*POLYLINE",RTNONE);
int rc = acedSSGet("_X",NULL,NULL,rb,ss);
acutRelRb(rb);
if (rc == RTNORM) {
// В наборе ss только полилинии
// При помощи acedSSLength() получаешь их количество
// При помощи acedSSName() получаешь имя примитива полилинии
}

Re: Как организовать итерацию по базе?

Александр, а Вы не могли бы показать код, который пробегает по всей базе, выводит мена всех примитивов? Или хотя бы где его возможно увидеть.
И еще один вопрос: как я могу поменять параметры конкретно необходимого мне примитива, например линии или окружности? Опять же где возможно увидеть код.
Спасибо.

Re: Как организовать итерацию по базе?

> Lanter
Запросто. Только чтобы я не занимался пустой тратой времени уточни:
1) что ты понимаешь под именем примитива?
2) что тебе известно о (цитирую) конкретно необходимого мне примитива, например линии или окружности - это должно быть или имя примитива (ads_name или AcDbObjectId) или метка примитива (группа 5 в DXF или AcDbHandle).
Ну а код как обычно нужно искать в ObjectARX SDK (или в Help'е, или в примерах).

Re: Как организовать итерацию по базе?

Под именем примитива я понимаю AcDbObjectId.
На данный момент мне известно о примитиве следующее:

acedEntSel("\nУкажите объект: ", ent1, pt1);
acdbGetObjectId(entId1, ent1);
acdbOpenAcDbEntity(pEnt1, entId1, AcDb::kForWrite);

В данном случае я выбрал примитив мышкой.
Теперь я хочу изменить его параметры из командной строки;
(под параметрами понимаю линейные размеры, координаты, цвет и пр.)
Вопрос далее:
А если я например хочу найти в базе определнный примитив, то я буду искать его по его метке?
Соответственно в случае успеха я хочу также поменять его параметры.
Я рисую линию:

AcGePoint3d startPt(32,112.5,0);
AcGePoint3d endPt(161.2,140.8,0);
AcDbLine* pLine = new AcDbLine(startPt,endPt);
pMS->appendAcDbEntity(pLine)
pLine->close();

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

Re: Как организовать итерацию по базе?

И еще вопрос, каким образом я могу обрабатывать параметры примитива? Присвоить переменной значение функции наподбие GetParam() и обрабатывать то что есть в переменной?
Если да то какой тип переменной и какой функцией?

Re: Как организовать итерацию по базе?

1) Вот пример команды, которая меняет цвет выбранного примитива при помощи командной строки:

static void ChangeColor(void)
{
  ads_point p;  ads_name  ent;
  int nColor;
  if (acedEntSel("\nВыберите примитив для изменения цвета: ",ent,p) == RTNORM) {
    AcDbObjectId id; acdbGetObjectId(id,ent);
    AcDbObjectPointer<AcDbEntity> pEnt(id,AcDb::kForWrite);
    if (pEnt.openStatus() == Acad::eOk) {
      nColor =  pEnt->colorIndex();
      char buf[256]; sprintf(buf,"\nУкажите номер цвета (0...256) <%d>: ",nColor);
      acedInitGet(RSG_NONEG,NULL);
      if (acedGetInt(buf,&nColor) == RTNORM) {
        nColor = nColor % 257; // На всякий случай приводим к диапазону 0...256
        pEnt->setColorIndex(nColor);
      }
    }
  }
}

Так как понятие "цвета" есть у всех примитивов, то нет необходимости уточнять какой именно это примитив!
2) Вот команда, которая удлиняет выбранный отрезок в два раза (относительно середины отрезка):

static void Lengthen2(void)
{
  ads_point p;  ads_name  ent;
  if (acedEntSel("\nВыберите отрезок для удлинения в два раза: ",ent,p) == RTNORM) {
    AcDbObjectId id; acdbGetObjectId(id,ent);
    AcDbObjectPointer<AcDbEntity> pEnt(id,AcDb::kForWrite);
    if (pEnt.openStatus() == Acad::eOk) {
      AcDbLine *pLine = AcDbLine::cast(pEnt.object()); // Приводим к отрезку
      if (!pLine) {
        acutPrintf("\nЭто не отрезок!");
        return;
      }
      AcGeVector3d dir = pLine->startPoint() - pLine->endPoint();
      pLine->setStartPoint(pLine->startPoint() + dir*0.5);
      pLine->setEndPoint  (pLine->endPoint()   - dir*0.5);
    }
  }
}

В данном случае приходится выполнить приведение к отрезку (AcDbLine)
3) Для того, чтобы после закрытия и повторного открытия чертежа найти нужный примитив, ты должен знать его метку (группа DXF 5, AcDbHandle - значение AcDbObjectId не сохраняется между сеансами AutoCAD). Так что при добавлении примитива в базу ты должен его получить и где-то сохранить.
Для получения AcDbObjectId примитива (или объекта) по строке метки можно воспользоваться функцией:

//---------------------------------------------------------
// Функция по строке метки (handle) возвращает AcDbObjectId
// объекта в текущем чертежее
//---------------------------------------------------------
static AcDbObjectId GetObjectIdByHandleString(char *str)
{
  AcDbHandle h(str);
  AcDbObjectId id = AcDbObjectId::kNull;
  acdbCurDwg()->getAcDbObjectId(id,false,h);
  return id;
}

Вот пример ее использования:

static void GetObjectByHandle(void)
{
  Acad::ErrorStatus es;
  char buf[1024];
  if (acedGetString(FALSE,"\nУкажите метку примитива: ",buf) == RTNORM) {
    AcDbObjectId id = GetObjectIdByHandleString(buf);
    if (!id.isValid()) {
      acutPrintf("\nОбъекта с такой меткой в чертеже нет!");
      return;
    }
    AcDbObjectPointer<AcDbObject> pObj(id,AcDb::kForRead);
    if ((es = pObj.openStatus()) != Acad::eOk) {
      acutPrintf("\nНе смогли открыть объект: %s",acadErrorStatusText(es));
      return;
    }
    // По AcDbObjectId получаем строку - представление AcDbHandle
    pObj->objectId().handle().getIntoAsciiBuffer(buf);
    acutPrintf("\nName: %s id=%0X handle=%s",pObj->isA()->name(),pObj->objectId().asOldId(),buf);
  }
}

Re: Как организовать итерацию по базе?

Lanter пишет:

И еще вопрос, каким образом я могу обрабатывать параметры примитива? Присвоить переменной значение функции наподбие GetParam() и обрабатывать то что есть в переменной?

Как это будет по-русски? :) Что такое параметры примитива? Есть понятие параметра кривой (AcDbCurve), но похоже речь не об этом. Увы, но я ничего не понял...

Re: Как организовать итерацию по базе?

P.S.: Дальнейшие вопросы оформляйте отдельными темами - на этом форуме принято в каждой теме задавать только один вопрос.

Re: Как организовать итерацию по базе?

Александр, спасибо за исчерпывающий ответ.
Извните за "нерусский". :)

Re: Как организовать итерацию по базе?

Могу ля прбежаться по базе и выбрать все блоки не используя acedSSGet? Скажем, используя AcDbBlockTableIterator?

Re: Как организовать итерацию по базе?

> Draft_men
Можешь.

Re: Как организовать итерацию по базе?

А как узнать, на что ссылается "record" в "block table" - на блок или скажем на *ModelSpace?

    const char *pName;
        AcDbBlockTableIterator *pBTItr;
        if (pBlockTable->newIterator(pBTItr) == Acad::eOk) {
        while (!pBTItr->done()) {
            AcDbBlockTableRecord *pRecord;
            if (pBTItr->getRecord(pRecord, AcDb::kForRead)
                == Acad::eOk)
            {
                
                pRecord->getName(pName);
                acutPrintf("\nText is: %s",pName);
                pRecord->close();
            }    
            pBTItr->step();
        }
    }

Re: Как организовать итерацию по базе?

> Draft_men
*ModelSpace - это тоже блок, но имеющий особенный смысл.
А так можно проверить, что это обычный блок:

bool isUsualBlock = (!pRecord->isFromExternalReference() && !pRecord->isFromOverlayReference() && !pRecord->isLayout());

Re: Как организовать итерацию по базе?

> Александр Ривилис
Спасибо!!!

Re: Как организовать итерацию по базе?

> Александр Ривилис
Однако все равно выдаёт мне блоки с непонятными именами *X11,*X12,*X13 и т.д.

Re: Как организовать итерацию по базе?

P.S.: А еще если не нужны анонимные блоки, то:

!pRecord->isAnonymous();

Re: Как организовать итерацию по базе?

Углубившись, понял, что заблудился ("чем дальше в лес - тем толще партизаны"). Мне показалось, или нет, что:
1)для того чтобы выбрать все блоки в "Model space", отделная функция!
2)для того чтобы выбрать все блоки в "Paper space", отделная функция!
Вопрс, а нелзя ли выбрать все болки одним махом?

Re: Как организовать итерацию по базе?

> Draft_men
Не путай описание блоков (AcDbBlockTableRecord) со вставками блоков (AcDbBlockReference). Когда поймешь что именно тебе нужно получить (все имена блоков и их содержимое или все вставки всех блоков), только тогда "партизаны" покажутся худенькими и приветливыми. :)

Вопрос, а нелзя ли выбрать все болки одним махом?

Так что же ты собираешься выбирать?

Re: Как организовать итерацию по базе?

Вставки блока, однозначно! Только они могут быть как в "model space" так и в "paper space".

Re: Как организовать итерацию по базе?

Ок, с этим разобрался! )) Но, есть одно "но", но "всёж", что это за *X11,*X12,*X13- описания блоков??? (я так понимаю это штриховки)

Re: Как организовать итерацию по базе?

Это не описания, а наименования "анонимных" блоков (все начинаются со звездочки). Они получаются при создании штриховок, размеров, таблиц и т.д., и кроме того ты сам можешь создавать анонимные блоки. Все они не видны в списке команды _INSERT.

Re: Как организовать итерацию по базе?

Хорошо!!!
Значит, скачу я по базе, все очень волшебно, "аттрибуты" вокруг, "блоки" всякие, и все чудесно но...
Вот кусок кода, который выбирает: аттрибуты, определения аттрибутов и пару видов текста->

                for (; !pBlockIterator->done(); pBlockIterator->step())
                {    
                        pBlockIterator->getEntity(pEntity, AcDb::kForWrite);
                        const char *pCname = pEntity->isA()->name();
                            //acutPrintf("class %s.\n",pCname);
                        if ( pEntity->isA() == AcDbBlockReference::desc () )
                        {
                            aBlkR = AcDbBlockReference::cast(pEntity);
                            AcDbObjectIterator *objIterator;
                            objIterator = aBlkR->attributeIterator();
                            for (objIterator->start(); !objIterator->done(); objIterator->step())
                            {
                                AcDbAttribute *pAtt;
                                aBlkR->openAttribute(pAtt,objIterator->objectId(),AcDb::kForWrite);
                                AcDbObjectId styleId = NULL;
                                char *pName = GetTextStyleName(pAtt->textStyle());
                                pAtt->setTextString(convertText(pAtt->textString()));
                                pAtt->close();
                            }
                            pEntity->close();
                        }
                        else
                        if ( pEntity->isA() == AcDbAttributeDefinition::desc () )
                        {
                            aTtdef = AcDbAttributeDefinition::cast(pEntity);
                            AcDbObjectId styleId = NULL;
                            char *pName = GetTextStyleName(aTtdef->textStyle());
                            aTtdef->setTextString(convertText(aTtdef->textString()));
                            aTtdef->close();
                            pEntity->close();
                        }
                        else
                            if ( pEntity->isA() == AcDbText::desc () )
                            {
                                teXt = AcDbText::cast(pEntity);
                                if (teXt != NULL) {
                                    AcDbObjectId styleId = NULL;
                                    char *pName = GetTextStyleName(teXt->textStyle());
                                    //acutPrintf("\nStyle name: %s",pName);
                                    teXt->setTextString(convertText(teXt->textString()));
                                }
                                pEntity->close();
                            }
                        else
                            if ( pEntity->isA() == AcDbMText::desc () )
                            {
                                MteXt = AcDbMText::cast(pEntity);
                                if (MteXt != NULL) {
                                    AcDbObjectId styleId = NULL;
                                    char *pName = GetTextStyleName(MteXt->textStyle());
                                    //acutPrintf("\nStyle name: %s",pName);
                                    MteXt->setContents(convertText(MteXt->contents()));
                                }
                                pEntity->close();
                            }
                            else pEntity->close();
                }

А мне еще надо выбрать все что связано с текстом в "деменшонах", а этож еще куча "ифов", можно ли как-то оптимизировать енто дело?

Re: Как организовать итерацию по базе?

Практически никак...