ADN Club > ObjectARX

Операции с объектами, расположенными на ModelSpace без его открытия

(1/3) > >>

Wing:
Здравствуйте.

Наткнулся на то, что в некоторых командах открывается ModelSpace, примерно так:

--- Код - C++ [Выбрать] ---AcDbBlockTable *pTable;AcDbBlockTableRecord *pModelSpace;acdbHostApplicationServices()->workingDatabase()->getBlockTable(pTable, AcDb::kForRead);pTable->getAt(ACDB_MODEL_SPACE, pModelSpace, AcDb::kForWrite);return pModelSpace;а в некоторых командах вызываются acdbOpenAcDbEntity() и далее всякие операции без открытия Model Space.

Вопрос - может быть, в командах не надо открывать Model Space? А для чего надо, в каких случаях?
Если можно, дайте ссылки, где можно прочитать о подобном.

И второй вопрос, в двух командах используется ads_regen(). В первом случае Model Space открывается, но перед вызовом ads_regen() пришлось закрывать все объекты и сам Model Space, иначе при удалении всех объектов с чертежа была странная картина: некоторые объекты (не те, что выделены для команды) оставались, но их нельзя было выделить, и при отключении всех слоев они тоже оставались видимыми, и прекрасно масштабировались мышью. Во второй команде такого эффекта нет, хотя там на момент вызова ads_regen объекты остаются открытыми (с помощью acdbOpenAcDbEntity), но открытия Model Space в этой команде нет вообще.
Получается, что ads_regen() требует закрытого Model Space для своей работы, но позволяет иметь открытыми объекты. Так ли это? Может быть, вообще не открывать Model Space?
Есть ли в описанных вариантах применения ads_regen() что-то явно неправильное?

Спасибо.

Александр Ривилис:
Приветствую на форуме! На всякий случай напоминаю, что у нас принято "один вопрос - одна тема".
Теперь по существу вопросов. ModelSpace открывается обычно в двух случаях:
1) Нужно добавить новый примитив к ModelSpace. В этом случае ModelSpace должен быть открыт для записи (AcDb::kForWrite)
2) Производится итерация по всему пространству модели для выбора каких-либо примитивов по каким-либо критериям. В этом случае достаточно открыть ModelSpace для чтения (AcDb::kForRead)
Следует активно использовать интеллектуальные указатели (AcDbBlockTableRecordPointer, AcDbObjectPointer и т.д.). Они не дадут забыть закрыть ModelSpace и другие объекты/примитивы.
Напомню, что если объект (любой, в том числе и ModelSpace) открыт для записи, то повторно открыть его как для записи, так и для чтения нельзя. И соответственно ads_regen() сработать не сможет - она итерирует по пространству модели чтобы отобразить все примитивы в нём.

Надеюсь, что мне удалось доступно объяснить. Если это не так - задавай уточняющие вопросы с примерами своего кода, а я постараюсь его "оптимизировать" по своему усмотрению. Я бы, например, никогда не стал бы писать такой код, как у тебя приведен, который возвращает указатель на пространство модели из функции. Уж очень опасно забыть не закрыть ModelSpace. Это просто приведёт к тому, что AutoCAD перестанет работать.

Wing:
Спасибо за ответы, Александр!

Использование Model Space присутствует в обоих вопросах, поэтому счел уместным объединить. Т.е. это две части одного вопроса, хотя бы частично. Ваше замечание учту.

Насчет указателей, я согласен с тем, что они лучше, но как быть с тем, что руками мы закрываем сначала объекты, потом Model Space, а порядок вызова деструкторов не определен? Ничего не испортится, если закроется сначала Model Space, а потом объект? А если с ними вместе открывать другие объекты, например слои, есть требования по порядку закрытия?


Для выбора всех объектов по  acedSSGet( L"_A", ....);  не надо открывать Model Space, я правильно понимаю?
Такой код есть и работает. О каких итерациях тогда речь?

Александр Ривилис:

--- Цитата: Wing от 21-11-2013, 11:40:23 ---Насчет указателей, я согласен с тем, что они лучше, но как быть с тем, что руками мы закрываем сначала объекты, потом Model Space, а порядок вызова деструкторов не определен? Ничего не испортится, если закроется сначала Model Space, а потом объект? А если с ними вместе открывать другие объекты, например слои, есть требования по порядку закрытия?

--- Конец цитаты ---
Ну во-первых порядком вызова деструкторов можно управлять. Например, конструкция вида:

--- Код - C++ [Выбрать] ---// Точка 1{ AcDbObjectPointer<AcDbCurve> pPoly(eid,AcDb::kForRead); if (pPoly.openStatus() != Acad::eOk) {    acutPrintf(_T("\nЭто не кривая!.")); return; }}// Точка 2В "Точке 2" объект с AcDbObjectId равным eid будет закрыт, так как pPoly вышел из "области видимости" и сработал его деструктор.
Основное правило - если объект нужен, т.е. программа считывает его данные или наоборот модифицирует его, то он (объект) должен быть открыт. В противном случае очень желательно его закрыть как можно быстрее.


--- Цитата: Wing от 21-11-2013, 11:40:23 ---Для выбора всех объектов по  acedSSGet( L"_A", ....);  не надо открывать Model Space, я правильно понимаю?
Такой код есть и работает. О каких итерациях тогда речь?

--- Конец цитаты ---
Понимаешь правильно. Более того, если в этот момент ModelSpace окажется открыта на запись, то функция acedSSGet( L"_A", ....); не сработает, так она сама пытается открыть ModelSpace, а как я писал уже выше это становится для неё невозможным.
Что я понимал по итерациями? Я имел в виду, что ты сам можешь написать аналог функции acedSSGet( L"_A", ....); А для этой цели тебе пришлось бы выполнить итерацию по ModelSpace, т.е. найти все примитивы, которые есть в ModelSpace.
Пример:

--- Код - C++ [Выбрать] ---Acad::ErrorStatus ObjectIdArrayFromCurrentSpace(AcDbObjectIdArray &ids){  ids.setLogicalLength(0);  AcDbBlockTableRecordPointer pCurSpace(acdbCurDwg()->currentSpaceId(),AcDb::kForRead);  AcDbBlockTableRecordIterator *iter = NULL;  pCurSpace->newIterator(iter);  if (iter) {    AcDbObjectId eId;    for (;!iter->done(); iter->step()) {      iter->getEntityId(eId); ids.append(eId);    }    delete iter;  }  return Acad::eOk;}

Wing:
{ { .... } }    - так управлять временем жизни не удобно, если объекты нужны на нескольких страницах кода, а также если их области видимости почему-либо пересекаются.
Вариант с приоритетом разрушения был в loki, но, емнип, там реализовано для объектов, а не для автоуказателей. Можно, по идее, и самому сделать нечто подобное - создал AcDbObjectPointer, запихнул в контейнер с приоритетом разрушения, и забыл.
Или можно открывать самому, а в контейнер пихать открытые указатели с приоритетом закрытия.
Может есть что-то такое уже готовое, arx-ное?

Если закрыть сначала ModelSpace, а потом объект на нем, это ошибка?

По acedSSGet( L"_A", ....); понял, спасибо.

Навигация

[0] Главная страница сообщений

[#] Следующая страница

Перейти к полной версии