ObjectARX, AutoCAD. Среда программирования библиотеки C++

         

Создание и cтирание cписка


ObjectARX-приложение может динамически размещать единственный буфер результатов,  вызывая acutNewRb (). Запрос к acutNewRb () должен определить тип буфера, чтобы разместить; acutNewRb () автоматически инициализирует restype поле буфера, чтобы содержать указанный код типа.

Следующий типовой кодовый фрагмент размещает буфер результатов, чтобы содержать трехмерную точку и затем инициализирует значение точки:

struct resbuf *head;

if ((head=acutNewRb(RT3DPOINT)) == NULL) {

acdbFail("Unable to allocate buffer\n");

return BAD;

}

head->resval.rpoint[X] = 15.0;

head->resval.rpoint[Y] = 16.0;

head->resval.rpoint[Z] = 11.18;

Если новый буфер результатов должен содержать строку, приложение должно явно разместить память, чтобы содержать строку:

struct resbuf *head;

if ((head=acutNewRb(RTSTR)) == NULL) {

acdbFail("Unable to allocate buffer\n");

return BAD;

}

if ((head->resval.rstring = malloc(14)) == NULL) {

acdbFail("Unable to allocate string\n");

return BAD;

}



strcpy(head->resval.rstring, "Hello, there.");

Память, размещенная для строк, которые связаны с динамическим списком,  выпущена, когда список выпущен, так что следующий запрос выпускает всю память, размещенную в предыдущем примере:

acutRelRb(head);

Чтобы выпускать строку без того, чтобы выпустить буфер, вызовите свободным () и установите строковый указатель на NULL как показано в следующем примере:

free(head->resval.rstring);

head->resval.rstring = NULL;

Установка resval.rstring к NULL предотвращает последующий запрос к acutRelRb () из попытки выпустить строку второй раз.

Если элементы списка известны заранее, более быстрый способ создавать это состоит в том, чтобы вызвать acutBuildList (), который берут переменное число пар параметра (с исключениями типа RTLB, RTLE, -3, и других) и возвращают указатель на список буферов результатов, который содержит указанные типы и значения, связанные вместе в порядке, в котором их пропускали к acutBuildList (). Эта функция размещает память как требовано и инициализирует все значения. Последний параметр к acutBuildList () должен быть единственный параметр, чей значение является или нулем или RTNONE.

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

struct resbuf *result;

ads_point pt1 = {1.0, 2.0, 5.1};

result = acutBuildList(

RTREAL, 3.5,

RTSTR, "Hello, there.",

RT3DPOINT, pt1,

0 );

Если это не может создавать список, acutBuildList () возвращает NULL; иначе, это размещает пространство, чтобы содержать список. Этот список должен быть выпущен последующим запросом к acutRelRb ():

if (result != NULL)

acutRelRb(result);



Создание и Изменение Записи Таблицы Уровня


Следующие показы примера, получающие таблицу уровня для текущей базы данных и открытия этого для записи. Это создает новую запись таблицы уровня (AcDbLayerTableRecord) и устанавливает некоторые атрибуты уровня (имя, закрепляемый атрибут, вкл\выкл, область просмотра, и блокированный). Тогда это создает цветной объект класса и устанавливает цвет уровня к красному.

Чтобы устанавливать linetype для уровня, этот пример открывает linetype таблицу для чтения и получает объект ID записи linetype желательный linetype (здесь, “DASHED” - “ПОДЧЕРКНУТЫЙ ШТРИХОВОЙ ЛИНИЕЙ”). Как только это имеет объект ID для linetype, это закрывает linetype таблицу и устанавливает linetype для новой записи таблицы уровня. Этот пример использует добавляющийся () функцию, чтобы добавить запись таблицы уровня на таблицу уровня. Наконец, это закрывает запись таблицы уровня и таблицу уровня непосредственно.

void

addLayer()

{

AcDbLayerTable *pLayerTbl;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pLayerTbl, AcDb::kForWrite);

if (!pLayerTbl->has("ASDK_TESTLAYER")) {

AcDbLayerTableRecord *pLayerTblRcd

= new AcDbLayerTableRecord;

pLayerTblRcd->setName("ASDK_TESTLAYER");

pLayerTblRcd->setIsFrozen(0);// layer to THAWED

pLayerTblRcd->setIsOff(0); // layer to ON

pLayerTblRcd->setVPDFLT(0); // viewport default

pLayerTblRcd->setIsLocked(0);// un-locked

AcCmColor color;

color.setColorIndex(1); // set color to red

pLayerTblRcd->setColor(color);

// For linetype, we need to provide the object ID of

// the linetype record for the linetype we want to

// use. First, we need to get the object ID.

//

AcDbLinetypeTable *pLinetypeTbl;

AcDbObjectId ltId;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pLinetypeTbl, AcDb::kForRead);

if ((pLinetypeTbl->getAt("DASHED", ltId))

!= Acad::eOk)

{

acutPrintf("\nUnable to find DASHED"

" linetype. Using CONTINUOUS");

// CONTINUOUS is in every drawing, so use it.

//

pLinetypeTbl->getAt("CONTINUOUS", ltId);

}

pLinetypeTbl->close();

pLayerTblRcd->setLinetypeObjectId(ltId);

pLayerTbl->add(pLayerTblRcd);

pLayerTblRcd->close();

pLayerTbl->close();

} else {

pLayerTbl->close();

acutPrintf("\nlayer already exists");

}

}



Создание и Начальная загрузка Базы данных


Используйте new, чтобы создать базу данных и delete, чтобы уничтожить ее. AcDbDatabase конструктор имеет один параметр со значением по умолчанию Adesk:: kTrue. Если этот параметр - Adesk:: kTrue, то база данных заполняется со стандартными объектами базы данных, описана в “ Начальная База данных. ”, если параметр - Adesk:: kFalse, то пустая база данных создана и может заполняться,  считывая чертежный файл.

Используйте следующую функцию, чтобы читать в чертежном файле:

AcadErrorStatus

AcDbDatabase::readDwgFile(char* fileName);

Если Вы получаете любой из кодов ошибки слежения, Вы вероятно хотите возвратить рисунок к стандарту, AutoCAD возвращает механизм, обеспеченный интерфейсом пользователя:

KDwgNeedsRecovery

KDwgCRCDoesNotMatch

KDwgSentinelDoesNotMatch

KdwgObjectImproperlyRead

ПРЕДУПРЕЖДЕНИЕ! Никогда не удалите базу данных, возвращенную acdbHostApplicationServices()->workingDatabase().



Создание и регистрация заказного режима объектной привязки


Чтобы создавать заказной режим объектной привязки, Вы должны получить подкласс из AcDbCustomOsnapMode и регистрировать это с заказным объектным поспешным менеджером.



Создание Интерфейсов пользователя с MFC


ObjectARX приложения может быть сформированы с динамически связанной MFC библиотекой. Вы можете использовать эту библиотеку, чтобы создать стандартные

графические интерфейсы пользователя Windows.



Создание изображения


Последовательность запроса, чтобы создать изображения для полей ввода изображения и кнопок изображения подобна обрабатывающей списку последовательности. Ads_start_image () функция начинает создание изображения, и ads_end_image () заканчивает это. Однако, опции для того, чтобы рисовать определены следующей отдельной функцией, вызывает вместо параметров:

§

N ads_vector_image () рисует вектор (единственный, прямо выравнивать) в текущем изображении.

§         N ads_fill_image () рисует заполненный прямоугольник в текущем изображении.

§         N ads_slide_image () рисует слайд AutoCAD в изображении.

Векторы и заполненные прямоугольники полезны для простых изображений, типа цветных образчиков (заполненные прямоугольники) использования диалогового окна AutoCAD Select Color, чтобы отобразить выбор пользователя цвета. Для сложных изображений, слайды более удобны. Однако их отображение может быть потребление время. Если Вы используете их, сохраните их простой.

Рисующая изображение функция, ads_vector_image (), требует, чтобы Вы определили абсолютные координаты, в то время как ads_fill_image () и ads_slide_image () требуют стартовой координаты с относительной шириной и высотой. Чтобы делать это правильно, Вы должны знать точные измерения о поле ввода изображения или кнопке изображения. Поскольку эти измерения обычно назначаются, когда диалоговое окно размещено, пакет PDB обеспечивает функцию, ads_dimensions_tile (), который возвращает ширину и высоту специфического поля ввода. Вызовите эту функцию прежде, чем Вы начинаете создавать изображение. Начало координат поля ввода (0,0), является всегда его левым верхним углом.

Цвета могут быть определены как номера цвета AutoCAD или как один из “логических” номеров цвета, показанных в следующей таблице.

ADI

номера цвета

Цвет

Номер

Мнемоническое описание ADI

-2

BGLCOLOR

Текущий фон экрана графики AutoCAD

-15

DBGLCOLOR

Текущий цвет фона диалогового окна

-16

DFGLCOLOR

Цвет символа диалогового окна Current (для текста)

-18

LINELCOLOR

Диалоговое окно текущего цвета линии

<
Значения и мнемоника определены Интерфейсом Устройства Autodesk (ADI).

В следующем примере, “cur_color” - поле ввода изображения, которое будет заполнено полностью заплатой красных. Только один запрос необходим, чтобы получить измерения изображения:

short width, height;

ads_dimensions_tile(hdlg, "cur_color", &width, &height);

ads_start_image(hdlg, "cur_color");

ads_fill_image(0, 0, width, height, 1); // 1 == red.

ads_end_image();

Рисующие изображение функции могут использоваться друг с другом. Здесь, код заполняет изображение и затем рисует вертикальную полосу по этому:

short width, height, x;

ads_dimensions_tile(hdlg, "stripe", &width, &height);

ads_start_image(hdlg, "stripe");

ads_fill_image(0, 0, 0, height, 3); // 3 == AutoCAD green.

// Center the vector vertically.

//

x = width/2;

ads_vector_image(x, 0, x, height, 4); // 4 == cyan.

ads_end_image();

Скольжения, которые Вы отображаете с ads_slide_image () могут быть автономное скольжение (.sld) файлы или часть библиотеки скольжений (.slb) файл. Если скольжение находится в .sld файле, Вы определяете его имя без .sld расширения (например, “frntview”). Если скольжение находится в библиотеке скольжений, Вы определяете имя библиотеки сначала (без расширения), сопровождаемый именем скольжения непосредственно (также без расширения) включенный в круглые скобки (например, “ allviews (frntview) ”). Ads_slide_image () функциональные исследования скольжения или файла библиотеки скольжения согласно потоку путь поиска файлов библиотеки AutoCAD.

Скольжение в следующем примере находится в отдельном файле, вызвал topview.sld:

short x, y;

ads_dimensions_tile(hdlg, "view", &x, &y);

ads_start_image(hdlg, "view");

ads_slide_image(0, 0, x, y, "topview");

ads_end_image();

Векторы в скольжениях часто рисуются в белом (номер цвета 7), который является заданным по умолчанию цветом фона изображения. Если ваше поле ввода изображения - пробел, когда Вы сначала отображаете скольжение, пробуете изменить его цветной атрибут к graphics_background. (Вы можете также изменять фон изображения,  предшествуя ads_slide_image () запрос с ads_fill_image () запрос).


Создание классов и средств управления


1 Использование ClassWizard, создайте диалоговый класс. Если Вы запускаете ClassWizard с экрана создания диалога, это запросит Вас создавать новый класс. Нажмите OK для нового класса, и затем дайте диалогу имя. Для этого примера используют AsdkAcUiDialogSample.

2 Выключатель к позиции табуляции member variable.

3 Для IDC_BUTTON_ANGLE и IDC_BUTTON_POINT ресурсов добавляют, что средство управления CBUTTON вызвало m_ctrlAngleButton и m_ctrlPickButton, соответственно.

4 Для IDC_EDIT_ANGLE, IDC_EDIT_XPT, IDC_EDIT_YPT, и IDC_EDIT_ZPT ресурсов добавляют, что средство управления CEDIT вызвало m_ctrlAngleEdit, m_ctrlXPtEdit, m_ctrlYPtEdit, и m_ctrlZPtEdit, соответственно.

5 Для IDC_LIST_BLOCKS ресурса добавляют, что управление CLISTBOX вызвало m_ctrlBlockList.

6 Для IDC_COMBO_REGAPPS ресурса добавляют, что управление CCOMBOBOX вызвало m_ctrlRegAppComboBox.

7 Теперь открывают AsdkAcUiDialogSample.h файл заголовка и заменяют образование из нового диалогового класса. Это должно быть получено из CACUIDIALOG:

class AsdkAcUiDialogSample : public CAcUiDialog

8 Теперь мы изменим{*заменим*} типы, чтобы использовать средство управления AcUi. Начало,  открывая AsdkAcUiDialogSample.h файл. Измените{*замените*} список управления, чтобы быть следующим:

CAcUiSymbolComboBox  m_ctrlRegAppComboBox;

CacUiListBox        m_ctrlBlockListBox;

CAcUiPickButton m_ctrlPickButton;

CacUiPickButton   m_ctrlAngleButton;

CacUiAngleEdit    m_ctrlAngleEdit;

CAcUiNumericEdit m_ctrlXPtEdit;

CAcUiNumericEdit m_ctrlYPtEdit;

CAcUiNumericEdit m_ctrlZPtEdit;

9 Также добавляют пару полей, чтобы проследить точку и угловые значения и некоторые функции помощника. Они должны быть добавлены к общественному разделу класса:

AcGePoint3d m_ptValue;

double m_dAngle;

void DisplayPoint();

bool ValidatePoint();

void DisplayAngle();

bool ValidateAngle();

void DisplayBlocks();

void DisplayRegApps();



Создание Классов Расширения Протокола


Чтобы создавать заказной режим объектной привязки, Вы должны создать классы расширения протокола, чтобы обработать входную точку "в юридическое лицо" обработка. Класс AcDbCustomOsnapInfo определяет протокол, который каждый заказной режим объектной привязки должен осуществить для уместных примитивов. Этот базовый класс содержит функцию getOsnapInfo (), который исполняет входную обработку точки на примитиве:

class AcDbCustomOsnapInfo : public AcRxObject {

public:

ACRX_DECLARE_MEMBERS(AcDbCustomOsnapInfo);

virtual Acad::ErrorStatus

getOsnapInfo(

AcDbEntity* pickedObject,

int gsSelectionMark,

const AcGePoint3d& pickPoint,

const AcGePoint3d& lastPoint,

const AcGeMatrix3d& viewXform,

AcArray<AcGePoint3d>& snapPoints,

AcArray<int>& geomIdsForPts,

AcArray<AcGeLine3d>& snapLines,

AcArray<int>& geomIdsForLines);

};

Создавать расширение протокола классифицирует для заказных режимов объектной привязки

1 Определяют абстрактный класс расширения протокола, полученный из AcDbCustomOsnapInfo.

Например, если ваш класс пользователя назван AcmeSocketInfo, определите это следующим образом:

class AcmeSocketInfo : public AcDbCustomOsnapInfo{

public:

ACRX_DECLARE_MEMBERS(AcDbSocketInfo);

virtual Acad::ErrorStatus

getOsnapInfo(

AcDbEntity* pickedObject,

int gsSelectionMark,

const AcGePoint3d& pickPoint,

const AcGePoint3d& lastPoint,

const AcGeMatrix3d& viewXform,

AcArray<AcGePoint3d>& snapPoints,

AcArray<int>& geomIdsForPts,

AcArray<AcGeLine3d>& snapLines,

AcArray<int>& geomIdsForLines);

};

ACRX_NO_CONS_DEFINE_MEMBERS(AcmeSocketInfo, AcDbCustomOsnapInfo);

2 Инициализируют основной класс расширения протокола и добавляют это к иерархии классов во время выполнения.

Например, добавьте следующие линии к вашему acrxEntryPoint () функция:

AcmeSocketInfo::rxInit();

acrxBuildClassHierarchy();

3 Для каждого уместного класса примитива, получите класс расширения протокола из базового класса.

Например, Вы могли бы получать класс по имени AcmeSocketForLines, который осуществляет getOsnapInfo () чтобы обработать входную обработку точки для линий.

ОБРАТИТЕ ВНИМАНИЕ, что заданное по умолчанию выполнение должно быть связано с AcDbEntity для каждого зарегистрированного класса, полученного из AcDbCustomOsnapInfo.

4 Создают образец каждого объекта расширения протокола и добавляют объекты к соответствующим AcRxClass дескрипторным объектам, использующим addX () функция.

Например:

pSocketForLine = new AcmeSocketForLine;

AcDbLine::desc()->addX(AcmeSocketInfo::desc(), pSocketForLine);



Создание ключей и значений приложения ObjectArx


Программа инсталляции приложения ObjectARX должна быть разработана, чтобы управлять разделом приложения системного реестра. Этот раздел системного реестра должен включить клавиши{*ключи*} и значения, идентифицирующие основной модуль приложения и набора команд для приложения.

Значение в клавише{*ключе*} Loader должно включить полный путь и имя файла модуля, который AutoCAD должен загрузиться сначала. Модуль загрузчика впоследствии ответствен за загрузку любых других модулей, которые составляют приложение.

Следующий пример иллюстрирует размещение и типы значения прикладного раздела системного системного реестра:

\\ HKEY_LOCAL_MACHINE\SOFTWARE\

...

RegistryPathWhereLoaderIsIdentified\

Loader\Module:REG_SZ:DirPathFileName

Name\DescriptiveName:REG_SZ:User Friendly App Name

Commands\GlobalCommandName1:REG_SZ:LocalCommandName1

GlobalCommandName2:REG_SZ:LocalCommandName2

GlobalCommandName3:REG_SZ:LocalCommandName3

GlobalCommandName4:REG_SZ:LocalCommandName4

GlobalCommandName5:REG_SZ:LocalCommandName5

Groups\

GroupName:REG_SZ:GroupName

...

 Значение Модуля должно присутствовать, но не используется кроме как метка - заполнитель в системном реестре. Точно так же Название{*имя*} Приложения Дружественный к пользователю должно присутствовать, но в настоящее время не используется.

Значение в клавише{*ключе*} Groups может использоваться, чтобы уникально идентифицировать группы команд приложений ObjectARX и поэтому команды также.



Создание MFC-диалога, используя Visual Studio


1 В Visual C++ добавляют ресурс диалога.

2 Создают следующее диалоговое окно, используя средство управления Студии Приложения:

3 Удостоверятся ресурс, ИДЕНТИФИКАТОРЫ соответствуют{*согласовывают*} этой диаграмме, или остающийся код не будет работать.



Создание Неповторно используемой Команды


Делать команду неповторно используемой

1 Объявляют статическую Булеву переменную в вашем приложении для каждой команды, Вы желаете быть неповторно используемыми. Статически инициализируйте каждую переменную к FALSE.

2 Всякий раз, когда пользователь вводит команду или действие, Вы хотите предотвратить повторную входимость к, сначала проверять{*отмечать*} его статическую Булеву переменную. Если это - FALSE, устанавливает это в TRUE и продолжает команду. Если это - TRUE, команда повторно вводится, так перенесите сообщение, спрашивающее пользователя, чтобы закончить команду в другом документе, в котором это используется.

3 Всегда задерживают Булеву переменную к FALSE, когда команда закончена, отменена, или заканчивается по любой причине.



Создание Нового Уровня


Следующий код получает таблицу идентификаторов уровня от базы данных, создает новую запись таблицы уровня ASDK_MYLAYER.

void

createNewLayer()

{

AcDbLayerTable *pLayerTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pLayerTable, AcDb::kForWrite);

AcDbLayerTableRecord *pLayerTableRecord =

new AcDbLayerTableRecord;

pLayerTableRecord->setName("ASDK_MYLAYER");

// Defaults are used for other properties of

// the layer if they are not otherwise specified.

//

pLayerTable->add(pLayerTableRecord);

pLayerTable->close();

pLayerTableRecord->close();

}



Создание Новой Базы данных от Существующей Базы данных


Следующая функция - эквивалент команды WBLOCK*:

Acad:: ErrorStatus

 AcDbDatabase::wblock(AcDbDatabase*& NewDb);

Эта функция создает новую базу данных от вызванной базы данных ("this").

Любые неупомянутые символы во входной базе данных опущены в новой базе данных (который делает новую базу данных потенциально уборщиком и меньший чем оригинал). Однако, это не заботится о копировании определенных приложением объектов, чей монопольное использование внедрено в названном объектном словаре. Вы должны передать{*переместить*} данные прикладной программы от исходной базы данных до целевой базы данных, используя AcEditorReactor функции уведомления.



Создание Новой Базы данных с примитивами


Другие две формы AcDbDatabase:: wblock () функция создает новую базу данных, чей образцовый пространственный блочный отчет{*запись*} таблицы содержит указанные объекты от входной базы данных. Первая форма этой функции копирует объекты с названного блочного отчета{*записи*} таблицы. Вторая форма функции копирует массив объектов.



Создание Объекта COM


API Автоматизации ответствен за создание соответствующего объекта COM для данного объекта резидента базы. AutoCAD осуществляет набор интерфейсов для всех объектов резидента базы данных с соответствующими компонентами Автоматизации.

Многие из этих интерфейсов будут осуществлены автоматически для ваш AcDbObject-получаемый или AcDbEntity полученный класс, когда Вы используете ATL-ОСНОВАННЫЕ обеспеченные шаблоны.

При создании расширений{*продлений*} к API Автоматизации, Вы могут были должны создать объект COM для данного указателя AcDbObjectId или AcDbObject. Это может быть сделано, используя CoCreateInstance сопровождаемый при помощи AcAxOleLinkManager и IACADBASEOBJECT, чтобы основать соответствующие связи. Следующие функции экспортируются для этой цели:

// Получить IUNKNOWN

существующего объекта COM (или недавно созданный объект COM,

// если не существуете) который представляет AcDbObject, пропускал{*прошел*} в.

//

HRESULT

AcAxGetIUnknownOfObject(LPUNKNOWN* ppUnk, AcDbObjectId& objId,

LPDISPATCH pApp);

HRESULT

AcAxGetIUnknownOfObject(LPUNKNOWN* ppUnk, AcDbObject* pObj,

LPDISPATCH pApp);

Объекты COM созданы через CoCreateInstance () использование CLSID, который идентифицирует тип объекта. Чтобы отыскивать передачу CLSID для данного объекта AcDbObject-derived, используйте его getClassID () функция. Эта функция определена на уровне AcDbObject и перегружена на каждом другом уровне в иерархии классов, которая имеет различный тип объекта COM, чтобы представить это.

// Получить соответствующий класс обертки COM ID.

//

virtual Acad::ErrorStatus getClassID(CLSID* pClsid) const;

Например, если Вы создаете заказной примитив (другими словами, AcDbEntity -dполучил{*происходил*} класс) и не перегружать getClassID (), тогда возвращенный CLSID - тот для AcadEntity. Это означает, что ваши заказные примитивы будут по крайней мере иметь функциональные возможности основного уровня, даже если Вы не обеспечиваете поддержку COM для вашего примитива.

Имеется дополнительное требование для использования следующих API, чтобы создать объекты COM для вашего AcDbObject-полученного класса:


IAcadBlock::AddCustomObject(BSTR ClassName, LPDISPATCH* pObject)

IAcadModelSpace::AddCustomObject(BSTR ClassName,

LPDISPATCH* pObject)

IAcadPaperSpace::AddCustomObject(BSTR ClassName,

LPDISPATCH* pObject)

CAcadDictionary::AddObject(BSTR Keyword, BSTR ObjectName,

IAcadObject** pObject)

Эти функции берут фактическое AcDbObject-полученное имя класса (например, AcDbMyObject) и создают объект COM для Вас. После того, как объект COM создан, IAcadBaseObjectId:: SetObjectId () будет,  обратился к этому, чтобы позволить AcDbObject-полученному классу быть инициализированным и добавлен к базе данных.

К obtai n CLSID для данного AcDbObject-полученного имени класса, системный реестр системы должен содержать вход с именем вашего AcDbObject и его передачи CLSID значение.

Размещение системного реестра напоминает это:

HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\

ObjectDBX\

ActiveXCLSID\

AcRxClassName\CLSID:REG_SZ:

{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}

В примере выше, замените AcRxClassName именем вашего AcDbObject-полученного класса (другими словами, AcDbMyObject).


Создание объектов в AutoCAD


Этот раздел описывает создание строки, круга, уровня, и группы в AutoCAD и показывает, как AutoCAD прибавляет эти объекты к базе данных. Сначала, предположите, что  пользователь создает строку в модельном пространстве  command: line 4,2 10,7

В базе данных, AutoCAD создает образец класса AcDbLine и затем сохраняет это в модельном пространственном блочном отчете таблицы как показано:

Когда Вы сначала вызываете AutoCAD, и база данных находится в ее заданном по умолчанию состоянии, объекты добавлены в пространство модели, основное пространство в AutoCAD, который используется для модельной геометрии и графики. Бумажное пространство предназначено, чтобы поддержать “документационную” геометрию и графику, типа основ пленки для изготовления топологических чертежей, блоков заголовка, и annotational текста. Команды создания объекта в AutoCAD (LINE, в этом случае) заставляют объект быть добавленными к текущей базе данных также как к  блоку пространства модели. Вы можете спрашивать любой объект, принадлежащий базе данных.

Затем, предположите, что  пользователь создает круг  командой:

circle 9,3 2

Снова, AutoCAD создает образец соответствующего объекта — здесь, AcDbCircle — и прибавляет это к пространству модели.

Затем, пользователь создает уровень:

layer_make mylayer

 AutoCAD создает новую запись таблицы уровня и затем прибавляет его в таблицу уровней.

Наконец, группируем все объекты вместе:

group 3,2 9,3

AutoCAD создает новую группу и прибавляет ее к словарю GROUP, который содержится в объектном словаре имен. Новая группа содержит список  ID объектов, которые составляют группу.



Создание Образцов Примитивов AutoCAD


Этот раздел демонстрирует, как создать простые и сложные примитивы и добавлять их к базе данных. Это также иллюстрирует создание простого примитива, простого блока, блок с атрибутами, и блочной вставкой (блочная ссылка{*справочники*}).



Создание приложения ObjectARX


Приложение ObjectARX - DLL, который совместно использует адресное пространство AutoCAD и делает прямые функциональные запросы к AutoCAD. ObjectARX приложения типично осуществляют команды, к которым можно обращаться изнутри AutoCAD.

Эти команды часто осуществляются, используя заказные классы. Создание приложения ObjectARX подразумевает следующие общие шаги.

1.       Создайте заказные классы, чтобы осуществить новые команды.

Вы можете получать заказные классы из большинства таблиц идентификаторов  иерархии классов ObjectARX.

2.       Определите, которые сообщения AutoCAD ваше приложение ObjectARX обработает. AutoCAD посылает разнообразие сообщений к приложениям ObjectARX, указывая, что специфические события произошли в пределах AutoCAD. Вы решаете, которым сообщениям ваше приложение ответит  и которые действия будут вызваны.

3.       Осуществьте точку входа для AutoCAD.

AutoCAD звонит в приложение ObjectARX через AcrxEntryPoint(), которая заменяет функцию main() программы C++. Вы ответственны за осуществление acrxEntryPoint() в вашем приложении. AcrxEntryPoint() вызывает функции, которые вы связали с определенными сообщениями AutoCAD.

4.       Инициализация реализации.

В пределах вашего приложения ObjectARX, Вы будете должны инициализировать любые заказные классы, что Вы создали, и восстанавливаете ObjectARX дерево классов во время выполнения. Дополнительно, если Вы прибавляете команды, Вы должны регистрировать их в AutoCAD.

5.       Готовьтесь к разгрузке.

Чтобы создавать хорошее приложение ObjectARX, Вы должны удалить любые заказные классы и команды, когда ваше приложение разгружено.

Следующие разделы обсуждают общие шаги разработки приложения ObjectARX более подробно.

ОБРАТИТЕ ВНИМАНИЕ, что ObjectARX Мастер доступен для создания ObjectARX проекты. См. objectarx\utils каталог в ObjectARX SDK.



Создание примитивов


Следующий код ObjectARX создает линию и прибавляет это к  таблице блоков пространства модели:

AcDbObjectId

createLine()

{

AcGePoint3d startPt(4.0, 2.0, 0.0);

AcGePoint3d endPt(10.0, 7.0, 0.0);

AcDbLine *pLine = new AcDbLine(startPt, endPt);

AcDbBlockTable *pBlockTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForRead);

AcDbBlockTableRecord *pBlockTableRecord;

pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,

AcDb::kForWrite);

pBlockTable->close();

AcDbObjectId lineId;

pBlockTableRecord->appendAcDbEntity(lineId, pLine);

pBlockTableRecord->close();

pLine->close();

return lineId;

}

CreateLine()  получает блочную таблицу для текущего рисунка.

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

ОБРАТИТЕ ВНИМАНИЕ, когда Вы используете любые объекты ObjectARX, Вы должны  их как можно скорее закрыть.

createCircle () создает круг и прибавляет это к блочной таблице пространства модели:

AcDbObjectId createCircle()

{

AcGePoint3d center(9.0, 3.0, 0.0);

AcGeVector3d normal(0.0, 0.0, 1.0);

AcDbCircle *pCirc = new AcDbCircle(center, normal, 2.0);

AcDbBlockTable *pBlockTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForRead);

AcDbBlockTableRecord *pBlockTableRecord;

pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,

AcDb::kForWrite);

pBlockTable->close();

AcDbObjectId circleId;

pBlockTableRecord->appendAcDbEntity(circleId, pCirc);

pBlockTableRecord->close();

pCirc->close();

return circleId;

}



Создание Простого Примитива


Следующий пример демонстрирует создание строки и добавления в конец этого к образцовому пространственному блочному отчету{*записи*} таблицы, как описано в главе 2, “ Учебник для начинающих Базы данных. ”

AcDbObjectId

createLine()

{

AcGePoint3d startPt(4.0, 2.0, 0.0);

AcGePoint3d endPt(10.0, 7.0, 0.0);

AcDbLine *pLine = new AcDbLine(startPt, endPt);

AcDbBlockTable *pBlockTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForRead);

AcDbBlockTableRecord *pBlockTableRecord;

pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,

AcDb::kForWrite);

pBlockTable->close();

AcDbObjectId lineId;

pBlockTableRecord->appendAcDbEntity(lineId, pLine);

pBlockTableRecord->close();

pLine->close();

return lineId;

}



Создание Словаря


Следующий пример создает новый словарь (ASDK_DICT) и добавляет это к словари имен объектов. Тогда это создает два новых объекта класса пользователя AsdkMyClass (полученный из AcDbObject) и добавляет их к словарю, используя setAt () функция.

ОБРАТИТЕ ВНИМАНИЕ, что Вы должны закрыть объекты после добавления их с setAt () функция.

// This function creates two objects of class AsdkMyClass.

// It fills them in with the integers 1 and 2, and then adds

// them to the dictionary associated with the key ASDK_DICT. If this

// dictionary doesn’t exist, it is created and added to the named

// object dictionary.

//

void

createDictionary()

{

AcDbDictionary *pNamedobj;

acdbHostApplicationServices()->workingDatabase()->

getNamedObjectsDictionary(pNamedobj, AcDb::kForWrite);

// Check to see if the dictionary we want to create is

// already present. If not, create it and add

// it to the named object dictionary.

//

AcDbDictionary *pDict;

if (pNamedobj->getAt("ASDK_DICT", (AcDbObject*&) pDict,

AcDb::kForWrite) == Acad::eKeyNotFound)

{

pDict = new AcDbDictionary;

AcDbObjectId DictId;

pNamedobj->setAt("ASDK_DICT", pDict, DictId);

}

pNamedobj->close();

if (pDict) {

// Create new objects to add to the new dictionary,

// add them, then close them.

//

AsdkMyClass *pObj1 = new AsdkMyClass(1);

AsdkMyClass *pObj2 = new AsdkMyClass(2);

AcDbObjectId rId1, rId2;

pDict->setAt("OBJ1", pObj1, rId1);

pDict->setAt("OBJ2", pObj2, rId2);

pObj1->close();

pObj2->close();

pDict->close();

}

}



Создание Сложного Примитива


Эти показы примера, как создавать объект AcDb2dPolyline и устан некоторых из его свойств — уровень, окрашивают индекс, закрытый параметр. Это тогда создает четыре объекта (AcDb2dPolylineVertex вершины, устанавливает их местоположение, и добавляет их к объекту ломаной линии. Наконец, это закрывает всю открытую вершину объектов —, ломаную линию, запись таблицы блоков, и таблицу блоков. Когда объект ломаной линии закрыт, AutoCAD добавляет объект AcDbSequenceEnd к этому автоматически.

void

createPolyline()

{

// Set four vertex locations for the pline.

//

AcGePoint3dArray ptArr;

ptArr.setLogicalLength(4);

for (int i = 0; i < 4; i++) {

ptArr[i].set((double)(i/2), (double)(i%2), 0.0);

}

// Dynamically allocate an AcDb2dPolyline object,

// given four vertex elements whose locations are supplied

// in ptArr. The polyline has no elevation, and is

// explicitly set as closed. The polyline is simple;

// that is, not curve fit or a spline. By default, the

// widths are all 0.0 and there are no bulge factors.

//

AcDb2dPolyline *pNewPline = new AcDb2dPolyline(

AcDb::k2dSimplePoly, ptArr, 0.0, Adesk::kTrue);

pNewPline->setColorIndex(3);

// Get a pointer to a Block Table object.

//

AcDbBlockTable *pBlockTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForRead);

// Get a pointer to the MODEL_SPACE BlockTableRecord.

//

AcDbBlockTableRecord *pBlockTableRecord;

pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,

AcDb::kForWrite);

pBlockTable->close();

// Append the pline object to the database and

// obtain its object ID.

//

AcDbObjectId plineObjId;

pBlockTableRecord->appendAcDbEntity(plineObjId,

pNewPline);

pBlockTableRecord->close();

// Make the pline object reside on layer "0".

//

pNewPline->setLayer("0");

pNewPline->close();

}



Создание Средства просмотра


ObjectDBX включает компоненты, которые могут использоваться, чтобы разработать средство просмотра для геометрических моделей, сохраненных в базе данных AutoCAD. Эта работа компонентов вместе, чтобы формировать полную библиотеку рассмотрений но может использоваться или заменен независимо разработчиками. Компоненты взаимодействуют с AcDb моделями через AcGi API, который является тем же самым интерфейсом, что система графики AutoCAD использует, чтобы взаимодействовать с AcDb.



Создание Заказного Глифа


Вы можете создавать заказной глиф происходящий от AcGiGlyph и регистрацию глифа с вашим заказным режимом объектной привязки. Две функции должны быть осуществлены в вашем полученном классе: setLocation() и viewportDraw(). SetLocation() функция заставляет местоположение глифа рисоваться, и viewportDraw() функция рисует глиф.

Имеются несколько требований для графики, используемой в viewportDraw () который должен соблюстись. Графика должна быть выровненная дисплеем, и на нее нельзя воздействовать ориентацией примитива, текущий UCS, или текущий вид преобразовывает. Дополнительно, графика должна масштабироваться, чтобы приспособить текущий Авто-привязка размер маркера, который может быть определен,  используя функцию acdbCustomOsnapManager()>osnapGlyphSize().

ОБРАТИТЕ ВНИМАНИЕ, возвращаете ли Вы указатель NULL вместо заказного глифа, AutoCAD не будет рисовать никакой глиф для режима объектной привязки.



Создание Заказных Классов


Вы можете усиливать классы в иерархии ObjectARX, чтобы создать ваши собственные

заказные классы. Кроме того, Вы можете использовать обширную графику

Библиотеки ObjectARX при создании заказных классов.


Вы можете получать заказные классы из большинства ObjectARX иерархии классов.

Это позволяет Вам усиливать функциональные возможности классов ObjectARX при создании ваших собственных объектов. Определение заказных классов обсуждено подробно в гл. 11, "Получении Заказного ObjectARX Класса".



Создание Заказных Режимов объектной привязки


Заказные режимы объектной привязки позволяют разработчику устанавливать следующие атрибуты:

§         Ключевое слово

Заказное объектное поспешное ключевое слово, что пользователь типы в, чтобы активизировать объектную привязку. И местные и глобальные ключевые слова должны быть определены.

§         класс расширения Протокола

Указатель на класс, который исполняет обработку " в юридическое лицо " режима объектной привязки.

§         Глиф(Glyph)

Заказной глиф для режима объектной привязки.

§         ToolTip строка

По умолчанию ToolTip

строка для заказного режима объектной привязки.

Для подробной информации относительно установки этих атрибутов, см. ObjectARX Ссылку.

Заказной режим объектной привязки определен,  регистрируя образец AcDbCustomOsnapMode класса с заказным объектным менеджером привязок, описан в предыдущей секции.

Когда заказной режим объектной привязки используется, AutoCAD берет объект класса, возвращенный AcDbCustomOsnapMode:: entityOsnapClass (), взгляды соответствующий объект расширения протокола для выбранного примитива, и вызывает AcDbCustomOsnapInfo:: getOsnapInfo () чтобы получить точки или линии, связанные с тем примитивом и режимом объектной привязки. Если она кандидат, точка связана с тем режимом объектной привязки, AutoCAD, отображает объект глифа от образца, возвращенного AcDbCustomOsnapMode::gluph () и ToolTip строка, возвращенная AcDbCustomOsnapMode:: tooltipString ().



Создание записи простой таблицы блока


Следующий пример демонстрирует создание новой записи таблицы блоков и добавления ее в конец этой таблицы. Он создает линию и добавляет ее в новый блок.

void

makeABlock()

{

// Create and name a new block table record.

//

AcDbBlockTableRecord *pBlockTableRec

= new AcDbBlockTableRecord();

pBlockTableRec->setName("ASDK-NO-ATTR");

// Get the block table.

//

AcDbBlockTable *pBlockTable = NULL;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForWrite);

// Add the new block table record to the block table.

//

AcDbObjectId blockTableRecordId;

pBlockTable->add(blockTableRecordId, pBlockTableRec);

pBlockTable->close();

// Create and add a line entity to the component’s

// block record.

//

AcDbLine *pLine = new AcDbLine();

AcDbObjectId lineId;

pLine->setStartPoint(AcGePoint3d(3, 3, 0));

pLine->setEndPoint(AcGePoint3d(6, 6, 0));

pLine->setColorIndex(3);

pBlockTableRec->appendAcDbEntity(lineId, pLine);

pLine->close();

pBlockTableRec->close();

}



Создание записи таблицы блоков с определениями атрибута


Блок AutoCAD - коллекция примитивов, который сохранен в записи таблицы блоков. Каждый блок имеет объект AcDbBlockBegin, сопровождаемый одним или большее количество объектов AcDbEntity, и заканчивается объектом AcDbBlockEnd (см. иллюстрацию на странице 100).

Блок может содержать определения атрибута, которые являются шаблонами для создания атрибутов. Атрибут - информационный текст, связанный с блоком. В зависимости от обеспеченной пользователем установки, атрибуты со значением могут или не может быть скопирован, когда блок вставлен в рисунок. Часто, приложение запрашивает пользователя относительно атрибута со значением во время выполнения.

Создавать запись таблицы блоков

1 Создают новую запись таблицы блоков.

2 Добавляют запись таблицы блоков на таблицу блоков.

3 Создают примитивы и добавляют их к записи таблицы блоков.

4 Создают определения атрибута, устанавливают их значения, и добавляют их к записи таблицы блоков.

Когда Вы закрываете запись таблицы блоков, блок начинает и блокирует конечные объекты,  добавлены к блоку автоматически.

Следующий пример создает новую запись таблицы блоков по имени ASDK-BLOCK-WITH-ATTR и добавляет это к таблице блоков. Затем это создает примитив круга и добавляет это к новой записи таблицы блоков. Это создает два примитива определения атрибута (второй - аналог первых) и добавляет в конец их к той же самой записи таблицы блоков.

void

defineBlockWithAttributes(

AcDbObjectId& blockId, // This is a returned value.

const AcGePoint3d& basePoint,

double textHeight,

double textAngle)

{

int retCode = 0;

AcDbBlockTable *pBlockTable = NULL;

AcDbBlockTableRecord* pBlockRecord = new AcDbBlockTableRecord;

AcDbObjectId entityId;

// Step 1: Set the block name and base point of the

// block definition.

//

pBlockRecord->setName("ASDK-BLOCK-WITH-ATTR");

pBlockRecord->setOrigin(basePoint);

// Open the block table for write.

//

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForWrite);


// Step 2: Add the block table record to block table.

//

pBlockTable->add(blockId, pBlockRecord);

// Step 3: Create a circle entity.

//

AcDbCircle *pCircle = new AcDbCircle;

pCircle->setCenter(basePoint);

pCircle->setRadius(textHeight * 4.0);

pCircle->setColorIndex(3);

// Append the circle entity to the block record.

//

pBlockRecord->appendAcDbEntity(entityId, pCircle);

pCircle->close();

// Step 4: Create an attribute definition entity.

//

AcDbAttributeDefinition *pAttdef

= new AcDbAttributeDefinition;

// Set the attribute definition values.

//

pAttdef->setPosition(basePoint);

pAttdef->setHeight(textHeight);

pAttdef->setRotation(textAngle);

pAttdef->setHorizontalMode(AcDb::kTextLeft);

pAttdef->setVerticalMode(AcDb::kTextBase);

pAttdef->setPrompt("Prompt");

pAttdef->setTextString("DEFAULT");

pAttdef->setTag("Tag");

pAttdef->setInvisible(Adesk::kFalse);

pAttdef->setVerifiable(Adesk::kFalse);

pAttdef->setPreset(Adesk::kFalse);

pAttdef->setConstant(Adesk::kFalse);

pAttdef->setFieldLength(25);

// Append the attribute definition to the block.

//

pBlockRecord->appendAcDbEntity(entityId, pAttdef);

// The second attribute definition is a little easier

// because we are cloning the first one.

//

AcDbAttributeDefinition *pAttdef2

= AcDbAttributeDefinition::cast(pAttdef->clone());

// Set the values that are specific to the

// second attribute definition.

//

AcGePoint3d tempPt(basePoint);

tempPt.y -= pAttdef2->height();

pAttdef2->setPosition(tempPt);

pAttdef2->setColorIndex(1); // Red

pAttdef2->setConstant(Adesk::kTrue);

// Append the second attribute definition to the block.

//

pBlockRecord->appendAcDbEntity(entityId, pAttdef2);

pAttdef->close();

pAttdef2->close();

pBlockRecord->close();

pBlockTable->close();

return;

}


Создании объектов в ObjectARX


Пример ObjectARX кода в этом разделе создает те же самые объекты как в предыдущем разделе (линия и круг). Показывается код для создания нового уровня, изменение цвета линии, и добавления группы к словарю GROUP.



Создавать обертку Автоматизации для заказного объекта или примитива


1 Основанный ваш проект согласно шагам в “ Введение Файла Проекта ATL. ”

2 В файле заголовка объекта COM, включите axtempl.h (главное ActiveX файл заголовка шаблона Автоматизации) и файл (ы) заголовка для ваших заказных объектов или примитивов.

3 Изменяют образование из объекта COM или примитива,  удаляя IDISPATCHIMPL часть образования и заменяя это со следующим кодом:

// Для заказного объекта.

//

public IAcadObjectDispatchImpl<CWrapperClass,

&CLSID_WrapperClass,IWrapperClass,

&IID_IWrapperClass,&LIBID_LIBRARYLib>

// For a custom entity.

//

public IAcadEntityDispatchImpl<CWrapperClass,

&CLSID_WrapperClass,IWrapperClass,

&IID_IWrapperClass,&LIBID_LIBRARYLib>

4 Добавляют следующие вхождения в COM_MAP:

COM_INTERFACE_ENTRY(IAcadBaseObject)

COM_INTERFACE_ENTRY(IAcadObject)

COM_INTERFACE_ENTRY(IAcadEntity) // For an entity only.

COM_INTERFACE_ENTRY(IRetrieveApplication)

COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) // Only

// necessary to support events.

5 Добавляют следующую требуемую перегрузку к заголовку file:

// IAcadBaseObjectImpl

//

virtual HRESULT

CreateNewObject(

AcDbObjectId& objId,

TCHAR* entryName,

TCHAR* keyName);

Эта абстрактная функция, определенная в IACADBASEOBJECTIMPL шаблоне должна быть перегружена, чтобы позволить Вам добавлять заданные по умолчанию объекты к базе данных.

6 Осуществляют CreateNewObject () для любго объекта или определенного примитива.

Следующий пример показывает выполнение CreateNewObject () из AsdkSquareWrapper:

HRESULT CAsdkSquareWrapper::CreateNewObject(

AcDbObjectId& objId,

AcDbObjectId& ownerId,

TCHAR* keyName)

{

try

{

//AXEntityDocLock(ownerId);

Acad::ErrorStatus es;

AcDbObjectPointer<AsdkSquare> pSq;

if((es = pSq.create()) != Acad::eOk)

throw es;

AcDbDatabase* pDb = ownerId.database();

pSq->setDatabaseDefaults(pDb);

AcDbBlockTableRecordPointer

pBlockTableRecord(ownerId, AcDb::kForWrite);

if((es = pBlockTableRecord.openStatus()) != Acad::eOk)


throw es;

if((es = pBlockTableRecord->appendAcDbEntity(objId, pSq.object())) != Acad::eOk)

throw es;

}

catch(const Acad::ErrorStatus)

{

//To become more sophisticated

//

return Error(L"Failed to create square",

IID_IAsdkSquareWrapper, E_FAIL);

}

return S_OK;

}

7 В файле IDL, добавьте importlib ("c:\ACAD\acad.tlb"); после importlib stdole32.tlb и importlib stdole2.tlb. Удостоверитесь, чтобы использовать правильный путь, который соответствует вашей инсталляции AutoCAD.

8 Перемещают acad.tlb секцию в вершину файла IDL и перемещают ваш заказной объектный код так, чтобы это было в пределах той секции.

ОБРАТИТЕ ВНИМАНИЕ, что  модификации файла IDL заставят компилятор выпускать предупреждение, заявляющее, что интерфейс не соответствует. Вы можете игнорировать это сообщение.

9 Изменяют{*заменяют*} образование в файле IDL от IDISPATCH до IACADOBJECT для заказного объекта или IACADENTITY для заказного примитива.

10 В секции файла IDL, который соответствует вашей обертке coclass, добавьте [источник] связывают с помощью интерфейса IACADOBJECTEVENTS; после [заданной по умолчанию] линии, чтобы поддерживать события. Файл IDL будет теперь казаться подобным следующему коду:

import "oaidl.idl";

import "ocidl.idl";

[

uuid(800F70A1-6DE9-11D2-A7A6-0060B0872457),

version(1.0),

helpstring("AsdkSquareLib 1.0 Type Library")

]

library ASDKSQUARELIBLib

{

importlib("stdole32.tlb");

importlib("stdole2.tlb");

importlib("v:\acad\acad2000\acad.tlb");

[

object,

uuid(800F70AD-6DE9-11D2-A7A6-0060B0872457),

dual,

helpstring("IAsdkSquareWrapper Interface"),

pointer_default(unique)

]

interface IAsdkSquareWrapper : IAcadEntity

{

[propget, id(1), helpstring("property Number")]

HRESULT Number([out, retval] short *pVal);

[propput, id(1), helpstring("property Number")]

HRESULT Number([in] short newVal);

};

[

uuid(800F70AE-6DE9-11D2-A7A6-0060B0872457),



helpstring("AsdkSquareWrapper Class")

]

coclass AsdkSquareWrapper

{

[default] interface IAsdkSquareWrapper;

[source] interface IAcadObjectEvents;

};

};

11 После #include <Atlcom.h> в stdafx.h, включите acad15.h, сначала, сопровождаемый любыми необходимыми ObjectARX файлами заголовка.

12 в конце stdafx.cpp, включите acad15_i.c.

13, если приложение ARX и обертка COM объединено, добавьте следующий код к вашему главному CPP файл, и назовите это DllMain в AcRx:: kInitAppMsg и AcRx:: kUnloadAppMsg с соответствующими параметрами. Это инициализирует карту объекта ATL, среди других вещей:

extern "C" HINSTANCE _hdllInstance;

extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance,

DWORD dwReason,LPVOID /*lpReserved*/);

14 Добавляют желательные ActiveX методы, и свойства к вашему классу обертки выбором Добавляют Метод или Добавляют Свойство от подручного меню Интерфейса представления{*вида*} Класса.

15 Для любого ObjectARX обертываемого класса, перегрузите getClassId () функция для заказного объекта или примитива со следующим:

Acad::ErrorStatus

Class::getClassID(CLSID* pClsid) const

{

*pClsid = CLSID_WrapperClass;

return Acad::eOk;

}

16 В файле, который содержит,  перегрузка для getClassId (), добавляет:

#include <objbase.h>

#include <initguid.h>

#include

"library_i.c"            // Файл, содержащий фактические определения

// IIDs

и CLSIDS

для проекта COM.

17 Компоновки и регистр приложение согласно шагам в “ Формирование и Регистрация COM DLL. ”


Специфические для приложения объекты документа


Эта секция выделяет, как приложения MDI-Aware должны быть структурированы. Фактически все разработчики ObjectARX-приложения должны обслужить{*поддержать*} карту между поддерживаемыми системой объектами документа и передачей специфических для приложения данных. Любая такая карта должна быть манипулирована с определенными значениями указателя AcApDocument (адреса).

Это требует, чтобы приложение по крайней мере осуществило повторные вызовы для AcApDocManagerReactor методов documentCreated () и documentToBeDestroyed (), создавать и удалять передачу docu-ment-specific состояние. Удостоверитесь, что ваши указатели AcApDocument современны, поскольку они будут вероятно многократно использоваться, поскольку документы закончены и созданы. Как альтернатива, Вы можете осуществлять обработчики для того, когда ваш acrxEntryPoint () функция вызвана с AcRx:: kLoadDwgMsg и AcRx:: kUnloadDwgMsg сообщения, которые вызваны с документом в вопросе, являющемся текущим.

Такие специфические для приложения данные должны содержать любое состояние, которое должно быть связано с каждым открытым документом, который должен упорствовать{*сохраниться*} поперек команд. Одна альтернатива выполнения была бы должна обслужить{*поддержать*} AcArray шаблон класса, чей образцы состоят из указателя AcApDocument и указателя на, или образца, вашего документированного - определенного состояния, и чей == оператор перезагружен, чтобы сравнить только AcApDocument* члена. Другой подход был бы состоял в том, чтобы обслужить{*поддержать*} пару массивов с соответствующими элементами, делайте находку на указателях документа, и выберите соответствующий элемент из

Другой массив.



Специфичные для приложения Данные


Ads_client_data_tile () функция назначает специфичные для приложения данные к полю ввода. Данные доступны при повторном вызове время как пакет повторного вызова client_data поле. Клиентские данные не представлены в DCL; это имеет силу только, в то время как ваше приложение выполняется. Использование клиентских данных сопоставимо использованию определяемых пользователем атрибутов. Основное различие - то, что определяемые пользователем атрибуты являются только для чтения, в то время как клиентские данные могут изменяться во время выполнения. (Также, конечные пользователи могут осматривать определяемые пользователем атрибуты в файле приложения DCL, но клиентские данные невидимы для них.)

Клиентские данные могут иметь любой тип, который Вы выбираете. Это объявлено как указатель на пусто.

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

Клиентские данные - полезный способ передать информацию к функции повторного вызова, потому что никакие дополнительные параметры не могут быть добавлены к функции.

Поскольку ваша программа должна поддержать список, отображенный списком (или всплывающий список), клиентские данные хороши для обработки этой информации. Предыдущий пример mk_list () функция уже заставит список оценить параметр.

Это - тип указателя, который предоставляет себя, чтобы использовать как клиентские данные. Например, основная функция, чтобы обработать то же самое диалоговое окно могла включать следующий код (проверка ошибок минимизирована для простоты):

struct resbuf *usrhead;

int

handler()

{

struct resbuf *csyshead, *usrhead;

ads_hdlg cldlg;

if (ads_new_dialog("clistdlg", dcl_id, NULLCB, &cldlg))

return BAD;

csyshead = acutBuildList(RTSTR, "Red-Green-Blue",

RTSTR, "Cyan-Magenta-Yellow",

RTSTR, "Hue-Saturation-Value", 0);

if (csyshead == NULL)

return BAD;

ads_client_data_tile(cldlg, "colorsyslist", csyshead);

ads_action_tile(cldlg, "colorsyslist", listcallback);

...

// Start dialog box and do other processing.

//

...

}

Затем, функция повторного вызова listcallback () вызывает mk_list () следующим образом:

static void CALLB

listcallback(ads_callback_packet *cpkt)

{

if ((cpkt->reason == CBR_SELECT) || (cpkt->reason == CBR_DOUBLE_CLICK)) {

// This is not the default tile, so treat both the same.

//

usrhead = mk_list(cpkt->value, cpkt->client_data);

}

}



Спецификации Ключевого слова


Необязательный kwl параметр определяет список ключевых слов, которые будут признаны следующим вводом пользователя (acedGetxxx ()) функциональный запрос. Значение ключевого слова, которое пользователь вводит, может быть восстановлено{*отыскано*} последующим запросом к acedGetInput () (. Значение ключевого слова было бы доступно, если функция ввода пользователя была acedGetKword ().) значения ключевых слов и действия, чтобы исполнить для каждого - ответственность ObjectARX-приложения.

AcedGetInput () функция всегда возвращает ключевое слово, поскольку это появляется в kwl параметре, с тем же самым преобразованием букв в прописные (но не с необязательными символами, если те определены после запятой). Независимо от того, как пользователь вводит ключевое слово, приложение должно делать только одно строковое сравнение, чтобы идентифицировать это, как демонстрируется в следующем примере. Доля кода, которая следует за показами запрос к acedGetReal () предшеств запросом к acedInitGet () который определяет два ключевых слова. Приложение проверяет эти ключевые слова и устанавливает входное значение соответственно.

int stat;

ads_real x, pi = 3.14159265;

char kw[20];

// Null input is not allowed.

acedInitGet(RSG_NONULL, "Pi Two-pi");

if ((stat = acedGetReal("Pi/Two-pi/<number>: ", &x)) < 0) {

if (stat == RTKWORD && acedGetInput(kw) == RTNORM) {

if (strcmp(kw, "Pi") == 0) {

x = pi;

stat = RTNORM;

} else if (strcmp(kw, "Two-pi") == 0) {

x = pi * 2;

stat = RTNORM;

}

}

}

if (stat != RTNORM)

acutPrintf("Error on acedGetReal() input.\n");

else

acutPrintf("You entered %f\n", x);

Запрос к acedInitGet () предотвращает пустой указатель, вводят, и определяет два ключевых слова: “Pi” и “Два - pi”. Когда acedGetReal () вызван{*назван*}, пользователь отвечает на подсказку Pi/Two-pi / <номеру>,  вводя или реальное значение (сохраненный в местной переменной x) или одном из ключевых слов. Если пользователь вводит ключевое слово, acedGetReal () возвращает RTKWORD. Приложение отыскивает ключевое слово,  вызывая acedGetInput () (обратите внимание, что это проверяет{*отмечает*} состояние ошибки этой функции), и затем устанавливает значение x к pi или 2pi, в зависимости от которого ключевое слово было введено. В этом примере, пользователь может вводить или p, чтобы выбрать pi или t, чтобы выбрать 2pi.



Списки AutoLISP


AcutBuildList() функция вызвана в сочетании и с acedRetList(), который возвращает структуру списка AutoLISP.

Следующий типовой кодовый фрагмент передает список четырех точек:

struct resbuf *res_list;

ads_point ptarray[4];

// Initialize the point values here.

.

.

.

res_list = acutBuildList(

RT3DPOINT, ptarray[0],

RT3DPOINT, ptarray[1],

RT3DPOINT, ptarray[2],

RT3DPOINT, ptarray[3], 0);

if (res_list == NULL) {

acdbFail("Couldn’t create list\n");

return BAD;

}

acedRetList(res_list);

acutRelRb(res_list);

Точечные пары и вложенные списки могут быть возвращены AutoLISP,  вызывая acutBuildList () чтобы формировать список, созданный со специальными кодами типа строительства списка. Эти коды необходимы только для сложных списков. Для обычного (то есть одномерный) списки, acedRetList () можно пропускать простой список буферов результатов, как показано в предыдущем примере.

ОБРАТИТЕ ВНИМАНИЕ список, возвращенный AutoLISP acedRetList () может включать только следующие коды типа результата: RTREAL, RTPOINT, RTSHORT, RTANG, RTSTR, RTENAME, RTPICKS, RTORINT, RT3DPOINT, RTLB, RTLE, RTDOTE, RTNIL, и RTT. (Хотя имеется RTNIL код возврата, если Вы возвращаете только список ноля, Вы можете вызывать acedRetNil ()). Это может содержать типы результата RTLONG, если список возвращается другому ObjectARX-приложению.

Использование кодов типа строительства списка просто. В acutBuildList () запросу, вложенный список предшествует тип результата, закодируют RTLB (для Списка, начинают) и сопровождается типом результата, закодируют RTLE (для Списка Конец). Точечная пара может также быть создана. Точечные пары также начинаются с RTLB и конца с RTLE; точка обозначена типом результата, закодируют RTDOTE, и появляется между двумя членами пары.

ПРИМЕЧАНИЕ Это – изменение от более ранних версий. Приложения, которые не получают точечную пару от AutoLISP больше, должны изменить формат точечной пары перед возвращением этого с acedRetList () (. Более ранний порядок, с RTDOTE в конец, все еще поддерживается.)


ПРЕДУПРЕЖДЕНИЕ! AcutBuildList () функция не проверяет правильно построенный список AutoLISP. Например, если RTLB и коды RTLE не сбалансированы, эта ошибка не обнаружена. Если список хорошо не сформирован, AutoLISP может терпеть неудачу. Исключение кода RTLE, как гарантируют,  будет фатальной ошибкой.

Следующий типовой кодовый фрагмент создает вложенный список, чтобы возвратиться AutoLISP:

res_list = acutBuildList(

RTLB, // Begin sublist.

RTSHORT, 1,

RTSHORT, 2,

RTSHORT, 3,

RTLE, // End sublist.

RTSHORT, 4,

RTSHORT, 5,

0);

if (res_list == NULL) {

acdbFail("Couldn’t create list\n");

return BAD;

}

acedRetList(res_list);

acutRelRb(res_list);

The list that this example returns to AutoLISP has the following form:

((1 2 3) 4 5)

The following code fragment constructs a dotted pair to return to AutoLISP:

res_list = acutBuildList(

RTLB, // Begin dotted pair.

RTSTR, "Sample",

RTDOTE,

RTSTR, "Strings",

RTLE, // End dotted pair.

0);

if (res_list == NULL) {

acdbFail("Couldn’t create list\n");

return BAD;

}

acedRetList(res_list);

acutRelRb(res_list);

Список, который этот пример возвращается AutoLISP, имеет следующую форму:

((“Sample” . “Strings”))

ОБРАТИТЕ ВНИМАНИЕ В AutoLISP, кодах группы DXF связери точечных пар и значениях. В ObjectARX-приложении это ненужно, потому что единственный{*отдельный*} буфер результатов содержит, и код группы (в его restype поле) и значении (в его resval поле). В то время как ObjectARX обеспечивает коды типа строительства списка как удобство, большинство ObjectARX-приложений не требует их.


Списки буфера результата


Буфера Результатов могут быть объединены в списках связей, описан позже подробно, и поэтому подходящие для обработки объектов, чей длины могут измениться и объекты, которые могут содержать смесь типов данных. Много функций ObjectARX возвращают или ввод или отдельные буфера результатов (типа acedSetVar()) или списков буфера результата (типа acdbEntGet() и acdbTblSearch()).



Списки Фильтра Набора Выбора


Когда entmask параметр определяет, что список значений поля примитива, acedSSGet () просматривает выбранные примитивы и создает набор выборов, содержащий названия{*имена*} всех основных примитивов, которые соответствуют{*согласовывают*} указанным критериям. Например, используя этот механизм, Вы можете получить набор выборов, который включает все примитивы данного типа, на данном уровне, или данного цвета.

Вы можете использовать фильтр вместе с любой из опций выбора. Опция “X” говорит, что создала набор выборов, используя только фильтрация; как в предыдущих версиях AutoCAD, если Вы используете,  опция “X”, acedSSGet () просматривает полную базу данных рисунка.

ОБРАТИТЕ ВНИМАНИЕ, определена ли только фильтрация (“X”) но entmask параметр - NULL, acedSSGet () выбирает все примитивы в базе данных.

Entmask параметр должен быть список буфера результата. Каждый буфер определяет свойство, чтобы проверить{*отметить*} и значение, которое составляет соответствие; restype поле буфера - код группы DXF, который указывает вид свойства, чтобы смотреть для, и его resval поле определяет значение, чтобы соответствовать{*согласовать*}.

Следующее - некоторые примеры.

struct resbuf eb1, eb2, eb3;

char sbuf1[10], sbuf2[10]; // Buffers to hold strings

ads_name ssname1, ssname2;

eb1.restype = 0;// Entity name

strcpy(sbuf1, "CIRCLE");

eb1.resval.rstring = sbuf1;

eb1.rbnext = NULL; // No other properties

// Retrieve all circles.

acedSSGet("X", NULL, NULL, &eb1, ssname1);

eb2.restype = 8; // Layer name

strcpy(sbuf2, "FLOOR3");

eb2.resval.rstring = sbuf2;

eb2.rbnext = NULL; // No other properties

// Retrieve all entities on layer FLOOR3.

acedSSGet("X", NULL, NULL, &eb2, ssname2);

ОБРАТИТЕ ВНИМАНИЕ resval, указанный в каждом буфере должен иметь соответствующий тип.

Например, типы имени - строки (resval.rstring); повышение и толщина - с двойной точностью с плавающей точкой значения (resval.rreal); цвет, признаки - следуйте, и пометьте значения - короткие целые числа (resval.rint); векторы вытеснения - трехмерные точки (resval.rpoint); и т.д.


Если entmask определяет больше чем одно свойство, примитив включен в выбор, устанавливают только, если это соответствует всем указанным условиям{*состояниям*}, как показано в следующем примере:

eb3.restype = 62; // Entity color

eb3.resval.rint = 1; // Request red entities.

eb3.rbnext = NULL; // Last property in list

eb1.rbnext = &eb2; // Add the two properties

eb2.rbnext = &eb3; // to form a list.

// Retrieve all red circles on layer FLOOR3.

acedSSGet("X", NULL, NULL, &eb1, ssname1);

Примитив проверен против всех полей, указанных в списке фильтрации, если список не содержит относительные или условные операторы, как описано в “ Относительные Испытания ” на странице 207 и “ Фильтрация Условного выражения ” на странице 208.

AcedSSGet () функциональные возвращения RTERROR, если никакие примитивы в базе данных не соответствуют{*согласовывают*} указанным критериям фильтрации.

Предыдущий acedSSGet () примеры используют опцию “X”, которая просматривает полную базу данных рисунка. Если списки фильтра используются вместе с другими опциями (выбор пользователя, окно, и т.д), фильтр применяется только к примитивам, первоначально выбранным.

Следующее - пример фильтрации выбранных пользователем примитивов.

eb1.restype = 0; // Entity type group

strcpy(sbuf1, "TEXT");

eb1.resval.rstring = sbuf1; // Entity type is text.

eb1.rbnext = NULL;

// Ask the user to generally select entities, but include

// only text entities in the selection set returned.

acedSSGet(NULL, NULL, NULL, &eb1, ssname1);

Следующий пример демонстрирует фильтрацию предыдущего набора выборов.

eb1.restype = 0; // Entity type group

strcpy(sbuf1, "LINE");

eb1.resval.rstring = sbuf1; // Entity type is line.

eb1.rbnext = NULL;

// Select all the lines in the previously created selection set.

acedSSGet("P", NULL, NULL, &eb1, ssname1);

eb1.restype = 8; // Layer

strcpy(sbuf1, "FLOOR9");

eb1.resval.rstring = sbuf1; // Layer name

eb1.rbnext = NULL;

// Select all the entities within the window that are also on the layer FLOOR9.

acedSSGet("W", pt1, pt2, &eb1, ssname1);

ОБРАТИТЕ ВНИМАНИЕ, что  значение некоторых кодов группы может отличиться от примитива до примитива, и не, все коды группы присутствуют во всех примитивах. Если специфический код группы определен в фильтре, примитивы, которые не содержат тот код группы,  исключены из наборов выбора, которые acedSSGet () возвращается.

 


Списки и другие динамически размещенные данные


Структура resbuf включает поле указателя, rbnext, для соединения буферов результатов в список. Буфера Результатов могут быть размещены статически,  объявляя их в приложении. Вы делаете это, когда только единственный буфер результатов используется (например, acedGetVar () и acedSetVar ()) или когда, только короткий список необходим. Но более длинные списки проще, чтобы обработать,  размещая их динамически, и списки, возвращенные функциями ObjectARX всегда размещаются динамически. Один из наиболее часто используемые функции, который возвращает список связей - acedGetArgs ().

“ Оценка Внешних Функций ” на странице 526 показывает AutoLISP, запрашивающий  внешней подпрограммы, которая берет параметры трех отличных типов: строка, целое число, и реальное значение:

( Doit pstr iarg rarg)

Следующий код сегментирует показы, как осуществить функцию с такой последовательностью запроса. Типовая функция проверяет, чтобы список параметров был правилен и сохранил значения в местном масштабе перед действием на них (операции не показываются). Пример предполагает, что предыдущий запрос к acedDefun () назначил внешнюю подпрограмму функциональный код 0, и что все функции, определенные этим приложением берут по крайней мере один параметр:

// Выполнить определенную функцию.

int dofun()

{

struct resbuf *rb;

char str[64];

int ival, val;

ads_real rval;

ads_point pt;

// Get the function code.

if ((val = acedGetFuncode()) == RTERROR)

return BAD; // Indicate failure.

// Get the arguments passed in with the function.

if ((rb = acedGetArgs()) == NULL)

return BAD;

switch (val) { // Which function is called?

case 0: // (doit)

if (rb->restype != RTSTR) {

acutPrintf("\nDOIT called with %d type.", rb->restype);

acutPrintf("\nExpected a string.");

return BAD;

}

// Save the value in local string.

strcpy(str, rb->resval.rstring);

// Advance to the next result buffer.

rb = rb->rbnext;

if (rb == NULL) {

acutPrintf("\nDOIT: Insufficient number of arguments.");


return BAD;

}

if (rb->restype != RTSHORT) {

acutPrintf("\nDOIT called with %d type.", rb->restype);

acutPrintf("\nExpected a short integer.");

return BAD;

}

// Save the value in local variable.

ival = rb->resval.rint;

// Advance to the last argument.

rb = rb->rbnext;

if (rb == NULL) {

acutPrintf("\nDOIT: Insufficient number of arguments.");

return BAD;

}

if (rb->restype != RTREAL) {

acutPrintf("\nDOIT called with %d type.", rb->restype);

acutPrintf("\nExpected a real.");

return BAD;

}

// Save the value in local variable.

rval = rb->resval.rreal;

// Check that it was the last argument.

if (rb->rbnext != NULL) {

acutPrintf("\nDOIT: Too many arguments.");

return BAD;

}

// Operate on the three arguments.

. . .

return GOOD; // Indicate success

break;

case 1:

// Execute other functions.

. . .

}

}

ОБРАТИТЕ ВНИМАНИЕ, что этот пример исключителен в одном отношении: acedGetArgs () - единственная ObjectARX глобальная функция, которая возвращает список связей, который приложение должно явно не выпустить. Следующая секция описывает обычный путь управления памятью, необходимой для списков.


Списки параметров в AutoLISP и C


Много встроенных функций AutoLISP принимают произвольное число параметров. Это естественно для среды LISP, но требовать, чтобы списки параметров переменной длины для каждой сопоставимой функции в ObjectARX библиотеке наложили бы бесполезную сложность. Чтобы избегать этой проблемы, простое правило применялось к библиотеке: функция ObjectARX, которая является аналогом функции AutoLISP, берет все параметры, которые функция AutoLISP берет. Где параметр необязательный в AutoLISP, в ObjectARX библиотеке специальное значение, обычно нулевой указатель, 0, или 1, можно проходить, чтобы указать, что опция не требуется.

Несколько ObjectARX библиотечные функции - исключения к этому правилу. AcutPrintf () функция подобен стандартной библиотеке для C printf () функция. Подобно стандартной версии, это осуществлено как функция variadic; то есть требуется список параметров переменной длины. AcedCommand () и acedCmd () функции более сложен. Функция команды AutoLISP не только принимает переменное число параметров различных типов, но это также принимает типы, определенные особенно для AutoCAD, типа наборов выбора и точек. Достигать той же самой гибкости в ObjectARX, acedCommand () берет список параметров переменной длины и кроме того берет параметры, чтобы определить тип значений, которые пропускают; acedCmd () требует подобного набора значений, но проходит как список связей. Поэтому, acedCommand () и acedCmd () параметры не соответствуют точно функции команды AutoLISP. Наконец, AutoLISP entget функция имеет необязательный параметр для etrieving расширенных данных. В ObjectARX, acdbEntGet () функция не имеет соответствующего параметра. Вместо этого, имеется дополнительная функция, acdbEntGetX (), если определенно для поиска расширенных данных.



Списки Примитива с Кодами DXF в ObjectARX


Как предварительно упомянуто, списки с кодами группы DXF представляют примитивы AutoCAD. AcutBuildList() функция создает такие списки. Чтобы создавать примитив, вызовите, и acutBuildList () и acdbEntMake ().

ОБРАТИТЕ ВНИМАНИЕ, что определения Примитива начинают с нуля (0) группы, которая описывает тип примитива. Поскольку списки прошли к acutBuildList () закончены с 0 (или RTNONE), это создает конфликт. Специальный тип результата закодирует RTDXF0, решает конфликт. Создайте нулевую группу в списках DXF, пропускал к acutBuildList () с RTDXF0. Если Вы пытаетесь заменять литеральный нуль на RTDXF0, acutBuildList () усекает список.

Следующий типовой кодовый фрагмент создает список DXF, который описывает круг и затем передает новый примитив к acdbEntMake (). Круг центрирован в (4,4), имеет радиус 1, и окрашен красным:

struct resbuf *newent;

ads_point center = {4.0, 4.0, 0.0};

newent = acutBuildList(

RTDXF0, "CIRCLE",

62, 1, // 1 == red

10, center,

40, 1.0, // Radius

0 );

if (acdbEntMake(newent) != RTNORM) {

acdbFail("Error making circle entity\n");

return BAD;

}



Список Ключевого слова


Если Вы имеете ключевые слова, которые являются значимыми в перетащенной последовательности, используют следующую функцию, чтобы определить их:

void

AcEdJig::setKeywordList(const char* kyWdList);

 Список ключевого слова - одиночная строка, в которой каждое ключевое слово отделено от другие пробелами. Требуемые символы напечатаны прописными буквами, и остаток от каждого ключевого слова - нижний регистр.

Например, “Close Undo ”, определяет два ключевых слова. DragStatus перечислимые партнеры оценивают с каждым ключевым словом. Первое ключевое слово - kKW1, второй - kKW2, и так далее. Когда Вы осуществляете ваш AcEdJig класс, Вы можете использовать эти возвращаемые значения в ваших выполнении sampler(), update(), и entity() функции.



Сравнение Таблиц идентификаторов и Словарей


Таблицы идентификаторов и словари исполняют по существу ту же самую функцию; они содержат входы, которые являются базой данных, возражает, что можно искать, используя текстовую строковую клавишу{*ключ*}. Вы можете добавлять входы к этим контейнерным объектам, и Вы можете использовать iterator, чтобы шагнуть через входы и сделать запрос их содержания.

База данных AutoCAD всегда содержит установленный набор девяти таблиц идентификаторов, описанных в следующем разделе. Вы не можете создавать или удалять таблицу идентификаторов, но Вы можете добавлять или изменять{*заменять*} входы в таблице идентификаторов, которые вызваны{*названы*} записи. Каждая таблица идентификаторов содержит только специфический тип объекта.

Например, AcDbLayerTable содержит только объекты типа AcDbLayerTableRecord. Таблицы идентификаторов определены этим способом главным образом для совместимости с Выпуском AutoCAD 12 и предыдущих выпусков AutoCAD.

Словари обеспечивают подобный механизм для сохранения и восстановления{*поиска*} объектов со связанными клавишами{*ключами*} имени. База данных AutoCAD создает названный объектный словарь всякий раз, когда это создает новый рисунок. Названный объектный словарь может рассматриваться как главное “оглавление” для структур объекта небытия в рисунке. Этот словарь, по умолчанию, содержит четыре словаря: словарь ГРУППЫ, MLINE

словарь стиля, словарь размещения, и графический стиль называет словарь. Вы можете создавать любое число дополнительных объектов и добавлять их к названному объектному словарю. Однако, лучшая практика должна добавить один объект непосредственно к названному объектному словарю и иметь тот объект, в свою очередь имеют другие объекты, связанные с вашим приложением. Как правило, объект обладания - контейнерный класс типа словаря. Используйте ваш назначенный Зарегистрированный Символ Разработчика с четырьмя символами для имени этого класса.

Объект AcDbDictionary может содержать любой тип AcDbObject, включая другие словари. Объект словаря не исполняет контроль соответствия типов входов. Однако, MLINE словарь стиля должен содержать только образцы класса AcDbMlineStyle, и словарь ГРУППЫ должен содержать только образцы AcDbGroup. Приложение может требовать определенного печатания для входов в словаре, который это создает и обслуживает{*поддерживает*}.



Иерархия классов для таблиц идентификаторов,


Иерархия классов для таблиц идентификаторов, записей таблицы идентификаторов, словарей, и iterators следующие.



Важное различие между таблицами идентификаторов и словарями - те записи таблицы идентификаторов, не может быть стерт непосредственно Приложением ObjectArx.

Эти записи могут быть стерты только с командой PURGE или выборочно фильтрован из с wblock

операциями. Объекты, принадлежащие словарю могут быть стерты.

ПРЕДУПРЕЖДЕНИЕ! Стирание словарей или входов словаря (см. “ Обязательные Объекты Базы данных ” на странице 22) вероятно,  заставит AutoCAD или другие приложения терпеть неудачу.

Другое важное различие - те записи таблицы идентификаторов, сохраняют их связанное имя поиска в поле на их определении класса. Словари, с другой стороны, сохраняют клавишу{*ключ*} имени как часть словаря, независимого от объекта, это связано с, как показано в ниже.

Symbol Table

               -------> Symbol table record  <name> <other class-specific members>

Dictionary <name>         ------->  Object <class-specific fields>


Сравнение вызовов глобальных функций ObjectARX и AutoLISP


Много ObjectARX глобальные функции уникален к ObjectARX

среде программирования, но многие обеспечивают те же самые функциональные возможности как функции AutoLISP: они имеют то же самое имя как сопоставимая функция AutoLISP, если бы не префикс (aced, acut, и т.д.). Это подобие заставит это облегчить, чтобы преобразовать программы от AutoLISP до ObjectARX. Однако, имеются важные различия между интерпретирующей средой AutoLISP и откомпилированной средой C++.



Среда программирования ObjectARX


ObjectARX среда программирования обеспечивает объектно-ориентированный C++

прикладной программный интерфейс для разработчиков, чтобы использовать, настроить, и расширить AutoCAD. ObjectARX библиотеки включают непостоянный набор инструментальных средств для прикладных разработчиков, чтобы воспользоваться преимуществом открытой архитектуры AutoCAD, обеспечивая прямой доступ к структурам базы данных AutoCAD, графической системе, и коренным определениям команд. Кроме того, эти библиотеки разработаны с возможностью интерфейса с VLisp

и другим прикладным языкам программирования так, чтобы разработчики могли выбирать инструментальные средства программирования.

Как разработчик, Вы можете использовать ObjectARX, чтобы выполнить следующие задачи:

·         Обращение к базе данных AutoCAD

·         Взаимодействие с редактором AutoCAD

·         Создание интерфейса пользователя, использующее MFC

·         Поддержка многодокументной среды

·         Создание заказных классов

·         Формирование комплексного приложения

·         Взаимодействуют с другими средами программирования

Этот раздел - краткий обзор этих тем. Более подробно они будут обсуждены в последующих разделах.



Средство управления Ввода Пользователя


Используйте следующую функцию, чтобы изменить средство управления ввода гипотетического пользователя:

void setUserInputControls(AcEdJig::UserInputControls uic);

 Ввод пользователя управляет помещенными ограничениями на перетащенную последовательность или тип приемлемого возвращаемого значения (например, не позволяя отрицательные ответы, не позволяя нулевой ответ, или,  ограничивая входное значение к двумерной координате).

Они также определяют, как различные действия пользователя затрагивают перетащенную последовательность.

Например, kAcceptMouseUpAsPoint определяет, что выпуск кнопки мыши указывает входное значение.

Средство управления ввода пользователя может быть одно из следующих значений:

§         kGovernedByOrthoMode

§         kNullResponseAccepted

§         kDontEchoCancelForCtrlC

§         kDontUpdateLastPoint

§         kNoDwgLimitsChecking

§         kNoZeroResponseAccepted

§         kNoNegativeResponseAccepted

§         kAccept3dCoordinates

§         kAcceptMouseUpAsPoint

§         kAnyBlankTerminatesInput

§         kInitialBlankTerminatesInput

Как только Вы установили список ключевого слова, тип курсора, и средство управления ввода пользователя, ваш sampler() функция должна вызвать одну из следующих функций AcEdJig, чтобы получить угол, расстояние, или точку:

DragStatus

AcEdJig::acquireAngle(double &ang);

DragStatus

AcEdJig::acquireAngle(

double &ang,

const AcGePoint3d &basePt);

DragStatus

AcEdJig::acquireDist(double &dist);

DragStatus

AcEdJig::acquireDist(

double &dist,

const AcGePoint3d &basePt);

DragStatus

AcEdJig::acquirePoint(AcGePoint3d &point);

DragStatus

AcEdJig::acquirePoint(

AcGePoint3d &point,

const AcGePoint3d &basePt);

После вызова sampler() функция, Вы можете исполнять любой дальнейший анализ на полученном геометрическом значении и перетаскивать состояние. Вы будете также хотеть кэшировать возвращаемое значение в статической переменной для доступа в вашей update() или entity() функции.

§         update() функция - типично, где Вы изменяете объект, обычно,  применяя преобразование к исходному объекту.

§         entity() функция возвращает указатель на объект, который будет восстановлен.



Ссылки Монопольного использования (Ownership References)


Если Вы создаете вашу собственную иерархию монопольных использований, Вы должны установить подключение{*связь*} между владельцем и находящимся в собственности объектом. Объект не может иметь множественных владельцев.

Создавать подключение{*связь*} монопольного использования

1 Определяют, что владелец имеет объект.

2 Определяют, что объект принадлежит владельцу.

AcDbObject протокол всегда определяет связь{*ссылку*} от владельца к находящемуся в собственности объекту и обратной связи{*ссылке*} от объекта до его владельца.

Следующий код иллюстрирует установку двухсторонней связи{*ссылки*} монопольных использований между владельцем и ее содержанием:

// Uses the OwnerDemo class defined in the next example

// (see "ObjectARX Example," below).

//

// Sets pOwner to be the owner of pOwned.

//

void

makeOwner(OwnerDemo* pOwner, AcDbObject* pOwned)

{

// First let pOwner know it is the owner. This

// establishes ownership for filing persistence.

//

pOwner->setIdData(pOwned->ojectId());

// Now set up the backpointer so that the owned

// object knows who its owner is.

//

pOwned->setOwnerId(pOwner->objectId());

}

Обычно используемые члены контейнерного класса устанавливают двухстороннюю связь{*ссылку*} автоматически. Например, следующий функциональный запрос устанавливает блочный отчет{*запись*} таблицы как владелец объекта, и также прибавляет объект к блочному списку отчета{*записи*} таблицы находящихся в собственности объектов.

BlockTableRecord- > appendAcDbEntity (...);

Точно так же AcDbDictionary:: setAt () функция и AcDbSymbolTable:: добавляется () функция устанавливает двухсторонние связи{*ссылки*} между владельцем и ее объектами в одном шаге.

Если Вы непосредственно управляете объектами, использующими entmod () или entmake () в AutoLISP, Вы сначала прибавляете находящийся в собственности объект к базе данных, используя entmake (), то присоединяете ее ads_name или название{*имя*} объекта с соответствующим кодом группы DXF в представлении объекта владельца.



Ссылки Указателя


Ваш класс пользователя может также содержать интенсивно или мягкие ссылки указателя к другим объектам в базе данных. Указатель - односторонняя связь{*ссылка*} (то есть не имеется никакой информации в упомянутом объекте, который указывает источник указателя). Объект может указывать на, или быть указано, любое число других объектов.



Стадия Трансляции


И для глубокого клона и wblock

клонируют функции, объекты, которые упомянуты первичным объектом,  также оттранслированы. После того, как объекты скопированы, AutoCAD транслирует ссылки как описано в следующем три случая.

§

Случай 1: Если упомянутый объект был скопирован, старая ссылка оттранслирована, чтобы обратиться{*отнестись*} к скопированному объекту. В этом случае, это не имеет значение, если скопированный объект находится в той же самой базе данных как исходные объекты или в новой базе данных.

§         Случай 2: Этот случай предполагает, что исходный объект и скопированный объект постоянно находятся в той же самой базе данных. Если упомянутый объект не был скопирован, ссылка оставлена на месте

§         Случай 3: Этот случай предполагает, что исходный объект и скопированный объект находятся в различных базах данных. Если упомянутый объект не был скопирован, ссылка к этому установлена в NULL (потому что это не находится в базе данных адресата).


Как пример Случая 1, предположите, что Вы имеете Примитив 1, который содержит ссылку указателя к Примитиву B1. И Примитив 1 и Примитив B1 отобран, чтобы клонироваться. Перед трансляцией, Примитив 2 все еще относится к Примитиву B1. После трансляции, Примитив 2 модифицирован, чтобы отнестись к Примитиву B2.





Как пример Случая 2, предположите, что Вы имеете те же самые два примитива: Примитив 1 содержит ссылку указателя к Примитиву B1. Примитив 1 клонировался, но Примитив B1 - нет. Источник и адресат (клон), объекты находятся в той же самой базе данных.





Случай 3 подобен Случаю 2, кроме клонированных объектов находятся в новой базе данных. В этом случае, ссылка указателя Примитива 2 установлена в NULL, потому что Примитив B1 не в новой базе данных.




Статические OPM Интерфейсы COM


Если заказной объект не осуществляет обертку объекта COM для себя, GetIUnknownOfObject генерирует заданную по умолчанию обертку, которая осуществляет методы IACADENTITY или IACADOBJECT, в зависимости от того, если основной объект может приводиться AcDbEntity. OPM тогда использует этот объект, чтобы отобразить Цвет, Уровень, Linetype, и Lineweight свойства, также известный как примитив общие свойства. ICategorizeProperties, IPerPropertyBrowsing, и IOPMPROPERTYEXTENSION - интерфейсы flavoring.

Эта секция описывает OPM flavoring

интерфейсы подробно и объясняет, как использовать их, чтобы управлять дисплей статических свойств в OPM.

Все другие статические интерфейсы будут зарегистрированы в другом месте как часть документации Автоматизации.



Статический


Когда командный процессор в данном сеансе редактирования не имеет никакого активного AutoCAD, командует, ObjectARX команды, Визуально ШЕПЕЛЯВЯТ оценки, ActiveX запросы, макрокоманды меню AutoCAD, или макрокоманды VBA. В этой точке, Приглашение ко вводу команды отображается в окне команды. Обратите внимание, что немодальные диалоги и инструментальные панели могут быть зарегистрированы, поскольку они не работают через командный процессор.



Стек Команды


Команды AutoCAD сохранены в группах в стеке команды, который

Определенный AcEdCommandStack классом. Один образец стека команды

Создан в сеанс AutoCAD. Этот стек состоит из заказных команд

То, что Вы определили. AcedRegCmds () макрокоманда дает Вам, обращаются к

Стек команды.

Когда Вы прибавляете команду, Вы также назначаете это название{*имя*} группы. Хорошая политика{*полис*}

Должен использовать ваш буферизованный префикс разработчика для названия{*имени*} группы, чтобы избежать названия{*имени*}

Столкновения с другими командами. Команда называет в пределах данной группы

Должен быть уникален, и названия{*имена*} группы должны быть уникальны. Однако, множественные приложения

Может прибавлять команду того же самого названия{*имени*}, потому что группа называет Делает команды однозначными.

ОБРАТИТЕ ВНИМАНИЕ, что автоплата поддерживает схему регистрации разработчика предотвратить Namespace

находится в противоречии между различными приложениями. Каждый буферизованный разработчик Выбирает одни или более буферизованные символы разработчика (RDS), чтобы использовать исключительно. Буферизованный Символы разработчика - одно из требований “ Сформированные с ObjectARX ” программа эмблемы. Для получения дополнительной информации, идите интерактивно к  http://www.veritest.com/autodesk/main(f).htm.

Вы обычно прибавляете команды по одному с AcEdCommandStack:: addCommand () функция, и Вы удаляете команды Группа с AcEdCommandStack:: removeGroup () функция. Вы можете также Используйте AcEdCommandStack:: removeCmd () функция, чтобы удалить команды По одному. Как часть его очистки перед выходом, ваше приложение нуждается к Удалите любые команды это буферизованный.

Сигнатура для addCommand () функция

Acad::ErrorStatus

addCommand(

const char* cmdGroupName,

const char* cmdGlobalName,

const char* cmdLocalName,

Adesk::Int32 commandFlags,

AcRxFunctionPtr functionAddr,

AcEdUIContext *UIContext=NULL,

int fcode=-1,

HINSTANCE hResourceHandle=NULL);


CmdGroupName

Представление ASCII группы, чтобы прибавить команду к.

Если группа не существует, это создано прежде, чем команда добавлена.

CmdGlobalName

Представление ASCII команды называет, чтобы добавиться. Это название{*имя*} представляет глобальное или неоттранслированное название{*имя*} (см. “ Глобальная переменная против Местных Названий{*имен*} Команды ” на странице 42).

CmdLocalName

Представление ASCII команды называет, чтобы добавиться. Это название{*имя*} представляет местное или оттранслированное название{*имя*}.

CommandFlags

Флажки, связанные с командой. Возможные значения - ACRX_CMD_TRANSPARENT, ACRX_CMD_MODAL, ACRX_CMD_USEPICKSET, и ACRX_CMD_REDRAW (см. “ Прозрачный против Модальных Команд ” на странице 42).

FunctionAddr

Адрес функции, которая будет выполнена, когда эта команда вызвана в соответствии с AutoCAD.

UiContext

Входной указатель на AcEdUIContext класс повторного вызова.

Fcode

Введите целочисленный код, назначенный на команду.

ПРИМЕЧАНИЕ, которое строго рекомендует, чтобы все имена команд имели Ваш зарегистрированный префикс разработчика с четырьмя символами, чтобы избежать возможных конфликтов с командами  в других приложениях. Например, MOVE команда  разработчика с префиксом ASDK

должна быть ASDKMOVE.

Использование вашего зарегистрированного префикса разработчика также рекомендуется для имен группы.

Сигнатура для removeCmd()

virtual Acad::ErrorStatus

AcEdCommandStack::removeCmd

(const char* cmdGroupName,

const char* cmdGlobalName) = 0;

Сигнатура для removeGroup()

virtual Acad::ErrorStatus

AcEdCommandStack::removeGroup

(const char* groupName);


Стек Отмены


Архив состояния, зарегистрированного в течение сеанса редактирования, который используется, чтобы отменить команду сеанса редактирования командой, когда требуется. Базы данных часто связываются со стеком отмены, который снабжен ведущим приложением.

В случае AutoCAD, базы данных типично открываются согласно только одному документу одновременно, потому что стеки отмены соответствуют документам.



Стирание объекта


Любой объект в базе данных может быть стерт следующей функцией:

Acad::ErrorStatus

AcDbObject::erase(Adesk::Boolean Erasing = Adesk::kTrue);

ОБРАТИТЕ ВНИМАНИЕ  Erase() имеет различные результаты для объектов базы данных и примитивов, с последствиями для нестирания их:

§         когда объект базы данных стерт, информация относительно того объекта удалена из словаря. Если объект нестерт со стиранием (kfalse), информация автоматически не повторно представлена. Вы Должен использовать setAt () функция, чтобы прибавить информацию к словарю снова.

§         когда объект стерт, это просто помечено как стерто в блочном отчете{*записи*} таблицы. Объект может быть нестерт со стиранием (kfalse).

По умолчанию, Вы не можете открывать стертый объект с acdbOpenObject () функция. Если Вы пытаетесь делать так, eWasErased код ошибки будет возвращен.

extern Acad::ErrorStatus

acdbOpenObject(AcDbObject*& obj,

AcDbObjectId objId,

AcDb::OpenMode openMode,

Adesk::Boolean openErasedObject =

Adesk::kFalse);

Чтобы открывать стертый объект, используйте kTrue для последнего{*прошлого*} параметра acdbOpenObject () функция.

Контейнерные объекты типа ломаных линий и блочных отчетов{*записей*} таблицы обычно обеспечивают опцию пропуска стертых элементов при выполнении итераций по их содержанию.

Заданное по умолчанию поведение должно пропустить стертые элементы.

Стертые объекты не зарегистрированы из к DWG или DXF файлам.



Строковые Преобразования


Функции acdbRToS () и acdbAngToS () преобразовывают значения, используемые в AutoCAD к строковым значениям, которые могут использоваться в выводе или как текстовые данные. AcdbRToS () функция преобразовывает реальное значение, и acdbAngToS () преобразовывает угол. Формат строки результата управляется значением переменных системы AutoCAD: модули и точность определены LUNITS и LUPREC для реальных (линейных) значений и AUNITS и AUPREC для угловых значений. Для и функционирует, DIMZIN dimensioning переменное средство управления, как продвижение и конечные нули написаны к строке результата. Дополнительные функции acdbDisToF () и acdbAngToF () преобразовывают строки назад в реальные значения (расстояния) или углы. Если пропускается строка, сгенерированная acdbRToS () или acdbAngToS (), acdbDisToF () и acdbAngToF () (соответственно), как гарантируют,  возвратят имеющее силу значение.

Например, следующие показы фрагмента вызывают к acdbRToS () (. Проверка Ошибки не показывается, но должна быть включена в приложения.)

Ads_real x = 17.5;

char fmtval [12];

// Точность - 3-ий параметр: 4 места в первом

// Вызвать, 2 места в другие.

AcdbRToS

(x, 1, 4, fmtval); // Режим 1 = научный

AcutPrintf

(" Значение, отформатированное как %s\n ", fmtval);

AcdbRToS

(x, 2, 2, fmtval); // Режим 2 = десятичное число

AcutPrintf

(" Значение, отформатированное как %s\n ", fmtval);

AcdbRToS

(x, 3, 2, fmtval); // Режим 3 = разработка

AcutPrintf

(" Значение, отформатированное как %s\n ", fmtval);

AcdbRToS

(x, 4, 2, fmtval); // Режим 4 = архитектурный

AcutPrintf

(" Значение, отформатированное как %s\n ", fmtval);

AcdbRToS

(x, 5, 2, fmtval); // Режим 5 = дробный

AcutPrintf

(" Значение, отформатированное как %s\n ", fmtval);

Они вызывают (принятие, что DIMZIN переменная равняется 0) отображают следующий

Значения на экране текста AutoCAD.

Значение, отформатированное как 1.7500E+01

Значение, отформатированное как 17.50

Значение, отформатированное как 1‘ -5.50 І


Значение, отформатированное как 1’ -5 1/2 І

Значение, отформатированное как 17 1/2

Когда UNITMODE переменная системы установлена в 1, который определяет, что модули отображены как введено, строка, возвращенная acdbRToS () отличается для разработки (режим равняется 3), архитектурный (режим равняется 4), и дробный (режим равняется 5) модулям. Например, первые две линии предшествующего типового вывода были бы, тот же самый, но последние строки будет появляться следующим образом:

Значение, отформатированное как 1 ‘ 5.50 І

Значение, отформатированное как 1 ‘ 5-1/2 І

Значение, отформатированное как 17-1/2

AcdbDisToF () функциональные дополнения acdbRToS (), так следующее вызывают, которые используют строки, сгенерированные в предыдущих примерах, весь результат набора к тому же самому значению, 17.5. (Снова, примеры не показывают проверку ошибок.)

acdbDisToF("1.7500E+01", 1, &result); // 1 = scientific

acdbDisToF("17.50", 2, &result); // 2 = decimal

// Note the backslashes. Needed for inches.

acdbDisToF("1’-5.50\"", 3, &result); // 3 = engineering

acdbDisToF("1’-5 1/2\"", 4, &result); // 4 = architectural

acdbDisToF("17 1/2", 5, &result); // 5 = fractional

Следующие показы фрагмента вызывают к acdbAngToS () которые являются подобными предыдущему acdbRToS () примеры.

ads_real ang = 3.14159;

char fmtval[12];

// Precision is the 3rd argument: 0 places in the first

// call, 4 places in the next 3, 2 in the last.

acdbAngToS(ang, 0, 0, fmtval); // Mode 0 = degrees

acutPrintf("Angle formatted as %s\n", fmtval);

acdbAngToS(ang, 1, 4, fmtval); // Mode 1 = deg/min/sec

acutPrintf("Angle formatted as %s\n", fmtval);

acdbAngToS(ang, 2, 4, fmtval); // Mode 2 = grads

acutPrintf("Angle formatted as %s\n", fmtval);

acdbAngToS(ang, 3, 4, fmtval); // Mode 3 = radians

acutPrintf("Angle formatted as %s\n", fmtval);

acdbAngToS(ang, 4, 2, fmtval); // Mode 4 = surveyor’s



acutPrintf("Angle formatted as %s\n", fmtval);

Они вызывают ( все еще принятие что DIMZIN равняется 0) отображают следующие значения на экране текста AutoCAD.

Angle formatted as 180

Angle formatted as 180d0¢0²

Angle formatted as 200.0000g

Angle formatted as 3.1416r

Angle formatted as W

ОБРАТИТЕ ВНИМАНИЕ, что  UNITMODE переменная системы также воздействует на строки, возвращенные acdbAngToS () когда это возвращает строку в модулях инспектора (режим равняется 4). Если UNITMODE равняется 0, возвращенная строка может включать пробелы (например, “ N 45d E ”); если UNITMODE равняется 1, строка не содержит никакие пробелы (например, “N45dE”).

AcdbAngToF() функциональные дополнения acdbAngToS (), так следующее вызывает весь набор параметр результата к тому же самому значению, 3.14159. (Это округлено до 3.1416 в примере, который использует радианы.)

AcdbAngToF ("180", 0, *result); // 0 = градусы

AcdbAngToF ("180d0" 0 \ "", 1, *result); // 1 = deg/min/sec

AcdbAngToF ("200.0000g", 2, *result); // 2 = grads

AcdbAngToF ("3.1416r", 3, *result); // 3 = радианы

AcdbAngToF ("W", 4, *result); // 4 = инспектор

ОБРАТИТЕ ВНИМАНИЕ, когда Вы имеете строку, которая определяет угол в градусах{*степенях*}, минутах, и секундах, Вы должны использовать наклонную черту влево (\), чтобы выйти из символа секунд (І) так, чтобы,  казалось,  не было конца строки. Второй из предшествующего acdbAngToF () примеры демонстрируют это.


Struct resbuf


Следующая структура буфера результата, resbuf, определена в конъюнкции с объединением, ads_u_val, который размещает различный AutoCAD и ObjectARX типы данных, следующим образом:

union ads_u_val {

ads_real rreal;

ads_real rpoint[3];

short rint; // Must be declared short, not int.

char *rstring;

long rlname[2];

long rlong;

struct ads_binary rbinary;

};

struct resbuf {

struct resbuf *rbnext; // Linked list pointer

short restype;

union ads_u_val resval;

};

ОБРАТИТЕ ВНИМАНИЕ, что  поле long integer - resval.rlong - подобно двоичному полю данных resval.rbinary; оба держат расширенные данные примитива.

Следующий рисунок показывает схематическую форму списка буфера результата:



SubErase, subOpen, subClose, and subCancel


Ф-ции erase(), open(), close(), и cancel() все имеют соответствующие виртуальные функции, начинающиеся с префиксной замены. Вы можете отменять эти вспомогательные функции, чтобы обеспечить дополнительные функциональные возможности для полученных классов. Вспомогательная функция вызвана невиртуальной “главной” функцией. Например, erase() - subErase(). Сигнатура для subErase() следующие:

virtual Acad::ErrorStatus

subErase(Adesk::Boolean pErasing);

 Перегрузите вспомогательную функцию

1 Проверяют правильность вашей окрестности. Например, если ваш объект имеет жесткую ссылку указателя к другому объекту, и ваш объект не стирается, Вы можете проверять, чтобы объект, к которому Вы относите все еще, существовал. Если имеются проблемы, немедленно возвращают соответствующее состояние ошибки и не упускают сообщение, потому что ваше плохое состояние ошибки эффективно уничтожит операцию.

2, если все - OK, затем вызывает Ваше Родительское подстирание:: () функция. Исследуйте его результат. Если это не возвращает eOK, то возвращается.

3, если все - OK, затем исполняет ваши действия.

Лучше не изменить{*заменить*} любое государство{*состояние*} во вспомогательной функции. Если Вы изменили{*заменили*} государство{*состояние*}, затем пробовать изменить{*заменить*} это после вызова родительского выполнения класса той же самой функции (в случае, если код ошибки возвращен). Если Вы изменили{*заменить*} государство{*состояние*} перед вызовом родительской функции класса, то подготовлены, чтобы полностью изменить это, если родительский класс возвращает плохое состояние.

Следующий пример показывает выполнению subErase() функция, которая называется, когда объект стерт. subErase() проверяет жесткие ссылки указателя к другим объектам и стирает их также.

class AsdkEllipse : public AcDbEllipse

// Этот класс расширяет AcDbEllipse,  добавляясь в функциональных возможностях

// Сохранять динамический массив жесткого объекта IDs указателя.

//

// subErase () функция элемента отменяет и


// Осуществленный, так, когда объект этого класса

// Стертый, объекты, указанные жестким указателем IDs

// Сохраненный в пределах объекта будет также стерт.

//

{

public:

ACRX_DECLARE_MEMBERS(AsdkEllipse);

AsdkEllipse() {};

AsdkEllipse(const AsdkEllipse&);

AsdkEllipse(const AcDbObjectIdArray& ellipses)

: mEllipseIds(ellipses) {};

AsdkEllipse(const AcGePoint3d& center,

const AcGeVector3d& unitNormal,

const AcGeVector3d& majorAxis,

double radiusRatio,

double startAngle = 0.0,

double endAngle = 6.28318530717958647692);

AsdkEllipse(const AcDbObjectIdArray& ellipses,

const AcGePoint3d& center,

const AcGeVector3d& unitNormal,

const AcGeVector3d& majorAxis,

double radiusRatio,

double startAngle = 0.0,

double endAngle = 6.28318530717958647692);

AcDbObjectId ellipseId(unsigned short which);

Acad::ErrorStatus setEllipseId(

const AcDbObjectId& objId, unsigned short which);

Acad::ErrorStatus setEllipseIds(

const AcDbObjectIdArray& Ids);

Acad::ErrorStatus appendId(const AcDbObjectId& objId);

Acad::ErrorStatus appendIds(

const AcDbObjectIdArray& objIds);

inline Adesk::Boolean removeId(

const AcDbObjectId& objId);

// AcDbObject overrides.

//

virtual Acad::ErrorStatus subErase(

Adesk::Boolean pErasing);

virtual Acad::ErrorStatus dwgInFields(

AcDbDwgFiler* filer);

virtual Acad::ErrorStatus dwgOutFields(

AcDbDwgFiler* filer) const;

virtual Acad::ErrorStatus dxfInFields(

AcDbDxfFiler* filer);

virtual Acad::ErrorStatus dxfOutFields(

AcDbDxfFiler* filer) const;

virtual Acad::ErrorStatus wblockClone(

AcRxObject* pOwnerObject,

AcDbObject*& pClonedObject,

AcDbIdMapping& idMap,

Adesk::Boolean isPrimary = Adesk::kTrue) const;

// AcDbEntity overrides.

//

virtual void list() const;

// AcRxObject overrides.

//

virtual AcRxObject* clone() const;

private:

AcDbObjectIdArray mEllipseIds;

static int mInFlux; // == 1 when first object’s

// subErase is active.

};

ACRX_DXF_DEFINE_MEMBERS(AsdkEllipse, AcDbEllipse,



AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0, ASDKELLIPSE,

REFERENC);

// Static class data member definition.

//

int AsdkEllipse::mInFlux = Adesk::kFalse;

AsdkEllipse::AsdkEllipse(const AsdkEllipse& master)

{

set(master.center(), master.normal(),

master.majorAxis(), master.radiusRatio(),

master.startAngle(), master.endAngle());

mEllipseIds = master.mEllipseIds;

}

AsdkEllipse::AsdkEllipse(const AcGePoint3d& center,

const AcGeVector3d& unitNormal,

const AcGeVector3d& majorAxis,

double radiusRatio,

double startAngle,

double endAngle) :

AcDbEllipse(center, unitNormal, majorAxis, radiusRatio,

startAngle, endAngle)

{ }

AsdkEllipse::AsdkEllipse(const AcDbObjectIdArray& ellipses,

const AcGePoint3d& center,

const AcGeVector3d& unitNormal,

const AcGeVector3d& majorAxis,

double radiusRatio,

double startAngle,

double endAngle) :

AcDbEllipse(center, unitNormal, majorAxis, radiusRatio,

startAngle, endAngle), mEllipseIds(ellipses)

{ }

AcDbObjectId

AsdkEllipse::ellipseId(unsigned short which)

{

assertReadEnabled();

if (which > mEllipseIds.length())

return AcDbObjectId::kNull;

return mEllipseIds[which];

}

Acad::ErrorStatus

AsdkEllipse::setEllipseId(const AcDbObjectId& objId,

unsigned short which)

{

assertWriteEnabled();

if (which > mEllipseIds.length())

return Acad::eInvalidIndex;

mEllipseIds[which] = objId;

return Acad::eOk;

}

Acad::ErrorStatus

AsdkEllipse::setEllipseIds(const AcDbObjectIdArray& objIds)

{

assertWriteEnabled();

if (objIds.length() == 0)

return Acad::eNullObjectId;

mEllipseIds = objIds;

return Acad::eOk;

}

Acad::ErrorStatus

AsdkEllipse::appendId(const AcDbObjectId& objId)

{

assertWriteEnabled();

if (objId == AcDbObjectId::kNull)

return Acad::eNullObjectId;

mEllipseIds.append(objId);

return Acad::eOk;

}

Acad::ErrorStatus

AsdkEllipse::appendIds(const AcDbObjectIdArray& objIds)

{

assertWriteEnabled();

if (objIds.length() == 0)

return Acad::eNullObjectId;



mEllipseIds.append(objIds);

return Acad::eOk;

}

inline Adesk::Boolean

AsdkEllipse::removeId(const AcDbObjectId& objId)

{

assertWriteEnabled();

return mEllipseIds.remove(objId);

}

// This implementation of subErase opens and erases all

// objects that this entity has hard pointer references

// to. The effect is that when one AsdkEllipse is erased,

// all the others it has hard pointers to also erase as

// a "group".

//

Acad::ErrorStatus

AsdkEllipse::subErase(Adesk::Boolean pErasing)

{

Acad::ErrorStatus es = AcDbEllipse::subErase(pErasing);

if (es != Acad::eOk)

return es;

if (mInFlux == Adesk::kFalse) {

mInFlux = Adesk::kTrue;

AsdkEllipse *pEllipse;

int es;

for (int i = 0; i < mEllipseIds.length(); i++) {

es = acdbOpenObject(pEllipse, mEllipseIds[i],

AcDb::kForWrite, Adesk::kTrue);

if (es != Acad::eOk)

continue;

pEllipse->erase(pErasing);

pEllipse->close();

}

mInFlux = Adesk::kFalse;

}

return Acad::eOk;

}

Acad::ErrorStatus

AsdkEllipse::dwgInFields(AcDbDwgFiler* filer)

{

assertWriteEnabled();

AcDbEllipse::dwgInFields(filer);

mEllipseIds.setLogicalLength(0);

int idCount;

filer->readInt32((long*)&idCount);

AcDbHardPointerId objId;

for (int i = 0; i < idCount; i++) {

filer->readItem(&objId);

mEllipseIds.append(objId);

}

return filer->filerStatus();

}

Acad::ErrorStatus

AsdkEllipse::dwgOutFields(AcDbDwgFiler* filer) const

{

assertReadEnabled();

AcDbEllipse::dwgOutFields(filer);

filer->writeInt32(mEllipseIds.length());

for (int i = 0; i < mEllipseIds.length(); i++) {

filer->writeHardPointerId(mEllipseIds[i]);

}

return filer->filerStatus();

}

Acad::ErrorStatus

AsdkEllipse::dxfInFields(AcDbDxfFiler* filer)

{

assertWriteEnabled();

Acad::ErrorStatus es = AcDbEllipse::dxfInFields(filer);

if (es != Acad::eOk) {

return es;

}

// Check to see if we’re at the right subclass data

// marker.

//

if (!filer->atSubclassData("AsdkEllipse")) {

return Acad::eBadDxfSequence;



}

struct resbuf inbuf;

AcDbObjectId objId;

int idCount;

filer->readItem(&inbuf);

if (inbuf.restype == AcDb::kDxfInt32) {

idCount = inbuf.resval.rint;

} else {

filer->pushBackItem();

filer->setError(Acad::eInvalidDxfCode,

"\nError: expected group code %d",

AcDb::kDxfInt32);

return filer->filerStatus();

}

for (int i = 0; i < idCount; i++) {

es = filer->readItem(&inbuf);

if (es != Acad::eOk) {

filer->setError(Acad::eMissingDxfField,

"\nError: expected more group code %d’s",

AcDb::kDxfHardPointerId);

return filer->filerStatus();

}

if (inbuf.restype == AcDb::kDxfHardPointerId) {

acdbGetObjectId(objId, inbuf.resval.rlname);

mEllipseIds.append(objId);

} else {

filer->pushBackItem();

filer->setError(Acad::eInvalidDxfCode,

"\nError: expected group code %d",

AcDb::kDxfHardPointerId);

return filer->filerStatus();

}

}

return filer->filerStatus();

}

Acad::ErrorStatus

AsdkEllipse::dxfOutFields(AcDbDxfFiler* filer) const

{

assertReadEnabled();

AcDbEllipse::dxfOutFields(filer);

filer->writeItem(AcDb::kDxfSubclass, "AsdkEllipse");

filer->writeInt32(AcDb::kDxfInt32,

mEllipseIds.length());

for (int i = 0; i < mEllipseIds.length(); i++) {

filer->writeObjectId(AcDb::kDxfHardPointerId,

mEllipseIds[i]);

}

return filer->filerStatus();

}

void

AsdkEllipse::list() const

{

assertReadEnabled();

AcDbEllipse::list();

acutPrintf("\nClass:\t%s", isA()->name());

for (int i = 0; i < mEllipseIds.length(); i++) {

acutPrintf("\nReferenceId[%d]:\t%ld", i,

(mEllipseIds[i]).asOldId());

}

}

// Called whenever an object of this class is dragged,

// moved, stretched, rotated, etc. so be careful what

// this function is made to do.

//

AcRxObject*

AsdkEllipse::clone() const

{

assertReadEnabled();

return new AsdkEllipse(*this);

}

Acad::ErrorStatus

AsdkEllipse::wblockClone(

AcRxObject* pOwnerObject,

AcDbObject*& pClonedObject,



AcDbIdMapping& idMap,

Adesk::Boolean isPrimary) const

{

assertReadEnabled();

static AcDbObjectId btr, pspace = AcDbObjectId::kNull;

AcTransaction *pTrans = NULL;

pClonedObject = NULL;

if (pspace == AcDbObjectId::kNull) {

AcDbBlockTable *pTable;

database()->getSymbolTable(pTable, AcDb::kForRead);

pTable->getAt(ACDB_PAPER_SPACE, pspace);

pTable->close();

}

if ( idMap.deepCloneContext() == AcDb::kDcXrefBind && ownerId() == pspace)

return Acad::eOk;

// Have we already done this entity ?

//

AcDbIdPair idPair(objectId(), (AcDbObjectId)NULL, Adesk::kTrue);

if (idMap.compute(idPair) == TRUE && idPair.value()  != NULL)

{

pClonedObject = NULL;

return Acad::eOk;

}

AcDbBlockTableRecord *pBTR = AcDbBlockTableRecord::cast(pOwnerObject);

if (pBTR != NULL) {

if (isPrimary == Adesk::kTrue)

btr = pBTR->objectId();

else

btr = AcDbObjectId::kNull;

} else if (btr != AcDbObjectId::kNull) {

pTrans = actrTransactionManager->startTransaction();

pTrans->getObject((AcDbObject*&)pBTR, btr,

AcDb::kForWrite);

pOwnerObject = pBTR;

}

Acad::ErrorStatus es = AcDbEllipse::wblockClone(pOwnerObject,

pClonedObject, idMap, btr != AcDbObjectId::kNull);

if (pTrans)

actrTransactionManager->endTransaction();

acutPrintf("\nWblockClone error status: %s",

acadErrorStatusText(es));

return Acad::eOk;

}

void

createEllipses()

{

const ellipseCount = 10;

AsdkEllipse *pEllipse;

pEllipse = new AsdkEllipse(AcGePoint3d(4.0, 4.0, 0.0),

AcGeVector3d(0.0, 0.0, 1.0),

AcGeVector3d(2.0, 0.0, 0.0),

0.5);

AcDbVoidPtrArray ellipses;

ellipses.append(pEllipse);

// Now use the getTransformedCopy() function with a

// scaling matrix (in X & Y only) to create new

// AsdkEllipses, each 0.5 units larger than the last in

// the X & Y direction, but identical in the Z

// direction. This would be similar to the

// getOffsetCurves() function, but that function

// returns AcDbSpline entities instead of AcDbEllipses.

//



double j = 1.1;

AcGeMatrix3d scale;

for (int i = 0; i < ellipseCount; i++, j += 0.1) {

scale.setToScaling(j, pEllipse->center());

scale.entry[2][2] = 1.0; // Z scaling == 1

// getTransformed copy uses this->clone() to create

// a new object, which the ent pointer is assigned

// to point to. Therefore, ent should NOT point to an

// existing entity or there will be a memory leak!

//

// Since this->clone() is used, the AsdkEllipse class

// must override this member function to

// be sure that an AsdkEllipse is created instead

// of just an AcDbEllipse.

//

AsdkEllipse *pNextEllipse;

((AsdkEllipse*)ellipses[0])->getTransformedCopy(

scale, (AcDbEntity*&)pNextEllipse);

ellipses.append(pNextEllipse);

}

AcDbBlockTable *pBlockTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForRead);

AcDbBlockTableRecord *pBlockTableRecord;

pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,

AcDb::kForWrite);

pBlockTable->close();

AcDbObjectIdArray ellipseIds;

AcDbObjectId tempId;

for (i = 0; i < ellipses.length(); i++) {

pBlockTableRecord->appendAcDbEntity(tempId,

(AsdkEllipse*)ellipses[i]);

ellipseIds.append(tempId);

}

pBlockTableRecord->close();

// Set up the hard pointers and close the ellipses.

//

for (i = 0; i < ellipses.length(); i++) {

// Add in all the IDs.

//

((AsdkEllipse*)ellipses[i])

->setEllipseIds(ellipseIds);

// Now remove the object ID of the "*this" ellipse

// so it doesn’t reference itself.

//

((AsdkEllipse*)ellipses[i])->removeId(

((AsdkEllipse*)ellipses[i])->objectId());

((AsdkEllipse*)ellipses[i])->close();

}

}

void

initApp()

{

acedRegCmds->addCommand("ASDK_ELLIPSES",

"ASDK_ELLIPSES", "ELLIPSES",

ACRX_CMD_MODAL, createEllipses);

AsdkEllipse::rxInit();

acrxBuildClassHierarchy();

}

void

unloadApp()

{

acedRegCmds->removeGroup("ASDK_ELLIPSES");

// Remove the AsdkEllipse class from the ACRX runtime

// class hierarchy. If this is done while the database is

// still active, it should cause all objects of class

// AsdkEllipse to be turned into proxies.

//

deleteAcRxClass(AsdkEllipse::desc());

}

extern "C" AcRx::AppRetCode

acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)

{

switch (msg) {

case AcRx::kInitAppMsg:

acrxDynamicLinker->unlockApplication(appId);

acrxDynamicLinker->registerAppMDIAware(appId);

initApp();

break;

case AcRx::kUnloadAppMsg:

unloadApp();

}

return AcRx::kRetOK;

}


Связь между Приложениями


Функция ObjectARX acedInvoke () в одном приложении используется, чтобы вызвать внешние функции, определенные и осуществленные другими приложениями ObjectARX.

Внешняя функция, вызванная acedInvoke() должна быть определена в настоящее время загруженным ObjectARX-приложением.

AcedInvoke() функция вызывает внешнюю функцию именем, что его приложение определило в acedDefun() запрос, который является именем функции, что AutoLISP вызывает, чтобы вызвать функцию. Если внешняя функция была определена как команда AutoLISP, с “ C: ” как префикс к его имени, эти символы должны быть включены в строку, как которая acedInvoke () определяет (когда команда вызвана с выражением AutoLISP).

ПРЕДУПРЕЖДЕНИЕ! Поскольку приложения, загруженные в то же самое время не могут иметь двойные имена функции, Вы должны брать это во внимание при проектировании приложения, которое использует больше чем единственный программный файл; избегите проблемы со схемой обозначения или соглашением, которое гарантирует, что имя каждой внешней функции будет уникально. Лучшее решение состоит в том, чтобы использовать ваш Зарегистрированный Символ Разработчика (RDS) как префикс.

Имя внешней функции, и любых значений параметра, которых это требует, пропускают к acedInvoke() в форме списка связей буферов результатов. Это также возвращает его результат в списке буфера результата; второй параметр к acedInvoke () - адрес указателя буфера результата.

Следующая типовая функция вызывает acedInvoke () чтобы вызвать факт функции факториала () в типовой программе fact.cpp:

static void test()

{

int stat, x = 10;

struct resbuf *result = NULL, *list;

// Get the factorial of x from file fact.cpp.

list = acutBuildList(RTSTR, "fact", RTSHORT, x, RTNONE);

if (list != NULL) {

stat = acedInvoke(list, &result);

acutRelRb(list);

}

if (result != NULL) {

acutPrintf("\nSuccess: factorial of %d is %d\n", x, result->resval.rint);

acutRelRb(result);

}

else

acutPrintf("Test failed\n");


}

Если функция, как предполагается,  будет вызвана с acedInvoke(), приложение, которое определяет это, должен регистрировать функцию,  вызывая acedRegFunc(). (В некоторых случаях acedRegFunc() запрос требован, как описано позже в этой секции.)

Когда acedRegFunc() вызван, чтобы регистрировать функцию, ObjectARX вызывает функцию непосредственно, без того, чтобы пройти цикл отправки приложения. Чтобы определять функцию, вызовите acedRegFunc ().

Внешний функциональный обработчик, зарегистрированный acedRegFunc() не должен иметь никакие параметры и должен возвратить целое число (который является одним из прикладного результата, закодирует — или RSRSLT или RSERR).

Следующая выборка показывает, как funcload () функция в fact.cpp может изменяться, чтобы регистрировать ее функции также как определять их:

typedef int (*ADSFUNC) (void);

// Сначала, определите структуру таблицы: строка, дающая имя AutoCAD функции,

//  и указателя на функцию, возвращающую тип int.

struct func_entry {char *func_name; ADSFUNC func;};

// Объявить функции, которые обрабатывают, вызывает.

int fact (void); // Remove the arguments

int squareroot (void);

// Здесь мы определяем массив имен функции и обработчиков.

//

static struct func_entry func_table[] =

{              {"fact", fact},

{"sqr", squareroot},

};

...

static int funcload()

{

int i;

for (i = 0; i < ELEMENTS(func_table); i++) {

if (!acedDefun(func_table[i].func_name, i))

return RTERROR;

if (!acedRegFunc(func_table[i].func, i))

return RTERROR;

}

return RTNORM;

}

Как показывают выборки кода, первый параметр к acedRegFunc () - указатель функции (названный по имени функциональный обработчик, определенный в исходном тексте), а не внешнее имя функции, определенное acedDefun () и вызванный AutoLISP или acedInvoke (). И acedDefun () и acedRegFunc () передают тот же самый целочисленный функциональный код .

Если зарегистрированная функция должна отыскать параметры, это должно делать так,  делая ее собственный запрос к acedGetArgs ().



AcedGetArgs () запрос перемещен, чтобы быть в пределах функционального fact(). Указатель буфера результата rb сделан переменной скорее чем параметр. (Это не соответствует запросу к fact () в dofun () функция. Если все внешние функции зарегистрированы, поскольку этот пример принимает, dofun () функция может быть удалена полностью; см. примечание, которое следует за этим примером.) новый код показывается в типе жирного начертания:

static int fact()

{

int x;

struct resbuf *rb;

rb = acedGetArgs();

if (rb == NULL)

return RTERROR;

if (rb->restype == RTSHORT) {

x = rb->resval.rint; // Save in local variable.

} else {

acdbFail("Argument should be an integer.");

return RTERROR;

}

if (x < 0) { // Check the argument range.

acdbFail("Argument should be positive.");

return RTERROR;

} else if (x > 170) { // Avoid floating-point overflow.

acdbFail("Argument should be 170 or less.");

return RTERROR;

}

acedRetReal(rfact(x)); // Call the function itself, and

// return the value to AutoLISP.

return RTNORM;

}

Сопоставимое изменение было бы должно быть сделано к squareroot().

ОБРАТИТЕ ВНИМАНИЕ, вызывает ли приложение acedRegFunc() чтобы регистрировать обработчик для каждой внешней функции, это определяет, это может предполагать, что эти функции будут вызваны acedInvoke(), и это может опустить kInvkSubrMsg случай acrxEntryPoint () функция. Если Вы проектируете приложение, которое требует больше чем единственный файл кода ObjectARX, эта методика предпочтительна, потому что это размещает бремя обработки функции, вызывает ObjectARX библиотеку скорее чем на acrxEntryPoint() функцию.

Если функциональный запрос начинает последовательность запроса, которая заставляет функцию в том же самом приложении быть вызванной с acedInvoke (), последняя функция должна быть зарегистрирована acedRegFunc(). Если вызванная функция не зарегистрирована, acedInvoke () сообщает о ошибке. Следующий рисунок иллюстрирует эту ситуацию:





В иллюстрации выше,

§         A_tan () вызывает B_sin ()

§         A_tan () вызывает C_cos ()

§         B_sin () вызывает A_pi ()

§         C_cos () вызывает A_pi ()

Где приложение A определяет A_tan () и A_pi (), приложение B определяет B_sin (), и приложение C определяет C_cos (). A_pi () функция должен быть зарегистрирован acedRegFunc().

Чтобы предотвращать acedInvoke() от сообщающих ошибок регистрации, регистрируйте любую внешнюю функцию, которая, как предполагается,  будет вызвана с acedInvoke().

AcedRegFunc() функция может быть вызван также, чтобы нерегистрировать внешнюю функцию. То же самое приложение должно или регистрировать или нерегистрировать функцию; ObjectARX запрещает приложение от непосредственно управления другим приложением.


Свойства Уровня


AcDbLayerTableRecord класс содержит функции члена для определения множества свойств уровня, которые затрагивают дисплей их связанных примитивов.

Все примитивы должны обратиться{*отнестись*} к правильной{*допустимой*} записи таблицы уровня. Руководство программиста AutoCAD обеспечивает детальное описание свойств уровня.

Следующие разделы перечисляют функции члена для установки и запроса свойств уровня.

Frozen/Thawed  (Заморозить / таять)

Когда уровень закрепляется, графика не восстановлена.

void AcDbLayerTableRecord::setIsFrozen(Adesk::Boolean);

Adesk::Boolean

AcDbLayerTableRecord::isFrozen() const;

On/Off  (Вкл\выкл)

Когда уровень ВЫКЛЮЧЕН, графический не отображены.

void AcDbLayerTableRecord::setIsOff(Adesk::Boolean);

Adesk::Boolean

AcDbLayerTableRecord::isOff() const;

Viewport

(Область просмотра)

Этот setVPDFLT () функция определяет,является ли уровень по умолчанию видимым или невидимым в новых областях просмотра.

void AcDbLayerTableRecord::setVPDFLT(Adesk::Boolean);

Adesk::Boolean

AcDbLayerTableRecord::VPDFLT() const;

Locked/Unlocked

(Блокировал / разблокировал)

Примитивы на блокированном уровне не могут изменяться пользователем AutoCAD или открыт для записи () функция в пределах программы.

void AcDbLayerTableRecord::setIsLocked(Adesk::Boolean);

Adesk::Boolean

AcDbLayerTableRecord::isLocked() const;

Color (Цвет)

Цвет, установленный setColor () функция используется, когда цвет примитива - BYLAYER.

void AcDbLayerTableRecord::setColor(const AcCmColor &color);

AcCmColor

AcDbLayerTableRecord::color() const;

Linetype

Linetype, установленный setLinetypeObjectId () функция используется, когда linetype примитива - BYLAYER.

void AcDbLayerTableRecord::setLinetypeObjectId(AcDbObjectId);

AcDbObjectId

AcDbLayerTableRecord::linetypeObjectId() const;



Таблица блоков


Примитивы в базе данных типично принадлежат записи таблицы блоков. Таблица блоков содержит три записи по умолчанию, *MODEL_SPACE, *PAPER_SPACE, и *PAPER_SPACE0, которые соответствуют трем начальным пространствам рисунка, которые могут быть отредактированы непосредственно пользователями AutoCAD. Для примеров добавления примитивов к записи таблицы блоков пространства модели, см. главу 2, “ Учебник для начинающих Базы данных, ” и глава 6, “примитивы”.

*PAPER_SPACE и записи *PAPER_SPACE0 соответствуют двум предопределенным размещениям пространства листа в AutoCAD. Вы можете добавлять, изменять, и удалять размещения пространства листа.

Новые записи таблицы блоков созданы, когда пользователь выпускает команду BLOCK или команду INSERT, чтобы вставить внешний рисунок. Новые записи таблицы блоков также созданы с acdbEntMake () функция. БЛОК? Списки команд содержание таблицы блоков, за исключением *MODEL_SPACE и записей *PAPER_SPACE. См. главу 6, “ примитивы, ” для примеров создания блок-ссылки и записи таблицы блоков. (Блочная ссылка - примитив, который обращается{*относится*} к данной записи таблицы блоков.)



Таблица Уровня


Таблица уровня содержит один уровень, уровень 0, по умолчанию. Пользователь добавляет уровни к этой таблице с командой LAYER.



Таблицы идентификаторов


Имена, используемые в записях таблицы идентификаторов и в словарях должны следовать за этими правилами:

§         Имена может быть любая длина в ObjectARX, но имена символа, введенные пользователями в AutoCAD ограничены 255 символами.

§         AutoCAD сохраняет регистр имен, но не использует регистр на сравнениях. Например, AutoCAD полагает ", что “этаж" будет тем же самым символом как “ЭТАЖ”.

§         Имена может быть составлен из всех символов, позволенных в именах файла Windows NT, кроме запятой (,), backquote (‘), точка с запятой (;), и знак "=" (=).

База данных AutoCAD содержит следующие таблицы идентификаторов (в круглых скобках -  имя класса и команда AutoCAD, используемая для добавления входов):

§         N Таблица блоков (AcDbBlockTable; BLOCK)

§         N таблица Уровня (AcDbLayerTable; LAYER)

§         N Текстовая таблица стиля (AcDbTextStyleTable; STYLE)

§         N Linetype таблица (AcDbLinetypeTable; LTYPE)

§         N таблица Представления{*вида*} (AcDbViewTable; VIEW)

§         N

таблица ВЕРХНИХ РЕГИСТРОВ (AcDbUCSTable; UCS)

§         N

таблица Области просмотра (AcDbViewportTable; VPORT)

§         N таблица приложений Registered (AcDbRegAppTable)

§         N

таблица стилей Измерения (AcDbDimStyleTable; DIMSTYLE)

Каждая таблица содержит объекты соответствующего подкласса AcDbSymbolTableRecord.

Каждый класс таблицы идентификаторов обеспечивает getAt () функцией для поиска записи, указанной по имени. Сигнатуры для перезагруженных форм getAt () функция следующие. (##BASE_NAME## Замещает любой из девяти типов класса таблицы идентификаторов.)


Acad::ErrorStatus
AcDb##BASE_NAME##Table::getAt(const char* pEntryName,
AcDb::OpenMode mode,
AcDb##BASE_NAME##TableRecord*&
pRecord,
Adesk::Boolean openErasedRecord =
Adesk::kFalse) const;
или
Acad::ErrorStatus
AcDb##BASE_NAME##Table::getAt(const char* pEntryName,
AcDbObjectId& recordId,
Adesk::Boolean getErasedRecord =
Adesk::kFalse) const;
Эта первая версия этой функции возвращает указатель на открытую запись в pRecord, если запись соответствия найдена, и операция открытия (с указанным режимом) преуспевает. Если openErasedRecord - kTrue, функция возвращает объект, даже если это было стерто. Если openErasedRecord - kFalse, функция возвращает указатель NULL и состояние ошибки eWasErased для стертых объектов.
Вторая версия getAt () функция возвращает AcDbObjectId записи, указанной по имени в значении recordId, если запись соответствия найдена.
Если getErasedRecord - kTrue, функция возвращает объект соответствия, даже если это было стерто. Объект не открыт.
Как только Вы получили запись и открыли это, Вы можете получить и устанавливать различные значения члена. Для определенного класса записи таблицы идентификаторов для законченного списка компонентных функций класса, см. ObjectARX Ссылку.
Другие важные функции, обеспеченные всеми классами таблицы идентификаторов -, has() и add() функции. См. пример в “ Создание и Изменение Записи Таблицы Уровня ” на странице 150.
Сигнатура для has()
Adesk::Boolean
AcDb##BASE_NAME##Table::has(const char* pName) const;
has() возвращает kTrue, если таблица содержит запись с именем, которое соответствует pName.
add() имеет следующие сигнатуры:
Acad::ErrorStatus
AcDb##BASE_NAME##Table::add(AcDb##BASE_NAME##TableRecord*
pRecord);
Acad::ErrorStatus
AcDb##BASE_NAME##Table::add(AcDbObjectId& recordId,
AcDb##BASE_NAME##TableRecord*
pRecord);
Эта функция добавляет запись, указанную pRecord, и к базе данных, содержащей таблицу и таблицу непосредственно. Если добавления преуспевают, и параметр pId - не-NULL, это установлено в AcDbObjectId записи в базе данных.

Текст


Пример в этом разделе показывает использование AcGiTextStyle класса. Это рисует прямоугольник вокруг части текста AcGi, который может ориентироваться и расположен где-нибудь в пространстве.

Нормаль и векторы направления текста должны быть перпендикулярны к друг другу. Если вы неуверены из направлений, полагаете, что  направление будет по X оси и нормали по Z оси в правосторонней координатной системе.

Вычислите Y ось от них. Тогда векторное произведение Y оси к Z оси даст Вам интерпретацию нормального плана направления. Убедитесь, что направление не выровнено с нормалью, или Вы не будете иметь направления относительно нормали.

AcGiTextStyle:: loadStyleRec () функция загружает шрифт, если это уже не загружено. (Функция This не загружает ACAD

СТИЛЬ.) Его возвращаемые значения следующие:

0x10       Другой файл (не FONTALT) открытый на месте имени файла BigFont

0x08       Другой файл (не FONTALT) открытый на месте имени файла

0x04       имя файла BigFont не сумел быть загруженным

0x02       Имя файла не сумел быть загруженным

0x01       Файлы открылся как запрашивается

Текст может масштабироваться способом путей. Используйте AcGiTextStyle:: setTextSize () чтобы масштабировать ширину и высоту текста в то же самое время. Используйте setXScale () чтобы масштабировать ширину текста. Используйте setTrackingPercent () чтобы определить, как символы специфического шрифта помещены рядом с друг другом. Если Вы определяете значение 1.0, интервал не изменяется; если Вы определяете меньше чем 1.0, символы сожмут вместе; и если это - больше чем 1.0, символы, будут дальше обособленно. Этот пример устанавливает трэкинг процент к значению .80.

AcGiTextStyle::extents

() функция возвращает размер мировой координаты поля ограничения текста. Если penups параметр - kTrue, то любые нерисовавшие перьевые шаги, сделанные, в то время как пользователь рисовал текст, будут включены в поле ограничения. Необработанная опция сообщает вычислению игнорировать обработку управляющего кода (так, чтобы “%%%” не интерпретировался бы как единственный знак процента, но как три знака процента).


Следующий пример рисует текст и затем рисует поле ограничения вокруг части текста.

Adesk::Boolean

AsdkTextStyleSamp::worldDraw(AcGiWorldDraw* pW)

{

AcGePoint3d pos(4.0, 4.0, 0.0);

AcGeVector3d norm(0.0, 0.0, 1.0);

AcGeVector3d dir(-1.0, -0.2, 0.0);

char *pStr = "This is a percent, ’%%%’.";

int len = strlen(pStr);

AcGiTextStyle style;

AcGeVector3d vec = norm;

vec = vec.crossProduct(dir);

dir = vec.crossProduct(norm);

style.setFileName("txt.shx");

style.setBigFontFileName("");

int status;

if (!((status = style.loadStyleRec()) & 1))

pStr = "Font not found.";

pW->geometry().text(pos, norm, dir, pStr, len,

Adesk::kFalse, style);

pos.y += 2.0;

style.setTrackingPercent(80.0);

style.setObliquingAngle(10.0);

AcGePoint2d ext = style.extents(pStr, Adesk::kFalse,

strlen(pStr), Adesk::kFalse);

pW->geometry().text(pos, norm, dir, pStr, len,

Adesk::kFalse, style);

// Draw a rectangle around the last text drawn.

// First, create a polyline the size of the

// bounding box. Then, transform it to the

// correct orientation, and then to the location of the

// text.

// Compute the matrix that orients the box.

//

AcGeMatrix3d textMat;

norm.normalize();

dir.normalize();

AcGeVector3d yAxis = norm;

yAxis = yAxis.crossProduct(dir);

yAxis.normalize();

textMat.setCoordSystem(AcGePoint3d(0.0, 0.0, 0.0), dir, yAxis, norm);

// Create the bounding box and enlarge it a little.

//

double offset = ext.y / 2.0;

AcGePoint3d verts[5];

verts[0] = verts[4] = AcGePoint3d(-offset, -offset, 0.0);

verts[1] = AcGePoint3d(ext.x + offset, -offset, 0.0);

verts[2] = AcGePoint3d(ext.x + offset, ext.y + offset, 0.0);

verts[3] = AcGePoint3d(-offset, ext.y + offset, 0.0);

// Orient and then translate each point in the

// bounding box.

//

for (int i = 0; i < 5; i++) {

verts[i].transformBy(textMat);

verts[i].x += pos.x;

verts[i].y += pos.y;

verts[i].z += pos.z;

}

pW->geometry().polyline(5, verts);

return Adesk::kTrue;

}


Текущий Документ


Программируемые запросы могут быть сделаны, чтобы заставить контекст выполнения документа стать активными без пользователя, фактически воспринимающего документ как “активизировано”.

Это - промежуточное состояние, только, используемое прежде всего приложениями ActiveX и VBA.



Терминология


Следующая секция определяет некоторых обычно используемые сроки{*термины*}, чтобы описать многодокументную среду.



Тип Регенерации Области просмотра


С тех пор AcGi - только спецификация интерфейса, это может использоваться для многих различных целей. В AutoCAD AcGi спецификация имеет несколько различных выполнения, каждый с определенной целью. 2D-display канал используется, чтобы генерировать 2-ые изображения, отображенные на экране, и имеется различная трехмерная система для постоянно представляемых видов. В дополнение к этим связанным дисплеем выполнению, имеется несколько другие, включая любого, что Вы можете развиваться.

Важно знать два других AcGi выполнения, используемые двигателем базы данных. Первый - для полномочного графического генерирования, и второй используется, чтобы взорвать объект в основные ObjectDBX примитивы. Полномочное графическое выполнение используется, когда заказной объект сохранен, сохранять графику в метафайле, который можно повторно запускать, когда рисунок загружен на системе, где заказное приложение не доступно. Взрывающееся выполнение используется взрывающимся механизмом и обнаружить границы в пределах сложного объекта.

Это могло бы быть важно для Вас, чтобы различить между этими различными выполнением.

Поэтому, AcGi выставляет тип регенерации области просмотра, котором можно делать запрос от вашего worldDraw () метод.

Тип регенерации области просмотра установлен в соответствии с AutoCAD. Вы можете сделать запрос его значения, используя AcGiWorldDraw:: regenType () функция. Значения для AcGiRegenType

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

kAcGiHideOrShadeCommand исполняет удаление невидимой линии и указывает, что команда HIDE ИЛИ SHADE - в действительности. Примитивы должны быть представлены, используя лица в этом режиме.

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

kAcGiSaveWorldDrawForR12 - тип, используемый для взрывающейся операции.

kAcGiSaveWorldDrawForProxy - тип, используемый для генерирования полномочной графики. В этом случае все ваше исполнение должно быть сделано в worldDraw () так как viewportDraw () не поддержан для полномочной графики.



Тип заполнения


Заполняющийся тип перечисленное значение, AcGiFillType, может иметь одно из двух значений:

kAcGiFillAlways

kAcGiFillNever

Примитивы, которые могут быть заполнены - круги, многоугольники, оболочки, сети, текст, образовывают дугу сектора, и образовывают дугу аккорды. Ломаные линии и простые дуги не могут быть заполнены.

Прежде, чем AutoCAD вызывает worldDraw (), это устанавливает заполняющийся тип в зависимости от перегенерального типа. Если перегенеральный тип - kAcGiStandardDisplay, AutoCAD устанавливает заполняющийся тип в kAcGiFillNever. Иначе, AutoCAD устанавливает заполняющийся тип в kAcGiFillAlways. Это значение повторно инициализировано согласно перегенеральному типу прежде, чем viewportDraw () вызван.

Если пользователь выпускает определение команды FILL, чтобы выключить режим Fill, никакие объекты не заполнены независимо от перегенерального типа. Точно так же, если пользователь явно включает режим Fill, объекты будут заполнены. Если пользователь не выпускает команду FILL, и AcGiSubEntityTraits:: setFillType () был установлен, это, режим Fill используется независимо от перегенерального типа.



Типичная операция глубокого клона


Следующая выборка кода показывает типичное использование AcDbDatabase:: deepCloneObjects ().

Инициализировать глубокую операцию клона

1 Получают набор объектов, которые нужно клонировать.

2 Помещенный объектные ID в список (типа AcDbObjectIdArray).

3 Создают новую карту ID (класса AcDbIdMapping) который будет заполнен deepCloneObjects () функция.

4 Называют deepCloneObjects () функцией, проходящей в списке объектов, которые нужно клонировать, объект ID владельца, к которому клонированные объекты должны быть добавлены в конец, и карта ID, созданная в шаге 1.

В этом примере, объект ID владельца - запись таблицы блоков пространства модели.

DeepCloneObjects () функция заполняет карту объекта ID (idMap). Приложение может тогда выполнять итерации через объекты, содержащиеся в карте, используя специальный iterator объект (AcDbIdMappingIter) и исполнять дополнительные операции на тех объектах, типа преобразования каждого объекта некоторой матрицей.

Следующий код показывает типичное использование deepCloneObjects ():

void

cloneSameOwnerObjects()

{

// Step 1: Obtain the set of objects to be cloned.

ads_name sset;

if (acedSSGet(NULL, NULL, NULL, NULL, sset) != RTNORM) {

acutPrintf("\nNothing selected");

return;

}

// Step 2: Add obtained object IDs to list of objects

// to be cloned.

long length;

acedSSLength(sset, &length);

AcDbObjectIdArray objList;

AcDbObjectId ownerId = AcDbObjectId::kNull;

for (int i = 0; i < length; i++) {

ads_name ent;

acedSSName(sset, i, ent);

AcDbObjectId objId;

acdbGetObjectId(objId, ent);

// Check to be sure this has the same owner as the first

// object.

//

AcDbObject *pObj;

acdbOpenObject(pObj, objId, AcDb::kForRead);

if (pObj->ownerId() == ownerId)

objList.append(objId);

else if (i == 0) {

ownerId = pObj->ownerId();

objList.append(objId);

}

pObj->close();

}

acedSSFree(sset);

// Step 3: Get the object ID of the desired owner for

// the cloned objects. We’ll use model space for


// this example.

//

AcDbBlockTable *pBlockTable;

acdbHostApplicationServices()->workingDatabase()

->getSymbolTable(pBlockTable, AcDb::kForRead);

AcDbObjectId modelSpaceId;

pBlockTable->getAt(ACDB_MODEL_SPACE, modelSpaceId);

pBlockTable->close();

// Step 4: Create a new ID map.

//

AcDbIdMapping idMap;

// Step 5: Call deepCloneObjects().

//

acdbHostApplicationServices()->workingDatabase()

->deepCloneObjects(objList, modelSpaceId, idMap);

// Now we can go through the ID map and do whatever we’d

// like to the original and/or clone objects.

//

// For this example, we’ll print out the object IDs of

// the new objects resulting from the cloning process.

//

AcDbIdMappingIter iter(idMap);

for (iter.start(); !iter.done(); iter.next()) {

AcDbIdPair idPair;

iter.getMap(idPair);

if (!idPair.isCloned())

continue;

acutPrintf("\nObjectId is: %Ld", idPair.value().asOldId());

}

}


Типовое ObjectARX-приложение


Сравните типовые приложения программ факториала, распределенных с AutoCAD. Программа fact.ccp - для среды программы ObjectARX, в то время как fact.c - для среды программы ADS. Следующая версия fact.cpp объявляет и осуществляет acrxEntryPoint (); иначе, fact.cpp почти идентичен fact.c. Функция acrxEntryPoint () заменяет главное в fact.c:

#include <stdio.h>

#include "adslib.h"

#include "rxdefs.h"

// Utility definition to get an array’s element count (at compile

// time). For example:

//

// int arr[] = {1,2,3,4,5};

// ...

// printf("%d", ELEMENTS(arr));

//

// would print a five. ELEMENTS("abc") can also be used to tell

// how many bytes are in a string constant INCLUDING THE TRAILING

// NULL.

#define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))

// All the functions that we’ll define will be listed in a single

// table, together with the internal function that we call to handle

// each. The functions all take a single argument (the resbuf that

// has the arguments) and return an integer (RTNORM or RTERROR for

// good or bad status).

// First, define the structure of the table: a string giving the

// AutoCAD name of the function, and a pointer to a function

// returning type int.

struct func_entry {

char *func_name;

int (*func) _((struct resbuf *));

};

// Here we declare the functions that handle the calls; at the moment

// there are two of them.

int fact _((struct resbuf *rb));

int squareroot _((struct resbuf *rb));

// Here we define the array of function names and handlers.

static struct func_entry func_table[] = {

{/*MSG0*/"fact", fact},

{/*MSG0*/"sqr", squareroot},

};

// To add more functions to this table, just put them in the list,

// after declaring the function names. Note that in standard C it’s

// all right to have a superfluous comma after the last item.

// The code from here to the end of dofun() is UNCHANGED when you


// add or delete functions.

// Declarations of other local functions:

void main _((int, char **));

int dofun _((void));

int funcload _((void));

ads_real rfact _((int x));

ads_real rsqr _((ads_real x));

// ACRXENTRYPOINT -- This function replaces main() for an ObjectARX

// program.

extern "C" AcRx::AppRetCode

acrxEntryPoint(AcRx::AppMsgCode msg, void* ptr)

{

switch(msg) {

case AcRx::kInitAppMsg:

acrxUnlockApplication(ptr);

break;

case AcRx::kInvkSubrMsg:

dofun();

break;

case AcRx::kLoadADSMsg:

funcload();

}

return AcRx::kRetOK;

}

// FUNCLOAD -- Define this application’s external functions.

// Return RTERROR on error, else RTNORM.

static int funcload()

{

int i;

for (i = 0; i < ELEMENTS(func_table); i++) {

if (!acedDefun(func_table[i].func_name, (short)i))

return RTERROR;

}

return RTNORM;

}

// DOFUN -- Execute external function (called upon an RQSUBR

// request). Return value from the function executed, RTNORM

// or RTERROR.

static int dofun()

{

struct resbuf *rb;

int val;

// Get the function code and check that it’s within range.

// (It can’t fail to be, but paranoia doesn’t hurt.)

if ((val = acedGetFunCode()) < 0 || val >= ELEMENTS(func_table))

{

acdbFail(/*MSG2*/"Received nonexistent function code.");

return RTERROR;

}

// Fetch the arguments, if any.

rb = acedGetArgs();

// Call the handler and return its success-failure status.

val = (*func_table[val].func)(rb);

acutRelRb(rb);

return val;

}

// The code from the beginning of main() to here is UNCHANGED when

// you add or delete functions.

// FACT -- First set up the argument, then call the factorial

// function.

static int

fact(struct resbuf *rb)

{

int x;

if (rb == NULL)

return RTERROR;

if (rb->restype == RTSHORT) {

x = rb->resval.rint; // Save in local variable

} else {

acdbFail(/*MSG3*/"Argument should be an integer.");

return RTERROR;

}

if (x < 0) { // Check argument range



acdbFail(/*MSG4*/"Argument should be positive.");

return RTERROR;

} else if (x > 170) { // Avoid floating-point overflow

acdbFail(/*MSG5*/" Argument should be 170 or less.");

return RTERROR;

}

acedRetReal(rfact(x)); // Call the function itself, and

// return the value to AutoLISP

return RTNORM;

}

// This is the implementation of the actual external factorial

// function.

static ads_real rfact(int n)

{

ads_real ans = 1.0;

while (n)

ans *= n--;

return ans;

}

// SQUAREROOT -- First set up the argument, then call the root

// function.

static int

squareroot(struct resbuf *rb)

{

ads_real x;

if (rb == NULL)

return RTERROR; // A proper error msg would

// be better.

if (rb->restype == RTSHORT) { // Save in local variable.

x = (ads_real) rb->resval.rint;

} else if (rb->restype == RTREAL) {

x = rb->resval.rreal; // Can accept either real

// or integer.

} else {

acdbFail(

/*MSG6*/

"Argument should be a real or integer value.");

return RTERROR;

}

if (x < 0) { // Check argument range.

acdbFail(/*MSG7*/"Argument should be positive.");

return RTERROR;

}

acedRetReal(rsqr(x)); // Call the function itself, and

// return the value to AutoLISP.

return RTNORM;

}

// This is the implementation of the actual external function

static ads_real rsqr(ads_real x) // Square root by Newton’s  method.

{

int n = 50;

ads_real y, c, cl;

if (x == 0.0) {

return 0.0;

}

y = (x * 2 + .1) / (x + 1.0);

c = (y - x / y) / 2;

cl= 0.0;

while ((c != cl) && (n-- > 0)) {

y -= c;

cl = c;

c = (y - x / y) / 2;

}

return y;

}


Типовой файл DCL


Следующий DCL для создания типового диалогового окна сохранен в файле, вызвал hello.dcl:

hello : dialog {

label = "Sample Dialog Box";

: text {

label = "Hello, world";

}

ok_only;

}



Типовой Код


Этот пример создает класс, который дает возможность пользователю создать эллипс,  выбирая его среднюю точку и затем перемещая, чтобы выбрать желательную главную ось и незначительные{*младшие*} длины оси. В течение перетащенных операций, пользователь будет способен видеть то, что эллипс напоминает в любое время.

ОБРАТИТЕ ВНИМАНИЕ, пробует ли пользователь делать незначительную{*младшую*} ось дольше чем главная ось, эллипс закончится как круг, потому что отношение{*коэффициент*} радиуса не может быть большее чем 1.0.

class AsdkEllipseJig : public AcEdJig

// This class allows the user to create an ellipse by

// picking its center point and then dragging to select the

// desired major axis and minor axis lengths. During the

// drag operations, the user will be able to visually see

// what the ellipse looks like at any time.

//

{

public:

AsdkEllipseJig(const AcGePoint3d&, const AcGeVector3d&);

void doIt();

virtual DragStatus sampler();

virtual Adesk::Boolean update();

virtual AcDbEntity* entity() const;

private:

AcDbEllipse *mpEllipse;

AcGePoint3d mCenterPt, mAxisPt;

AcGeVector3d mMajorAxis, mNormal;

double mRadiusRatio;

int mPromptCounter;

};

// The following defines the constructor that accepts a point to be

// used as the centerpoint of the ellipse and the current UCS normal

// vector to be used as the normal for the ellipse. It also

// initializes the radius ratio to a small value so that during

// selection of the major axis, the ellipse will appear as a line.

// The prompt counter is also initialized to 0.

//

AsdkEllipseJig::AsdkEllipseJig(

const AcGePoint3d& pt,

const AcGeVector3d& normal)

: mCenterPt(pt),

mNormal(normal),

mRadiusRatio(0.00001),

mPromptCounter(0)

{ }

// This function creates an AcDbEllipse object and gets the

// jig started acquiring the necessary info to properly fill

// it in.

//

void

AsdkEllipseJig::doIt()

{

mpEllipse = new AcDbEllipse;

// Get the major axis vector from the user.


// At this time, mPromptCounter == 0.

//

setDispPrompt("\nEllipse major axis: ");

AcEdJig::DragStatus stat = drag();

// Get the ellipse’s radius ratio.

//

mPromptCounter++; // now == 1

setDispPrompt("\nEllipse minor axis: ");

stat = drag();

// Now add the ellipse to the database’s current space.

//

append();

}

// This function is called by the drag function to

// acquire a sample input.

//

AcEdJig::DragStatus

AsdkEllipseJig::sampler()

{

DragStatus stat;

setUserInputControls((UserInputControls)

(AcEdJig::kAccept3dCoordinates

| AcEdJig::kNoNegativeResponseAccepted

| AcEdJig::kNoZeroResponseAccepted));

if (mPromptCounter == 0) {

// Aquire the major axis endpoint.

//

// If the newly acquired point is the same as it was

// in the last sample, then we return kNoChange so the

// AsdkEllipseJig::update() function will not be called

// and the last update call will be able to finish, thus

// allowing the ellipse to fully elaborate.

//

static AcGePoint3d axisPointTemp;

stat = acquirePoint(mAxisPt, mCenterPt);

if (axisPointTemp != mAxisPt)

axisPointTemp = mAxisPt;

else if (stat == AcEdJig::kNormal)

return AcEdJig::kNoChange;

}

else if (mPromptCounter == 1) {

// Aquire the distance from ellipse center to minor

// axis endpoint. This will be used to calculate the

// radius ratio.

//

// If the newly acquired distance is the same as it was

// in the last sample, then we return kNoChange so the

// AsdkEllipseJig::update() function will not be called

// and the last update call will be able to finish, thus

// allowing the ellipse to fully elaborate.

//

static double radiusRatioTemp = -1;

stat = acquireDist(mRadiusRatio, mCenterPt);

if (radiusRatioTemp != mRadiusRatio)

radiusRatioTemp = mRadiusRatio;

else if (stat == AcEdJig::kNormal)

return AcEdJig::kNoChange;

}

return stat;

}

// This function is called to update the entity based on the

// input values.

//

Adesk::Boolean

AsdkEllipseJig::update()



{

switch (mPromptCounter) {

case 0:

// At this time, mAxis contains the value of one

// endpoint of the desired major axis. The

// AcDbEllipse class stores the major axis as the

// vector from the center point to where the axis

// intersects the ellipse path (such as half of the true

// major axis), so we already have what we need.

//

mMajorAxis = mAxisPt - mCenterPt;

break;

case 1:

// Calculate the radius ratio. mRadiusRatio

// currently contains the distance from the ellipse

// center to the current pointer position. This is

// half of the actual minor axis length. Since

// AcDbEllipse stores the major axis vector as the

// vector from the center point to the ellipse curve

// (half the major axis), to get the radius ratio we

// simply divide the value currently in mRadiusRatio

// by the length of the stored major axis vector.

//

mRadiusRatio = mRadiusRatio / mMajorAxis.length();

break;

}

// Now update the ellipse with the latest setting.

//

mpEllipse->set(mCenterPt, mNormal, mMajorAxis,

mRadiusRatio);

return Adesk::kTrue;

}

// This function must be implemented to return a pointer to

// the entity being manipulated by the jig.

//

AcDbEntity*

AsdkEllipseJig::entity() const

{

return mpEllipse;

}

// This function uses the AcEdJig mechanism to create and

// drag an ellipse entity. The creation criteria are

// slightly different from the AutoCAD command. In this

// case, the user selects an ellipse center point and

// drags to visually select the major and minor axes

// lengths. This sample is somewhat limited; if the

// minor axis ends up longer than the major axis, then the

// ellipse will just be round because the radius ratio

// cannot be greater than 1.0.

//

void

createEllipse()

{

// First, have the user select the ellipse center point.

// We don’t use the jig for this because there is

// nothing to see yet.

//

AcGePoint3d tempPt;

struct resbuf rbFrom, rbTo;

acedGetPoint(NULL, "\nEllipse center point: ",



asDblArray(tempPt));

// The point we just got is in UCS coordinates, but

// AcDbEllipse works in WCS, so convert the point.

//

rbFrom.restype = RTSHORT;

rbFrom.resval.rint = 1; // from UCS

rbTo.restype = RTSHORT;

rbTo.resval.rint = 0; // to WCS

acedTrans(asDblArray(tempPt), &rbFrom, &rbTo,

Adesk::kFalse, asDblArray(tempPt));

// Now you need to get the current UCS z-Axis to be used

// as the normal vector for the ellipse.

//

AcGeVector3d x =

acdbHostApplicationServices()->workingDatabase()->ucsxdir();

AcGeVector3d y =

acdbHostApplicationServices()->workingDatabase()->ucsydir();

AcGeVector3d normalVec = x.crossProduct(y);

normalVec.normalize();

// Create an AsdkEllipseJig object passing in the

// center point just selected by the user and the normal

// vector just calculated.

//

AsdkEllipseJig *pJig

= new AsdkEllipseJig(tempPt, normalVec);

// Now start up the jig to interactively get the major

// and minor axes lengths.

//

pJig->doIt();

// Now delete the jig object, since it is no longer needed.

//

delete pJig;

}

void

initApp()

{

acedRegCmds->addCommand("ASDK_VISUAL_ELLIPSE",

"ASDK_VELLIPSE", "VELLIPSE", ACRX_CMD_MODAL,

createEllipse);

}

void

unloadApp()

{

acedRegCmds->removeGroup("ASDK_VISUAL_ELLIPSE");

}

extern "C" AcRx::AppRetCode

acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)

{

switch (msg) {

case AcRx::kInitAppMsg:

acrxDynamicLinker->unlockApplication(appId);

acrxDynamicLinker->registerAppMDIAware(appId);

initApp();

break;

case AcRx::kUnloadAppMsg:

unloadApp();

}

return AcRx::kRetOK;

}


Типовой Код для dwgInFields ()


Следующее - типовой код для AsdkPoly:: dwgInFields ():

Acad::ErrorStatus

AsdkPoly::dwgInFields(AcDbDwgFiler* filer)

{

assertWriteEnabled();

Acad::ErrorStatus es;

if ((es = AcDbCurve::dwgInFields(filer)) != Acad::eOk)

{

return es;

}

// Object Version - must always be the first item.

//

Adesk::Int16 version;

filer->readItem(&version);

if (version > VERSION)

return Acad::eMakeMeProxy;

switch (version)

{

case 1:

{

AcGePoint3d center;

filer->readPoint3d(&center);

AcGePoint3d startPoint;

filer->readPoint3d(&startPoint);

filer->readInt32(&mNumSides);

filer->readVector3d(&mPlaneNormal);

acutDelString(mpName);

filer->readString(&mpName);

filer->readHardPointerId(&mTextStyle);

//convert data from old format

acdbWcs2Ecs(asDblArray(center),asDblArray(center),

asDblArray(mPlaneNormal),Adesk::kFalse);

mCenter.set(center.x,center.y);

mElevation = center.z;

acdbWcs2Ecs(asDblArray(startPoint),asDblArray(startPoint),

asDblArray(mPlaneNormal),Adesk::kFalse);

mStartPoint.set(startPoint.x,startPoint.y);

assert(mElevation == startPoint.z);

break;

}

case 2:

filer->readPoint2d(&mCenter);

filer->readPoint2d(&mStartPoint);

filer->readInt32(&mNumSides);

filer->readVector3d(&mPlaneNormal);

acutDelString(mpName);

filer->readString(&mpName);

filer->readHardPointerId(&mTextStyle);

filer->readDouble(&mElevation);

break;

default:

assert(false);

}

return filer->filerStatus();

}



Типовой Код для dwgOutFields ()


Большинство запросов регистратора - writeItem (), функция элемента, которая была перезагружена для всех поддержанных типов данных. Имеются также другие функции, типа writeInt32 () используемый в следующем примере, который может использоваться, чтобы поддержать автоматическое приведение типа. Такие функции вынуждают параметр быть обработанными как указанный тип независимо от его фактического типа в памяти.

ОБРАТИТЕ ВНИМАНИЕ, имеет ли ваш класс целочисленные компоненты данных, Вы должны использовать чтение и функции записи, которые явно заявляют целочисленный размер (например, writeInt32).

Следующее - типовой код от AsdkPoly:: dwgOutFields ():

Acad::ErrorStatus

AsdkPoly::dwgOutFields(AcDbDwgFiler* filer) const

{

assertReadEnabled();

Acad::ErrorStatus es;

if ((es = AcDbCurve::dwgOutFields(filer))   != Acad::eOk)

{

return es;

}

// Object Version - must always be the first item.

//

Adesk::Int16 version = VERSION;

filer->writeItem(version);

filer->writePoint2d(mCenter);

filer->writePoint2d(mStartPoint);

filer->writeInt32(mNumSides);

filer->writeVector3d(mPlaneNormal);

filer->writeString(mpName);

// mTextStyle is a hard pointer id, so filing it out to

// the purge filer (kPurgeFiler) prevents purging of

// this object.

//

filer->writeHardPointerId(mTextStyle);

filer->writeDouble(mElevation);

return filer->filerStatus();

}



 Типы Курсора


Если Вы хотите установить специальный тип курсора, используйте следующую функцию:

void

AcEdJig::setSpecialCursorType(AcEdJig::CursorType);

CursorType может быть одно из значений в следующей таблице:

Курсор

Описание

KCrosshair

Перекрестия, выровненные с системой координат пользователя (ВЕРХНИЕ РЕГИСТРЫ)

kRectCursor

Прямоугольный курсор окна, выровненный с системой координат дисплея

KRubberBand

Тот же самый как kCrosshair, кроме также отображает резиновую полосу от арифметической запятой

kTargetBox

OSNAP курсор; подобный kEntitySelect курсору, кроме его размера управляется переменной системы $APERTURE

kCrosshairNoRotate

Перекрестия, выровненные с системой координат дисплея

KInvisible

Никакая графика курсора; только графика объекта отображена

kEntitySelect

Одиночное поле указки объекта; объект фактически не выбран в этом случае{*регистре*}. Выбор Примитива обработан с acedSSGet ()

KParallelogram

Прямоугольник, выровненный с ВЕРХНИМИ РЕГИСТРАМИ (может быть параллелограмм на дисплее)

kEntitySelectNoPersp

Тот же самый как kEntitySelect, кроме поля указки подавлен в перспективном представлении{*виде*}; использованный, когда точный геометрический пункт{*точка*} необходим наряду с выбранным объектом

KPkfirstOrGrips

Заданный по умолчанию курсор; что курсор напоминает “между” командами

kArrow

Отображает курсор стрелки, используемый для диалоговых окон в AutoCAD

Этот шаг необязательный. AcquirePoint () функции позволяют Вам определять этот дополнительный курсор. При установке типа курсора для acquireDist () и acquireAngle () функции не имеют никакого эффекта. AcquireXXX () функции выберут курсор для Вас, если Вы явно не определяете тот.



Типы Монопольного использования


Владельцы могут быть или интенсивно или мягкие владельцы их объектов.



Типы Объектных Реакторов


Реакторные классы, показанные выше также упомянуты как переходные реакторные классы. Если Вы хотите, чтобы ваша программа получила уведомление события, вы будете обычно использовать переходные реакторы, которые контролируют события, которые случаются с объектами базы данных. Они могут также контролировать события базы данных, взаимодействие пользователя, и другие события системы, в то время как приложение выполняется.

Другой вид реактора, названного постоянный реактор, использует объект базы данных (образец класса AcDbObject или полученного класса) как реактор. Объекты Базы данных могут получать также как посылать уведомление. Постоянные реакторные зависимости в пределах базы данных - часть базы данных, так что они сохраняются в DWG и DXF файлах и восстановлены, когда рисунок загружен.

Использовать AcDbObject

как реактор

1 Получают новый AcDbObject класс и осуществляют функции уведомления для событий, ваш объект ответит на.

2 Инициализируют объектный реактор.

3 Добавляют объектный реактор к базе данных и дают этому владельца, предпочтительно контейнерный объект, так, чтобы это было зарегистрировано из правильно.

4 Добавляют объектный реактор к реакторному списку уведомителя, используя addPersistentReactor () функция. Эта функция требует, чтобы Вы прошли в объекте ID объектного реактора, который Вы создавали в шаге 2.

AutoCAD удалит объектный реактор, потому что это - объект базы данных.

ОБРАТИТЕ ВНИМАНИЕ, когда Вы копируете объект, любые постоянные реакторы, приложенные к объекту скопированы также. Переходные реакторные приложения не скопированы, когда объект скопирован.



Точки


Точки AutoCAD определены как следующий тип массива:

typedef ads_real ads_point [3];

Точка всегда включает три значения. Если точка двумерна, третий элемент массива может игнорироваться; самое безопасное инициализировать это к 0.

ObjectARX

определяет следующие значения точки:

 

#define X 0

#define Y 1

#define Z 2

В отличие от простых типов данных (или списки точки в AutoLISP), точка не может быть назначена с единственной{*отдельной*} инструкцией. Чтобы назначать указатель, Вы должны копировать индивидуальные элементы массива, как показано в следующем примере:

newpt [X] = oldpt [X];

newpt [Y] = oldpt [Y];

newpt [Z] = oldpt [Z];

Вы можете также копировать значение точки с ads_point_set () макрокоманда. Результат - второй параметр к макрокоманде.

Следующие типовые кодовые наборы точка, чтобы равняться к сути от:

ads_point to, from;

from[X] = from[Y] = 5.0; from[Z] = 0.0;

ads_point_set(from, to);

ОБРАТИТЕ ВНИМАНИЕ на макрокоманду This, подобно ads_name_set () макрокоманда, определен по-другому, в зависимости от того, действительно ли символ __ STDC __ (для стандарта C) определен.

Стандартная версия C ads_point_set () требует, чтобы ваша программа включила string.h.

Из-за соглашений передачи параметров языка C, точки пропускает ссылка без адреса оператор (косвенности) и. (C всегда передает параметры массива ссылкой, с указателем на первый элемент массива.)

AcedOsnap () библиотечная функция берет точку как параметр, и возвращает точку в результате. Это объявлено следующим образом:

int acedOsnap(pt, mode, result)

ads_point pt;

char *mode;

ads_point result;

AcedOsnap () функция ведет себя подобно AutoLISP osnap функция. Требуется точка (запятая) и некоторые режимы объектной привязки (указанный в строковом режиме), и возвращает самую близкую точку (в результате). Значение int, что acedOsnap () возвращения - код состояния, который указывает успех (RTNORM) или отказ{*неудачу*}.

Следующий кодовый фрагмент вызывает acedOsnap ():

int findendpoint(ads_point oldpt, ads_point newpt)

{

ads_point ptres;

int foundpt;

foundpt = acedOsnap(oldpt, "end", ptres);

if (foundpt == RTNORM) {

ads_point_set(ptres, newpt);

}

return foundpt;

}

Поскольку точки - массивы, oldpt и ptres автоматически проходят к acedOsnap () ссылкой (то есть как указатели на первый элемент каждого массива) скорее чем значением. AcedOsnap () функция возвращает ее результат (в противоположность ее состоянию) устанавливая значение newpt параметра.

ObjectARX

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

typedef ads_real *ads_pointp;



Топологические Объекты


Топологические объекты являются или первичными или вторичными, в зависимости от того, связаны ли они к определенному топологическому измерению.

Первичные топологические объекты используются, чтобы охватить оцененное пространство модели полностью. Они определены в терминах точечных множеств и также упомянуты как n-simplexes, где n - их топологическое измерение. 0-симплексная часть - вершина, 1-симплексная часть - край, 2-симплексная часть - лицо, и 3-симплексная часть - комплекс.

Они не включают их границы, но они могут быть ограничены симплексами любого более низкого измерения.

Первичные топологические объекты - следующее:

Комплекс

Связанный топологически трехмерная область{*регион*} точек R 3 в E 3. Это - объем, созданный вне вершины, лиц, и граней. Комплекс обычно ограничивается одним или большее количество оболочек.

Лицо

Связанный топологически двумерная область{*регион*} точек R 2 в E 3. Это ограничено, orientable подмножество поверхности на границе оболочки комплекса. Лицо обычно ограничивается одним или большее количество циклов.

Край

Связанный топологически одномерная область{*регион*} точек R 1 в E 3. Это ограничено, orientable подмножество кривой на границе цикла лица. Край обычно ограничивается одной или двумя вершиной.

Вершина

Связанный топологически нульмерная область{*регион*} точек R 0 в E 3. Это - единственная точка на лице. Вершина ограничена только отдельно.

Геометрии, возвращенной каждым из этих первичных топологических объектов можно делать запрос, далее используя Библиотеку Геометрии Autodesk.

Вторичные топологические объекты - связанные коллекции первичных топологических объектов, и не обязательно связаны к определенному топологическому измерению. Они представляют отображение границы от симплекса с  более высоким измерением до набора симплексов с  более низким измерением, которые определяют связанную часть его границы. Каждый первичный топологический объект принадлежит по крайней мере одному вторичному топологическому объекту.


Вторичные топологические объекты - следующее:



Brep



Коллекция всего в оцененном пространстве{*пробеле*}; то есть коллекция всех первичных и других связанных вторичных топологических объектов для уникального E 3. По крайней мере, эта коллекция должна содержать единственный комплекс.



Оболочка

(Shell)



Неупорядоченная коллекция лиц, которые ограничили комплекс. По крайней мере, эта коллекция должна содержать единственное лицо. Может иметься самое большее одна внешняя оболочка, и должна иметься внешняя оболочка для там, чтобы быть внутренними оболочками (voids).



Цикл

(LOOP)



Упорядоченная коллекция граней и вершины, которая формирует связанные границы из лица, которое может состоять из единственной вершины (для особенности, типа вершины конуса) или упорядоченной связанной последовательности граней. Может иметься самое большее один внешний цикл, и должен иметься внешний цикл для там, чтобы быть внутренними циклами (отверстия).


Транзакции и генерирование графики


Вы можете нас e AcTransactionManager::queueForGraphicsFlush () и AcTransactionManager:: flushGraphics () чтобы рисовать примитивы по требованию, даже если они связаны с транзакциями, и некоторые транзакции активны, который подразумевал бы, что  модификация на примитивах не совершена{*передана*} базе данных. AcTransactionManager::queueForGraphicsFlush () стоит в очереди, все приемлемые примитивы, связанные со всеми транзакциями для графической модификации и AcTransactionManager:: flushGraphics () рисуют их. Вы можете также использовать AcDbEntity::draw() чтобы рисовать индивидуальный примитив. Это помогает Вам видеть частность

Примитив на экране без того, чтобы ожидать до конца наиболее удаленной транзакции, когда все модификации к всем примитивам рис. Использование AcTransactionManager::enableGraphicsFlush () чтобы позволять или отключить рисунок примитивов. Когда команда концы, Вы оставляете контроль относительно графического генерирования, и это автоматически позволяется.



Traverser Классы


Traverser объекты типично формируются, используя по умолчанию AcBrTraverser* конструктор и затем инициализируя с одной из функций set*. Обратите внимание, что владелец списка должен быть установлен прежде, чем позиция списка может быть установлена независимо, обеспечивать контекст.

Все классы, полученные из AcBrTraverser поддерживают конструкторы копии, операторы назначения, isEqualTo (), и isNull (), наряду с общими функциями обхода.

Функции инициализатора семантически связаны к типам AcBr, соответствующим к определенному traverser (то есть два типа, содержащиеся в полученном traverser имени класса, типа AcBrBrep и AcBrEdge для AcBrBrepEdgeTraverser).

Все функции инициализатора сбрасывают критерии для следующего () и сделанного (). Они относятся к общим алгоритмическим категориям следующим образом:

§         setListOwnerAndCurrentPosition от другого traverser, используя его владельца списка как текущая позиция и его текущая позиция, поскольку владелец списка (то есть меняет владельца списка и текущую позицию). Этот алгоритм только имеет силу для отображения между связанным traversers типа AcBrLoopEdgeTraverser и AcBrEdgeLoopTraverser.

§         setListOwnerAndCurrentPosition от объекта AcBr, используя это как текущая позиция и ее владелец как владелец списка. Этот алгоритм только имеет силу в случаях, где владелец списка однозначен, типа владельца оболочки лица при установке AcBrShellFaceTraverser.

§         setListOwner от другого traverser, используя его текущую позицию как владелец списка и defaulting текущая позиция к первой позиции в новом списке смежных вершин. Этот алгоритм только имеет силу для установки вниз иерархический traversers использование другого убывающего иерархического traverser от следующего уровня (типа использования AcBrShellFaceTraverser, чтобы инициализировать AcBrFaceLoopTraverser), или для установки вверх иерархический traversers использование другого восходящего иерархического traverser от следующего уровня вниз (типа использования AcBrVertexEdgeTraverser, чтобы инициализировать AcBrEdgeLoopTraverser).


§         setListOwner от объекта AcBr, используя это как владелец списка и по умолчанию - ing текущая позиция к первой позиции в новом списке смежных вершин. Этот алгоритм имеет силу для всех типов traverser.

§         setCurrentPosition от объекта AcBr, используя это как текущая позиция в уже установленном списке. Этот алгоритм имеет силу для большинства traverser, напечатает, но требует, чтобы владелец списка уже был установлен предварительно.

Классы traverser включают следующее:

§          AcBrTraverser

§          AcBrBrepComplexTraverser

§          AcBrBrepShellTraverser

§          AcBrBrepFaceTraverser

§          AcBrBrepEdgeTraverser

§          AcBrBrepVertexTraverser

§          AcBrComplexShellTraverser

§          AcBrShellFaceTraverser

§          AcBrFaceLoopTraverser

§          AcBrLoopEdgeTraverser

§          AcBrLoopVertexTraverser

§          AcBrVertexLoopTraverser

§          AcBrVertexEdgeTraverser

§          AcBrEdgeLoopTraverser

§          AcBrMesh2dElement2dTraverser

§          AcBrElement2dNodeTraverser


Требования системного реестра для компонента Дизайн-центра AutoCAD


Для вашего компонента, который будет замечен Дизайн-центром AutoCAD, это должно быть должным образом зарегистрировано. Это означает, что это должно быть включено во вхождения системного реестра Дизайн-центра AutoCAD. Получить правильный путь системного реестра, сначала получают начальный путь AutoCAD. Это может быть выполнено,  используя acrxProductKey () функция. Добавьте \AutodeskApps\AcadDC к начальному пути, чтобы закончить путь Дизайн-центра AutoCAD. Под путем Дизайн-центра AutoCAD - ключи для довольных приложений средства доступа. Следующие параграфы описывают основные ключи и их определенные дополнительные клавиши.



TrueType Разработка Шрифта


Хотя ни SimpleView ни WhipView, через AcGix, не поддерживает TrueType шрифты, имеется процедура, доступная в ObjectDBX для тех, кто хотят пробовать добавить TrueType поддержку шрифта на их собственный. Механизм - textMsg () метод AcGixVectorTaker класса.

Когда объект текста TrueType должен быть отображен, AcGix вызывает textMsg () методом vectortaker. В этой точке vectortaker выполнение может или обрабатывать текст или возвращать Adesk:: kFalse, чтобы инструктировать AcGix исполнять его обработку по умолчанию, которая должна преобразовать текст в SHX шрифт (txt.shx по умолчанию) и затем исполнять стандарт SHX обработка.

Координаты, снабженные textMsg () находятся в текущих образцовых координатах.

Они могут быть преобразованы к Мировой системе координат (WCS), использование снабженного преобразовывает.

Задача представления TrueType шрифты в трехмерном пространстве сложна, и это осуществление рекомендуется только для тех смотрящий достичь полной совместимости дисплея AutoCAD. Один подход может быть только, чтобы обработать это сообщение, если текст может быть представлен в виде плана для вашей области просмотра, и иначе использовать заданную по умолчанию обработку.

TextMsg () метод определен в AcGixVectorTaker.h:

virtual Adesk::Boolean

textMsg(

Adesk::Int16 nViewportId,

const TextPacket * pPacket) = 0;

Структура TextPacket содержит информацию относительно текста плюс матрица преобразования, имел обыкновение преобразовывать от текущей модели до WCS.

struct TextPacket

{

TextPacket(

const TextInfo* pInfo,

int nColor,

const AcGeMatrix3d& xModel);

int m_nColor;

const TextInfo* m_pInfo;

const AcGeMatrix3d& m_xCurrentModelToWorld;

};

Структура TextInfo содержит всю информацию относительно текста:

struct TextInfo

{

AcGePoint3d m_Position;

AcGeVector3d m_Normal;

AcGeVector3d m_Direction;

double m_Height;

double m_Width;

double m_Oblique;

const char* m_pMsg;

Adesk::Int32 m_Length;

Adesk::Boolean m_Raw;

double m_Thickness;

const AcGiTextStyle * m_pTextStyle;

};



Удаление объекта


Когда Вы создаете образец объекта AcDbObject с намерением добавления в конец этого к базе данных, используете AcDbObject:: новый () функция. Когда объект сначала создан и еще не был добавлен к базе данных, Вы можете удалять это. Однако, как только объект был добавлен к базе данных, Вы не можете удалять это; AutoCAD управляет стиранием всех объектов резидента базы.



Удаление Системной Информации Системного реестра


Может быть полезно удалить информацию Приложения ObjectArx от системного реестра, если приложение модернизировано или удалено. ObjectARX API включает функцию acrxUnregisterApp (), который является коллегой acrxRegisterApp (). Это удаляет информацию относительно приложения от раздела AutoCAD системного реестра.



Undo базы данных и средства управления транзакции


Большинство ObjectARX-приложений не будет должно иметь дело с отменой и операционным управлением, но они должны знать некоторые важные точки:

§         Отмена и операционное управление выполнен на основании "в документ ". В AutoCAD, это управляется через (или в конъюнкции с) блокировкой документа.

§         Всякий раз, когда документы блокированы для kWrite или kXWrite, “начинают команда” скобка отмены написана к файлу, и затем база данных и другие модификации выполнена. Когда документы разблокированы от kWrite или kXWrite состояния, передача “конечная команда” скобка отмены будет написана. (Обратите внимание, что они могут быть вложены.) К времени приложение закончено, работая на документе, это должно было сбалансировать, его документ блокирует и разблокирует запросы. Если запросы не сбалансированы, файл отмены будет работать неправильно, оставляя действия из sync от после первой блокировки записи, и через первую блокировку, сбалансированную разблокирующимся. Последующий запрос отмены должен отложить это в sync.

§         параметр для установления имени команды обеспечивается, который отображен, когда команда UNDO выполнена. Созданные маркеры отмены - тот же самый что касается встроенного AutoCAD и команд ObjectARX, и могут поэтому управляться через ГРУППУ ОТМЕН.

§         Документы может иметь отмену, выполненную независимо от друг друга.

§         По умолчанию, когда образец AcDbDatabase создан, его отмена и операционное управление связана с текущим документом.

§         Обращают внимание, что имеются два метода AcEditorReactor, которые используются, чтобы соединить базы данных со средствами отмены документа и операционным менеджером: databaseConstructed() и databaseToBeDestroyed(). Если Вы получаете такое уведомление, знаете, что ассоциация между базой данных и любыми документами неопределена в ту временами, так документ, блокировка может или не может треб в databaseConstructed () повторный вызов. Конечно, любое действие, которое отменяет любые модификации, сделанные в то время,  также отменит создание базы данных.

§         по умолчанию AcDbDatabase конструкторы сделает запрос объекта AcDbHostApplicationServices для контроллера отмены.



UNLOAD


Разгружает указанную программу ARX. Некоторые приложения не могут быть разгружены. См. “ Разгрузка Приложения ObjectArx ” на странице 44 для описания того, как программист решает, может ли программа быть разгружена пользователем с этой командой.



Управление использованием памяти расширенными данными


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

ObjectARX обеспечивает две функции, acdbXdSize () и acdbXdRoom (), помогать в управлении памятью, которая простиралась, данные занимают. Когда acdbXdSize () пропускают список буфера результата расширенных данных, это возвращает объем памяти (в байтах) который данные займут; когда acdbXdRoom () пропускают имя примитива, это возвращает остающееся число свободных байтов, которые могут все еще быть добавлены в конец к примитиву.

AcdbXdSize () функция должна читать расширенный список данных, который может быть большой. Следовательно, эта функция может быть медленна, так что рекомендуется, чтобы Вы не вызвали это часто. Лучший подход состоит в том, чтобы использовать это (вместе с acdbXdRoom ()) в обработчике ошибки. Если запрос к acdbEntMod () сбои, Вы можете использовать acdbXdSize () и acdbXdRoom () чтобы выяснить, потерпел ли запрос неудачу, потому что примитив исчерпал расширенные данные, и затем брать соответствующее действие, если это - причина для отказа{*неудачи*}.



Управление памятью


Некоторые ObjectARX глобальные функции размещают память автоматически. В большинстве случаев, приложение должно явно выпустить эту память, как будто само приложение разместило это. AutoLISP имеет автоматическую сборку "мусора", но ObjectARX делает нет.

ПРЕДУПРЕЖДЕНИЕ! Отказ делать это замедляет систему и может заставлять AutoCAD заканчиваться.



Управление памятью Буфера результата


Основное различие между списками буфера результата и сопоставимыми списками результата AutoLISP - то, что ObjectARX-приложение должно явно управлять списками, которые это создает и использования. Создает ли приложение список или имеет тот, пропускал к этому, это - ответственность приложения выпустить буфера результатов, которые это размещает. ObjectARX не имеет никакой автоматической сборки "мусора", поскольку AutoLISP делает. Приложение должно вызвать библиотечную функцию acutRelRb () чтобы выпустить динамически размещенные буфера результатов, когда приложение закончено с ними.

AcutRelRb () функция выпускает полный список, который следует за указанным буфером результатов, включая указанный (главный) буфер, непосредственно и любая строка оценивает это буфера в точке списка к. Чтобы выпускать строку без того, чтобы удалить буфер непосредственно, или выпускать строку, принадлежащую на статический буфер результатов, приложение должно вызвать функцию стандартной библиотеки C free().

ПРЕДУПРЕЖДЕНИЕ! Не запишите данные к динамическому местоположению, которое не было размещено с прямым, вызывает к malloc () или с ObjectARX библиотекой (включая acutNewRb ()). Это может разрушать данные в памяти. Наоборот, вызывая free() или acutRelRb() чтобы выпустить данные, который был размещен статически — в статическом или объявлении — динамической локальной переменной также, может разрушать память. Вставка статически размещенной переменной, типа строки, в список буфера результата заставляет вашу программу терпеть неудачу, когда Вы выпускаете список с acutRelRb ().

Выборка вызывает к acutRelRb() появляются в нескольких из примеров кода в следующих секциях.



Управление ресурсами


Управление ресурсами - важное соображение{*рассмотрение*} при проектировании Приложения ObjectArx, которое использует MFC

библиотеку, общедоступную с AutoCAD и другими приложениями.

Вы должны вставить ваше состояние модуля (использование CDynaLinkLibrary) в цепочку, которую MFC исследует, когда это исполняет операции типа расположения ресурса.

Однако, строго рекомендуется, чтобы Вы явно управляли ресурсами вашего приложения так, чтобы они не нашлись в противоречии с другими ресурсами от AutoCAD или других Приложений ObjectArx.

Явно устанавливать ресурсы

1 Перед взятием любых шагов, которые вызвали бы MFC, чтобы искать ваш ресурс, вызывают функцию AFX AfxSetResourceHandle() чтобы установить заказной ресурс как системное значение по умолчанию.

2 Перед установкой системного ресурса к вашему ресурсу, вызовите AfxGetResourceHandle() чтобы получить текущий системный ресурс.

3 Немедленно после выполнения любых функций, которые требуют,  заказной ресурс, системный ресурс должен быть сброшен к маркеру{*дескриптору*} ресурса, предварительно сохраненному.

Запрос функций API AutoCAD (или при вызове команд AutoCAD) внутри диалога командует обработчиком, который нуждается в ресурсах AutoCAD, типа acedGetFileD (), задерживает ресурс к AutoCAD перед запросом функций.

Восстановите ваш прикладной ресурс впоследствии. (Используйте acedGetAcadResourceInstance () чтобы получить маркер{*дескриптор*} ресурса AutoCAD.)



Управление точками ввода


Вводные точки приобретены,  выполняя  события ввода через ряд вычислений. Эти вычисления упомянуты как фильтры, и они могут быть настроены разработчиком. ObjectARX обеспечивает API, чтобы контролировать  точки ввода, обрабатывать и изменять их. Следующие секции обсуждают эти темы.



Управление транзакцией


Обработка Транзакции - теперь часть ObjectDBX вместо AutoCAD, и соответствующая библиотека - acdb.dll вместо выполнимой программы AutoCAD. Имеется один новый класс, AcDbTransactionManager, как часть этого изменения.