Длинные транзакции
Длинные транзакции используются, чтобы поддержать Особенность редактирования Ссылки{*справочников*} AutoCAD и очень полезны для Приложений ObjectArx. Эти классы и функции обеспечивают схему приложений, чтобы проверить объекты для редактирования и проверяют{*отмечают*} их назад в к их первоначальному местоположению. Эта операция заменяет первоначальные объекты отредактированными. Имеются три типа длинного операционного контроля:
§ От нормального блока в пределах того же самого рисунка
§ От внешней ссылки (таблица перекрестных ссылок) рисунка
§ От несвязанной, временной базы данных
Для Всех Операционных систем
Модифицируйте путь к приложению для каждой операционной системе. Используя сценарий InstallShield, это может быть сделано следующим способом. (SzAppPath принят, чтобы включить общедоступный путь и любые другие пути, требуемые вашим приложением.)
szExe = "your.exe";
szProdKey = "Software\\Microsoft\\Windows\\";
szProdKey = szProdKey + "CurrentVersion\\App Paths\\" + szExe;
RegDBSetKeyValueEx(szProdKey, "Path", REGDB_STRING, szAppPath, -1);
Добавление Функциональных возможностей к Объектной Модели
В самом простом случае, ваш класс обертки COM выставит{*подвергнет*} один или большее количество функций, которые Вы хотели бы делать доступным разработчикам, использующим среды программирования типа VBA.
Создавать обертку Автоматизации для ObjectARX-приложения
1 Основанный ваш проект согласно шагам в “ Введение Файла Проекта ATL. ”
2 В файле заголовка объекта COM, добавьте #include "Axtempl.h" (главное ActiveX файл заголовка шаблона Автоматизации).
3, если Вы хотите, прикладное свойство, добавляет следующий вход в COM_MAP:
COM_INTERFACE_ENTRY(IRetrieveApplication)
4 В файле IDL, добавьте importlib ("c:\ACAD\acad.tlb"); после importlib stdole32.tlb и importlib stdole2.tlb. Удостоверитесь, чтобы использовать правильный путь, который соответствует вашей инсталляции AutoCAD.
5, если ObjectARX-приложение и обертка COM объединено, добавьте следующий код к вашему главному CPP файл, и назовите это DllMain в AcRx:: kInitAppMsg и AcRx:: kUnloadAppMsg с соответствующими параметрами.
Это инициализирует карту объекта ATL, среди других вещей.
extern "C" HINSTANCE _hdllInstance;
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance,
DWORD dwReason,LPVOID /*lpReserved*/);
6 Компоновки и регистр приложение согласно шагам в “ Формирование и Регистрация COM DLL. ”
Добавление Группы к Словарю Группы
Cледующий код создает группу (pGroup) из линии и круга, созданного в createLine () и createCircle (), и помещает группу в словарь GROUP. Объект IDs линии и круга пропускают в функцию. Обратите внимание, как словарь GROUP открыт для записи, изменяется, и затем явно закрыт.
void
createGroup(AcDbObjectIdArray& objIds, char* pGroupName)
{
AcDbGroup *pGroup = new AcDbGroup(pGroupName);
for (int i = 0; i < objIds.length(); i++) {
pGroup->append(objIds[i]);
}
// Put the group in the group dictionary that resides
// in the named object dictionary.
//
AcDbDictionary *pGroupDict;
acdbHostApplicationServices()->workingDatabase()
->getGroupDictionary(pGroupDict, AcDb::kForWrite);
AcDbObjectId pGroupId;
pGroupDict->setAt(pGroupName, pGroup, pGroupId);
pGroupDict->close();
pGroup->close();
}
Добавление Объектно - определенных Данных
Вы можете использовать любой из четырех механизмов для добавления образец-определенных данных в вашем приложении:
Расширенные{*продленные*} данные (xdata)
Xrecords (см. главу 7, “ Контейнерные Объекты ”)
словари Расширений{*продления*} любого объекта
Объекты пользователя, которые могут держаться, данные (видят главу 12, “ Происходящий от AcDbObject ”)
Добавление Примитива к Базе данных
Когда объект был полностью модифицирован, и перетащенная последовательность закончилась, использование, AcEdJig::append() функцию, чтобы прибавить объект к текущему пространственному блочному отчету{*записи*} таблицы. (Вы можете также использовать стандартные функции для добавления в конец объекта к блочному отчету{*записи*} таблицы.)
Добавление Заказного Объекта или Примитива к Объектной Модели
Если ваш класс обертки COM формирует заказной объект или примитив, Вы будете должны изменить ATL-ГЕНЕРИРОВАННЫЙ код, чтобы поддержать соответствующие интерфейсы.
Каталог \docsamps\square содержит пример класса обертки для заказного примитива, письменного как отдельный DLL.
Добавлять свойства
1 Идут к Представлению Класса в IDE Visual C++, щелкают правой кнопкой мыши на заказном интерфейсе примитива (типа IAsdkSquareWrapper), и выбирают AddProperty.
2 Для Типа Свойства, выберите Двойной. Для Имени Свойства, выберите свойство (типа SquareSize). Оставьте пробел параметров.
3 В заглушке, что Мастер, созданный для Вас, добавьте следующий код запроса (типа функции get_SquareSize от выборки многоугольника):
AcDbObjectPointer<AsdkSquare> pSq(m_objId, AcDb::kForRead);
if (pSq.openStatus() != Acad::eOk)
return E_ACCESSDENIED;
double size;
pSq->squareSideLength(size);
*pVal = size;
return S_OK;
4 В заглушке, которую Мастер создавал, добавьте следующий код модификации (типа функции put_SquareSize от выборки многоугольника):
AcDbObjectPointer<AsdkSquare> pSq(m_objId, AcDb::kForWrite);
if (pSq.openStatus() != Acad::eOk)
return E_ACCESSDENIED;
pSq->setSquareSideLength(newVal);
return S_OK;
5 В AutoCAD, загрузите приложение (типа squareui.arx) и выполните команду, чтобы создать заказной примитив.
6 Удостоверятся, ЧТО OPM загружен. Выберите объект. Вы должны видеть и быть способными изменить общие свойства примитив и побочная длина. Обратите внимание, что SquareSize свойство отображает под “Общей” категорией.
Добавьте Код, чтобы Поддержать Новый Объект COM ATL
1 Теперь мы должны добавить код, чтобы поддержать новый интерфейс. Сначала добавьте включающийся для dcapi.idl файла AsdkDesignCenterSamp .idl. Это включает, должен быть сделан после двух заданного по умолчанию импорта:
import "oaidl.idl";
import "ocidl.idl";
#include "dcapi.idl"
2 Открывают AsdkDcContent .h файл заголовка и изменяют{*заменяют*} образование для нового класса, чтобы включить CWINDOWIMPLBASE и IAcDcContentView следующим образом:
class ATL_NO_VTABLE CAsdkDcContent :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CAsdkDcContent, &CLSID_AsdkDcContent>,
public ISupportErrorInfo,
public IDispatchImpl<IAsdkDcContent, &IID_IAsdkDcContent,
&LIBID_ASDKDESIGNCENTERSAMPLib>,
public CWindowImplBase,
public IAcDcContentView
{
3 Теперь вводят интерфейсы объекта в карту COM, используя макрокоманду COM_INTERFACE_ENTRY:
BEGIN_COM_MAP(CAsdkDcContent)
COM_INTERFACE_ENTRY(IAsdkDcContent)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IAcDcContentView)
END_COM_MAP()
4 Добавляют карту сообщения к классу:
BEGIN_MSG_MAP(CAsdkDcContent)
END_MSG_MAP()
5 Добавляют следующие объявления для интерфейса IAcDcContentView и некоторых сервисных методов:
public:
void OpenAndDisplayTextFile();
void OpenAndInsertTextFile();
CString OpenAndReadTextFile(DWORD& length);
STDMETHOD(Initialize)(/*[in]*/ VARIANT varBrowser);
STDMETHOD(SetImageLists)();
STDMETHOD(NavigatorNodeExpanding)(
/*[in]*/ VARIANT varhNode
, /*[in]*/ BSTR bstrFullPath);
STDMETHOD(NavigatorNodeCollapsing)(
/*[in]*/ VARIANT varhNode
, /*[in]*/ BSTR bstrFullPath);
STDMETHOD(NavigatorNodeClick)(
/*[in]*/ VARIANT varhNode
, /*[in, string]*/ BSTR bstrFullPath);
STDMETHOD(NavigatorMouseUp)(
/*[in]*/ VARIANT varhNode
, /*[in, string]*/ BSTR bstrFullPath
, /*[in]*/ VARIANT varX
, /*[in]*/ VARIANT varY);
STDMETHOD(PaletteItemClick)(/*[in]*/ BSTR bstrItemText);
STDMETHOD(PaletteItemDblClick)(/*[in]*/ BSTR bstrItemText);
STDMETHOD(PaletteColumnClick)(/*[in]*/ VARIANT varIndex);
STDMETHOD(PaletteMouseUp)(
/*[in]*/ VARIANT varButton
, /*[in]*/ VARIANT varItemTexts
, /*[in]*/ VARIANT varX
, /*[in]*/ VARIANT varY);
STDMETHOD(PaletteMouseDown)(
/*[in]*/ VARIANT varButton
, /*[in]*/ BSTR bstrFullText
, /*[in]*/ VARIANT varX
, /*[in]*/ VARIANT varY);
STDMETHOD(RenderPreviewWindow)(
/*[in]*/ BSTR bstrFullText
, /*[in]*/ VARIANT varhPreviewWindow);
STDMETHOD(PreviewMouseUp)(
/*[in]*/ VARIANT varButton
, /*[in]*/ VARIANT varX
, /*[in]*/ VARIANT varY);
STDMETHOD(Refresh)();
STDMETHOD(PaletteBeginDrag)(
/*[in]*/ VARIANT varItemTexts
, /*[in]*/ VARIANT varX
, /*[in]*/VARIANT varY);
STDMETHOD(ReleaseBrowser)();
STDMETHOD(QueryContextMenu)(
/*[in]*/ VARIANT varhMenu
, /*[in]*/ VARIANT varIndex
, /*[in]*/ VARIANT varCmdFirst
, /*[in]*/ VARIANT varCmdLast
, /*[in]*/ VARIANT varItemTexts);
STDMETHOD(InvokeCommand)(/*[in]*/ VARIANT varMenuID);
STDMETHOD(IsExpandable)(
/* [string][in] */ BSTR bstrItemText
, /* [retval][out] */ VARIANT __RPC_FAR
*pvarIsExpandable);
STDMETHOD(GetLargeImage)(
/* [in] */ BSTR bstrFileName
, /* [out][in] */ VARIANT __RPC_FAR
*pvarhLargeImage);
STDMETHOD(GetSmallImageListForContent)(
/*[in]*/ BSTR bstrFileName
, /*[out]*/ VARIANT *pvarhImageList);
STDMETHOD(GetLargeImageListForContent)(
/*[in]*/ BSTR bstrFileName
, /*[out]*/ VARIANT *pvarhImageList);
private:
char * m_strSelectedItemText;
IAcDcContentBrowser* m_pBrowser;
6 Добавляют код, чтобы осуществить методы, только добавленные. Обратите внимание, что многие из этих методов только необходимы закончить интерфейс. Пример использует одиночный щелчок (PaletteItemClick) и двойной щелчок (PaletteItemDblClick) события.
Adesk::Boolean append(AcDbEntity* pEntity)
{
AcDbBlockTable *pBlockTable;
AcApDocument* pDoc = acDocManager->curDocument();
Acad::ErrorStatus es = acDocManager->lockDocument(pDoc);
if (es != Acad::eOk) {
acedAlert("Failed to lock the document!");
return Adesk::kFalse;
}
AcDbDatabase* pDb = pDoc->database();
es = pDb->getBlockTable(pBlockTable, AcDb::kForRead);
if (es != Acad::eOk) {
acedAlert("Failed to get block table!");
return Adesk::kFalse;
}
AcDbBlockTableRecord *pBlockRec;
es = pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockRec,
AcDb::kForWrite);
if (es != Acad::eOk) {
acedAlert(" Failed to get block table record!");
pBlockTable->close();
return Adesk::kFalse;
}
es = pBlockRec->appendAcDbEntity(pEntity);
if (es != Acad::eOk) {
acedAlert("Failed to append entity!");
pBlockTable->close();
pBlockRec->close();
delete pEntity;
return Adesk::kFalse;
}
pBlockRec->close();
pBlockTable->close();
acDocManager->unlockDocument(pDoc);
return Adesk::kTrue;
}
STDMETHODIMP CAsdkDcContent::Initialize(VARIANT varBrowser)
{
m_pBrowser = (IAcDcContentBrowser*)varBrowser.punkVal;
m_pBrowser->AddRef();
return S_OK;
}
STDMETHODIMP CAsdkDcContent::SetImageLists()
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::NavigatorNodeExpanding(
VARIANT varhNode,
BSTR bstrFullPath)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::NavigatorNodeCollapsing(
VARIANT varhNode,
BSTR bstrFullPath)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::NavigatorNodeClick(
VARIANT varhNode,
BSTR bstrFullPath)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::NavigatorMouseUp(
VARIANT varhNode,
BSTR bstrFullPath,
VARIANT varX,
VARIANT varY)
{
return S_OK;
}
CString CAsdkDcContent::OpenAndReadTextFile(DWORD& length)
{
CFile fileText;
fileText.Open(m_strSelectedItemText, CFile::modeRead);
length = fileText.GetLength();
char *strBuff = new char[length];
fileText.Read(strBuff, length);
fileText.Close();
CString cstrBuff(strBuff);
delete strBuff;
cstrBuff.SetAt(length, ’\0’);
cstrBuff.FreeExtra();
return cstrBuff;
}
void CAsdkDcContent::OpenAndDisplayTextFile()
{
DWORD length;
CString cstrBuff = OpenAndReadTextFile(length);
BSTR bstrBuf = cstrBuff.AllocSysString();
m_pBrowser->SetItemDescription(bstrBuf);
::SysFreeString(bstrBuf);
}
STDMETHODIMP CAsdkDcContent::PaletteItemClick(BSTR bstrItemText)
{
USES_CONVERSION;
m_strSelectedItemText = OLE2T(bstrItemText);
OpenAndDisplayTextFile();
return S_OK;
}
void CAsdkDcContent::OpenAndInsertTextFile()
{
DWORD length;
CString cstrBuff = OpenAndReadTextFile(length);
cstrBuff.Replace("\015\012", "\\P");
struct resbuf resbufViewCtr;
resbufViewCtr.restype = RT3DPOINT;
acedGetVar("VIEWCTR", &resbufViewCtr);
AcGePoint3d pt(resbufViewCtr.resval.rpoint[X],
resbufViewCtr.resval.rpoint[Y],
resbufViewCtr.resval.rpoint[Z]);
AcDbMText *pMText = new AcDbMText();
pMText->setLocation(pt);
pMText->setContents(cstrBuff);
append(pMText);
pMText->downgradeOpen();
pMText->draw();
pMText->close();
}
STDMETHODIMP CAsdkDcContent::PaletteItemDblClick(
BSTR bstrItemText)
{
USES_CONVERSION;
m_strSelectedItemText = OLE2T(bstrItemText);
OpenAndInsertTextFile();
return S_OK;
}
STDMETHODIMP CAsdkDcContent::PaletteColumnClick(
VARIANT varIndex)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::PaletteMouseUp(
VARIANT varButton,
VARIANT varItemTexts,
VARIANT varX,
VARIANT varY)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::PaletteMouseDown(
VARIANT varButton,
BSTR bstrFullText,
VARIANT varX, VARIANT varY)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::RenderPreviewWindow(
BSTR bstrFullText,
VARIANT varhPreviewWindow)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::PreviewMouseUp(
VARIANT varButton,
VARIANT varX,
VARIANT varY)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::Refresh()
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::PaletteBeginDrag(
VARIANT varItemTexts,
VARIANT varX,
VARIANT varY)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::ReleaseBrowser()
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::QueryContextMenu(
VARIANT varhMenu,
VARIANT varIndex,
VARIANT varCmdFirst,
VARIANT varCmdLast,
VARIANT varItemTexts)
{
return S_OK;
}
STDMETHODIMP CAsdkDcContent::InvokeCommand(VARIANT varMenuID)
{
return S_OK;
}
STDMETHODIMP
CAsdkDcContent::IsExpandable(
/* [string][in] */ BSTR bstrItemText,
/* [retval][out] */ VARIANT __RPC_FAR *pvarIsExpandable)
{
pvarIsExpandable->iVal = TRUE;
return S_OK;
}
STDMETHODIMP
CAsdkDcContent::GetLargeImage(
/* [in] */ BSTR bstrFileName,
/* [out][in] */ VARIANT __RPC_FAR *pvarhLargeImage)
{
return E_NOTIMPL;
}
STDMETHODIMP
CAsdkDcContent::GetSmallImageListForContent(
BSTR bstrFileName,
VARIANT *pvarhImageList)
{
return E_NOTIMPL;
}
STDMETHODIMP
CAsdkDcContent::GetLargeImageListForContent(
BSTR bstrFileName,
VARIANT *pvarhImageList)
{
return E_NOTIMPL;
}
7 Теперь включают соответствующие файлы заголовка в sdtafx.h файл. Вы будете также должны добавить определение, чтобы неопределить _DEBUG, так как библиотеки AutoCAD - не-отладка. Имеется то, что файл должен напомнить:
#if defined(_DEBUG) && !defined(ARX_DEBUG)
#undef _DEBUG
#define ARX_DEBUG
#endif
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define STRICT
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#define _ATL_APARTMENT_THREADED
#include <afxwin.h>
#include <afxdisp.h>
#include <atlbase.h>
// You may derive a class from CComModule and use
// it if you want to override something, but do not
// change the name of _Module.
//
extern CComModule _Module;
#include <atlcom.h>
#include <atlwin.h>
#include <adslib.h>
#include <dbmain.h>
#include <dbsymtb.h>
#include <dbmtext.h>
#include <acdocman.h>
#include <aced.h>
#include <rxregsvc.h>
#ifdef ARX_DEBUG
#undef ARX_DEBUG
#define _DEBUG
#endif
Добавьте Код к Обработчикам
Как только Вы добавили обработчики, Вы готовы добавить код, чтобы иметь дело с вашим диалогом. Этот раздел суммирует то, что каждый обработчик делает с законченной распечаткой.
1 Сначала мы добавляем несколько сервисных функций, чтобы конвертировать{*преобразовывать*}, отображать, и проверить правильность значений.
Примечание мы использует CACUINUMERIC и средство управления CACUIANGLEEDIT, чтобы делать это:
// Utility functions
void AsdkAcUiDialogSample::DisplayPoint()
{
m_ctrlXPtEdit.SetWindowText(m_strXPt);
m_ctrlXPtEdit.Convert();
m_ctrlYPtEdit.SetWindowText(m_strYPt);
m_ctrlYPtEdit.Convert();
m_ctrlZPtEdit.SetWindowText(m_strZPt);
m_ctrlZPtEdit.Convert();
}
bool AsdkAcUiDialogSample::ValidatePoint()
{
if (!m_ctrlXPtEdit.Validate())
return false;
if (!m_ctrlYPtEdit.Validate())
return false;
if (!m_ctrlZPtEdit.Validate())
return false;
return true;
}
void AsdkAcUiDialogSample::DisplayAngle()
{
m_ctrlAngleEdit.SetWindowText(m_strAngle);
m_ctrlAngleEdit.Convert();
}
bool AsdkAcUiDialogSample::ValidateAngle()
{
if (!m_ctrlAngleEdit.Validate())
return false;
return true;
}
2 Теперь добавляют некоторые сервисные функции, чтобы выполнить итерации более чем двух таблиц идентификаторов и отображать названия{*имена*} в двух различных списках:
void AsdkAcUiDialogSample::DisplayBlocks()
{
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);
// Iterate through the block table and display
// the names in the list box.
//
char *pName;
AcDbBlockTableIterator *pBTItr;
if (pBlockTable->newIterator(pBTItr) == Acad::eOk) {
while (!pBTItr->done()) {
AcDbBlockTableRecord *pRecord;
if (pBTItr->getRecord(pRecord, AcDb::kForRead)
== Acad::eOk) {
pRecord->getName(pName);
m_ctrlBlockListBox.InsertString(-1, pName);
pRecord->close();
}
pBTItr->step();
}
}
pBlockTable->close();
}
void AsdkAcUiDialogSample::DisplayRegApps()
{
AcDbRegAppTable *pRegAppTable;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pRegAppTable, AcDb::kForRead);
// Iterate through the reg app table and display the
// names in the list box.
//
char *pName;
AcDbRegAppTableIterator *pItr;
if (pRegAppTable->newIterator(pItr) == Acad::eOk) {
while (!pItr->done()) {
AcDbRegAppTableRecord *pRecord;
if (pItr->getRecord(pRecord, AcDb::kForRead)
== Acad::eOk) {
pRecord->getName(pName);
m_ctrlRegAppComboBox.InsertString(-1, pName);
pRecord->close();
}
pItr->step();
}
}
pRegAppTable->close();
}
3 Добавляют объявления для функций и переменных к определению класса файл заголовка:
void DisplayPoint();
bool ValidatePoint();
void DisplayAngle();
bool ValidateAngle();
void DisplayBlocks();
void DisplayRegApps();
CString m_strAngle;
CString m_strXPt;
CString m_strYPt;
CString m_strZPt;
4 Затем - обработчики кнопки для выбора точки и угла, используя редактора AutoCAD. Обратите внимание, как BeginEditorCommand (), CompleteEditorCommand (), и CancelEditorCommand () функции используются, чтобы скрыть диалог, позволять запрос к acedGetPoint и acedGetAngle, и наконец или отменять или восстанавливать изображение диалога, основанного на как выбранный пользователь:
// AsdkAcUiDialogSample обработчики сообщения
void AsdkAcUiDialogSample::OnButtonPoint()
{
// Hide the dialog and give control to the editor
//
BeginEditorCommand();
ads_point pt;
// Get a point
//
if (acedGetPoint(NULL, "\nPick a point: ", pt) == RTNORM) {
// If the point is good, continue
//
CompleteEditorCommand();
m_strXPt.Format("%g", pt[X]);
m_strYPt.Format("%g", pt[Y]);
m_strZPt.Format("%g", pt[Z]);
DisplayPoint();
} else {
// otherwise cancel the command (including the dialog)
CancelEditorCommand();
}
}
void AsdkAcUiDialogSample::OnButtonAngle()
{
// Hide the dialog and give control to the editor
//
BeginEditorCommand();
// Set up the default point for picking an angle
// based on the m_strXPt, m_strYPt, and m_strZPt values
//
ads_point pt;
acdbDisToF(m_strXPt, -1, &pt[X]);
acdbDisToF(m_strYPt, -1, &pt[Y]);
acdbDisToF(m_strZPt, -1, &pt[Z]);
double angle;
// Get a point from the user
//
if (acedGetAngle(pt, "\nPick an angle: ", &angle) == RTNORM) {
// If we got an angle, go back to the dialog
//
CompleteEditorCommand();
// Convert the acquired radian value to degrees since the
// AcUi control can convert that to the other formats.
//
m_strAngle.Format("%g", angle*(180.0/PI));
DisplayAngle();
} else {
// otherwise cancel the command (including the dialog)
//
CancelEditorCommand();
}
}
5 Теперь обработчики окна редактирования осуществлены. В основном мы только хотим конвертировать{*преобразовать*} значения к текущим параметрам настройки Модулей:
void AsdkAcUiDialogSample::OnKillfocusEditAngle()
{
// Get and update text the user typed in.
//
m_ctrlAngleEdit.Convert();
m_ctrlAngleEdit.GetWindowText(m_strAngle);
}
void AsdkAcUiDialogSample::OnKillfocusEditXpt()
{
// Get and update text the user typed in.
//
m_ctrlXPtEdit.Convert();
m_ctrlXPtEdit.GetWindowText(m_strXPt);
}
void AsdkAcUiDialogSample::OnKillfocusEditYpt()
{
// Get and update text the user typed in.
//
m_ctrlYPtEdit.Convert();
m_ctrlYPtEdit.GetWindowText(m_strYPt);
}
void AsdkAcUiDialogSample::OnKillfocusEditZpt()
{
// Get and update text the user typed in.
//
m_ctrlZPtEdit.Convert();
m_ctrlZPtEdit.GetWindowText(m_strZPt);
}
6 обработчик поля со списком позволяет пользователю напечатывать строку и затем регистрировать это как прикладное имя. Это действительно не имеет смысл для приложения, но это показывает использованию поля со списком:
void AsdkAcUiDialogSample::OnKillfocusComboRegapps()
{
CString strFromEdit;
m_ctrlRegAppComboBox.GetWindowText(strFromEdit);
if (m_ctrlRegAppComboBox.FindString(-1, strFromEdit) == CB_ERR)
if (acdbRegApp(strFromEdit) == RTNORM)
m_ctrlRegAppComboBox.AddString(strFromEdit);
}
7, чтобы делать некоторую проверку правильности данных, мы обрабатываем это в OnOk () обработчик. Это, конечно, может быть сделано в любое время. Также обратите внимание, что OnOk () обработчик сохраняет данные в параметр пользователя (системный реестр), используя SetDialogData () функция:
void AsdkAcUiDialogSample::OnOK()
{
if (!ValidatePoint()) {
AfxMessageBox("Sorry, Point out of desired range.");
m_ctrlXPtEdit.SetFocus();
return;
}
if (!ValidateAngle()) {
AfxMessageBox("Sorry, Angle out of desired range.”);
m_ctrlAngleEdit.SetFocus();
return;
}
// Store the data into the registry
//
SetDialogData("ANGLE", m_strAngle);
SetDialogData("POINTX", m_strXPt);
SetDialogData("POINTY", m_strYPt);
SetDialogData("POINTZ", m_strZPt);
CAcUiDialog::OnOK();
}
8 Наконец, OnInitDialog () функция заботится о всей инициализации, включая изменение размеров и требования постоянства данных:
BOOL AsdkAcUiDialogSample::OnInitDialog()
{
// Set the dialog name for registry lookup and storage
//
SetDialogName("AsdkAcUiSample:AsdkAcUiDialog");
CAcUiDialog::OnInitDialog();
DLGCTLINFOdlgSizeInfo[]= {
{ IDC_STATIC_GROUP1, ELASTICX, 20 },
{ IDC_STATIC_GROUP1, ELASTICY, 100 },
{ IDC_EDIT_XPT,ELASTICX, 20 },
{ IDC_EDIT_YPT,ELASTICX, 20 },
{ IDC_EDIT_ZPT,ELASTICX, 20 },
{ IDC_EDIT_ANGLE, ELASTICX, 20 },
{ IDC_STATIC_GROUP2, MOVEX, 20 },
{ IDC_STATIC_GROUP2, ELASTICY, 100 },
{ IDC_STATIC_GROUP2, ELASTICX, 80 },
{ IDC_LIST_BLOCKS, MOVEX, 20 },
{ IDC_LIST_BLOCKS, ELASTICY, 100 },
{ IDC_STATIC_TEXT2,MOVEX, 20 },
{ IDC_STATIC_TEXT2,MOVEY, 100 },
{ IDC_LIST_BLOCKS, ELASTICX, 80 },
{ IDC_STATIC_TEXT2,ELASTICX, 80 },
{ IDC_STATIC_GROUP3, MOVEY, 100 },
{ IDC_STATIC_GROUP3, ELASTICX, 20 },
{ IDC_COMBO_REGAPPS, MOVEY, 100 },
{ IDC_COMBO_REGAPPS, ELASTICX, 20 },
{ IDC_STATIC_TEXT3,MOVEY, 100 },
{ IDC_STATIC_TEXT3,ELASTICX, 20 },
{ IDOK,MOVEX, 100 },
{ IDCANCEL, MOVEX, 100 },
};
const DWORD numberofentries =
sizeof dlgSizeInfo / sizeof DLGCTLINFO;
SetControlProperty(dlgSizeInfo, numberofentries);
// Must be within a 100-unit cube centered about 0,0,0.
//
m_ctrlXPtEdit.SetRange(-50.0, 50.0);
m_ctrlYPtEdit.SetRange(-50.0, 50.0);
m_ctrlZPtEdit.SetRange(-50.0, 50.0);
// Must be between 0 and 90 degrees.
//
m_ctrlAngleEdit.SetRange(0.0, 90.0 /*(PI/2.0)*/);
// Assign a title for the dialog.
//
SetWindowText("AcUiDialog Sample");
// Load the default bitmaps.
//
m_ctrlPickButton.AutoLoad();
m_ctrlAngleButton.AutoLoad();
// Get and display the preserved data from the registry.
//
if (!GetDialogData("ANGLE", m_strAngle))
m_strAngle = "0.0";
if (!GetDialogData("POINTX", m_strXPt))
m_strXPt = "0.0";
if (!GetDialogData("POINTY", m_strYPt))
m_strYPt = "0.0";
if (!GetDialogData("POINTZ", m_strZPt))
m_strZPt = "0.0";
DisplayPoint();
DisplayAngle();
DisplayBlocks();
DisplayRegApps();
return TRUE; // return TRUE unless you set the focus to a control
}
Добавьте Поддержку Системного реестра и Новый Объект COM ATL
1 Добавляют следующую функцию инициализации системного реестра к AsdkDesignCenterSamp.cpp. Эта функция основает системный реестр, основанный на ресурсах системного реестра, которые будут добавлены в более позднем шаге.
void registerAppInfo(HINSTANCE hInstance)
{
USES_CONVERSION;
HRESULT hRes = S_OK;
CComPtr<IRegistrar> p;
hRes = CoCreateInstance(CLSID_Registrar, NULL,
CLSCTX_INPROC_SERVER, IID_IRegistrar, (void**)&p);
if(SUCCEEDED(hRes))
{
// Get the AutoCAD Product key from the
// registry into a CString.
//
CString csProdKey = acrxProductKey();
// Use CStrings to obtain the authorization
// stamp from the registry.
//
CString csPath = "SOFTWARE\\Autodesk\\AutoCAD\\R15.0\\";
CString csStamp = csProdKey.Right(csProdKey.GetLength()
- csPath.GetLength());
_TCHAR szRegKey[_MAX_PATH];
_tcscpy(szRegKey, csStamp);
LPOLESTR pszId = T2OLE("AUTH");
// do a runtime swap of the registry key value.
//
p->AddReplacement(pszId, T2OLE(szRegKey));
_TCHAR szModule[_MAX_PATH];
GetModuleFileName(hInstance, szModule, _MAX_PATH);
LPCOLESTR szType = OLESTR("REGISTRY");
LPOLESTR pszModule = T2OLE(szModule);
// Pull the registry entries from the resource ID.
//
hRes = p->ResourceRegister(pszModule, IDR_REGISTRY1,
szType);
if(FAILED(hRes))
AfxMessageBox("Error registering the app info.");
}
}
2 Теперь добавляют новый Объект ATL, который поддержит интерфейс IAcDcContentView.
В Visual C++, выберите Вставку, Новый Объект ATL. В диалоге выбирают Объекты и выбирают Простой Объект. Нажмите Next, и введите имя для Объекта ATL. Для этого примера, назовите это AsdkDcContent. Теперь выберите позицию табуляции Names, и щелчок поддерживает ISupportErrorInfo. Нажмите OK, чтобы создать объект.
3 Затем мы должны добавить некоторую информацию системного реестра к секции ресурса проекта. Сначала создайте новый файл по имени AsdkDesignCenterSamp .rgs. Следующая распечатка должна быть изменена для вашего определенного проекта, где ID класса (CLSID) должен быть скопирован с вашего файла IDL. Используйте CLSID, который соответствует интерфейсу IAsdkDcContent. Так как они - значения GUID, они отличны для каждого нового проекта. Также для других проектов, Вы будете должны изменить секции расширений и также добавлять имя вашего определенного класса. Снова, этот пример использует AsdkDcContent.
HKLM
{
NoRemove ’SOFTWARE’
{
NoRemove ’Autodesk’
{
NoRemove ’AutoCAD’
{
NoRemove ’R15.0’
{
NoRemove ’%AUTH%’
{
NoRemove ’AutodeskApps’
{
NoRemove ’AcadDC’
{
NoRemove ’Extensions’
{
ForceRemove ’.txt’
{
val CLSID = s ’{<Your CLSID>}’
IconIndex = d ’0’
}
}
NoRemove ’Applications’
{
ForceRemove ’AsdkDcContent’
{
’Extensions’
{
.txt
{
val CLSID = s ’{<Your CLSID>}’
val IconIndex = d ’0’
}
}
CustomView = s ’Yes’
}
}
}
}
}
}
}
}
}
}
Сохраните этот файл, и в Visual C++ приносят ResourceView вперед. Откройте распечатку ресурсов, и разверните узла “REGISTRY”. Правый щелчок и импорт файл системного реестра. Это должно дать ресурсу ID IDR_REGISTRY1, но если это делает не, переименуйте это так, чтобы это соответствовало запросу в registerAppInfo.
Документ
Документ состоит из окна документа MDI, контекста выполнения, связанный редактор состояние, и единственная{*отдельная*} текущая база данных, плюс любое число побочных баз данных, которые открыты в сотрудничестве с этим. Текущая база данных - отображение того и отредактированная через команды. Побочные базы данных или используются таблицей перекрестных ссылок или для общего использования. Документ также включает переменные системы, которые связаны с данным рисунком типа текущей переменной области просмотра.
Документы уникально идентифицированы их адресом, который является указателем AcApDocument*.
Документ Блокировка
Все документы должны быть блокированы, чтобы изменяться. Документы могут также быть блокированы, чтобы предотвратить код в других контекстах выполнения от изменения их временно. Документы не должны быть блокированы, чтобы исполнить, запрос (читает) операции, и они никогда не предотвращены от выполняющих операций запроса на других документах. Основной документ блокировка обработана автоматически для AutoCAD, командует, ObjectARX
команды, и функции AutoLISP.
Немодальный диалог и код инструментальной панели, и любые команды, которые должны разработать -сторону активный документ, должны вручную исполнить документ блокировка.
Для более детальной информации относительно документа блокировка, см. “ Явный Документ Блокировка ” на странице 425.
Документо-независимые базы данных
Чтобы участвовать в отмене в AutoCAD, базы данных должны быть связаны с документом, потому что каждый документ имеет независимый стек отмены. Однако, эта особенность находится в прямом конфликте с потребностью загрузить базы данных, чей содержание предназначено, чтобы быть разделенным поперек документа сеансы редактирования. Другими словами, Вы должны решить между следующим два сценария для ваших побочных баз данных:
§
Связывают базу данных с определенным документом, и не позволяют редактирования этому с других сеансов редактирования, и возможно загружают DWG или DXF файл в множественные базы данных в течение каждого сеанса редактирования, который нуждается в этом.
§ Загружают DWG или DXF файл, чтобы совместно использовать это поперек сеансов редактирования, и не имеют никакой автоматической отмены для этого. Или не поддержите отмену для них во всем (прекрасно, если они только для чтения, или только модифицированный для фактического сохраняет, или находятся под контролем пересмотра), или быть очень осторожным при использовании отмены.
В ObjectARX, прежний сценарий - значение по умолчанию. Всякий раз, когда инициирован новый образец AcDbDatabase, это связано с текущим документом.
Это - одна из причин, приложение должно изменить{*заменить*} текущий документ без того, чтобы активизировать новый документ.
AcDbDatabase класс обеспечивает следующую функцию, которая отключает отмену базы данных и разрушает связь базы данных с документом:
void disableUndoRecording(Adesk::Boolean disable);
Любая AcDb уверенность относительно любых документо-определенных переменных системы примет встроенные значения по умолчанию для документо-независимых баз данных. Также, не имеется никакой потребности блокировать любые документы, чтобы обратиться к докумено-независимым базам данных.
ОБРАТИТЕ ВНИМАНИЕ На разработчиков, кто думают относительно вызова независимого контроллера отмены от контроллеров отмены множественного документа, должен остаться знающий, что выполняющий отмену в данном документе может вести к несогласованности и коррупции. Например: База данных X имеет контроллер отмены, не связанный с любым документом. Модификации от Документируют, сделаны к Базе данных X, тогда модификациями из Документа B, которые полагаются на объекты, созданные или изменяемые от Документа модификации. Теперь, отмена применяется в Документе A. Изменения{*замены*}, сделанные к Документу B будут разрушены.
Домен{*область*}
AutoCAD solids - контурные представления (часто упоминаемый как B-rep модели), состоят из коллекции топологических объектов связности и связал геометрические граничные объекты. Топологические объекты определены в AcBr библиотеке и описаны позже в этой главе, принимая во внимание, что геометрические объекты определены в AcGe библиотеке.
Объекты, определенные или сгенерированные AcBr библиотекой постоянно находятся в трехмерном Евклидовом пространстве модели (E 3). Единственные исключения - геометрические объекты, определенные в двумерном пространстве{*пробеле*} параметра поверхности (типа кривых параметра и значений параметра).
Вообще, только 2-разнообразный топологический домен{*область*} поддержан AcBr библиотекой. Особенности (которые являются геометрическими вырождениями) поддержаны, чтобы представить вершину конуса, но проводных тел и смешанной размерности solids (который может включать повисшие провода, и лица) не поддержаны; и при этом они не могут быть реализованы в AutoCAD.
Общий неразнообразный домен{*область*} - надмножество 2-разнообразного домена{*области*}, и позволяет отличным твердым объемам касаться в единственных{*отдельных*} точках, кривых, или лицах; и позволяет любую комбинацию каркаса, листа, и твердых объектов. Следующие неразнообразные объекты поддержаны в соответствии с AutoCAD и AcBr библиотекой:
§
Два 2-разнообразного solids, объединенный по общедоступному краю или вершине
§ объект AcDbBody, содержащий единственное лицо
Топологический объект может быть неограничен (то есть это не может иметь никакой более низкой размерной топологии ограничения) только в следующих случаях:
§ замкнутая поверхность, которая свойственно ограничена, и в u и v руководствах{*направлениях*} (типа полного тора или сферы), представлен лицом, которое не имеет никаких границ цикла.
§ замкнутая кривая, которая свойственно ограничена (типа полного круга или эллипса), представлен краем, который имеет совпадающее начало и конечную вершину.
Ограничения
Некоторые операции не могут поддерживать неоднородное масштабирование. Это включает все функции, которые возвращают внешнюю кривую или поверхность (включая поверхности НЕОДНОРОДНОГО РАЦИОНАЛЬНОГО В-СПЛАЙНА).
Полная цепочка трансформант от пути подпримитива кэшируется во время этого, путь подпримитива объекта AcBr установлен (по причинам эффективности). Если блок-ссылка перемещена, это укажет на новую матрицу трансформант, но объект AcBr не будет знать, что его кэшируемая трансформанта устаревшая. Если вставка изменена, чтобы обратиться к различному примитиву AutoCAD, путь подпримитива просто больше не имеет уместность и должен быть модифицирован, чтобы отразить новую ссылку примитива перед использованием, чтобы повторно инициализировать все уместные объекты AcBr.
Особенности (типа вершины конуса) карта к граням в AutoCAD и таким образом может использоваться, чтобы инициализировать AcBrEdge для специальной цели запроса для вершины, но нельзя делать запрос для геометрии кривой или использоваться, чтобы установить AcBrLoopEdgeTraverser. К ним можно также обращаться, используя AcBrLoopVertexTraverser, поскольку особенность соответствует единственной границе цикла лица.
Также, как с указателями AcDbObject, объекты AcBr не могут использоваться, как только объект базы данных AutoCAD был закрыт в базе данных или идет из контекста; они не постоянны. Любое изменение к объекту базы данных будет помечено как eBrepChanged ошибка, если уровень проверок правильности не был установлен, чтобы игнорировать изменения базы данных. Из-контекста или закрытого объекта базы данных будет вообще заставлять Acad:: eNotInDatabase быть возвращенным.
Иерархия Классов
AcBr иерархия классов - подмножество ObjectARX иерархии классов, и определяет следующие классы:
Обратите внимание, что объекты AcBr не получены из AcDbObject, и поэтому не могут быть зарегистрированы с базой данных AutoCAD.
Доступ к базам данных, связанным с нетекущими документами
Иногда Вы будете должны смотреть или изменить базы данных, связанные с другими документами, но не нуждаться в любом явном вводе пользователя в них. Вы могли бы даже смотреть на кое-что связанное с другим документом.
Чтобы просто исследовать базы данных, связанные с другими документами, Вы не должны блокировать документ, хотя, если документ блокирован в AcAp:: kXWrite режиме другим контекстом выполнения, Вы будете лишены доступа к любому из его элементов.
Чтобы изменять базы данных, связанные другими документами, или предотвращать другие контексты выполнения от изменения их на некоторое время, Вы должны блокировать документ, определяя AcAp::kXWrite, AcAp::kWrite, или AcAp::kRead, в зависимости от вашего намерения. Если командный процессор документа не статический, это обычно уже блокируется, и если это взаимно исключает вашу блокировку, Вы будете лишены доступа.
ОБРАТИТЕ ВНИМАНИЕ При изменении объектов базы данных в нетекущем документе, если Вы должны использовать сделки, убедитесь, что использовали операционного менеджера, связанного с документом.
Такие модификации не будут невыполнимые из текущего документа. Вместо этого они будут зарегистрированы со стеком отмены их ведущего документа, и уничтожены, используя отмену, когда ведущий документ текущий.Когда закончено с информацией, связанной с документом, убедитесь, что разблокировали это как можно скорее, минимизировали потенциал для конфликтов с другими командами.
Доступ к Базе данных AutoCAD
Рисунок AutoCAD - коллекция объектов, сохраненных в базе данных. Объекты представляют собой не только графические объекты, но также и внутренние конструкции
типа таблиц идентификаторов и словарей. ObjectARX обеспечивает ваше приложение доступом к этим структурам базы данных. Кроме того, Вы можете создавать новую базу данных объектов для вашего определенного приложения.
Доступ к интерфейсам COM от ObjectARX
Некоторые API только доступны как ActiveX, так, чтобы обратиться к ним от ObjectARX, Вы должны использовать COM от C++. Эта секция объясняет эти два метода, которые Вы можете использовать, чтобы делать так. Первый должен использовать MFC, и Visual C++ ClassWizard, чтобы читать AutoCAD напечатает библиотеку. Эта библиотека типов (acad.tlb) содержит ActiveX Объектную модель. Второй метод требует немного большего количества работы, но не требует использования MFC.
Доступ к Системе координат
Функции Примитива восстанавливают{*отыскивают*} и устанавливают значение координат, используя значения Мировой системы координат. Единственное исключение к этому правилу - AcDb2dPolylineVertex класс, описанный позже в этом разделе, который использует Систему координат Примитива (ECS) значения. Например, если Вы вызываете getCenter () функция на круге, AutoCAD возвращает X, Y
центр круга в мировых координатах.
Доступ к таблицам идентификаторов
AcdbTblNext() функция последовательно просматривает входы таблицы идентификаторов, и acdbTblSearch () функция возвращает определенные входы. Названия{*имена*} Таблицы определены строками. Допустимыеимена - “LAYER”, “LTYPE”, “VIEW”, “STYLE”, “BLOCK”, “UCS”, “VPORT”, and “APPID”. Обе из этих функций возвращают входы как списки буфера результата с кодами группы DXF.
Первый запрос к acdbTblNext() возвращает первый вход в указанной таблице.
Последующее звонит, которые определяют, что та же самая таблица возвращает последовательные входы, если второй параметр к acdbTblNext() (перемотка) не отличный от нуля, когда acdbTblNext() возвращает первый вход снова.
В следующем примере, функция getblock() возвращает первый блок (если любой) в текущем рисунке, и вызывает printdxf() функцией, чтобы отобразить содержание того блока в формате списка.
void getblock()
{
struct resbuf *bl, *rb;
bl = acdbTblNext("BLOCK", 1); // First entry
acutPrintf("\nResults from getblock():\n");
// Print items in the list as "assoc" items.
for (rb = bl; rb != NULL; rb = rb->rbnext)
printdxf(rb);
// Release the acdbTblNext list.
acutRelRb(bl);
}
Входы, отысканные в таблице БЛОКОВ, содержат группа -2, которая содержит имя первого примитива на блочном определении. В рисунке к одиночному блоку по имени ПОЛЕ, запрос к getblock () печатает следующий (значение имени изменяется от сеанса до сеанса):
Результаты от getblock ():
(0 . "BLOCK")
(2 . "BOX")
(70 . 0)
(10 9.0 2.0 0.0)
(-2 . <Entity name: 40000126>)
Первый параметр к acdbTblSearch () - строка, которая называет таблицу, но второй параметр - строка, которая называет специфический символ в таблице. Если символ найден, acdbTblSearch () возвращает его данные. Эта функция имеет третий параметр, setnext, который может использоваться, чтобы координировать операции с acdbTblNext (). Если setnext нулевой, acdbTblSearch () запрос не имеет никакого эффекта на acdbTblNext (), но если setnext отличный от нуля, следующий запрос к acdbTblNext () возвращает вход таблицы, который следует за входом, найденным acdbTblSearch ().
Setnext опция особенно полезна, когда имеющий дело с VPORT таблицей идентификаторов, потому что все области просмотра в специфической конфигурации области просмотра имеют то же самое имя (типа *ACTIVE).
Имейте в виду, что, если к VPORT таблице идентификаторов обращаются, когда TILEMODE выключен, изменения{*замены*} не имеют никакого видимого эффекта, пока TILEMODE не поворачивает обратно на. (TILEMODE установлен или командой SETVAR или, вводя ее имя непосредственно.) Не путают VPORT таблицу идентификаторов с примитивами области просмотра.
Чтобы находить и обрабатывать каждую область просмотра в конфигурации, названной 4VIEW, Вы могли бы использовать следующий код:
struct resbuf *v, *rb;
v = acdbTblSearch("VPORT", "4VIEW", 1);
while (v != NULL} {
for (rb = v; rb != NULL; rb = rb->rbnext)
if (rb->restype == 2)
if (strcmp(rb->resval.rstring, "4VIEW") == 0) {
.// Process the VPORT entry
.
.
acutRelRb(v);
// Get the next table entry.
v = acdbTblNext("VPORT", 0);
} else {
acutRelRb(v);
v = NULL; // Break out of the while loop.
break; // Break out of the for loop.
}
}
Доступ к текущему документу и связанным с ним объектам
Ключ вызывает ObjectARX-приложение, должен делать, когда это извлекает пользу, контроль должен выяснить текущий документ, который может быть выполнен с функцией acDocManager->curDocument().
ОБРАТИТЕ ВНИМАНИЕ, что текущий документ - не всегда активный документ. Дело обстоит так в течение переходных состояний, типа того, когда documentToBeActivated () реактор происходит. Не делайте попытку обширной обработки в течение переходных состояний.
Рассмотрите использование mdiActiveDocument () если Вы заинтересованы активным документом.
Из текущего документа, Вы можете определять текущую базу данных, уместного операционного менеджера, и связанное определенное документом состояние вашего приложения, и затем делать любые потребности, которые будут сделаны перед возвращением.
Как только команда сохранила текущий документ и связала информацию относительно ее стека, не требоваться сделать запрос текущего документа снова до завершения. Всякий раз, когда подсказка для ввода пользователя сделана, пользователь может переключать документы, но если это сделано, текущая команда приостановлена, и ее состояние стека сохранено, пока документ не оживлен.
Если ваше приложение работает от прикладного контекста выполнения, это должно блокировать и разблокировать текущий документ, чтобы изменить что - нибудь связанное этим. Это может делать так, непосредственно вызывая AcApDocManager::lockDocument () и unlockDocument () функцию члена.
Если ваше приложение работает от функции ObjectARX или AutoLISP, никакая блокировка не должна быть необходима, поскольку система устанавливает блокировки и удаляет их автоматически вокруг выражений AutoLISP и команд.
Другие соображения по прикладному контексту выполнения
Имеются также некоторые возможности и ограничения, которые применяются к коду, выполняющему в прикладном контексте выполнения.
§
когда контекст выполнения ваш код выполняется под, не неявен в вашей структуре кода, Вы можете делать этот запрос, чтобы найти,является ли это прикладной контекст выполнения:
Adesk::Boolean
AcApDocManager::isApplicationContext() const;
§ Все ActiveX члены ввода пользователя может использоваться, но удостовериться, что Вы вызываете их на сервисный объект, связанный с активным и текущим документом. Как отмечено выше, переключение документа будет заблокировано, когда ввод пользователя получен в этом контексте. Вы можете получить IACADDOCUMENT* образец, который соответствует потоку AcApDocument через запрос:
acDocManager()->curDocument()->cDoc()->GetIDispatch( BOOL bAddRef);
§ Все ObjectARX функции ввода пользователя может быть вызван с текущим активным документом, неявно используемым. Как отмечено выше, переключение документа будет заблокировано, когда ввод пользователя получен в этом контексте.
§ Прикладной код, выполняющийся от прикладного контекста может использовать следующую функцию члена, чтобы переключить или текущий и активный документ, вместе или индивидуально, как желательно.
virtual Acad::ErrorStatus
setCurDocument(
AcApDocument* pDoc,
AcAp::DocLockMode = AcAp::kNone,
bool activate = false) = 0;
§ чередуясь между запросом ввода пользователя и изменения или формирования текущего документа, можно запрашивать относительно ввода от множественных документов от единственного контекста выполнения и единственной последовательности кода. Недостаток{*препятствие*} - то переключение документа пользователем, заблокирован при запросе ввода, так что код должен знать, к которому документу требуется переключить.
§ когда активные и текущие документы отличаются, знать что ActiveX и ObjectARX ввод пользователя функции не будет работать должным образом. Используйте curDocument () и mdiActiveDocument () функции, чтобы проверить текущие и активные документы.
§ если приложение выгружается с текущим документом и активным отличным документом, следующее входное событие восстановит текущий документ назад к активному документу.
§ когда код, выполняющийся от прикладного контекста запрашивает ввод пользователя, используя ActiveX функции ввода пользователя, автоматическое интерактивное переключение документа заблокирован, хотя текущее переключение документа может быть выполнено.
Дуга
CircularArc () функция имеет две формы:
virtual Adesk::Boolean
AcGiWorldGeometry::circularArc(
const AcGePoint3d& center,
const double radius,
const AcGeVector3d& normal,
const AcGeVector3d& startVector,
const double sweepAngle,
const AcGiArcType arcType = kAcGiArcSimple) const = 0;
virtual Adesk::Boolean
AcGiWorldGeometry::circularArc(
const AcGePoint3d& start,
const AcGePoint3d& point,
const AcGePoint3d& end,
const AcGiArcType arcType = kAcGiArcSimple) const = 0;
Переменная типа дуги, AcGiArcType, может иметь одно из следующих значений:
§ kAcGiArcSimple Дуга непосредственно, которая - не fillable
§ kAcGiArcSector Область, ограниченная дугой и ее центром искривления
§ kAcGiArcChord Область, ограниченная дугой и ее конечными точками
Двумерные соты (Tessellation)
Кривые и кривые поверхности должны быть мозаичным —, разбитым в линии и многоугольники —, чтобы быть отображенными. Градус{*степень*} двумерных сот определяет насколько точный отображенная кривая будет (как близко это приблизит математическую “истинную” кривую) и сколько работы наверху требовано, чтобы генерировать графику для кривой. Очень маленький круг может требовать только, чтобы единственный пиксел отобразил это. Большой круг может требовать сотен маленьких долей линии, которые будут рассчитаны и отображен, чтобы создать гладкое появление.
deviation() функции, обеспеченные AcGiWorldDraw и классами AcGiViewportDraw возвращают отклонение, которое является допустимым максимальным различием в мировом пространстве между истинной математической поверхностью и мозаичной поверхностью, как показано в следующем рисунке:
Обратитесь к этому значению, позволяет заказным примитивам настраивать их двумерные соты к энергии команды VIEWRES процент на опцию, которая установлена пользователем. Результат - то, что заказные примитивы являются мозаичными к относительно та же самая гладкость как встроенные примитивы.
deviation () функция возвращает предложенное максимальное отклонение в мировом пространстве, учитывая тип отклонения, чтобы вычислить и точку в мировом пространстве для перспективного масштабирования если требовано. Сигнатура для deviation() функция
virtual double
AcGiWorldDraw::deviation(
AcGiDeviationType
devType,
const AcGePoint3d&) const = 0;
Типы отклонения
§ kAcGiMaxDevForCircle (для кругов и дуг)
§ kAcGiMaxDevForCurve
§ kAcGiMaxDevForBoundary
§ kAcGiMaxDevForIsoline
§ kAcGiMaxDevForFacet (для поверхностей; формула для вычисления этого отклонения использует значение FACETRES переменной системы)
DwgIn () Функция
DwgIn () функция, которая вызывает dwgInFields (), вызван следующими командами и условиями{*состояниями*}:
§
OPEN (использует kFileFiler)
§ UNDO (использует kUndoFiler)
§ INSERT, COPY, XREF (используйте kDeepCloneFiler и kIdXlateFiler)
§ WBLOCK (использует kWblockCloneFiler и kIdXlateFiler)
§ Любое время объект просматривается в (использует kPageFiler)
DwgOut () Функция
DwgOut () функция, которая вызывает{*называет*} dwgOutFields (), вызван следующими командами и условиями{*состояниями*}:
§ SAVE (uses kFileFiler)
§ SAVEAS (uses kFileFiler)
§ WBLOCK (uses kWblockCloneFiler and kIdXlateFiler)
§ INSERT, XREF (use kDeepCloneFiler and kIdXlateFiler)
§ COPY (использует тех же самых регистраторов как INSERT; копия требует записывающий состояние объекта и затем чтения этому назад в к объекту того же самого класса)
§ PURGE (uses a kPurgeFiler)
§ Любое время объект просматривается из (использует kPageFiler)
§ Любое время объект изменяется (для регистрации отмены; использует kUndoFiler)
DXF Коды Группы
Много функций ObjectARX возвращают коды типа, определенные в предшествующей таблице. Однако, в результатах от функций, которые обрабатывают, примитивы, restype поле содержат коды группы DXF, которые описаны в Руководстве Настройки AutoCAD. Например, в списке примитива, restype поле 10 указывает точку, в то время как restype 41 указывает реальное значение.
Рисунки AutoCAD состоят из структурных контейнеров для объектов базы данных, имеющих следующие компоненты:
§
уникальная метка, которая всегда позволяется и это сохраняется продолжении жизни рисунка
§ необязательный список xdata
§ необязательный набор постоянных реакторов
§ необязательный указатель монопольного использования на словарь расширения, который имеет другие объекты базы данных, помещенные в это приложением
Объекты Базы данных - объекты без уровня, linetype, цвета, или любых других геометрических или графических свойств, и примитивы получены из объектов и имеют геометрические и графические свойства.
Поскольку коды DXF - всегда меньше чем 2,000, и коды типа результата всегда большие, приложение может легко определять, когда список буфера результата содержит значения результата (как возвращено acedGetArgs (), например) или содержит данные определения примитива (как возвращено acdbEntGet () и другими функциями примитива).
Следующий рисунок показывает формат буфера результата круга, отысканного acdbEntGet ():
Следующий типовой кодовый фрагмент показывает функцию, dxftype (), который пропускают код группы DXF и связанный примитив, и возвращает соответствующий код типа. Код типа указывает то, что тип данных может представлять данные: RTREAL указывает, с двойной точностью с плавающей точкой значение, RT3DPOINT указывает ads_point, и так далее. Вид примитива (например, нормальный примитив типа круга, блочного определения, или входа таблицы типа области просмотра) обозначен определениями типов, которые сопровождают эту функцию:
#define ET_NORM 1 // Normal entity
#define ET_TBL 2 // Table
#define ET_VPORT 3 // Table numbers
#define ET_LTYPE 4
#define ET_LAYER 5
#define ET_STYLE 6
#define ET_VIEW 7
#define ET_UCS 8
#define ET_BLOCK 9
// Get basic C- language type from AutoCAD DXF group code (RTREAL,
// RTANG are doubles, RTPOINT double[2], RT3DPOINT double[3],
// RTENAME long[2]). The etype argument is one of the ET_
// definitions.
//
// Returns RTNONE if grpcode isn’t one of the known group codes.
// Also, sets "inxdata" argument to TRUE if DXF group is in XDATA.
short dxftype(short grpcode, short etype, int *inxdata)
{
short rbtype = RTNONE;
*inxdata = FALSE;
if (grpcode >= 1000) { // Extended data (XDATA) groups
*inxdata = TRUE;
if (grpcode == 1071)
rbtype = RTLONG; // Special XDATA case
else
grpcode %= 1000; // All other XDATA groups match.
} // regular DXF code ranges
if (grpcode <= 49) {
if (grpcode >= 20) // 20 to 49
rbtype = RTREAL;
else if (grpcode >= 10) { // 10 to 19
if (etype == ET_VIEW) // Special table cases
rbtype = RTPOINT;
else if (etype == ET_VPORT && grpcode <= 15)
rbtype = RTPOINT;
else // Normal point
rbtype = RT3DPOINT; // 10: start point, 11: endpoint
}
else if (grpcode >= 0) // 0 to 9
rbtype = RTSTR; // Group 1004 in XDATA is binary
else if (grpcode >= -2)
// -1 = start of normal entity -2 = sequence end, etc.
rbtype = RTENAME;
else if (grpcode == -3)
rbtype = RTSHORT; // Extended data (XDATA) sentinel
}
else {
if (grpcode <= 59) // 50 to 59
rbtype = RTANG; // double
else if (grpcode <= 79) // 60 to 79
rbtype = RTSHORT;
else if (grpcode < 210)
;
else if (grpcode <= 239) // 210 to 239
rbtype = RT3DPOINT;
else if (grpcode == 999) // Comment
rbtype = RTSTR;
}
return rbtype;
}
Приложение получает список буфера результата (вызвал rb), представляя вход в таблице идентификаторов области просмотра, и следующая инструкция C вызывает dxftype ():
Ctype = dxftype (rb-
> restype, ET_VPORT, &inxdata);
Предположим, что rb- >restype равняется 10. Тогда dxftype() возвращает RTPOINT, указывая, что примитив является двумерной точкой, чьи координаты (типа ads_real) находятся в rb->resval.rpoint [X] и rb->resval.rpoint [Y].
DXF Коды Группы для Xrecords
Следующая таблица перечисляет коды группы DXF, которые могут использоваться в records.
Диапазоны кодов DXF-групп для xrecords
From | To | DataType | |||
1 | 4 | Text | |||
6 | 9 | Text | |||
10 | 17 | Point or vector (3 reals) | |||
38 | 59 | Real | |||
60 | 79 | 16-bit integer | |||
90 | 99 | 32-bit integer | |||
102 | 102 | Control string “{“ or “}” | |||
140 | 149 | real | |||
170 | 179 | 16-bit integer | |||
210 | 219 | Real | |||
270 | 279 | 16-bit integer | |||
280 | 289 | 8-bit integer | |||
300 | 309 | Text | |||
310 | 319 | Binary chunk | |||
320 | 329 | Handle | |||
330 | 339 | Soft pointer ID | |||
340 | 349 | Hard pointer ID | |||
350 | 359 | Soft ownership ID | |||
360 | 369 | Hard ownership ID |
Для описания жестких и мягких владельцев и указателей, см. главу 12, “ Происходящий от AcDbObject. ”
DxfIn () Функция
DxfIn () функция, которая вызывает{*называет*} dxfInFields (), вызван следующим
Команды и функции:
§
OPEN
§ INSERT
§ acdbEntMod() или acdbEntMake()
DxfOut () Функция
DxfOut () функция, которая вызывает{*называет*} dxfOutFields (), вызван следующими командами и функциями:
§ WBLOCK
§ SAVE
§ SAVEAS
§ acdbEntGet ()
Файл реализации
Следующий код показывает выполнению для нового класса AsdkMyClass:
ACRX_DXF_DEFINE_MEMBERS(AsdkMyClass, AcDbObject,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0,
ASDKMYCLASS, SAMP2);
// Gets the value of the integer data member.
//
Acad::ErrorStatus
AsdkMyClass::getData(Adesk::Int16& val)
{
// Tells AutoCAD a read operation is taking place.
//
assertReadEnabled();
val = mIntval;
return Acad::eOk;
}
// Sets the value of the integer data member.
//
Acad::ErrorStatus
AsdkMyClass::setData(Adesk::Int16 val)
{
// Triggers openedForModify notification.
//
assertWriteEnabled();
mIntval = val;
return Acad::eOk;
}
// Files data in from a DWG file.
//
Acad::ErrorStatus
AsdkMyClass::dwgInFields(AcDbDwgFiler* pFiler)
{
assertWriteEnabled();
AcDbObject::dwgInFields(pFiler);
// For wblock filing we wrote out our owner as a hard
// pointer ID so now we need to read it in to keep things
// in sync.
//
if (pFiler->filerType() == AcDb::kWblockCloneFiler) {
AcDbHardPointerId id;
pFiler->readItem(&id);
}
pFiler->readItem(&mIntval);
return pFiler->filerStatus();
}
// Files data out to a DWG file.
//
Acad::ErrorStatus
AsdkMyClass::dwgOutFields(AcDbDwgFiler* pFiler) const
{
assertReadEnabled();
AcDbObject::dwgOutFields(pFiler);
// Since objects of this class will be in the Named
// Objects Dictionary tree and may be hard referenced
// by some other object, to support wblock we need to
// file out our owner as a hard pointer ID so that it
// will be added to the list of objects to be wblocked.
//
if (pFiler->filerType() == AcDb::kWblockCloneFiler)
pFiler->writeHardPointerId((AcDbHardPointerId)ownerId());
pFiler->writeItem(mIntval);
return pFiler->filerStatus();
}
// Files data in from a DXF file.
//
Acad::ErrorStatus
AsdkMyClass::dxfInFields(AcDbDxfFiler* pFiler)
{
assertWriteEnabled();
Acad::ErrorStatus es;
if ((es = AcDbObject::dxfInFields(pFiler)) != Acad::eOk)
{
return es;
}
// Check if we’ re at the right subclass getData marker.
//
if (!pFiler->atSubclassData("AsdkMyClass")) {
return Acad::eBadDxfSequence;
}
struct resbuf inbuf;
while (es == Acad::eOk) {
if ((es = pFiler->readItem(&inbuf)) == Acad::eOk) {
if (inbuf.restype == AcDb::kDxfInt16) {
mIntval = inbuf.resval.rint;
}
}
}
return pFiler->filerStatus();
}
// Files data out to a DXF file.
//
Acad::ErrorStatus
AsdkMyClass::dxfOutFields(AcDbDxfFiler* pFiler) const
{
assertReadEnabled();
AcDbObject::dxfOutFields(pFiler);
pFiler->writeItem(AcDb::kDxfSubclass, "AsdkMyClass");
pFiler->writeItem(AcDb::kDxfInt16, mIntval);
return pFiler->filerStatus();
}
// 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();
}
}
// Opens the dictionary associated with the key ASDK_DICT
// and iterates through all its entries, printing out the
// integer data value in each entry.
//
void
iterateDictionary()
{
AcDbDictionary *pNamedobj;
acdbHostApplicationServices()->workingDatabase()
->getNamedObjectsDictionary(pNamedobj, AcDb::kForRead);
// Get a pointer to the ASDK_DICT dictionary.
//
AcDbDictionary *pDict;
pNamedobj->getAt("ASDK_DICT", (AcDbObject*&)pDict, AcDb::kForRead);
pNamedobj->close();
// Get an iterator for the ASDK_DICT dictionary.
//
AcDbDictionaryIterator* pDictIter= pDict->newIterator();
AsdkMyClass *pMyCl;
Adesk::Int16 val;
for (; !pDictIter->done(); pDictIter->next()) {
// Get the current record, open it for read, and
// print its data.
//
pDictIter->getObject((AcDbObject*&)pMyCl,
AcDb::kForRead);
pMyCl->getData(val);
pMyCl->close();
acutPrintf("\nintval is: %d", val);
}
delete pDictIter;
pDict->close();
}
// The initialization function called from the acrxEntryPoint()
// function during the kInitAppMsg case is used to add commands
// to the command stack and to add classes to the ACRX class
// hierarchy.
//
void
initApp()
{
acedRegCmds->addCommand("ASDK_DICTIONARY_COMMANDS",
"ASDK_CREATE", "CREATE", ACRX_CMD_MODAL,
createDictionary);
acedRegCmds->addCommand("ASDK_DICTIONARY_COMMANDS",
"ASDK_ITERATE", "ITERATE", ACRX_CMD_MODAL,
iterateDictionary);
AsdkMyClass::rxInit();
acrxBuildClassHierarchy();
}
// The cleanup function called from the acrxEntryPoint() function
// during the kUnloadAppMsg case removes this application’s
// command set from the command stack and removes this application’s
// custom classes from the ACRX runtime class hierarchy.
//
void
unloadApp()
{
acedRegCmds->removeGroup("ASDK_DICTIONARY_COMMANDS");
// Remove the AsdkMyClass class from the ACRX runtime
// class hierarchy. If this is done while the database is
// still active, it should cause all objects of class
// AsdkMyClass to be turned into proxies.
//
deleteAcRxClass(AsdkMyClass::desc());
}
Файл Заголовка
Следующий код показывает объявлению класса для нового класса AsdkMyClass полученный из AcDbObject.
class AsdkMyClass : public AcDbObject
//
// This class demonstrates custom objects.
//
// To keep it simple, this class has a single integer data
// member. Get and set functions are provided for this
// data member.
//
{
public:
ACRX_DECLARE_MEMBERS(AsdkMyClass);
AsdkMyClass(): mIntval(0) {};
AsdkMyClass(const Adesk::Int16& val): mIntval(val) {};
Acad::ErrorStatus getData (Adesk::Int16&);
Acad::ErrorStatus setData (Adesk::Int16);
virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler*);
virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler*)
const;
virtual Acad::ErrorStatus dxfInFields (AcDbDxfFiler*);
virtual Acad::ErrorStatus dxfOutFields(AcDbDxfFiler*)
const;
private:
Adesk::Int16 mIntval;
};
Файлы Заголовка
Следующие файлы заголовка должны быть включены в источник ObjectARX-приложения file:
Adesk.h |
Содержит стандартные определения для среды программы ObjectARX. | ||
Rxdefs.h |
Устанавливает ObjectARX-приложение и взаимодействует с AutoCAD через acrxEntryPoint (). | ||
Adslib.h |
Устанавливает платформа-определенные определения и включает adscodes.h и ads.h. | ||
Adscodes.h |
Содержит определения значений кода, которые возвращены (или проходят к) библиотечные функции ADS. | ||
Ads.h |
Содержит определения типов библиотеки ADS и функциональные объявления. Следующие файлы заголовка могут быть включены в исходные файлы ObjectARX-приложения: | ||
Adsdlg.h |
Содержит Контроль Диалога Связанные языком объявления для создания диалоговых окон. | ||
Ol_errno.h |
Содержит символические коды для значений ошибки, используемых переменной системы AutoCAD ERRNO. | ||
Adsdef.h |
Устанавливает определения для среды программы ADS. |
Adslib.h файл заголовка содержит директивы для включения adscodes.h, adsdef.h, и ads.h; поэтому, прикладной исходный файл должен содержать только следующую директиву:
#include "Adslib.h"
ObjectARX-приложение не должно включить ol_errno.h, если это не использует символические коды, определенные там, чтобы обработать значение ERRNO. Приложение не должно включить adsdlg.h, если это не создает диалоговые окна.
Фильтр Точки ввода и Пример Монитора
Следующий пример демонстрирует использование фильтров точки ввода и мониторов.
#include "adslib.h"
#include "aced.h’
#include "dbmain.h"
#include "acdbabb.h"
#include "adeskabb.h"
#include "rxregsvc.h"
#include "acgi.h"
#include "acdocman.h"
#include "acedinpt.h"
#include "dbapserv.h"
class IPM : public AcEdInputPointMonitor
{
public:
virtual Acad::ErrorStatus
monitorInputPoint(
// Output. If changedTooltipStr is kTrue, newTooltipString
// has the new ToolTip string in it.
//
bool& appendToTooltipStr,
char*& additionalTooltipString,
// Input/Output
//
AcGiViewportDraw* drawContext,
// Input parameters:
//
AcApDocument* document,
bool pointComputed,
int history,
const AcGePoint3d& lastPoint,
const AcGePoint3d& rawPoint,
const AcGePoint3d& grippedPoint,
const AcGePoint3d& cartesianSnappedPoint,
const AcGePoint3d& osnappedPoint,
AcDb::OsnapMask osnapMasks,
// const AcArray<AcDbCustomOsnapMode>& customOsnapModes
const AcArray<AcDbObjectId>& apertureEntities,
const AcArray< AcDbObjectIdArray,
AcArrayObjectCopyReallocator< AcDbObjectIdArray > >&
nestedPickedEntities,
int gsSelectionMark,
const AcArray<AcDbObjectId>& keyPointEntities,
const AcArray<AcGeCurve3d*>& alignmentPaths,
const AcGePoint3d& computedPoint,
const char* tooltipString);
};
Acad::ErrorStatus
IPM::monitorInputPoint(
// Output. If changedTooltipStr is kTrue, then newTooltipString
// has the new ToolTip string in it.
//
bool& appendToTooltipStr,
char*& additionalTooltipString,
// Input/Output
//
AcGiViewportDraw* pDrawContext,
// Input parameters:
//
AcApDocument* document,
bool pointComputed,
int history,
const AcGePoint3d& lastPoint,
const AcGePoint3d& rawPoint,
const AcGePoint3d& grippedPoint,
const AcGePoint3d& cartesianSnappedPoint,
const AcGePoint3d& osnappedPoint,
AcDb::OsnapMask osnapMasks,
// const AcArray<AcDbCustomOsnapMode>& customOsnapModes
const AcArray<AcDbObjectId>& apertureEntities,
const AcArray< AcDbObjectIdArray,
AcArrayObjectCopyReallocator< AcDbObjectIdArray > >&
nestedPickedEntities,
int gsSelectionMark,
const AcArray<AcDbObjectId>& keyPointEntities,
const AcArray<AcGeCurve3d*>& alignmentPaths,
const AcGePoint3d& computedPoint,
const char* tooltipString)
{
acutPrintf("\nhistory: %d\n", history);
if (pointComputed)
{
acutPrintf(
"rawPoint: %.2f, %.2f, %.2f\n",
rawPoint[0],
rawPoint[1],
rawPoint[2]);
if (history & Acad::eGripped)
acutPrintf(
"grippedPoint: %.2f, %.2f, %.2f\n",
grippedPoint[0],
grippedPoint[1],
grippedPoint[2]);
if (history & Acad::eCartSnapped)
acutPrintf(
"cartesianSnappedPoint: %.2f, %.2f, %.2f\n",
cartesianSnappedPoint[0],
cartesianSnappedPoint[1],
cartesianSnappedPoint[2]);
if (history & Acad::eOsnapped)
{
acutPrintf(
"osnappedPoint: %.2f, %.2f, %.2f\n",
osnappedPoint[0],
osnappedPoint[1],
osnappedPoint[2]);
#define OSMASK_CHECK(x) if (osnapMasks & AcDb:: ## x)
acutPrintf("%s ", #x)
OSMASK_CHECK(kOsMaskEnd);
OSMASK_CHECK(kOsMaskMid);
OSMASK_CHECK(kOsMaskCen);
OSMASK_CHECK(kOsMaskNode);
OSMASK_CHECK(kOsMaskQuad);
OSMASK_CHECK(kOsMaskInt);
OSMASK_CHECK(kOsMaskIns);
OSMASK_CHECK(kOsMaskPerp);
OSMASK_CHECK(kOsMaskTan);
OSMASK_CHECK(kOsMaskNear);
OSMASK_CHECK(kOsMaskQuick);
OSMASK_CHECK(kOsMaskApint);
OSMASK_CHECK(kOsMaskImmediate);
OSMASK_CHECK(kOsMaskAllowTan);
OSMASK_CHECK(kOsMaskDisablePerp);
OSMASK_CHECK(kOsMaskRelCartesian);
OSMASK_CHECK(kOsMaskRelPolar);
#undef OSMASK_CHECK
acutPrintf("\n");
}
acutPrintf("%d apertureEntities: ", apertureEntities.length());
for (int i = 0; i < apertureEntities.length(); i++)
acutPrintf("<%x> ", apertureEntities[i].asOldId());
acutPrintf("\n");
}
else {
acutPrintf("No point computed");
if (history & Acad::eCyclingPt)
acutPrintf(", but new cycling osnap: %.2f, %.2f, %.2f\n",
osnappedPoint[0], osnappedPoint[1], osnappedPoint[2]);
else
acutPrintf(".\n");
}
if (NULL != pDrawContext)
{
pDrawContext->subEntityTraits().setColor(2);
pDrawContext->geometry().circle(rawPoint, 1.0,
AcGeVector3d::kZAxis);
}
else
acutPrintf("ViewportDraw is NULL!\n");
if (history & Acad::eNotDigitizer)
acutPrintf("PICK!\n");
if (NULL != tooltipString)
{
acutPrintf("TooltipString: %s\n", tooltipString);
additionalTooltipString = ", anotherString!";
appendToTooltipStr = true;
}
if (history & Acad::eOrtho)
{
acutPrintf("Ortho found at %.2f, %.2f, %.2f\n",
computedPoint[0], computedPoint[1], computedPoint[2]);
}
return Acad::eOk;
}
class IPF : public AcEdInputPointFilter {
public:
Acad::ErrorStatus
processInputPoint(
bool& changedPoint,
AcGePoint3d& newPoint,
bool& changedTooltipStr,
char*& newTooltipString,
bool& retry,
AcGiViewportDraw* pDrawContext,
AcApDocument* document,
bool pointComputed,
int history,
const AcGePoint3d& lastPoint,
const AcGePoint3d& rawPoint,
const AcGePoint3d& grippedPoint,
const AcGePoint3d& cartesianSnappedPoint,
const AcGePoint3d& osnappedPoint,
AcDb::OsnapMask osnapMasks,
// const AcArray<AcDbCustomOsnapMode>& customOsnapModes
const AcArray<AcDbObjectId>& pickedEntities,
const AcArray< AcDbObjectIdArray,
AcArrayObjectCopyReallocator< AcDbObjectIdArray > >&
nestedPickedEntities,
// Of 0th element in pickedEntities.
int gsSelectionMark,
// AutoSnap Info:
const AcArray<AcDbObjectId>& keyPointEntities,
const AcArray<AcGeCurve3d*>& alignmentPaths,
const AcGePoint3d& computedPoint,
const char* tooltipString);
};
Acad::ErrorStatus
IPF::processInputPoint(
bool& changedPoint,
AcGePoint3d& newPoint,
bool& changedTooltipStr,
char*& newTooltipString,
bool& retry,
AcGiViewportDraw* pDrawContext,
AcApDocument* document,
bool pointComputed,
int history,
const AcGePoint3d& lastPoint,
const AcGePoint3d& rawPoint,
const AcGePoint3d& grippedPoint,
const AcGePoint3d& cartesianSnappedPoint,
const AcGePoint3d& osnappedPoint,
// const AcArray<AcDbCustomOsnapMode>& customOsnapModes
const AcArray<AcDbObjectId>& pickedEntities,
const AcArray< AcDbObjectIdArray,
AcArrayObjectCopyReallocator< AcDbObjectIdArray > >&
nestedPickedEntities,
// Of 0th element in pickedEntities.
int gsSelectionMark,
// AutoSnap Info:
const AcArray<AcDbObjectId>& keyPointEntities,
const AcArray<AcGeCurve3d*>& alignmentPaths,
const AcGePoint3d& computedPoint,
const char* tooltipString)
{
// Change the computed point to an offset of (0.2, 0.2, 0.2)
// if the current computed point is an object snap point.
//
if (pointComputed && history & Acad::eOsnapped)
{
changedPoint = true;
newPoint = osnappedPoint + AcGeVector3d(0.2,0.2,0.0);
pDrawContext->geometry().circle(newPoint, 0.1,
AcGeVector3d::kZAxis);
}
return Acad::eOk;
}
// Input point monitor
IPM my_ipm;
// Input point filter
IPF my_ipf;
// Installs an input point monitor.
//
void testipm()
{
curDoc()->inputPointManager()->addPointMonitor(&my_ipm);
}
// Installs an input point filter.
//
void testipf()
{
curDoc()->inputPointManager()->registerPointFilter(&my_ipf);
}
// Turns on forced entity picking.
//
void testfp()
{
curDoc()->inputPointManager()->turnOnForcedPick();
}
// Disables the system cursor graphics.
//
void testcursor()
{
curDoc()->inputPointManager()->disableSystemCursorGraphics();
}
extern "C" __declspec(dllexport)
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void *p)
{
switch (msg)
{
case AcRx::kInitAppMsg:
acrxRegisterAppMDIAware(p);
acrxUnlockApplication(p);
acedRegCmds->addCommand("mkr", "testipm", "ipm",
ACRX_CMD_TRANSPARENT, testipm);
acedRegCmds->addCommand("mkr", "testipf", "ipf",
ACRX_CMD_TRANSPARENT, testipf);
acedRegCmds->addCommand("mkr", "testfp", "fp",
ACRX_CMD_TRANSPARENT, testfp);
acedRegCmds->addCommand("mkr", "testcursor", "cursor",
ACRX_CMD_TRANSPARENT, testcursor);
break;
case AcRx::kUnloadAppMsg:
acedRegCmds->removeGroup("mkr");
break;
}
return AcRx::kRetOK;
}
Фильтрация для Расширенных Данных
Расширенные данные (xdata) - текстовые строки, числовые значения, трехмерные точки, расстояния, названия уровня, или другие данные, приложенные к объекту, типично внешним приложением.
Размер расширенных данных - байты 16КБ.
Вы можете отыскивать расширенные данные для специфического приложения, определяя его имя в списке фильтра, используя -3 код группы. AcedSSGet () функциональные примитивы возвращений с расширенными данными, зарегистрированными к указанному имени; acedSSGet () не отыскивает индивидуума, расширил элементы данных (с кодами группы в диапазоне 1000-2000).
Следующий типовой кодовый фрагмент выбирает все круги, которые расширили данные, зарегистрированные на приложение, чей ИДЕНТИФИКАТОР - “APPNAME”.
eb1.restype = 0; // Entity type
strcpy(sbuf1, "CIRCLE");
eb1.resval.rstring = sbuf1; // Circle
eb1.rbnext = &eb2;
eb2.restype = -3; // Extended data
eb2.rbnext = &eb3;
eb3.restype = 1001;
strcpy(sbuf2, "APPNAME");
eb3.resval.rstring = sbuf2; // APPNAME application
eb3.rbnext = NULL;
// Select circles with XDATA registered to APPNAME.
acedSSGet("X", NULL, NULL, &eb1, ssname1);
Если больше чем одно прикладное имя включены в список, acedSSGet () включает примитив в выбор, устанавливают только, если это расширило{*продлило*} данные для всех указанных приложений. Например, следующий код выбирает круги расширенными{*продленными*} данными, зарегистрированными к “APP1” и “APP2”.
eb1.restype = 0; // Entity type
strcpy(sbuf1, "CIRCLE");
eb1.resval.rstring = sbuf1; // Circle
eb1.rbnext = &eb2;
eb2.restype = -3; // Extended data
eb2.rbnext = &eb3;
eb3.restype = 1001;
strcpy(sbuf2, "APP1");
eb2.resval.rstring = sbuf2; // APP1 application
eb2.rbnext = &eb4;
eb4.restype = 1001; // Extended data
strcpy(sbuf3, "APP2");
eb4.resval.rstring = sbuf3; // APP2 application
eb4.rbnext = NULL;
// Select circles with XDATA registered to APP1 & APP2.
acedSSGet("X", NULL, NULL, &eb1, ssname1);
Вы можете определить прикладные названия, использующие строки подстановочных знаков, так что Вы можете искать данные множественных приложений в одно время. Например, следующий код выбирает все круги расширенными данными, зарегистрированными к “APP1” или “APP2” (или оба).
eb1.restype = 0; // Entity type
strcpy(sbuf1, "CIRCLE");
eb1.resval.rstring = sbuf1; // Circle
eb1.rbnext = &eb2;
eb2.restype = -3; // Extended data
eb2.rbnext = &eb3;
eb3.restype = 1001; // Extended data
strcpy(sbuf2, "APP1,APP2");
eb3.resval.rstring = sbuf2; // Application names
eb3.rbnext = NULL;
// Select circles with XDATA registered to APP1 or APP2.
acedSSGet("X", NULL, NULL, &eb1, ssname1);
Следующая строка находит расширенные данные того же самого приложения.
strcpy(sbuf2, "APP[12]");
Фильтрация Точки ввода
Фильтры Точки ввода вызваны для всей строки и событий цифрового преобразователя, когда точка приобретается. Они могут изменять конечную позицию точки, возвращенную вызывающей программе в соответствии с AutoCAD и ToolTip
строкой, отображенной в соответствии с AutoCAD.
Фильтры Точки ввода обработаны перед любыми мониторами точки ввода, но в конце концов другие вычисления точки ввода выполнены в соответствии с AutoCAD. Точки вывода все еще подчиненны к AutoCAD XYZ
фильтрация точки.
ОБРАТИТЕ ВНИМАНИЕ Только на один фильтр точки ввода, может быть активен одновременно.
Фильтры точки ввода и мониторы
Фильтры точки ввода и мониторы позволяют Вам рассматривать и изменять входные данные, поскольку точки приобретаются в AutoCAD. Фильтры Точки ввода и мониторы контекстно-зависимы и если только быть зарегистрированными для уместных контекстов ввода.
Следующая диаграмма показывает, как фильтрация точки ввода и контроль вписываются в ввод ObjectARX обработка модели:
Формирование ADS приложения в среде ObjectARX
Приложения ADS осуществлены под ObjectARX как DLLs и имеют заданное по умолчанию расширение файла .arx. Для команд при формировании приложений ADS в среде программы ObjectARX, см. AutoCAD readdev.hlp файл.
Процедура, описанная в AutoCAD readdev.hlp файл для отладки приложений ADS в среде программы ADS также применяется в среде программы ObjectARX.
Формирование цепочки Фильтра
AcEdInputPointFilter класс обеспечивает функцию члена, чтобы поддержать последовательные фильтры точки ввода. Так как только один фильтр может быть активен одновременно, эта функция позволяет Вам сделать запрос текущего фильтра, внедрять, который просачивается ваш заказной фильтр, и затем отменяет текущий фильтр и регистрируется ваш собственный. Следующая функция обеспечивает последовательные функциональные возможности:
AcEdInputFilter *
AcEdInputPointFilter::revokeFilter(AcEdInputPointFilter *);
Формирование и Регистрация COM DLL
Файл системного реестра, который описывает ваше приложение, библиотеку типов, и объекты Automation, должен быть объединен в системный реестр системы Windows прежде, чем компоненты в вашем DLL будут доступны. Некоторые дополнительные шаги требованы, чтобы связать успешно COM DLL и отдельное ObjectARX-приложение.
Готовить COM DLL, который является отдельным от ObjectARX-приложения
1 Формируют COM DLL.
2 Добавляют любые украшенные названия символа, которые появляются по ошибкам компоновщика как нерешенные внешние символы к секции Экспорта ObjectARX файла DEF.
3 Восстанавливают ObjectARX-приложение.
4 В COM DLL, выберите Назначения из меню Project.
5 На позиции табуляции Link, добавьте библиотеку для вашего ObjectARX-приложения.
6 Выбирают OK.
7 Продолжают шаги ниже, чтобы формировать и регистрировать ваш COM DLL.
Формирование Иерархии Монопольных использований
Следующий пример иллюстрирует, как формировать иерархию монопольных использований, используя функции ObjectARX. Пример показывает заголовку и исходным файлам для нового класса, OwnerDemo, который иллюстрирует, как создать дерево монопольных использований. Этот класс имеет два компонента данных, простое целое число, чтобы представить нормальные данные, и жесткое монопольное использование компонент данных ИДЕНТИФИКАТОРА, чтобы провести{*держать*} объект ID находящегося в собственности объекта. Функции
Обеспечиваются для получения и установки значений обоих компонентов данных.
Пример также отменяет четыре требуемых виртуальных функции:
dwgInFields(), dwgOutFields(), dxfInFields(), и dxfOutFields().
Иерархия монопольных использований установлена в createObjs () подпрограмма к концу примера. Объект имеет объект B. Объект B имеет объект C. Объект добавлен к словарю (ASDK_DICT) в названном объектном словаре. printOut() и listTree () подпрограммы печатает информацию относительно объектов в ASDK_DICT словаре.
ObjectARX Example
// Class declarations
//
class AsdkOwnerDemo : public AcDbObject
// This is a custom object class to demonstrate what is
// necessary to create ownership trees.
//
// To keep it simple, this class has two data members: a
// simple integer to represent normal data, and a hard
// ownership ID data member to hold the object ID of an owned
// object.
//
// Get and set functions are provided for both data members.
//
{
public:
ACRX_DECLARE_MEMBERS(AsdkOwnerDemo);
AsdkOwnerDemo(): mIntval(0) {};
AsdkOwnerDemo(const Adesk::Int16& val): mIntval(val) {};
Adesk::Int16 intData();
Acad::ErrorStatus setIntData(const Adesk::Int16&);
AcDbHardOwnershipId idData();
Acad::ErrorStatus setIdData(const AcDbHardOwnershipId&);
Acad::ErrorStatus dwgInFields (AcDbDwgFiler*);
Acad::ErrorStatus dwgOutFields(AcDbDwgFiler*) const;
Acad::ErrorStatus dxfInFields (AcDbDxfFiler*);
Acad::ErrorStatus dxfOutFields(AcDbDxfFiler*) const;
private:
Adesk::Int16 mIntval;
AcDbHardOwnershipId mObjId;
};
ACRX_DXF_DEFINE_MEMBERS(AsdkOwnerDemo, AcDbObject,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0,
ASDKOWNERDEMO, OWNERSHIP);
// Gets the value of the integer data member.
//
Adesk::Int16
AsdkOwnerDemo::intData()
{
assertReadEnabled();
return mIntval;
}
// Sets the value of the integer data member.
//
Acad::ErrorStatus
AsdkOwnerDemo::setIntData(const Adesk::Int16& val)
{
assertWriteEnabled();
mIntval = val;
return Acad::eOk;
}
// Returns a copy of the ownership ID data member.
//
AcDbHardOwnershipId
AsdkOwnerDemo::idData()
{
assertReadEnabled();
return mObjId;
}
// Sets the value of the ownership ID data member.
//
Acad::ErrorStatus
AsdkOwnerDemo::setIdData(const AcDbHardOwnershipId& ownedId)
{
if (ownedId.asOldId() == 0L) {
return Acad::eInvalidInput;
}
assertWriteEnabled();
mObjId = ownedId;
// Now set the backpointer. A transaction is used for
// opening the object, so if the object is already
// open it won’t prevent this setting from taking place.
//
AcDbObject *pObj;
AcTransaction *pTrans
= actrTransactionManager->startTransaction();
pTrans->getObject(pObj, ownedId, AcDb::kForWrite);
pObj->setOwnerId(objectId());
actrTransactionManager->endTransaction();
return Acad::eOk;
}
// Files data in from a DWG file.
//
Acad::ErrorStatus
AsdkOwnerDemo::dwgInFields(AcDbDwgFiler* filer)
{
assertWriteEnabled();
AcDbObject::dwgInFields(filer);
// For wblock filing we wrote out our owner as a hard
// pointer Id so now we need to read it in to keep things
// in sync.
//
if (filer->filerType() == AcDb::kWblockCloneFiler) {
AcDbHardPointerId id;
filer->readItem(&id);
}
filer->readItem(&mIntval);
filer->readItem(&mObjId);
return filer->filerStatus();
}
// Files data out to a DWG file.
//
Acad::ErrorStatus
AsdkOwnerDemo::dwgOutFields(AcDbDwgFiler* filer) const
{
assertReadEnabled();
AcDbObject::dwgOutFields(filer);
// Since objects of this class will be in the Named
// Objects Dictionary tree and may be hard referenced
// by some other object, to support wblock we need to
// file out our owner as a hard pointer Id so that it
// will be added to the list of objects to be wblocked
//
if (filer->filerType() == AcDb::kWblockCloneFiler)
filer->writeHardPointerId((AcDbHardPointerId)ownerId());
filer->writeItem(mIntval);
filer->writeItem(mObjId);
return filer->filerStatus();
}
// Files data in from a DXF file.
//
Acad::ErrorStatus
AsdkOwnerDemo::dxfInFields(AcDbDxfFiler* filer)
{
assertWriteEnabled();
Acad::ErrorStatus es;
if ((es = AcDbObject::dxfInFields(filer)) != Acad::eOk)
{
return es;
}
// Check if we’re at the right subclass data marker.
//
if (!filer->atSubclassData("AsdkOwnerDemo")) {
return Acad::eBadDxfSequence;
}
struct resbuf inbuf;
while (es == Acad::eOk) {
if ((es = filer->readItem(&inbuf)) == Acad::eOk) {
if (inbuf.restype == AcDb::kDxfInt16) {
mIntval = inbuf.resval.rint;
} else if (inbuf.restype == AcDb::kDxfHardOwnershipId)
{
acdbGetObjectId(mObjId,
inbuf.resval.rlname);
}
}
}
return filer->filerStatus();
}
// Files data out to a DXF file.
//
Acad::ErrorStatus
AsdkOwnerDemo::dxfOutFields(AcDbDxfFiler* filer) const
{
assertReadEnabled();
AcDbObject::dxfOutFields(filer);
filer->writeItem(AcDb::kDxfSubclass, "AsdkOwnerDemo");
filer->writeItem(AcDb::kDxfInt16, mIntval);
// Null object IDs are invalid: don’t write them out.
//
if (mObjId.asOldId() != 0L) {
filer->writeItem(AcDb::kDxfHardOwnershipId, mObjId);
}
return filer->filerStatus();
}
// Creates an AsdkOwnerDemo object (pObjC) and adds data to
// it. Then, AsdkOwnerDemo pObjC is created and set to be
// the owner of pObjC. Next, AsdkOwnerDemo pObjA is created
// and set to own pObjB. Finally, pObjA is added to a
// dictionary in the named object dictionary. Technically,
// we could just add pObjA to the named object dictionary
// itself, but that’ s not appropriate because it would clutter
// up the named object dictionary.
//
void
createObjs()
{
AcDbObjectId objIdA, objIdB, objIdC;
AcDbDictionary *pNamedobj;
AcDbDictionary *pDict = NULL;
AcDbDatabase *pCurDwg = acdbHostApplicationServices()->workingDatabase();
// Create object C with a dummy integer data value of 3.
//
AsdkOwnerDemo *pObjC = new AsdkOwnerDemo(3);
// Append object C to database without setting an owner.
//
pCurDwg->addAcDbObject(objIdC, pObjC);
pObjC->close();
// Create object B with a dummy integer data value of 2.
//
AsdkOwnerDemo *pObjB = new AsdkOwnerDemo(2);
// Append object B to the database without setting an owner.
//
pCurDwg->addAcDbObject(objIdB, pObjB);
// Now set up ownership for object C. The
// AsdkOwnerDemo::setIdData() function takes the
// objectId parameter and copies it into the
// AcDbHardOwnershipId data member. This places the
// object ID in a position to be filed out/in via the
// dwgInFields/dwgOutFields/dxfInFields/dxfOutFields
// member functions. This constitutes primary
// "ownership." The AsdkOwnerDemo::setIdData() function
// also calls each owned object’s setOwnerId() member
// function to set the backpointer and establish the
// full two-way ownership link.
//
pObjB->setIdData(objIdC);
pObjB->close();
// Create object A with a dummy integer data value of 1.
//
AsdkOwnerDemo *pObjA = new AsdkOwnerDemo(1);
// Next, add objA to a dictionary in the named object
// dictionary. This will establish ownership for objA,
// set the ownership backlink, and add it to the
// database.
//
pCurDwg->getNamedObjectsDictionary(pNamedobj, AcDb::kForWrite);
// Get a pointer to the ASDK_DICT dictionary. If it
// doesn’t exist, then create it and add it to the
// named object dictionary.
//
if (pNamedobj->getAt("ASDK_DICT", (AcDbObject*&) pDict,
AcDb::kForWrite) == Acad::eKeyNotFound)
{
pDict = new AcDbDictionary;
AcDbObjectId DictId;
pNamedobj->setAt("ASDK_DICT", pDict, DictId);
}
pNamedobj->close();
// Add object A to the ASDK_DICT dictionary.
//
pDict->setAt("OBJA", pObjA, objIdA);
pDict->close();
// Now set up ownership for object B.
//
pObjA->setIdData(objIdB);
pObjA->close();
}
// The list tree function runs through all objects in the
// ASDK_DICT dictionary, follows their ownership trees, and
// lists out information on all objects in the tree.
//
void
listTree()
{
AcDbDictionary *pNamedobj;
AcDbDictionary *pDict;
acdbHostApplicationServices()->workingDatabase()
->getNamedObjectsDictionary(pNamedobj, AcDb::kForWrite);
// Get a pointer to the ASDK_DICT dictionary.
//
pNamedobj->getAt("ASDK_DICT",(AcDbObject*&)pDict,
AcDb::kForRead);
pNamedobj->close();
// Run through the entries and list their backpointers.
//
AcDbDictionaryIterator *pDictItr = pDict->newIterator();
for (; !pDictItr->done(); pDictItr->next()) {
printOut(pDictItr->objectId());
}
pDict->close();
}
// Recursively walks down an ownership tree of AsdkOwnerDemo
// class objects, printing out information on each one.
//
void
printOut(AcDbObjectId id)
{
AsdkOwnerDemo *pDemo;
acdbOpenObject((AcDbObject*&)pDemo, id, AcDb::kForRead);
acutPrintf("\nIntdata: %d ObjId: %ld Backpointer:"
" %ld OwnedObj: %ld", pDemo->intData(),
(pDemo->objectId()).asOldId(),
(pDemo->ownerId()).asOldId(),
(pDemo->idData()).asOldId());
// Recursive tree walk
//
if ((pDemo->idData()).asOldId() != 0L) {
printOut(pDemo->idData());
}
pDemo->close();
}
// The initialization function is called from acrxEntryPoint()
// during kInitAppMsg case. This function is used to add commands
// to the command stack and to add classes to the ACRX class
// hierarchy.
//
void
initApp()
{
acedRegCmds->addCommand("ASDK_OWNERSHIP_COMMANDS",
"ASDK_CREATE", "CREATE",ACRX_CMD_MODAL, createObjs);
acedRegCmds->addCommand("ASDK_OWNERSHIP_COMMANDS",
"ASDK_LISTREE", "LISTREE",ACRX_CMD_MODAL, listTree);
AsdkOwnerDemo::rxInit();
acrxBuildClassHierarchy();
}
// The clean up function is called from acrxEntryPoint() during the
// kUnloadAppMsg case. This function removes this application’s
// command set from the command stack and the
// AsdkOwnerDemo class from the ARX runtime class tree.
//
void
unloadApp()
{
acedRegCmds->removeGroup("ASDK_OWNERSHIP_COMMANDS");
// Remove the AsdkOwnerDemo class from the ACRX runtime
// class hierarchy. If this is done while the database is
// still active, it should cause all objects of class
// AsdkOwnerDemo to be turned into proxies.
//
deleteAcRxClass(AsdkOwnerDemo::desc());
}
// ObjectARX entry point
//
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 поддерживает развитие комплексных приложений, обеспечивая следующие возможности:
·
уведомление
· управление Транзакции
· Глубоко имитирующий
· редактирование Ссылки(справочников)
· расширение Протокола
· поддержка Proxy-объекта
· Взаимодействие с другими средами
ObjectARX приложения может связываться с другими интерфейсами программирования, типа VLisp, ActiveX, и COM. Кроме того, ObjectARX приложения могут взаимодействовать с Internet связанными с объектами URL, загружая и сохраняя чертежные файлы от WWW.
Формирование Приложения
Приложение, которое использует AcBr библиотеку, должно иметь библиотечный файл, libacbr.dll доступный, чтобы связаться против. Более важно, библиотека необходима, чтобы гарантировать надлежащую регистрацию классов AcBr с ObjectARX во время выполнения. Поэтому важно, что libacbr.dll, быть явно загружено приложением, если это уже не было загружено разработчиком модели или другим приложением. Лучший способ гарантировать это состоял в том, чтобы использовать acrxDynamicLoader () и acrxClassDictionary () чтобы загрузить libacbr.dll и проверять, было ли это загружено.
Следующий кодовый фрагмент обеспечивает пример:
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
switch (msg) {
case AcRx::kInitAppMsg:
if (!acrxClassDictionary->at("AcBrEntity")) {
acrxDynamicLinker->loadModule("libacbr.dll", 1);
acutPrintf("\n libacbr loaded \n");
}
acedRegCmds->addCommand(
"MY_APP",
"MY_CMD",
"MY_CMD",
ACRX_CMD_MODAL,
&myCmdImp);
acrxUnlockApplication(pkt); // try to allow unloading
break;
case AcRx::kUnloadAppMsg:
acedRegCmds->removeGroup("MY_APP");
break;
default:
break;
}
return AcRx::kRetOK;
}
ПРИМЕЧАНИЕ, которое важно не разгрузить libacbr.dll на выход от приложения, как другие приложения (или разработчик модели) может все еще зависеть от его присутствия.
Формировать и регистрировать ваш составляющий сервер
1 Формируют приложение COM.
Сообщение может казаться, указывая, что REGSRVR32 не сумел загружать AutoCAD.
Чтобы устранять это сообщение в будущем, удалите все заказные шаги компоновки для регистрации сервера COM от ваших назначений проекта COM.
2 Создают файл REG для вашего приложения с GUIDS для объекта и библиотеки типов, которые соответствуют в файле IDL.
Файл REG должен регистрировать следующую информацию:
§
имя объекта AcRxClass (так, чтобы GetIUnknownOfObject мог располагать класс)
§ библиотека типов объекта (так, чтобы, когда ATL вызывает LoadRegTypeLib, это будет преуспевать)
§ прикладное имя как сервер для объекта COM с той частностью CLSID (так, чтобы CoCreateInstance () работал правильно)
Следующий пример - файл REG для AsdkSquareWrapper:
REGEDIT
; This .REG file may be used by your SETUP program.
; If a SETUP program is not available, the entries below will be
; registered in your InitInstance automatically with a call to
; CWinApp::RegisterShellFileTypes and
; COleObjectFactory::UpdateRegistryAll.
HKEY_CLASSES_ROOT\TypeLib\{800F70A1-6DE9-11D2-A7A6-0060B0872457}
HKEY_CLASSES_ROOT\TypeLib\{800F70A1-6DE9-11D2-A7A6-0060B0872457}
\1.1 = AsdkSquareLib 1.0 Type Library
HKEY_CLASSES_ROOT\TypeLib\{800F70A1-6DE9-11D2-A7A6-0060B0872457}
\1.1\0\win32=
E:\TEMP\square\AsdkSquareLib\Debug\AsdkSquareLib.dll
HKEY_CLASSES_ROOT\TypeLib\{800F70A1-6DE9-11D2-A7A6-0060B0872457}
\1.1\9\win32 =
E:\TEMP\square\AsdkSquareLib\Debug\AsdkSquareLib.dll
HKEY_CLASSES_ROOT\CLSID\{800F70AE-6DE9-11D2-A7A6-0060B0872457} =
AsdkSquareWrapper Class
HKEY_CLASSES_ROOT\CLSID\{800F70AE-6DE9-11D2-A7A6-0060B0872457}
\InProcServer32 =
E:\TEMP\square\AsdkSquareLib\Debug\AsdkSquareLib.dll
HKEY_CLASSES_ROOT\Interface\{800F70AD-6DE9-11D2-A7A6-0060B0872457}
= IAsdkSquareWrapper Interface
HKEY_CLASSES_ROOT\Interface\{800F70AD-6DE9-11D2-A7A6-0060B0872457}
\TypeLib = {E3D2C633-69C9-11D2-A7A2-0060B0872457}
HKEY_CLASSES_ROOT\Interface\{800F70AD-6DE9-11D2-A7A6-0060B0872457}
\ProxyStubClsid32 = {00020424-0000-0000-C000-000000000046}
3 Выполненный файл РЕДЖА от Проводника.
Функции Данных Примитива
Некоторые функции работают на данных примитива и могут использоваться, чтобы изменить базу данных текущего рисунка. AcdbEntDel () функция удаляет указанный примитив. Примитив не очищен от базы данных, пока Вы не оставляете текущий рисунок.
Так, если приложение вызывает acdbEntDel () второй раз в течение того сеанса и определяет тот же самый примитив, примитив восстановлен. (Вы можете использовать acdbHandEnt () чтобы восстановить{*отыскать*} названия{*имена*} удаленных примитивов.)
ОБРАТИТЕ ВНИМАНИЕ На использование acdbEntDel (), атрибуты, и вершина ломаной линии не может быть удалена независимо от их родительских примитивов; acdbEntDel () работает только на основных примитивах. Чтобы удалять атрибут или вершину, используйте acedCommand () или acedCmd () чтобы вызвать AutoCAD ATTEDIT или команды PEDIT, используйте acdbEntMod () чтобы переопределить примитив без нежелательных подпримитивов, или откройте вершину, или припишите, и используйте ее стирание () метод стереть это.
AcdbEntGet () функция возвращает данные определения указанного примитива.
Данные возвращены как список связей буферов результатов. Тип каждого элемента (буфер) в списке определен кодом группы DXF. Первый элемент в списке содержит текущее имя примитива (restype == -1).
ObjectARX-приложение могло отыскивать и печатать данные определения для примитива, используя следующий две функции. (Printdxf () функция не обрабатывает расширенные данные.)
void getlast()
{
struct resbuf *ebuf, *eb;
ads_name ent1;
acdbEntLast(ent1);
ebuf = acdbEntGet(ent1);
eb = ebuf;
acutPrintf("\nResults of entgetting last entity\n");
// Print items in the list.
for (eb = ebuf; eb != NULL; eb = eb->rbnext)
printdxf(eb);
// Release the acdbEntGet() list.
acutRelRb(ebuf);
}
int printdxf(eb)
struct resbuf *eb;
{
int rt;
if (eb == NULL)
return RTNONE;
if ((eb->restype >= 0) && (eb->restype <= 9))
rt = RTSTR ;
else if ((eb->restype >= 10) && (eb->restype <= 19))
rt = RT3DPOINT;
else if ((eb->restype >= 38) && (eb->restype <= 59))
rt = RTREAL ;
else if ((eb->restype >= 60) && (eb->restype <= 79))
rt = RTSHORT ;
else if ((eb->restype >= 210) && (eb->restype <= 239))
rt = RT3DPOINT ;
else if (eb->restype < 0)
// Entity name (or other sentinel)
rt = eb->restype;
else
rt = RTNONE;
switch (rt) {
case RTSHORT:
acutPrintf("(%d . %d)\n", eb->restype,
eb->resval.rint);
break;
case RTREAL:
acutPrintf("(%d . %0.3f)\n", eb->restype,
eb->resval.rreal);
break;
case RTSTR:
acutPrintf("(%d . \"%s\")\n", eb->restype,
eb->resval.rstring);
break;
case RT3DPOINT:
acutPrintf("(%d . %0.3f %0.3f %0.3f)\n",
eb->restype,
eb->resval.rpoint[X], eb->resval.rpoint[Y],
eb->resval.rpoint[Z]);
break;
case RTNONE:
acutPrintf("(%d . Unknown type)\n", eb->restype);
break;
case -1:
case -2:
// First block entity
acutPrintf("(%d . <Entity name: %8lx>)\n", eb->restype, eb->resval.rlname[0]);
}
return eb->restype;
}
В следующем примере, следующие (заданные по умолчанию) условия{*состояния*} обращаются к текущему рисунку.
§ текущий уровень - 0
§ linetype - НЕПРЕРЫВЕН
§ текущее повышение - 0
§ маркеры примитива заблокированы
Также, пользователь рисовал линию со следующей последовательностью команд:
Command: line
From point: 1,2
To point: 6,6
To point: ENTER
Тогда запрос к getlast () печатал бы следующий (значение имени изменится).
Результат выполнения acdbEntGet () для последнего примитива:
(-1 . <Entity name: 60000014>)
(0 . "LINE")
(8 . "0")
(10 1.0 2.0 0.0)
(11 6.0 6.0 0.0)
(210 0.0 0.0 1.0)
ОБРАТИТЕ ВНИМАНИЕ На printdxf () функция печатает вывод в формате ассоциативного списка AutoLISP, но элементы сохранены в списке связей буферов результатов.
Буфер результатов в начале списка (с -1 кодом стража) содержит имя примитива, который этот список представляет. AcdbEntMod () функциональные использования это, чтобы идентифицировать примитив, который нужно изменить.
Коды для компонентов примитива (сохраненный в restype поле) - используемые DXF. Как с DXF, элементы заголовка примитива возвращены только, если они имеют значения другие чем значение по умолчанию. В отличие от DXF, необязательные поля определения примитива возвращены независимо от того, равняются ли они их значениям по умолчанию. Это упрощает обработку; приложение может всегда предполагать, что эти поля присутствуют. Также в отличие от DXF, связанного X, Y, и координат Z возвращены как одиночная переменная точки (resval.rpoint), не как отдельный X (10), Y (20), и Z (30) групп. Значение restype содержит номер группы координаты X (в диапазоне 10-19).
Чтобы находить группу с определенным кодом, приложение может пересекать список. Entitem () функция, показанная здесь ищет список буфера результата группу указанного типа.
static struct resbuf *entitem(rchain, gcode)
struct resbuf *rchain;
int gcode;
{
while ((rchain != NULL) && (rchain->restype != gcode))
rchain = rchain->rbnext;
return rchain;
}
Если код группы DXF, указанный gcode параметром - не подарок{*настоящее*} в списке (или если gcode - не, правильная{*допустимая*} группа DXF), entitem () “ уменьшается конец ” и возвращает NULL. Обратите внимание, что entitem () эквивалентен функции AutoLISP (assoc).
AcdbEntMod () функция изменяет примитив. Это передает список, который имеет тот же самый формат как список, возвращенный acdbEntGet (), но с некоторыми из значений группы примитива (возможно) изменяемых приложением. Эти функциональные дополнения acdbEntGet (); первичные средства, которыми ObjectARX-приложение модифицирует базу данных - восстанавливая{*отыскивая*} примитив с acdbEntGet (), изменяя его список примитива, и затем пропуская список назад к базе данных с acdbEntMod ().
ОБРАТИТЕ ВНИМАНИЕ, чтобы восстановить значение по умолчанию цвета примитива или linetype, использовать acdbEntMod () чтобы установить цвет в 256, который является BYLAYER, или linetype к BYLAYER.
Следующий кодовый фрагмент отыскивает данные определения первого примитива в рисунке, и изменяет его свойство уровня к MYLAYER.
ads_name en;
struct resbuf *ed, *cb;
char *nl = "MYLAYER";
if (acdbEntNext(NULL, en) != RTNORM)
return BAD; // Error status
ed = acdbEntGet(en); // Retrieve entity data.
for (cb = ed; cb != NULL; cb = cb->rbnext)
if (cb->restype == 8) { // DXF code for Layer
// Check to make sure string buffer is long enough.
if (strlen(cb->resval.rstring) < (strlen(nl)))
// Allocate a new string buffer.
cb->resval.rstring = realloc(cb->resval.rstring,
strlen(nl) + 1);
strcpy(cb->resval.rstring, nl);
if (acdbEntMod(ed) != RTNORM) {
acutRelRb(ed);
return BAD; // Error
}
break; // From the for loop
}
acutRelRb(ed); // Release result buffer.
Управление памятью - ответственность ObjectARX-приложения.
Код в примере гарантирует, что строковый буфер - правильный размер, и это выпускает буфер результатов, возвращенный acdbEntGet () (и прошло к acdbEntMod ()) как только операция закончена, действительно ли запрос к acdbEntMod () преуспевает.
ОБРАТИТЕ ВНИМАНИЕ, используете ли Вы acdbEntMod () чтобы изменить примитив на блочном определении, это воздействует на всю ВСТАВКУ или XREF к тому блоку; также, примитивы на блочных определениях не могут быть удалены acdbEntDel ().
Приложение может также добавлять примитив к базе данных рисунка, вызывая acdbEntMake () функция. Подобно acdbEntMod (), параметр к acdbEntMake () - список буфера результата, чей формат подобен таковому списка, возвращенного acdbEntGet (). (AcdbEntMake () запрос игнорирует поле имени примитива [-1], если это присутствует.) новый примитив добавлен в конец к базе данных рисунка (это становится последним{*прошлым*} примитивом в рисунке). Если примитив - сложный примитив (ломаная линия или блок), это не добавлено в конец к базе данных, пока это не закончено.
Следующий типовой кодовый фрагмент создает круг на уровне MYLAYER.
int status;
struct resbuf *entlist;
ads_point center = {5.0, 7.0, 0.0};
char *layer = "MYLAYER";
entlist = acutBuildList(RTDXF0, "CIRCLE",// Entity type
8, layer, // Layer name
10, center, // Center point
40, 1.0, // Radius
0 );
if (entlist == NULL) {
acdbFail("Unable to create result buffer list\n");
return BAD;
}
status = acdbEntMake(entlist);
acutRelRb(entlist); // Release acdbEntMake buffer.
if (status == RTERROR) {
acdbFail("Unable to make circle entity\n");
return BAD;
}
И acdbEntMod () и acdbEntMake () исполняют, те же самые проверки последовательности на данных примитива прошли к ним, поскольку команда DXFIN AutoCAD исполняет при чтении DXF файлы. Они терпят неудачу, если они не могут создавать правильные{*допустимые*} примитивы рисунка.
Функции Имени Примитива
Чтобы работать на примитиве, ObjectARX-приложение должно получить его имя для использования в последующем, вызывает{*звонит*} к функциям данных примитива или функциям набора выбора.
Функции acedEntSel (), acedNEntSelP (), и acedNEntSel () возвращение не только имя примитива но и дополнительная информация для использования приложения. Функции entsel требуют пользователей AutoCAD (или приложение) чтобы выбрать примитив, определяя точку на графическом экране; все другие функции имени примитива могут восстановить{*отыскивать*} примитив, даже если это не видимо на экране или находится на закрепляемом уровне. Подобно acedGetxxx () функции, Вы можете иметь acedEntSel (), acedNEntSelP (), и acedNEntSel () возвращают ключевое слово вместо точки, предшествуя им с запросом к acedInitGet ().
Если запрос к acedEntSel (), acedNEntSelP (), или acedNEntSel () возвращает RTERROR, и Вы хотите знать, определил ли пользователь точку, которая не имела никакого примитива или нажал ли пользователь ВОЗВРАЩЕНИЕ, Вы можете осматривать значение ERRNO системной переменной. Если пользователь определил, пустая точка, ERRNO равняется 7 (OL_ENTSELPICK). Если пользователь нажал ВОЗВРАЩЕНИЕ, ERRNO равняется 52 (OL_ENTSELNULL). (Вы можете использовать символические названия{*имена*}, если ваша программа включает файл заголовка.)
ПРИМЕЧАНИЕ Вы должно осмотреть ERRNO немедленно после acedEntSel (), acedNEntSelP (), или acedNEntSel () возвращения. Последующий запрос ObjectARX может изменять{*заменять*} значение ERRNO.
AcdbEntNext () функция восстанавливает{*отыскивает*} названия{*имена*} примитива последовательно. Если его первый параметр - NULL, это возвращает имя первого примитива в базе данных рисунка; если его первый параметр - имя примитива в текущем рисунке, это возвращает имя преуспевающего примитива.
Следующий типовой кодовый фрагмент иллюстрирует, как acedSSAdd () может использоваться вместе с acdbEntNext () чтобы создать наборы выбора и добавлять членов к существующему набору.
Ads_name ss, e1, e2;
// Set e1 to the name of first entity.
if (acdbEntNext(NULL, e1) != RTNORM) {
acdbFail("No entities in drawing\n");
return BAD;
}
// Set ss to a null selection set.
acedSSAdd(NULL, NULL, ss);
// Return the selection set ss with entity name e1 added.
if (acedSSAdd(e1, ss, ss) != RTNORM) {
acdbFail("Unable to add entity to selection set\n");
return BAD;
}
// Get the entity following e1.
if (acdbEntNext(e1, e2) != RTNORM) {
acdbFail("Not enough entities in drawing\n");
return BAD;
}
// Add e2 to selection set ss
if (acedSSAdd(e2, ss, ss) != RTNORM) {
acdbFail("Unable to add entity to selection set\n");
return BAD;
}
Следующий типовой кодовый фрагмент использует acdbEntNext () чтобы “идти” через базу данных, один примитив одновременно.
ads_name ent0, ent1;
struct resbuf *entdata;
if (acdbEntNext(NULL, ent0) != RTNORM) {
acdbFail("Drawing is empty\n");
return BAD;
}
do {
// Get entity’s definition data.
entdata = acdbEntGet(ent0);
if (entdata == NULL) {
acdbFail("Failed to get entity\n");
return BAD;
}
.
. // Process new entity.
.
if (acedUsrBrk() == TRUE) {
acdbFail("User break\n");
return BAD;
}
acutRelRb(entdata); // Release the list.
ads_name_set(ent0, ent1); // Bump the name.
} while (acdbEntNext(ent1, ent0) == RTNORM);
ПРИМЕЧАНИЕ Вы можете также пройти базу данных, “наталкиваясь” одиночная переменная в acdbEntNext () запрос (типа acdbEntNext (ent0, ent0)), но если Вы делаете, значение переменной, больше не определено однажды цикл концы.
AcdbEntLast () функция отыскивает имя последнего примитива в базе данных. Последний примитив - наиболее недавно созданный основной примитив, так что acdbEntLast () может быть вызван, чтобы получить имя примитива, который только что был создан посредством запроса к acedCommand (), acedCmd (), или acdbEntMake ().
AcedEntSel () функция запрашивает пользователя AutoCAD выбирать примитив, определяя точку на графическом экране; acedEntSel () возвращает, и имя примитива и значение указанной точки. Некоторые операции примитива требуют знания точки, которой примитив был выбран. Примеры от набора существующих команд AutoCAD включают ПЕРЕРЫВ, ВЫРЕЗКУ, ПРОСТИРАЮТСЯ, и OSNAP.
Функции контроля ввода пользователя
Функция acedInitGet () имеет два параметра: val и kwl. Val параметр определяет один или большее количество служебных битов, которые позволяют или отключают некоторые входные значения к следующему acedGetxxx () запрос. Kwl (для списка ключевого слова) параметр может определить ключевые слова, которые функции acedGetxxx (), acedEntSel (), acedNEntSelP (), acedNEntSel (), или acedDragGen () признают.
ОБРАТИТЕ ВНИМАНИЕ На служебные биты, и ключевые слова, установленные acedInitGet () применяются только к следующему запросу функции ввода пользователя. Они отвергнуты немедленно позже. Приложение не должно назвать acedInitGet () вторым разом, чтобы очистить любые специальные условия.
Функции Кривой
Абстрактный класс AcDbCurve обеспечивает множество функций для действия на кривых, включая функции для проектирования, распространения{*продления*}, и кривых смещения, также как набора функций для запроса параметров кривой. Кривые могут быть определены или в пространстве{*пробеле*} параметра или в Декартовом координатном пространстве. Трехмерная кривая - функция одного параметра (f (t)), в то время как трехмерная поверхность - функция двух параметров (f (u, v)). Конверсионные функции позволяют Вам конвертировать{*преобразовывать*} данные от его представления параметра до точек в Декартовой системе координат.
Сплайны, например, являются лучшими представленными в пространстве{*пробеле*} параметра. Чтобы разбивать сплайн на три равных части, Вы сначала находите параметры, которые соответствуют точкам сплайна и затем работают на сплайне в пространстве{*пробеле*} параметра.
Кривые могут использоваться как границы вырезки, границы продления, и как объекты конструкции для создания сложных трехмерных примитивов.
Вы можете проектировать кривую на план в данном направлении, как показано в следующем примере.
// Accepts an ellipse object ID, opens the ellipse, and uses
// its getOrthoProjectedCurve member function to create a
// new ellipse that is the result of a projection onto the
// plane with normal <1,1,1>. The resulting ellipse is
// added to the model space block Table Record.
//
void
projectEllipse(AcDbObjectId ellipseId)
{
AcDbEllipse *pEllipse;
acdbOpenObject(pEllipse, ellipseId, AcDb::kForRead);
// Now project the ellipse onto a plane with a
// normal of <1, 1, 1>.
//
AcDbEllipse *pProjectedCurve;
pEllipse->getOrthoProjectedCurve(AcGePlane(
AcGePoint3d::kOrigin, AcGeVector3d(1, 1, 1)),
(AcDbCurve*&)pProjectedCurve);
pEllipse->close();
AcDbObjectId newCurveId;
addToModelSpace(newCurveId, pProjectedCurve);
}
// Accepts an ellipse object ID, opens the ellipse, and uses
// its getOffsetCurves() member function to create a new
// ellipse that is offset 0.5 drawing units from the
// original ellipse.
//
void
offsetEllipse(AcDbObjectId ellipseId)
{
AcDbEllipse *pEllipse;
acdbOpenObject(pEllipse, ellipseId, AcDb::kForRead);
// Now generate an ellipse offset by 0.5 drawing units.
//
AcDbVoidPtrArray curves;
pEllipse->getOffsetCurves(0.5, curves);
pEllipse->close();
AcDbObjectId newCurveId;
addToModelSpace(newCurveId, (AcDbEntity*)curves[0]);
}
Функции множества Выбора
Интерактивный acedSSGet () вызов, не позволяется, в то время как диалоговое окно активно, но другие опции позволяются.
Функции, не позволенные, в то время как диалоговое окно активно
В то время как диалоговое окно активно, ads_start_dialog () функция выполняет ее команды. При этих условиях, Вы не можете называть некоторые функции ObjectARX, потому что ими или затрагивать дисплей, который не должен измениться, в то время как диалоговое окно видимо, или они требуют ввода пользователя, который не вовлекает диалоговое окно.
Если приложение вызывает одну из этих функций прежде, чем это вызывает ads_done_dialog (), AutoCAD заканчивает все диалоговые окна и отображает сообщение ошибки слежения:
AutoCAD rejected function
AutoCAD CMDACTIVE переменная системы имеет немного, который указывает,является ли диалоговое окно активным. Для подробной информации относительно переменных системы, см. Ссылку Команды AutoCAD.
Если пользователь ввел ввод, основанный на графическом экране скорее чем использование диалоговое окно непосредственно (например, определить точку или примитив), Вы должны скрыть диалоговое окно. То есть Вы должны вызвать ads_done_dialog () чтобы восстановить изображение графического экрана, и затем перезапускать диалоговое окно после того, как пользователь сделал выбор. Следующие списки показывают функции, которые не позволяются.
Функции обратного вызова
Определять, что действие принято когда диалоговое окно неперекрывающее расположение отобрано, связь функция ObjectARX с тем неперекрывающим расположением, вызывая ads_action_tile (). В пределах повторного вызова, Вы часто нуждаетесь в доступе к атрибутам в файле DCL. Ads_get_tile () и ads_get_attr () функции обеспечивают, этот доступ (ads_get_attr () сохраняет значение в DCL, в то время как ads_get_tile () получает текущее значение во время выполнения), но значения Вы наиболее вероятно, чтобы использовать, связали с отобранным неперекрывающим расположением, обеспечиваются автоматически.
В большинстве случаев, каждое активное неперекрывающее расположение в пределах диалогового окна генерирует повторный вызов. Функция повторного вызова должна делать законность, проверяющую ее связанное неперекрывающее расположение и модифицировать информацию в диалоговом окне, которое принадлежит значению неперекрывающего расположения.
Модифицирование диалогового окна может включать издание сообщения об ошибках, отключение других неперекрывающих расположений, и отображения соответствующего текста в окне редактирования или списке.
Только кнопка OK (или ее эквивалент) должна сделать запрос значений неперекрывающего расположения, чтобы сохранить назначения пользователь, наконец отобранный. Модифицируйте переменные, связанные со значениями неперекрывающего расположения в пределах повторного вызова для кнопки OK, не в пределах повторного вызова для индивидуального неперекрывающего расположения. Если постоянные переменные модифицированы в пределах индивидуальных повторных вызовов неперекрывающего расположения, не имеется никакого способа сбросить значения, если пользователь выбирает Отмену. Если повторный вызов кнопки OK обнаруживает ошибку, это должно отобразить сообщение об ошибках и фокус возвращения к неперекрывающему расположению по ошибке; это не должно выйти из диалогового окна.
Когда диалоговое окно включает несколько неперекрывающих расположений, чей обработка подобна, может быть удобно связать эти неперекрывающие расположения с отдельной функцией повторного вызова. Принцип не совершения на изменения пользователя до пользователя определяет, OK все еще применяется. Функция повторного вызова, обычная к нескольким неперекрывающим расположениям может быть с формированием изображений при помощи таблицы, используя определяемые пользователем атрибуты, чтобы обеспечить значения определенными к каждому неперекрывающему расположению.
Функции преобразования
AcDbEntity класс обеспечивает две функции преобразования:
virtual Acad::ErrorStatus
AcDbEntity::transformBy(const AcGeMatrix3d& xform);
virtual Acad::ErrorStatus
AcDbEntity::getTransformedCopy(const AcGeMatrix3d& xform,
AcDbEntity*& ent) const;
TransformBy () функция изменяет примитив, используя указанную матрицу.
В AutoCAD, это называется перемещением власти{*захвата*}, вращать, масштабировать, и отражать режимы. В некоторых случаях{*делах*}, однако, применяя преобразование требует, чтобы новый примитив был создан. В таких случаях{*делах*}, getTransformedCopy () функция используется так, чтобы заканчивающийся примитив мог быть образец различного класса чем первоначальный примитив.
Когда Вы взрываете блочную ссылку{*справочники*}, которая неоднородно масштабировалась, getTransformedCopy () функция - обратился к примитивам в блочной ссылке{*справочниках*}, чтобы создать новые примитивы (см. “ Взрывающиеся Примитивы ” на странице 123).
AcDbEntity класс предлагает две функции преобразования. TransformBy() функция применяет матрицу к объекту. GetTransformedCopy () функция дает возможность объекту возвратить копию себя С преобразованием, прикладным к этому.
Если объект однородно масштабируется и ортогональный, заданное по умолчанию выполнение AcDbEntity:: getTransformedCopy () функция имитирует объект и затем вызывает transformBy () функция на имитируемом объекте. (Используйте AcGeMatrix3d:: isUniScaledOrtho () функция, чтобы определить, масштабируется ли входная матрица однородно и ортогональный.)
Заказной AsdkPoly класс перегружает, и transformBy () функция и getTransformedCopy () функция. Когда AsdkPoly неравномерно масштабируется, это становится ломаной линией.
Acad::ErrorStatus
AsdkPoly::transformBy(const AcGeMatrix3d& xform)
{
// If we’re dragging, we aren’t really going to change our
// data, so we don’t want to make an undo recording nor do
// we really care if the object’s open for write.
//
if (mDragDataFlags & kCloneMeForDraggingCalled) {
mDragDataFlags &= kUseDragCache;
mDragPlaneNormal = mPlaneNormal;
mDragElevation = mElevation;
AcGeMatrix2d xform2d(xform.convertToLocal(mDragPlaneNormal,
mDragElevation));
mDragCenter = xform2d * center();
mDragStartPoint = xform2d * startPoint();
mDragPlaneNormal.normalize();
} else {
assertWriteEnabled();
AcGeMatrix2d xform2d(xform.convertToLocal(mPlaneNormal,
mElevation));
mCenter.transformBy(xform2d);
mStartPoint.transformBy(xform2d);
mPlaneNormal.normalize();
}
return Acad::eOk;
}
Acad::ErrorStatus AsdkPoly::getTransformedCopy(
const AcGeMatrix3d& mat,
AcDbEntity*& ent) const
{
assertReadEnabled();
Acad::ErrorStatus es = Acad::eOk;
AcGePoint3dArray vertexArray;
if ((es = getVertices3d(vertexArray)) != Acad::eOk)
{
return es;
}
for (int i = 0; i < vertexArray.length(); i++) {
vertexArray[i].transformBy(mat);
}
AcDbSpline *pSpline = NULL;
if ((es = rx_makeSpline(vertexArray, pSpline)) != Acad::eOk)
{
return es;
}
assert(pSpline != NULL);
pSpline->setPropertiesFrom(this);
ent = pSpline;
return es;
}
Функции управления Дисплея
Следующие функции управления дисплея не могут быть вызваны{*названы*}, в то время как диалоговое окно активно:
§ acedPrompt ()
§ acedMenuCmd ()
§ acedRedraw ()
§ acedGraphScr ()
§ acedTextScr ()
§ acedTextPage ()
Функции, которые записывают текст, типа acutPrintf (), являются полезными для отображения информации при испытании диалогового окна, но они не должны использоваться в готовом изделии.
Функции ввода пользователя
Ввод пользователя или acedGetxxx () функции делают паузу для пользователя, чтобы ввести данные обозначенного типа, и возвращать значение в параметре результата. Приложение может определить необязательную подсказку, чтобы отобразить перед функциональными паузами.
ОБРАТИТЕ ВНИМАНИЕ, что функции Several имеют подобные названия, но - не часть группы вводов пользователя: acedGetFunCode (), acedGetArgs (), acedGetVar (), и acedGetInput ().
Следующие функции ведут себя подобно функциям ввода пользователя: acedEntSel (), acedNEntSelP (), acedNEntSel (), и acedDragGen (). Следующая таблица кратко описывает функции ввода пользователя.
Имя функции | Описание | ||
AcedGetInt | Получает целочисленное значение | ||
AcedGetReal | Получает реальное значение | ||
AcedGetDist | Получает расстояние | ||
AcedGetAngle | Получает угол (к 0 градусам как определено ANGBASE переменной) | ||
AcedGetOrient | Получает угол (к 0 градусам вправо) | ||
AcedGetPoint | Получает точку | ||
AcedGetCorner | Получает угол прямоугольника | ||
AcedGetKword | Получает ключевое слово (см. описание ключевых слов позже в этой секции) | ||
AcedGetString | Получает строку |
С некоторыми функциями ввода пользователя типа acedGetString (), пользователь вводит значение в линию подсказки AutoCAD. С другими типа acedGetDist (), пользователь или вводит ответ на подсказке, выравнивают, или определяет значение, выбирая точки на графическом экране.
Если экран используется, чтобы определить значение, AutoCAD отображает линии с резиновой полосой, которые являются подчиненными к прикладному контролю{*управлению*}. Предшествующий запрос к acedInitGet () может заставлять AutoCAD высвечивать линию резиновый полоса (или поле).
AcedGetKword () функция отыскивает ключевое слово. Ключевые слова - также строковые значения, но они не содержат никакое незаполненное пространство, могут быть сокращены, и должны быть основаны перед acedGetKword () запрос запросом к acedInitGet (). Все функции ввода пользователя (кроме acedGetString ()) могут принимать значения ключевого слова в дополнение к значениям, которые они обычно возвращают, если acedInitGet () был вызван{*назван*}, чтобы основать ключевые слова. Функции Ввода пользователя, которые принимают ключевые слова, могут также принимать произвольный текст (без пространств{*пробелов*}).
ПРИМЕЧАНИЕ Вы может также использовать acedInitGet () чтобы позволить acedEntSel (), acedNEntSelP (), и acedNEntSel () принять ввод ключевого слова. AcedDragGen () функция также признает ключевые слова.
Пользователь AutoCAD не может ответить на функцию ввода пользователя, вводя выражение AutoLISP.
Функции ввода пользователя воспользуются преимуществом возможности с обнаружением ошибок AutoCAD. Тривиальные ошибки (типа ввода только единственный{*отдельный*} номер в ответ на acedGetPoint ()) пойман в соответствии с AutoCAD и не возвращен функцией ввода пользователя. Приложение должно только проверить условия{*состояния*}, показанные в следующей таблице.
Возвращаемые значения для функций ввода пользователя
Код |
Описание |
RTNORM |
Пользователь ввел имеющее силу значение |
RTERROR |
Функциональный запрос потерпел неудачу |
RTCAN |
Пользователь ввел ESC |
RTNONE |
Пользователь ввел только ВВОД |
RTREJ |
AutoCAD отклонил запрос как инвалид |
RTKWORD |
Пользователь ввел ключевое слово или произвольный текст |
Функция Инициализации Класса
Функция инициализации класса для каждого класса - rxInit (). Приложение, которое определяет заказной класс, должно вызвать эту функцию во время выполнения инициализация.
Эта функция определена автоматически каждым из три ACRX_xxx_DEFINE_MEMBERS () макрокоманды и исполняет следующие задачи:
· Регистрирует заказной класс
· Создает объект описателя класса
· Размещает объект описателя класса в словарь класса
Если Вы хотите определить ваш собственный rxInit () функция, используйте ACRX_DEFINE_MEMBERS () макрокоманда.
Функция Утилиты Текстового поля
Функция acedTextBox () находит диагональные координаты поля, которое включает текстовый примитив. Функция берет параметр, ent, который должен определить текстовое определение или строковую группу в форме списка буфера результата. AcedTextBox() функция устанавливает ее p1 параметр в минимальные КООРДИНАТНЫЕ координаты поля и ее p2 параметра к максимальным КООРДИНАТНЫМ координатам.
Если текст горизонтален и не вращается, p1 (угол левой нижней части) и p2 (верхний правый угол) описывают поле ограничения текста. Координаты выражены в Системе координат Примитива (ECS) ent с началом координат (0,0) в левой оконечной точке опорной линии. (Начало координат - не угол левой нижней части, если текст содержит символы с подстрочными элементами, типа g и p.) Для примера, следующий рисунок показывает результатам применения acedTextBox () к текстовому примитиву с высотой 1.0. Рисунок также показывает опорной линии и началу координат текста.
Следующий рисунок показывает значениям точки, которые acedTextBox () возвращается для выборок вертикального и выровненного текста. В обеих выборках, высота символов была введена как 1.0. (Для вращаемого текста, эта высота масштабируется, чтобы приспособить точки выравнивания.)
Обратите внимание, что с вертикальными текстовыми стилями, точки все еще возвращаются в слева направо, заказ{*по приказу;порядок*} " основание к вершине ", так что первый список точки содержит отрицательные смещения от текстового начала координат.
AcedTextBox () функция может также измерять строки в attdef и attrib примитивах. Для attdef, acedTextBox () измеряет строку отметки (группа 2); для attrib примитива, это измеряет текущее значение (группа 1).
Следующая функция, которая использует некоторый примитив, обрабатывающий функции, запрашивает пользователя выбирать текстовый примитив, и затем тянет{*рисует*} поле ограничения вокруг текста от координат, возвращенных acedTextBox ().
ОБРАТИТЕ ВНИМАНИЕ На выборку tbox () функциональные работы правильно только, если Вы - в настоящее время в Мировой системе координат (WCS). Если Вы - не, код должен преобразовать точки ECS, восстановленные{*отысканные*} из примитива в координаты UCS, используемые acedCommand (). См. “ Преобразования Системы координат ” на странице 271.
int tbox()
{
ads_name tname;
struct resbuf *textent, *tent;
ads_point origin, lowleft, upright, p1, p2, p3, p4;
ads_real rotatn;
char rotatstr[15];
if (acedEntSel("\nSelect text: ", tname, p1) != RTNORM) {
acdbFail("No Text entity selected\n");
return BAD;
}
textent = acdbEntGet(tname);
if (textent == NULL) {
acdbFail("Couldn’t retrieve Text entity\n");
return BAD;
}
tent = entitem(textent, 10);
origin[X] = tent->resval.rpoint[X]; //ECS coordinates
origin[Y] = tent->resval.rpoint[Y];
tent = entitem(textent, 50);
rotatn = tent->resval.rreal;
// acdbAngToS() converts from radians to degrees.
if (acdbAngToS(rotatn, 0, 8, rotatstr) != RTNORM) {
acdbFail("Couldn’t retrieve or convert angle\n");
acutRelRb(textent);
return BAD;
}
if (acedTextBox(textent, lowleft, upright) != RTNORM) {
acdbFail("Couldn’t retrieve text box
coordinates\n");
acutRelRb(textent);
return BAD;
}
acutRelRb(textent);
// If not currently in the WCS, at this point add
// acedTrans() calls to convert the coordinates
// retrieved from acedTextBox().
p1[X] = origin[X] + lowleft[X]; // UCS coordinates
p1[Y] = origin[Y] + lowleft[Y];
p2[X] = origin[X] + upright[X];
p2[Y] = origin[Y] + lowleft[Y];
p3[X] = origin[X] + upright[X];
p3[Y] = origin[Y] + upright[Y];
p4[X] = origin[X] + lowleft[X];
p4[Y] = origin[Y] + upright[Y];
if (acedCommand(RTSTR, "pline", RTPOINT, p1,
RTPOINT, p2, RTPOINT, p3,RTPOINT, p4, RTSTR, "c",
0) != RTNORM) {
acdbFail("Problem creating polyline\n");
return BAD;
}
if (acedCommand(RTSTR, "rotate", RTSTR, "L", RTSTR, "",
RTPOINT, origin, RTSTR, rotatstr, 0) != RTNORM) {
acdbFail("Problem rotating polyline\n");
return BAD;
}
return GOOD;
}
Предшествующий пример использует команду ROTATE AutoCAD, чтобы вызвать вращение. Более прямой способ делать это состоит в том, чтобы включить вращение в вычисление точек поля, следующим образом:
ads_real srot, crot;
tent = entitem(textent, 50);
rotatn = tent->resval.rreal;
srot = sin(rotatn);
crot = cos(rotatn);
.
.
.
p1[X] = origin[X] + (lowleft[X]*crot - lowleft[Y]*srot);
p1[Y] = origin[Y] + (lowleft[X]*srot + lowleft[Y]*crot);
p2[X] = origin[X] + (upright[X]*crot - lowleft[Y]*srot);
p2[Y] = origin[Y] + (upright[X]*srot + lowleft[Y]*crot);
p3[X] = origin[X] + (upright[X]*crot - upright[Y]*srot);
p3[Y] = origin[Y] + (upright[X]*srot + upright[Y]*crot);
p4[X] = origin[X] + (lowleft[X]*crot - upright[Y]*srot);
p4[Y] = origin[Y] + (lowleft[X]*srot + upright[Y]*crot);
Функциональная схема
Диалоговые окна - для интерактивного использования. Сценарий может запустить диалоговое окно, но не может управлять это или обеспечивать ввод, как только это открыто. Это - тот же самый как acedCommand () и acedCmd () функции.
Примеры, данные в этом разделе демонстрируют типичную последовательность функции диалогового окна следующим образом:
1 Загружают файл DCL ads_load_dialog () запрос.
2 Запрос ads_new_dialog () чтобы отобразить специфическое диалоговое окно на экране графики AutoCAD.
Проверьте состояние значения, которое ads_new_dialog () возвращается. При запросе ads_start_dialog () когда ads_new_dialog () запрос потерпел неудачу, может иметь непредсказуемых результатов.
3 Инициализируют диалоговое окно, основывая значения неперекрывающего расположения, списки, и изображения.
Функции, типично вызываемые в это время следующие:
§
ads_set_tile () и ads_mode_tile () для общего неперекрывающего расположения оценивает и состояния
§ ads_start_list (), ads_add_list (), и ads_end_list () для списков
§ ads_dimensions_tile () для установки значений неперекрывающего расположения, наряду с следующими функциями создания изображения:
Ads_start_image ()
Ads_vector_image ()
Ads_fill_image ()
Ads_slide_image ()
Ads_end_image ()
Вы можете также вызывать ads_client_data_tile () в это время, чтобы связать специфичные для приложения данные с диалоговым окном и его компонентами.
Вызовите ads_action_tile () в этой точке, чтобы основать функции повторного вызова.
4 Запрос ads_start_dialog () чтобы повернуть контроль над к диалоговому окну так, чтобы пользователь мог вводить ввод.
5 ввода пользователя Процесса изнутри ваших функций. Это - то, когда Вы наиболее вероятно, чтобы использовать ads_get_tile (), ads_get_attr (), ads_get_attr_string (), ads_set_tile (), и ads_mode_tile ().
6 пользователь нажимает кнопку выхода, вызывая функцию вызвать ads_done_dialog (), который тогда заставляет ads_start_dialog () возвращать значение. В этой точке, разгрузите файл DCL, вызывая ads_unload_dialog ().
Эту последовательность можно показывать схематично в псевдокоде следующим образом:
Load_dialog
New_dialog
Action_tile; и другие инициализации
Start_dialog
; Тогда изнутри выражений действия / функции повторного вызова:
Get_tile; и другая входная обработка
Set_tile
Done_dialog
Unload_dialog
Эта схема обрабатывает только одно диалоговое окно и один файл DCL одновременно. Приложения обычно имеют множественные диалоговые окна. Самый простой и самый быстрый способ обрабатывать эти диалоговые окна состоит в том, чтобы сохранить все из них в единственном файле DCL. Запрос ads_load_dialog тогда загружает все диалоговые окна сразу, и Вы можете вызывать ads_new_dialog для любого диалогового окна. Если память ограничена, однако, Вам, вероятно, придется создавать множественные файлы DCL и использование ads_unload_dialog, чтобы удалить набор тех диалоговых окон от памяти прежде, чем Вы загружаете другой набор с ads_load_dialog.
Гарантируйте, что Файлы Находятся на Пути
Для вашего приложения, чтобы найти эти библиотеки, Вы должны гарантировать, что путь системы пользователя содержит ссылку к COMMONFILES ^ " Autodesk Общедоступный ". Имеется множество способов делать эту работу, в зависимости от операционной системы. Они описаны ниже.
Геометрические Утилиты
Одна группа функций дает возможность приложениям получить геометрическую информацию.
AcutDistance () функция находит, что расстояние между двумя точками, acutAngle () находит угол между линией, и X ось текущих ВЕРХНИХ РЕГИСТРОВ (в КООРДИНАТНОМ плане), и acutPolar () находит точку посредством полярных координат (относительно начальной точки). В отличие от большинства функций ObjectARX, эти функции не возвращают значение состояния. AcdbInters () функция находит пересечение двух линий; это возвращает RTNORM, если это находит точку, которая соответствует спецификации.
ОБРАТИТЕ ВНИМАНИЕ В отличие от acedOsnap (), функции в этой группе просто вычисляют точку, линию, или угловые значения, и фактически не сделают запрос текущего рисунка.
Следующий типовой кодовый фрагмент показывает некоторый простой, вызывает к геометрическим сервисным функциям.
ads_point pt1, pt2;
ads_point base, endpt;
ads_real rads, length;
.
. // Инициализирует pt1 и pt2.
.
// Возвратить угол в КООРДИНАТНОМ плане текущих ВЕРХНИХ РЕГИСТРОВ, в радианах.
rads = acutAngle (pt1, pt2);
// Расстояние Возвращения в трехмерном пространстве{*пробеле*}.
length = acutDistance (pt1, pt2);
base [X] = 1.0; base [Y] = 7.0; base [Z] = 0.0;
acutPolar (base, rads, length, endpt);
Запрос к acutPolar () устанавливает endpt в точку, которая является тем же самым расстоянием от (1,7), поскольку pt1 - от pt2, и это - под тем же самым углом от X оси как угол между pt1 и pt2.
ObjectARX, AutoCAD. Среда программирования библиотеки C++
Этот метод используется, чтобы отыскать AcDbObjectId представляемого объекта резидента базы.
Обзор
Приложение ObjectARX - динамически загружаемая библиотека (DLL), использующая адресное пространство AutoCAD и посылающая ему прямые функциональные запросы. Можно добавлять новые классы к среде программы ObjectARX и экспортировать их для использования другими программами.
Создаваемые ObjectARX-объекты фактически неразличимы от встроенных объектов AutoCAD. Вы можете также расширить протокол ObjectARX, прибавляя функции во
время выполнения сеанса AutoCAD.
Эта глава содержит краткий обзор библиотек классов AutoCAD и дает информацию для получения помощи по ObjectARX.
Данное руководство предполагает, что Вы знакомы с AutoCAD и объектно-ориентированным программированием на C++.
Первичные базы данных
База данных AutoCAD сохраняет объекты, которые составляют рисунок AutoCAD. Эта глава обсуждает ключевые элементы базы данных: объекты, таблицы идентификаторов и словарь имен объектов.
Эта глава также представляет объектные маркеры(дескрипторы), объект IDs(цель), и протокол для открытия и заключительных объектов(целей) базы данных. Типовой код дает пример создания объектов, уровней, и групп, и добавления объектов(целей) к базе данных.
· Краткий обзор базы данных AutoCAD
· Основная база данных
· Создание объекта в AutoCAD
· Создание объекта в ObjectARX
Прикладные Основы ObjectARX
Эта глава описывает, как записывать и выполнить приложение ObjectARX. Это перечисляет сообщения, которые пропускает в соответствии с AutoCAD к приложению ObjectARX и показывает, как приложение типично отвечает на те сообщения. Эта глава также обсуждает регистрацию новых команд, как загружать и разгружать приложение по запросу AutoCAD, особенности загрузки и обработку ошибок.
· Создание приложения ObjectARX
· Пример приложения
· Регистрация новых команд
· Загрузка приложения ObjectARX
· Разгрузка приложения ObjectARX
· Запрос на загрузку
· ARX Command
· Выполнение приложения ObjectARX
Операции базы данных рисунка
Эта глава описывает основной протокол базы данных, включая, как создать базу данных, как читать в чертежном файле, и как сохранить базу данных. Wblock и операции вставки также описаны здесь. Для более детальной информации относительно deepClone и wblock операций, см. главу 18, при Глубоко Имитации. ”
Начальная База данных
Создание и Начальная загрузка Базы данных
Сохранение Базы данных
wblock Операция
Вставка Базы данных
Установка Текущих Значений Базы данных
Пример Операций Базы данных
Длинные транзакции
Внешние ссылки
Индексы и Фильтры
Рисунок Итоговой Информации
Из прошлого, сохраненного программным обеспечением Autodesk
Объекты Базы данных
Эта глава описывает темы, которые касаются всех объектов базы данных AutoCAD, включая объекты, записи таблицы идентификаторов и словари. Главные включенные концепции открывают и закрывают объекты, управляя объектами в памяти, монопольном использовании объекта, и расширяя объект, используя xdata или словарь расширения объекта. Другие общие операции на объектах, типа записи в файл и стирания, также обсуждены.
Открытие и Закрытие Объектов Базы данных
Удаляющие Объекты
Монопольное использование Базы данных Объектов
Добавление Объектно - определенных Данных
Стирающие Объекты
Объектная Запись в файл
Примитивы
Эта глава описывает примитивы — объекты базы данных с графическим представлением. Это перечисляет свойства и операции, все примитивы имеют в общем{*обычном*}. Примеры показывают, как создать блоки, вставки, и комплексные примитивы, и как выбирать и высветить подпримитивы.
Определенные Примитивы
Монопольное использование Примитива
Выпуск AutoCAD 12 Примитивов
Общие{*обычные*} Свойства Примитива
Общие{*обычные*} Функции Примитива
Создание Образцов Примитивов AutoCAD
Комплексные Примитивы
Доступ Системы координат
Функции Кривой
Связывающиеся Гиперсвязи с Примитивами
Контейнерные Объекты
Эта глава описывает контейнерные объекты, используемые в операциях базы данных AutoCAD: таблицы идентификаторов, словари, группы, и xrecords. Как часть любого рисунка, AutoCAD создает установленный набор таблиц идентификаторов и названного объектного словаря, который содержит два других словаря, MLINE стиль и словари ГРУПП.
Примеры главы демонстрируют, как добавить входы к таблицам идентификаторов, словарям, и группам, и как сделать запрос содержания этих контейнеров, использующих iterators.
Они также показывают, как создавать и использовать ваши собственные словари и xrecords, чтобы управлять данными прикладной программы и объектами. Для описания словаря расширения объекта AcDbObject, см. главу 5, “ Объекты Базы данных. ”
§ Сравнение Таблиц идентификаторов и Словарей
§ Таблицы идентификаторов (Symbol Tables)
§ Словари (Dictionaries)
§ Размещения (Layouts)
§ Xrecords
MFC
Библиотека фундаментальных классов Microsoft (MFC) позволяет разработчику осуществлять стандартные интерфейсы пользователя быстро. ObjectARX среда обеспечивает набор классов, что разработчик может использовать, чтобы создать MFC-ОСНОВАННЫЕ интерфейсы пользователя, которые ведут себя и появляются как встроенные интерфейсы пользователя Autodesk. Эта глава описывает, как использовать MFC
библиотеку как часть Приложения ObjectArx.
§
Введение
§ Использование MFC с Приложениями ObjectArx
§ Приложения ObjectArx с Динамически Связанным MFC
§ Встроенная MFC Поддержка Интерфейса пользователя
§ Использование AdUi и AcUi с VC
++ AppWizard
Наборы выборов, примитивы и функции таблиц идентификаторов
Глобальные функции, описанные в этой главе обрабатывают наборы выбора, рисуют примитивы и таблицы идентификаторов. См. Руководство Настройки AutoCAD для основной информации на этих темах.
§ Набор выборов и имена примитивов
§ Обработка Наборов Выбора
§ Имя Примитива и Функции Данных
§ Доступ Таблицы идентификаторов
Получение заказного класса ObjectARX
Эта глава описывает, как использовать макрокоманды ObjectARX, чтобы упростить задачу получения заказного ObjectARX класса. Эти макрокоманды позволяют заказному классу участвовать в AcRxObject механизме идентификации типа во время выполнения. Если Вы не должны отличить ваш заказной класс во время выполнения, Вы можете использовать стандартный стиль образования C++, чтобы создать новый класс.
·
Заказное Образование Класса
· Идентификация Класса Во время выполнения
· Макрокоманда Объявления Класса
· Макрокоманды Выполнения Класса
· Функция Инициализации Класса
Наследование от AcDbObject
Эта глава описывает, как получить заказной класс из AcDbObject. Это обеспечивает детальную информацию относительно регистраторов, четыре типа объектных ссылок (интенсивно и мягких владельцев, и интенсивно и мягких указателей), операций отмены и восстановления. Эта глава также обсуждает механизмы для объекта versioning. Описания в этой главе предполагают, что Вы знакомы с материалом, описанным в главе 5, “ Объекты Базы данных, ” и глава 11, при Наследовании Заказного ObjectARX Класса. ”
· Перегрузка виртуальных функций AcDbObject
· Реализация функций
· Сохранение объектов в DWG и DXF файлах
· Ссылки на объекты
· Ссылки монопольного использования
· Ссылки на указатели
· Проблемы длинных транзакций для заказных объектов
· Purge (Чистка)
· Undo and Redo (Отмена и Восстановление)
· subErase, subOpen, subClose, и subCancel
· Пример Заказного Объектного Класса
· Объектная Поддержка Версии
Наследование от AcDbEntity
Эта глава описывает, как получить класс пользователя из AcDbEntity, и включает определенные примеры отмены виртуальных методов, обеспеченных AcDbEntity классом.
Перегрузка общих операции объекта, типа точек захвата объекта (гриппов), также обсуждена в этой главе.
Материал в этой главе предполагает, что Вы знакомы с материалом, представленным в главе 6, “примитивы”; глава 11, при Наследовании Заказного ObjectARX Класса ”; и глава 12, “ Происходящий от AcDbObject. ”
§
Наследование заказных примитивов
§ Перегрузка общих функций примитива
§ Расширение функциональности примитива
§ Использование AcEdJig
Расширение Протокола
Все определения класса C++ установлены во времени компиляции.
При нормальных обстоятельствах, если Вы записываете транслятор файла или команду редактирования, которая работает в ряде существующего AutoCAD классов, Вы должны переопределить все существующие классы, чтобы включить новый транслятор или редактирующие функции. И Вы были бы должны перетранслировать вашу библиотеку также как все приложения, которые используют это.
Используя ObjectARX механизм расширения протокола, описанный в этой главе, Вы можете добавлять функциональные возможности к существующим классам ObjectARX во время выполнения, без любой модификации существующих классов и перетрансляции.
Определенное Расширение Протокола
Расширение Протокола Реализации
Расширение Протокола для MATCH-команд
Пример Расширения Протокола
Глобальные сервисные функции ObjectARX
Эта глава обсуждает некоторые общие характеристики ObjectARX глобальных сервисных функций. Для подробной информации относительно определенных функций, см. ObjectARX Ссылку.
§ Общие характеристики библиотечных функций ObjectARX
§ Переменные, Типы, и Значения, определенные в ObjectARX
§ Списки и Другие Динамически Размещенные Данные
§ Расширенные данные типы Исключительные Данные
§ Текстовые Строковые Проблемы Глобализации
Точки ввода в процессе выполнения
ObjectARX
позволяет приложениям настраивать обработку входную точки. Приложение может связывать новые объектные точки привязок и автопривязывать линии выравнивания с заказными и существующими примитивами, и может контролировать, входная точка обрабатывает и изменяет входные точки. Эта глава обсуждает эти темы.
§ Заказные Режимы объектной привязки
§ Ввод направляют Управление
Конфигурация приложения
Эта глава обсуждает конфигурирование вашего приложения для конечного пользователя.
§
Менеджер профилей
Главa 23. COM, ActiveX Автоматизация и Менеджер свойств объекта
Объектная модель программных компонентов Microsoft (COM) позволяет приложениям на платформе Windows связываться и обмениваться данными друг с другом.
Вы можете обращаться к интерфейсам COM, обеспеченным другими ObjectARX-приложениями или любым приложением COM-enabled, выполняющимся на Windows.
Дополнительно, используя COM с ObjectARX, Вы можете увеличивать ActiveX
модель Автоматизации AutoCAD. Элементы, объекты, или примитивы, которые Вы выставляете, будут тогда доступны другим средам программирования типа Visual Basic для Приложений (VBA) и к особенностям AutoCAD типа Менеджера Свойств объекта (OPM).
§
Краткий обзор
§ Использование Объектов COM AutoCAD от ObjectARX и Других Сред
§ AutoCAD ActiveX Выполнение Автоматизации
§ Взаимодействующий с AutoCAD
§ Документ Блокировка
§ Создание Файла Системного реестра
§ Демонстрация Функциональных возможностей Автоматизации
§ Менеджер Свойства объекта API
§ Статические OPM Интерфейсы COM
§ Реализация Статические Интерфейсы OPM
§ Динамические Свойства и OPM
API COM дизайн-центра AutoCAD
AutoCAD имеет особенности, которые используют механизм COM, чтобы сделать запрос и изменить объекты. AutoCAD Дизайн-центр (ADC) использует механизм COM, чтобы обеспечить легко доступное содержание рисунка. Эта глава описывает интерфейсы COM, которые должны быть осуществлены вашим приложением для этого, чтобы участвовать и расширить AutoCAD Дизайн-центр r.
§ AutoCAD Дизайн-центр API
§ Требования Системного реестра для AutoCAD Дизайн-центр Компонент
§ Реализация Интерфейсы для AutoCAD Дизайн-центр
§ Настройка AutoCAD Дизайн-центр
Библиотеки ObjectDBX
ObjectDBX - преемник Отключенного DWG, и эта глава описывает изменения и расширения, что ObjectDBX SDK обеспечивает, наряду с описанием того, как осуществить приложения, использующие ObjectDBX.
Введение
Использование ObjectDBX
Различия между ObjectDBX и ObjectARX
Локализация и XMX Файлы
Управление Транзакции
Создание Средства просмотра
Загрузка Требования
Установка ObjectDBX Библиотек
Советы и технические приемы
Известные Ограничения
Библиотека графического интерфейса
AutoCAD использует графическую библиотеку интерфейсов (AcGi), чтобы отобразить встроенные и заказные примитивы. Эта глава обсуждает черты примитива установки и примитивы использования, чтобы создать заказные графические примитивы. Для полного описания всех классов AcGi и их функций члена, см. ObjectARX Ссылку.
AcGi
Краткий обзор
Установка Черт Примитива
Примитивы
Использование Drawables в Вашем Объекте
Tessellation
Isolines
Преобразования
Использование границ обрезки в AcGi
Использование Библиотеки Геометрии
Эта глава обсуждает основные использования AcGe библиотеки, которая обеспечивает множество классов для представления 2-ой и трехмерной геометрии. Эта библиотека предназначена для использования любым приложением Autodesk и часто используется AcDb и AcGi библиотеками в ObjectARX.
§ Краткий обзор AcGe Библиотеки
§ Использование Основных Типов Геометрии
§ Использование Линии и Классов Плана
§ Параметрическая Геометрия
§ Специальные Классы Оценки
§ Постоянные AcGe примитивы
Использование Библиотеки Контурных представлений
Эта глава показывает, как использовать AcBr библиотеку (libacbr.dll), чтобы обратиться к топологическим, геометрическим, и аналитическим данным, содержащимся в некоторых примитивах AutoCAD, типа solids, тел, и областей{*регионов*} (то есть объекты класса AcDb3dSolid, AcDbBody, и AcDbRegion), и бесчисленных производных типов (например, объекты класса AcDbPart, AcAsSurface, и совместимых определенных клиентом типов). С целью краткости, эта глава обращается к всем этим объектам все вместе как solids.
§ Краткий обзор
§ Домен{*область*}
§ Ограничения
§ Иерархия Классов
§ Топологические Объекты
§ AcBr Описания Класса
§ Перечислимые типы
§ Формирование Приложения
Краткий обзор
AcBr библиотека может использоваться со следующими примитивами AutoCAD:
§ AcDb3dSolid представляет твердый; это включает один или большее количество объемов.
§ AcDbRegion представляет плоскую поверхность; это могло бы содержать множественные компланарные поверхности.
§ AcDbBody - конкретный базовый класс для всех объектов контурного представления, не охваченных AcDb3dSolid или AcDbRegion, включая производные типы, определенные Autodesk Mechanical Desktop и клиентские приложения.
§ AcDbPart представляет твердый или тело листа в контексте трансляции{*блока*} или особенности в Autodesk Mechanical Desktop.
§ AcAsSurface представляет отдельную поверхность как тело листа в Autodesk Mechanical Desktop.
AcBr библиотека обеспечивает доступ только для чтения к подмножеству данных моделирования, содержащихся в AutoCAD solids. Эти solids не требованы, чтобы быть базой данных, активной, и может быть создан способом из следующих путей:
§ команды создания объекта AutoCAD (типа СФЕРЫ), или эквивалентных сценариев AutoLISP.
§ Autodesk Механические команды создания Объекта оперативной памяти (типа ADREVOLVE), или эквивалентных сценариев AutoLISP.
§ Обращение команды EXPLODE AutoCAD на части или трансляции{*блоке*} в Autodesk Механический Рабочий стол.
§ внесение Файла, использующее ОТКРЫТЫЙ, DXFIN, ACISIN, ADSATIN, VDAFSIN, STEPIN, AMIDFIN, или IGESIN.
§ Программируемая реализация использования примитивов
AcDb3dSolid:: createFrustum (), AcDb3dSolid:: createBox (),
AcDb3dSolid:: createWedge (), AcDb3dSolid:: createSphere (),
AcDb3dSolid:: createTorus (), AcDbRegion:: createFromCurves ().
Типичные использования AcBr библиотеки включают следующее:
§ Передача примитива или данных подпримитива в ваше приложение для дисплея, анализа, или манипуляции.
§ Расположение специфических особенностей, представляющих интерес в твердом и запрашивающем для связанных данных, типа геометрии.
§ Передача данных примитива к другой системе моделирования (то есть обмен данных).
§ Поймавший в сети поверхностные данные в твердом для дисплея, анализа, или манипуляции.
§ Поддержка анализа (типа точки и сдерживания линии, ограничение блоков, и массовых свойств).
Глобальные Функции для Взаимодействия с AutoCAD
Глобальные функции, описанные в этой главе позволяют вашему приложению связываться с AutoCAD. Эта глава обсуждает функции для регистрации команд с AutoCAD, обработка ввода пользователя, обработка преобразований данных, и установки внешних устройств типа таблетки.
Запросы AutoCAD и Команды
Получение Ввода Пользователя
Преобразования
Обработка Символьного типа
Преобразования Системы координат
Управление Дисплея
Калибровка Таблетки
Универсальное сопоставление
Полномочные Объекты (Proxy)
Эта глава описывает полномочные объекты и условия их создания. Это также обсуждает пользователя, сталкивается с proxies, отображая полномочные примитивы, и редактируя полномочные примитивы. Эффект разгрузки приложения на заказных объектах и примитивах обсужден также.
Определение прокси-объекта
Цикл Жизни прокси-объекта
Прокси-объект для пользователя
Отображение прокси-примитивов
Редактирование прокси-примитивов
Разгрузка приложения
Уведомления
Эта глава описывает, как Вы можете создавать реакторы, которые отвечают на различные типы случая и регистрируют реакторы с соответствующими объектами, чтобы получить уведомление.
Краткий обзор уведомлений
Использование реакторов
Руководящие принципы использования уведомлений
Многодокументная среда
AutoCAD поддерживает многодокументную среду (MDI), который позволяет Вам иметь больше чем один рисунок, загруженный сразу на единственной сессии AutoCAD. Эта глава описывает, как работать с MDI в вашем ObjectARX-приложении.
§ Краткий обзор
§ Терминология
§ SDI Переменная Системы
§ Уровни Совместимости
§ Взаимодействующий с Множественными документами
§ Уведомление События Документа
§ Специфические для приложения Объекты Документа
§ Неповторно используемые Команды
§ Команды Много-документа
§ Отключение Переключения Документа
§ Прикладной Контекст Выполнения
§ Отмена Базы данных и Средства Управления Транзакции
§ Документированные - независимые Базы данных
§ MDI-ЗНАЮЩИЙ Приложение Примеры.
Управление транзакцией
Эта глава описывает операционную модель, которая может использоваться, чтобы работать на объектах AcDb. В этой модели, множественные операции на множественных объектах сгруппированы вместе в одну атомную операцию, вызвал сделку.
Транзакции могут быть вложены и могут быть закончены или прерван на усмотрение клиента. Эта модель может использоваться в конъюнкции с регулярным " в объект" открытый и близкий механизм, описанный в главе 5, “ Объекты Базы данных. ”
§
Краткий обзор Управления Транзакции
§ Менеджер Транзакции
§ Вложение транзакций
§ Границы Транзакции
§ Получение Указателей на Объекты в Транзакции
§ Недавно Созданные Объекты и транзакции
§ Совершают разовые Руководящие принципы
§ Отмена и транзакции
§ Смешивание Модели Транзакции с Открытым и Близким Механизмом
§ транзакции и Графическое порождение
§ Реакторы Транзакции
§ Пример Вложенных транзакций
Глубокое клонироване
Эта глава описывает глубокие функции аналога, которые копируют объект или любые объекты, принадлежащие скопированному объекту. Это охватывает оба основных случая использования AcDbDatabase::deepCloneObjects() функции, как более продвинутая тема перегрузки deepClone () и wblockClone() функции AcDbObject класса. Редактор функции уведомления реактора, связанные с глубоким аналогом, wblock аналог, и вставка операции также обсуждены.
Основы глубокого клонирования
Реализация deepClone() для Классов пользователя
Глобальная переменная против Местных Названий Команды
Когда Вы прибавляете команду к AutoCAD, Вы должны определить, и глобальное название{*имя*}, которое может использоваться на любом языке и ограниченном названии{*имени*}, которое является оттранслированной версией названия{*имени*} команды, которое нужно использовать в версии иностранного языка AutoCAD. Если Вы не должны транслировать название{*имя*} команды в местный язык, то же самое название{*имя*} может использоваться, и для глобальной переменной и местных названий{*имен*}.
Глобальные данные и функции
Следующая таблица перечисляет глобальные идентификаторы, определенные некоторыми из файлов заголовка.
Глобальные функции сохранения
ObjectARX также содержит две глобальных функции для сохранения рисунков:
Acad::ErrorStatus
acdbSaveAsR13(
AcDbDatabase* pDb,
const char* fileName);
Acad::ErrorStatus
acdbSaveAsR14(
AcDbDatabase* pDb,
const char* fileName);
Обе функции принимают указатель базы данных и имя файла, и выписывают рисунок в Выпуске AutoCAD 13 или Выпускают 14 формата DWG, соответственно.
Глобальные идентификаторы и файлы заголовка
Файл Заголовка |
Глобальные Определенные Функции | ||
gepnt2d.h |
AcGePoint2d::kOrigin | ||
gemat2d.h |
AcGeMatrix2d::kIdentity | ||
gevec2d.h |
AcGeVector2d::kIdentity AcGeVector2d::kXAxis AcGeVector2d::kYAxis | ||
geline2d.h |
AcGeLine2d::kXAxis AcGeLine2d::kYAxis | ||
gepnt3d.h |
AcGePoint3d::kOrigin | ||
gemat3d.h |
AcGeMatrix3d::kIdentity | ||
gevec3d.h |
AcGeVector3d::kIdentity AcGeVector3d::kXAxis AcGeVector3d::kYAxis AcGeVector3d::kZAxis | ||
geline3d.h |
AcGeLine3d::kXAxis AcGeLine3d::kYAxis AcGeLine3d::kZAxis | ||
geplane.h |
AcGePlane::kXYPlane AcGePlane::kYZPlane AcGePlane::kXZPlane | ||
gegbl.h |
AcGeContext::gOrthoVector() |
AcGeContext:: gOrthoVector - указатель на функцию что, учитывая вектор, вычисляет произвольный вектор, который является перпендикулярным к этому. Вы можете заменять вашу собственную функцию на данную функцию.
Допуски
Много методов принимают значение допуска как один из их параметров. Это значение имеет AcGeTol класс и всегда имеет значение по умолчанию, как определено в AcGeContext:: gTol. Функции типа isClosed () и isPlanar () вычисляют,являются ли точки начала и оконечные точки в пределах определенного допуска перед возвращением Булева значения. Вы можете изменять допуск для одного специфического функционального запроса, или Вы можете изменять глобальное значение допуска.
AcGeTol класс обеспечивает две функции для установки допуска для точек и векторов:
void
setEqualPoint(double);
void
setEqualVector(double);
AcGeTol класс также обеспечивает две функции для получения допуска для точек и векторов:
double equalPoint() const;
double equalVector() const;
EqualPoint и equalVector значения допуска используются следующим образом:
§ Две точки, p1 и p2, являются равным если
( p1 - p2) .length () < = equalPoint
§ Два вектора, v1 и v2, являются равным если
( v1 - v2) .length () < = equalVector
§ Два вектора, v1 и v2, являются параллельным если
( v1/v1.length () - v2/v2.length ()) .length () < equalVector
ИЛИ (v1/v1.length () + v2/v2.length ()) .length () < equalVector
§ Два вектора, v1 и v2, являются перпендикулярным если
abs((v1.dotProduct(v2))/(v1.length()*v2.length())) < = equalVector
§ Две линии или лучи - параллельный (перпендикуляр), если их направленные векторы - параллельный (перпендикуляр)
§ Две линии равен, если точки в параметре 0 равны, и их направления равны
ОБРАТИТЕ ВНИМАНИЕ, что эти правила подразумевают, что две линии - близко к друг другу как точечные множества в части пространства моделирования диаметра diam только, если допуск equalVector установлен более плотным чем equalPoint/diam.
Глобальные Исследования
Глобальная переменная traversers (типа AcBrBrepFaceTraverser и AcBrBrepEdgeTraverser) обеспечивает способность пересечь все топологические объекты в твердом (комплексы, оболочки, лица, грани, вершина).
Глобальные Итоговые Информационные Функции
ObjectARX содержит несколько глобальных функций для доступа к итоговой информации:
Acad:: ErrorStatus
AcdbGetSummaryInfo (
AcDbDatabase* pDb,
AcDbDatabaseSummaryInfo*& PInfo);
Acad:: ErrorStatus
AcdbPutSummaryInfo (
Константа
AcDbDatabaseSummaryInfo* pInfo);
AcDbSummaryInfoManager*
AcdbGetSummaryInfoManager ();
Для получения дополнительной информации на этих функциях, см. ObjectARX Ссылку{*справочники*}.
Графические Функции Нижнего уровня
Следующие графические функции не могут быть вызваны, в то время как диалоговое окно активно:
§
acedGrVecs ()
§ acedGrDrag ()
§ acedGrRead ()
§ acedGrText ()
§ acedGrDraw ()
§ acedGrText ()
Графическое перемещение Наборов Выбора
Функция acedDragGen () запрашивает пользователя перетаскивать группу отобранных объектов, как показано в следующем примере:
int rc;
ads_name ssname;
ads_point return_pt;
// Prompt the user for a general entity selection.
if (acedSSGet(NULL, NULL, NULL, NULL, ssname) == RTNORM)
// The newly selected entities
rc = acedDragGen(ssname,
"Drag selected objects", // Prompt
0, // Display normal cursor (crosshairs)
dragsample, // Transformation function
return_pt); // Set to the specified location.
Четвертый параметр указывает на функцию, которая делает преобразование примитива. См. “ Преобразование Наборов Выбора ” на странице 211 для примеров dragsample () и acedDragGen ().
Границы транзакции
Поскольку Вы, не система, отвечаете за старт, окончание, или транзакции прерывания выполнения, важно знать операционные границы. Операционная граница - время между началом и концом или аварийным прекращением работы транзакции.
Рекомендуется, чтобы Вы ограничили{*заключили*} вашу границу к самой маленькой возможной области{*контексту*}. Например, если Вы запускаете транзакцию в функции, пробуете заканчивать или прервать транзакцию прежде, чем Вы возвращаетесь от той функции, потому что Вы не можете иметь знание транзакции вне функции. Вы не должны следовать за этим правилом, если Вы поддерживаете некоторый глобального менеджера для ваших операционных действий, но Вы все еще ответствены за прерывание выполнения или окончание всех транзакций, которые Вы запускаете.
Множественные приложения могут использовать операционное управление для их работы, и операции на объектах совершены{*переданы*} в конце наиболее удаленной транзакции.
Поэтому, граница команды AutoCAD - то, насколько Вы можете протягивать границу ваших транзакций. Когда команда концы, там не должна быть никакие активные транзакции. Если имеются любые активные транзакции (операционный стек не пуст) когда команда концы, AutoCAD прервется. Как исключение, транзакции могут все еще быть активны, когда acedCommand () или прозрачная команда концы, но они должны весь быть решенными, когда основная команда концы и AutoCAD возвращается Приглашению ко вводу команды.
Это - вообще хорошая идея запустить транзакцию, когда одна из ваших функций вызвана как часть команды, зарегистрированной Вами и концом это, когда Вы возвращаетесь от той функции. Вы можете обобщать это к всем командам в AutoCAD, используя AcEditorReactor:: commandWillStart () и AcEditorReactor:: commandEnded () уведомления, но имеются некоторые команды, которые не должны быть проведены. Следующие команды не должны быть проведены:
§
ARX
§ DXFIN
§ INSERT
§ NEW
§ OPEN
§ PURGE
§ QUIT
§ RECOVER
§ REDO
§ SAVE
§ SCRIPT
§ U
§ UNDO
§ XREF
Группы и Словарь Группы
Группа - контейнерный объект, который обслуживает{*поддерживает*} упорядоченную{*заказанную*} коллекцию примитивов базы данных. О группах можно думать как названный постоянными наборами выбора. Они не имеют связи{*ссылки*} монопольных использований к примитивам, которые они содержат.
Когда примитив стерт, это автоматически удалено из групп, которые содержат это. Если примитив нестерт, это автоматически повторно вставлено в группу.
Используйте AcDbGroup:: newIterator () функция, чтобы получить iterator и шаг через примитивы в группе. AcDbGroup класс также обеспечивает функции для добавления в конец и prepending примитивов к группе, вставка примитивов по специфическому индексу в группе, удаление примитивов, и передачи примитивов от одной позиции в группе к другому. См. AcDbGroup в ObjectARX Ссылке.
Вы можете также назначать свойства на всех членов группы, использующей
setColor (), setLayer (), setLinetype (), setVisibility (), и
setHighlight () функции AcDbGroup класса. Эти операции имеют тот же самый эффект как открытие каждого примитива в группе и установке ее свойства непосредственно.
Группы должны всегда сохраняться в словаре ГРУППЫ, который может быть получен следующим образом:
AcDbDictionary* pGrpDict =
acdbHostApplicationServices()->working Database()->
getGroupDictionary(pGroupDict, AcDb::kForWrite);
Альтернативный способ получить словарь ГРУППЫ состоит в том, чтобы искать “ACAD_GROUP” в словаре имен объектов.
Следующие функции - часть приложения, что первые подсказки пользователь, чтобы выбрать некоторые примитивы, которые помещены в группу по имени “ASDK_GROUPTEST”. Тогда это вызывает функцию removeAllButLines () чтобы выполнить итерации по группе и удалять все примитивы, которые - не линии. Наконец, это изменяет{*заменяет*} остающиеся примитивы в группе к красному.
void
groups()
{
AcDbGroup *pGroup = new AcDbGroup("grouptest");
AcDbDictionary *pGroupDict;
acdbHostApplicationServices()->workingDatabase()
->getGroupDictionary(pGroupDict, AcDb::kForWrite);
AcDbObjectId groupId;
pGroupDict->setAt("ASDK_GROUPTEST", pGroup, groupId);
pGroupDict->close();
pGroup->close();
makeGroup(groupId);
removeAllButLines(groupId);
}
// Prompts the user to select objects to add to the group,
// opens the group identified by "groupId" passed in as
// an argument, then adds the selected objects to the group.
//
void
makeGroup(AcDbObjectId groupId)
{
ads_name sset;
int err = acedSSGet(NULL, NULL, NULL, NULL, sset);
if (err != RTNORM) {
return;
}
AcDbGroup *pGroup;
acdbOpenObject(pGroup, groupId, AcDb::kForWrite);
// Traverse the selection set, exchanging each ads_name
// for an object ID, then adding the object to the group.
//
long i, length;
ads_name ename;
AcDbObjectId entId;
acedSSLength(sset, &length);
for (i = 0; i < length; i++) {
acedSSName(sset, i, ename);
acdbGetObjectId(entId, ename);
pGroup->append(entId);
}
pGroup->close();
acedSSFree(sset);
}
// Accepts an object ID of an AcDbGroup object, opens it,
// then iterates over the group, removing all entities that
// are not AcDbLines and changing all remaining entities in
// the group to color red.
//
void
removeAllButLines(AcDbObjectId groupId)
{
AcDbGroup *pGroup;
acdbOpenObject(pGroup, groupId, AcDb::kForWrite);
AcDbGroupIterator *pIter = pGroup->newIterator();
AcDbObject *pObj;
for (; !pIter->done(); pIter->next()) {
pIter->getObject(pObj, AcDb::kForRead);
// If it is not a line or descended from a line,
// close it and remove it from the group. Otherwise,
// just close it.
//
if (!pObj->isKindOf(AcDbLine::desc())) {
// AcDbGroup::remove() requires that the object
// to be removed be closed, so close it now.
//
pObj->close();
pGroup->remove(pIter->objectId());
} else {
pObj->close();
}
}
delete pIter;
// Now change the color of all the entities in the group
// to red (AutoCAD color index number 1).
//
pGroup->setColorIndex(1);
pGroup->close();
}