Тема: Отключить обновление экрана на время изменения свойств AcDbEntity

Здравствуйте!
В ListBox есть возможность отключить обновление экрана во время "долгих" операций по обновлению содержимого. Есть ли такая возможность в ObjectArx? Если можно то название пример.
С уважением.

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Попробуй через функцию acedUpdateDisplayPause

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Спасибо!
А вообще, для ускорения обработки больших количеств (~10К-20К) acDbEntity (хочу сделать часть их "инвизибле", независимо от слоев) какие-нибудь есть примочки в ObjectArx?
С уважением,

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

1) Чтобы сделать примитив невидимым используй метод AcDbEntity::setVisibility
2) Обычно ~10К-20К обрабатываются на ObjectARX настолько быстро, что все эти манипуляции не нужны.
3) Если пользователь не будет видеть что происходит - он решит, что AutoCAD "завис". Тогда нужен как минимум индикатор прогресса (ProgressBar).

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Я пробовал манипулировать таким объемом, но время реакции занимает 30-40 сек. Ниже код, может что подскажете...

static void ArxProject1_myInput(void)
{
// Invite user to select entities
    int age;
    ads_name ssname, ent1;
    long lCount=0;
    age = acedSSGet(NULL,NULL, NULL, NULL, ssname);
    if (RTNORM == age)
    {    
        acedSSLength(ssname, &lCount);
    }
    acutPrintf ("Selected %u entities", lCount);
//    Iterate database
//    Get Current database
//    Get Model_space of current database
    AcDbBlockTableRecordIterator* pBlockIterator;
    AcGePoint3dArray ptArray;
    acdbHostApplicationServices()->workingDatabase()
        ->getSymbolTable(m_pBlockTable, AcDb::kForRead);
//    Get Model_space of current database
    m_pBlockTable->getAt(ACDB_MODEL_SPACE, m_pBlockTableRecord,
        AcDb::kForWrite);
    m_pBlockTable->close();
    m_pBlockTableRecord->newIterator (pBlockIterator);
    m_pBlockTableRecord->close();
    AcDbHandle acHandle;
    AcDbEntity *pEnt;
    char chHandle[17];
    while (!pBlockIterator->done ())
    {
        if (Acad::eOk == pBlockIterator->getEntity (pEnt,         AcDb::kForWrite))
        if (age == RTNORM)
        {
//            if (pEnt->visibility () == AcDb::kInvisible)
                pEnt->getAcDbHandle (acHandle);
            if (!acHandle.isNull ())
            {
                ltoa (acHandle, chHandle, 16);
                if (acdbHandEnt(chHandle, ent1) == RTNORM)
                {    
                    if (RTERROR == acedSSMemb (ent1, ssname))
                    pEnt->setVisibility (AcDb::kInvisible);
                    acedSSFree (ent1);
                }
            }
        }
        else
            if (pEnt->visibility () != AcDb::kVisible)
                    pEnt->setVisibility (AcDb::kVisible);
            
        pEnt->close();
        pBlockIterator->step();
    }
    acedSSFree(ssname);
}

С уважением,

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

И что ты пытаешься в этой функции сделать? Опиши словами, потому что в коде у тебя полная ерунда.

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Пользователь делает выборку. я "отключаю"(инвизибле) все элементы (AcDbEntity), которые не вошли в нее.

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Если он не выбрал ничего, то я пытаюсь сделать все "визибле".

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Однако! Если пользователь сделал выбор, то нужно организовать цикл только по тем примитивам, которые он выбрал!

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Так Dangee нужно наоборот все НЕвыбранные элементы спрятать :)
Это значит необходимо определить что будет в списке [все элементы] - [выбранные элементы] = [не выбранные элементы], по полученному списку и придется бегать :) И так при каждом выборе/щелчке.
Из не AutoCAD'овских способов оптимизации могу подсказать только:
1. Заполнить список [все элементы] 1 раз и только добавлять/уменьшать его при добавлении/удалении объекта в чертеже.
2. Вызывать изменение видимости только для тех объектов состояние которых изменилось, для этого достаточно запоминать список [выбранные элементы]. Правда непонятно как выбрать новые объекты если они не видимы!? только снова все показать и снова скрыть.
> Александр Ривилис
По сути необходима функция группового изменения видимости/невидимости объектов, либо функция которая делает все объекты чертежа невидимыми :)

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

> quiz
Я считаю саму по себе идею отключать видимость огромного числа примитивов в чертеже глупостью. Это будет достаточно длительный процесс от которого пользователь сойдет с ума и выкинет такую программу на помойку. ИМХО.

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

> Александр
Ривилис
Такая вещь все же нужна. У нас тут ребята редактируют в трехмерке. Соответственно получается  кошмарное наложение и эта возможность нужна для выделения маленьких кусочков схемы для корректировки.
Значит все-таки это будет "долгий" процесс?
>quiz

Это значит необходимо определить что будет в списке [все элементы] — [выбранные элементы] = [не выбранные элементы], по полученному списку и придется бегать :) И так при каждом выборе/щелчке.

Они же все есть в базе, соответственно, выборка будет идти по базе. Странная вещь при "выключении" этот процесс "занимает" 30-40 сек., при "включении" 2-3 сек. С чем это может быть связано?

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

> Dangee
Приведи код, которым ты выключаешь видимость и код которым включаешь. Если это код, который ты привел выше, то у тебя там очень много лишнего и потенциально медленного. Например, acedSSMemb, acdbHandEnt. Кстати и итератор ты не удаляешь.

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

static void SetViz(void)
{
  ads_name ss;
  int rtsel = acedSSGet(NULL,NULL,NULL,NULL,ss);
  AcDbObjectIdArray aSel;
  if (rtsel == RTNORM) {
    long sslen = 0; acedSSLength(ss,&sslen);
    aSel.setLogicalLength(sslen);
    for (long i=0; i < sslen; i++) {
      ads_name en; acedSSName(ss,i,en);
      AcDbObjectId id; acdbGetObjectId(id,en);
      aSel[i] = id;
    }
    AcDbBlockTableRecordPointer pCurSpace(acdbCurDwg()->currentSpaceId(),AcDb::kForRead);
    if (pCurSpace.openStatus() == Acad::eOk) {
      AcDbBlockTableRecordIterator *pIter = NULL;  pCurSpace->newIterator(pIter);
      if (pIter) {
        for (pIter->start(); !pIter->done(); pIter->step()) {
          AcDbObjectId id;
          if (pIter->getEntityId(id) == Acad::eOk) {
            if (!aSel.contains(id)) {
              AcDbEntityPointer pEnt(id,AcDb::kForRead);
              if (pEnt.openStatus() == Acad::eOk) {
                if (pEnt->visibility() == AcDb::kVisible && pEnt->upgradeOpen() == Acad::eOk) {
                  pEnt->setVisibility(AcDb::kInvisible);
                }
              }
            }
          }
        }
        delete pIter;
      }
    }
  } else {
    AcDbBlockTableRecordPointer pCurSpace(acdbCurDwg()->currentSpaceId(),AcDb::kForRead);
    if (pCurSpace.openStatus() == Acad::eOk) {
      AcDbBlockTableRecordIterator *pIter = NULL;  pCurSpace->newIterator(pIter);
      if (pIter) {
        for (pIter->start(); !pIter->done(); pIter->step()) {
          AcDbObjectId id;
          if (pIter->getEntityId(id) == Acad::eOk) {
            if (!aSel.contains(id)) {
              AcDbEntityPointer pEnt(id,AcDb::kForRead);
              if (pEnt.openStatus() == Acad::eOk) {
                if (pEnt->visibility() == AcDb::kInvisible && pEnt->upgradeOpen() == Acad::eOk) {
                  pEnt->setVisibility(AcDb::kVisible);
                }
              }
            }
          }
        }
        delete pIter;
      }
    }
  }
}

На 146382 примитивов приблизительно по 10 секунд на включение/выключение на моем не слишком быстром PC.

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Спасибо на добром коде. Ваша версия намного быстрее. Буду штудировать его.
А можно ли получить ссылку на исходники различных задач на ObjectArx для Автокада, для изучения?
С уважением

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

Информация об AutoCAD SDK:
http://usa.autodesk.com/adsk/servlet/in … id=1911627
ObjectARX for AutoCAD 2008 (exe, 30.2 Мб):
http://usa.autodesk.com/adsk/servlet/it … ;id=785550
> Александр Ривилис (2008-02-26 16:18:02)
В медленной реализации это возможно и глупость :) а в быстрой было бы многим полезно.
> Dangee (2008-02-27 09:17:08)
Попробуй еще вариант с хранением списка всех id в чертеже (сообщение от 2008-02-26 16:06:09). Только после получения списка отсортируй его и применяй бинарный поиск, тогда избавишься от итератора.
Еще можешь попробовать в этом же списке сохранить текущее состояние (видимость) объектов. Это чревато рассинхронизацией с базой чертежа, если кто-то захочет изменить видимость объекта другим способом, зато можно будет не открывать все объекты для чтения, а только те которые изменить сразу на запись.
Александр Вы как на это смотрите?
> Александр Ривилис (2008-02-26 18:53:37)
А зачем в блоке else вот этот код

...
if (!aSel.contains(id)) {
...
}

ведь у нас ничего не выбрано?
И тут:

AcDbEntityPointer pEnt(id,AcDb::kForRead);
if (pEnt.openStatus() == Acad::eOk) {
    if (pEnt->visibility() == AcDb::kInvisible && pEnt->upgradeOpen() == Acad::eOk) {
        pEnt->setVisibility(AcDb::kVisible);
    }
}

стоит ли проверять невидимость объекта, если количество видимых объектов значительно меньше количества невидимых? Большой переработки при установки видимости ВСЕМ не должно быть:

AcDbEntityPointer pEnt(id,AcDb::kForWrite);
if (pEnt.openStatus() == Acad::eOk) {
    pEnt->setVisibility(AcDb::kVisible);
}

Re: Отключить обновление экрана на время изменения свойств AcDbEntity

quiz пишет:

Александр Вы как на это смотрите?

Я не тестировал этот вариант, но он если и увеличит быстродействие, то незначительно. Основные потери в моем коде (IMHO) не на проходе по базе, а на включении/выключении видимости примитива. Кроме того для реализации твоей идеи фактически придется хранить еще массив (а лучше map) AcDbObjectId для всех примитивов. Это дополнительные расходы памяти, особенно неприятные при большом количестве примитивов в чертеже. Плюс необходимы еще и реакторы на добавление/удаление примитивов в базу. А для многодокументного режима нужно обрабатывать все это для каждого документа... По поводу обработки else в моем коде - полностью согласен. Просто быстро сделал copy/paste, а на детальное обдумывание времени не было.