Esta é a versão em html do arquivo http://www.cadtec.dees.ufmg.br/publico/Regina/ObjectARX%20B% C3%A1sico/ApostilaARX/ObjARX_Apostila.doc.
Google cria automaticamente versões em texto de documentos à medida que vasculha a web.
ObjectARX
For AutoCAD Release 14
Apostila do Desenvolvedor
Revisão Abril/98
1
a
Edição
Editor
José Ricardo Queiroz Franco
Autores
Alexandra Hütner Fernando Poinho Malard
Jacqueline Maria Flor
Juliana Mascarenhas
Índice Analítico
Usando a Plataforma ARX
ObjectARX é o ambiente de programação do AutoCAD Runtime Extension. Este ambiente inclui bibliotecas da linguagem C++, que permitem o desenvolvimento de aplicativos específicos de classes e protocolos no AutoCAD extendidos, e cria novos comandos que operam da mesma maneira que os comandos intrínsecos do AutoCAD.
A utilização da linguagem C++ orientada a objetos pelo ObjectARX, faz com que se tenha um desenvolvimento performático bastante superior aos já existentes. Na análise Orientada a Objetos, dados e procedimentos fazem parte de um só elemento básico ( objeto ou classe ). Esses elementos básicos, ao estabelecer comunicação entre si, caracterizam a execução do programa. Assim, ao contrário da filosofia estruturada, onde dados e procedimentos são entidades dissociadas, no paradigma da orientação a objetos os dados e procedimentos estão encapsulados em um só elemento. Em termos técnicos, o desenvolvimento exige alguns Softwares para que se possa fazer o devido uso das ferramentas de linguagem. Apesar de o ObjectARX já ter sido implementado na versão 13 do AutoCAD, é recomendável pela sua confiabilidade, a utilizaçào do AutoCAD release 14 for Windows. Da mesma forma recomenda-se o Visual C++ 4.1a e ainda mais eficiente, o Visual C++ 5.0. A Autodesk envia aos seus desenvolvedores um CD de consulta on line chamado ObjectARX que torna o trabalho ainda mais imediato.
I.
Visão Geral
Uma aplicação ARX é uma biblioteca de vínculo dinâmico (dynamic link library _ DLL) que compartilha o espaço no mesmo endereço do AutoCAD e chama funções diretamente do AutoCAD. As bibliotecas do ARX incluem macros para facilitar a definição de novas classes e oferecer a habilidade para adicionar funcionalidade às classes existentes. O ARX pode ser usado juntamente com o AutoCAD Development System (ADefS) e também com aplicativos em AutoLISP.
Ambiente ARX
O ambiente ARX fornece uma interface para a aplicação da linguagem orientada a objetos C++ que habilita desenvolvedores usar, customizar, e automatizar o AutoCAD. O ARX é de extrema versatilidade na utilização do seu banco de dados, no sistema gráfico, e na definição dos seus comandos nativos.
O ambiente ARX difere do ADS e do AutoLISP de enumeras formas. O AutoLISP é uma linguagem interpretada pelo AutoCAD, uma simples forma de apenas adicionar comandos. Sua conecção com o AutoCAD é feita através de um interprocesso de comunicação (IPC). Dessa mesma forma é também o ADS que é escrito em C e compilado antes de ser carregado via IPC pelo AutoLISP e só assim executado no AutoCAD. O ADS é apenas uma tradução do AutoLISP.
IPC
AutoLISP
IPCAutoCAD
Aplicativos ARX
Bibliotecas ARX
Classe AcRxO AcRx fornece o nível de classes para a inicialização DLL, linkagem e também registro e identificação das classes. A classe básica é AcRxObject.
O AcRx também fornece um conjunto de macros em C++ para ajudar na criação de novas classes em
ARX, que são derivadas do AcRxObject.
Outra importante classe é AcRxDictionary que é um dicionário de strings que aponta para outro objeto. O AcRx armazena classes, objetos e dicionários.
Classe hierárquica: AcRxObject AcRxClass AcRxDictionary AcRxDLinkerReactor AcRxDynamicLinker AcRxIterator AcRxDictionaryIterator AcRxService Classe AcEd
operam da mesma maneira que os comandos internos do AutoCAD. Ambos comandos residem na mesma estrutura interna, AcEdCommandStack. Uma classe importante é a AcEditorReactor, que monitora o editor do AutoCAD e notifica os eventos ocorridos.
Classe hierárquica: AcRxObject AcEdCommandIterator AcEdCommandStack AcEditor AcEdJig AcEditorReactor AcTransaction AcTransactionManager AcTransactionReactor Classe AcDb
O AcDb fornece classes que possibilitam o acesso na estrutura do banco de dados do AutoCAD. Este banco de dados armazena todas as informações para os objetos gráficos (entidades) e não gráficos que compõe um desenho do AutoCAD.
O banco de dados do AutoCAD contém:
Um conjunto de nove symbol tables
Um named object dictionary ( class AcDbDictionary ) que contém uma tabela de conteúdos para o AutoCAD que pode ser facilmente alterada
Um conjunto fixo de 200 variáveis de cabeçalho definidas pelo AutoCAD
Classe hierárquica: AcDbAuditInfo AcDbRecover
AcDbRecoverCallBack
AcDbHandle (Identificação do objeto) AcDbObjectId
AcDbHardOwnershipId AcDbHardPointerId AcDbSoftOwnershipId AcDbSoftPointerId
AcDbIdMapping (Usado para deep clone) AcDbIdMappingIter AcDbIdPair AcDbSymbolTableIterator (Iterators) AcDbBlockTableIterator AcDbBlockTableRecordIterator AcDbDimStyleTableIterator AcDbLayerTableIterator AcDbLinetypeTableIterator AcDbRegAppTableIterator AcDbTextStyleTableIterator AcDbUCSTableIterator AcDbAbstractViewTableIterator AcDbViewTableIterator AcDbViewportTableIterator AcDbGroup Iterator AcDbExtents AcDbDate AcDbIntArray AcDbObjectIdArray AcDbVoidPtrArray AcRxObject
AcDbDatabase (AutoCAD banco de dados) AcDbDictionaryIterator
AcDbDwgFiler (Arquivos) AcDbDwgCopyFiler AcDbDeepCloneFiler
AcDbWblockCloneFiler AcDbDwgUndoFiler AcDbDxfFiler
(AcRxObject)
AcDbObject (Classe mais importante) AcDbDictionary
AcDbEntity (AutoCAD entidades) AcDb3dSolid AcDbBlockBegin AcDbBlockEnd AcDbBlockReference AcDbMInsertBlock AcDbBody AcDbCurve AcDb2dPolyline AcDb3dPolyline AcDbArc AcDbCircle AcDbEllipse AcDbLeader AcDbLine AcDbRay AcDbSpline AcDbXline AcDbDimension AcDb2LineAngularDimension AcDb3PointAngularDimension
AcDbAlignedDimension AcDbDiametricDimension AcDbOrdinateDimension AcDbRadialDimension AcDbRotatedDimension AcDbFace AcDbFaceRecord AcDbFcf AcDbMline AcDbMText AcDbOleFrame AcDbPoint AcDbPolyFaceMesh AcDbPolygonMesh AcDbRegion AcDbSequenceEnd AcDbShape AcDbSolid AcDbText AcDbAttribute AcDbAttributeDefinition AcDbTrace AcDbVertex AcDb2dPolylineVertex AcDb3dPolylineVertex AcDbPolyFaceMeshVertex AcDbPolygonMeshVertex
AcDbViewport AcDbProxyEntity (AcRxObject) (AcDbObject) AcDbGroup AcDbMlineStyle
AcDbSymbolTable (Symbol tables) AcDbBlockTable AcDbDimStyleTable AcDbLayerTable AcDbLinetypeTable AcDbRegAppTable AcDbTextStyleTable AcDbUCSTable AcDbAbstractViewTable AcDbViewportTable AcDbViewTable
AcDbSymbolTableRecord (Symbol table records) AcDbAbstractViewTableRecord AcDbViewportTableRecord AcDbViewTableRecord AcDbBlockTableRecord AcDbDimStyleTableRecord AcDbLayerTableRecord AcDbLinetypeTableRecord AcDbRegAppTableRecord AcDbTextStyleTableRecord
AcDbUCSTableRecord AcDbProxyObject
AcDbObjectIterator
AcDbObjectReactor (Notificação de eventos) AcDbEntityReactor
AcDbDatabaseReactor
Classe AcGi
O AcGi fornece a interface gráfica usada para as entidades do AutoCAD. Ela é usada pelas funções membro do AcDbEntity como worldDraw( ), viewportDraw( ) e saveAs( ), que fazem parte do protocolo padrão da entidade. O worldDraw( ) deve ser definida para todas as classes de entidades customizadas. O objeto AcGiWorldDraw fornece um API através do qual o AcDbEntity::worldDraw
( ) podeproduzir uma representação gráfica em todos os viewports simultâneamente. Similarmente, o
objeto AcGiViewportDraw fornece um API através do qual o AcDbEntity::viewportDraw( ) pode produzir representações gráficas para cada viewport.
Classe hierárquica: AcRxObject AcGiEdgeData AcGiFaceData AcGiSubEntityTraits AcGiTextStyle AcGiVertexData AcGiViewport AcGiViewportDraw AcGiViewportGeometry AcGiWorldDraw AcGiWorldGeometry Classe AcGe
O AcGe é usado pelo AcDb e fornece classes úteis assim como vetores, pontos e matrizes (2D e 3D). Ela também disponibiliza objetos geométricos simples como pontos, curvas e superfícies. Essas classes que compõe AcGe podem ser usadas para operações básicas com vetores, pontos e matrizes. Os membros dessa classe devem ser declarados públicos.
Classe hierárquica: AcGePoint2d AcGeVector2d
AcGeMatrix2d AcGeScale2d AcGePoint2dArray AcGeVector2dArray AcGePoint3d AcGeVector3d AcGeMatrix3d AcGeScale3d AcGePoint3dArray AcGeVector3dArray AcGeTolerance AcGeInterval AcGeCurveBoundary AcGeDoubleArray AcGeKnotVector AcGeEntity2d AcGePointEnt2d AcGePosition2d AcGePointOnCurve2d AcGeCurve2d AcGeLinearEnt2d AcGeLine2d AcGeRay2d AcGeLineSeg2d AcGeCircArc2d AcGeEllipArc2d AcGeSplineEnt2d
AcGeCubicSpline2d AcGeNurbCurve2d AcGePolyLine2d AcGeExternalCurve2d AcGeEntity3d AcGePointEnt3d AcGePosition3d AcGePointOnCurve3d AcGePointOnSurface AcGeCurve3d AcGeLinearEnt3d AcGeLine3d AcGeRay3d AcGeLineSeg3d AcGeCircArc3d AcGeEllipArc3d AcGeExternalCurve3d AcGeSplineEnt3d AcGeCubicSpline3d AcGeNurbCurve3d AcGePolyLine3d AcGeAugPolyLine3d AcGeSurface AcGePlanarEnt AcGePlane AcGeBoundedPlane AcGeCylinder
AcGeCone AcGeSphere AcGeTorus AcGeNurbSurface AcGeExternalSurface AcGeOffsetSurface AcGeExternalBoundedSurface
Registrando comandos
No ARX pode-se adicionar novos comandos com a função ads_defun() ou com a macro
acedRegCmds(). Com a biblioteca de comandos ADS, os requisitos são antes passados pelo AutoLISP
e depois para o aplicativo. Com o ARX, os comandos são adicionados diretamente ao conjunto de comandos do AutoCAD.
Cada maneira de registrar os comandos afeta a forma de invocá-los. Se o comando de registro usado for o ads_defun():
Os comandos podem ser evoluídos através do AutoLISP ou das facilidades do ads_invoke()
Os comandos não poderão ser invocados usando a função command do AutoLISP ou a função
ads_command().
Se for usada a macro acedRegCmds():
Os comandos não são reconhecidos pelo AutoLISP ou pelas facilidades do ads_invoke()
Os comandos podem ser invocados usando a função command do AutolISP ou a função
ads_command()
Entrada de pontos
ARX e ADS tem modelos diferentes para comunicar com o AutoCAD. Um aplicativo ADS consiste num loop infinito que espera pela requisição do AutoLISP. Um aplicativo ARX tem um “entry
point” que é usado para mensagens. Então, quando um novo comando é registrado, ele passa a ser um
“entry point” adicional do aplicativo. Quando escrevemos funções virtuais para classes C++ nas biliotecas ARX, elas passam a ser novos “entry point” no aplicativo.
II.
Noções Básicas do Banco de Dados
O banco de dados do AutoCAD armazena os objetos e entidades que são feitas no desenho do AutoCAD. As entidades são objetos de desenho com representação gráfica e são possuídas pelo block table record que por sua vez é armazenado no block table. O banco de dados é constituído por elementos de banco de dados: o named object dictionary e um conjunto de symbol tables, dentre eles esta o block table.
DATABASE
Symbol Table
Layer Table
NOD
Block Table
Layer Table
Record
Objetos
Symbol Table
Record
Entidades
Block Table
Record
Banco de Dados do AutoCAD
Um desenho de AutoCAD é uma coleção de AcDb-objetos que são armazenados em um banco de dados. Cada objeto no banco de dados tem um handle que é uma identificação única dentro do contexto do desenho. Já as entidades são objetos com uma representação gráfica como, line, circle, etc.
Outros objetos de banco de dados importantes são os symbol tables e dictionaries, que são containers de armazenamento de objetos. No caso do symbol table tem-se um conjunto fixo de elementos no banco de dados, cada um dos quais contem instâncias de uma particular classe do
symbol table record. Não é permitido adicionar novos symbol table no banco de dados. Os dictionaries são objetos que mapeiam um symbol name para outro AcDb-objeto. Além disso
fornecem um container mais genérico para armazenamento de objetos, ele pode conter qualquer
AcDbObject ou subclasse, e também, pode-se criar novos elementos de banco de dados e
acrescentá-los em um novo dictionary.
Durante as sessões correntes do AutoCAD pode-se obter o banco de dados chamando a função global
acdbCurDwg( ). Múltiplos banco de dados podem ser carregados dentro de uma única sessão do
AutoCAD. Cada objeto na sessão tem um objeto ID, que é um único identificador para o objeto através de todos os banco de dados carregados. Em contraste, um objeto handle não é garantido ser único dentro de uma sessão do AutoCAD. Ele é único somente dentro de um escopo de um particular banco de dados.
Objeto ID
Com um objeto ID pode-se obter um ponteiro para o objeto do banco de dados atual, assim pode-se executar operações com ele. Para obter o objetoID :
Criar um objeto e acrescentar ao banco de dados
Usar o protocolo do banco de dados para obter o objeto ID dos objetos que são criados automaticamente se um banco de dados é criado
Usar o protocolo de classes específicas para obter o objeto ID
Usar um iterator para percorrer uma lista ou conjunto de objetos
Selecionar um conjunto de objetos
Objetos Essenciais do Banco de Dados
Quando os objetos são criados, eles são armazenados em containers no banco de dados. Entidades são adicionados para o block table record, e esses são adicionados para os symbol tables. Todos os outros objetos são adicionados para o named object dictionary ou para objetos que são seus proprietários.
O banco de dados tem inicialmente o seguinte aspecto:
Um conjunto de nove symbol tables que incluem o block table (MODEL_SPACE e PAPER_SPACE ) e o layer table ( layer 0 ).
Um named object dictionary que já contém p grupo dictionary e MLINE style dictionary ( STANDARD ).
Criando Objetos
Exemplo: Criação de uma line e sua adição no model space block table record:
AcDbObjectId
createLine()
{
AcGePoint3d endPt(10.0, 7.0, 0.0);
AcDbLine *pLine = new AcDbLine(startPt, endPt); AcDbBlockTable *pBlockTable;
acdbCurDwg()->getBlockTable(pBlockTable, AcDb::kForRead); AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite); pBlockTable->close(); AcDbObjectId lineId; pBlockTableRecord->appendAcDbEntity(lineId, pLine); pBlockTableRecord->close(); pLine->close(); return lineId; }
Exemplo: Criação de um circle e sua adição no model space block table record:
AcDbObjectId
createCircle()
{
AcGePoint3d center(9.0, 3.0, 0.0); AcGeVector3d normal(0.0, 0.0, 1.0);
AcDbCircle *pCirc = new AcDbCircle(center, normal, 2.0); AcDbBlockTable *pBlockTable; acdbCurDwg()->getBlockTable(pBlockTable, AcDb::kForRead); AcDbBlockTableRecord *pBlockTableRecord; pBlockTable->getAt(ACDB_MODEL_SPACE,pBlockTableRecord, AcDb::kForWrite); pBlockTable->close(); AcDbObjectId circleId; pBlockTableRecord->appendAcDbEntity(circleId, pCirc);
pBlockTableRecord->close(); pCirc->close();
return circleId; }
Exemplo: Obtem o layer symbol table do banco de dados, cria um novo layer table record e o
nomeia de ASDK_MYLAYER. O layer table record é adicionado para o layer table: void
createNewLayer() {
AcDbLayerTable *pLayerTable;
acdbCurDwg()->getLayerTable(pLayerTable, AcDb::kForWrite);
AcDbLayerTableRecord *pLayerTableRecord = new AcDbLayerTableRecord; pLayerTableRecord->setName("ASDK_MYLAYER"); AcDbLinetypeTable *pLinetypeTbl; acdbCurDwg()->getLinetypeTable(pLinetypeTbl, AcDb::kForRead); AcDbObjectId ltypeObjId; pLinetypeTbl->getAt("CONTINUOUS", ltypeObjId); pLayerTableRecord->setLinetypeObjectId(ltypeObjId); pLayerTable->add(pLayerTableRecord); pLayerTable->close(); pLayerTableRecord->close(); }
Abrindo e Fechando Objetos
Todo objeto precisa ter o protocolo de abrir e ser fechado. Esse protocolo garante que o objeto esta fisicamente na memória quando ele necessita ser acionado. Antes de modificar um objeto ele precisa ser aberto:
AcdbOpenObject( pObject, objId, AcDb::kForWrite );
O último parâmetro especifica se o objeto será lido (read), escrito (write) ou notificado (notify). No caso de write ele pode ser modificado. Quando a modificação estiver acabada, deve-se fechar o objeto, mas nunca antes do objeto ser adicionado no banco de dados:
PObject->close ( )
Exemplo: O exemplo a seguir muda a cor da entidade:
Acad::ErrorStatus
changeColor(AcDbObjectId entId, Adesk::UInt16 newColor)
{
AcDbEntity *pEntity;
acdbOpenObject(pEntity, entId, AcDb::kForWrite); pEntity->setColorIndex(newColor);
pEntity->close(); return Acad::eOk; }
Adicionando um Grupo para o Group Dictionary
Exemplo: Cria um group (pgroup) e coloca no group dictionary
void
createGroup(AcDbObjectIdArray& objIds, char* pGroupName)
{
AcDbGroup *pGroup = new AcDbGroup(pGroupName); for (int i = 0; i < objIds.length(); i++)
{ pGroup->append(objIds[i]); } AcDbDictionary *pGroupDict; acdbCurDwg()->getGroupDictionary(pGroupDict, AcDb::kForWrite); AcDbObjectId pGroupId;
pGroupDict->setAt(pGroupName, pGroup, pGroupId); pGroupDict->close();
}
III.
Escrevendo uma aplicação em ARX
Essa sessão descreve como escrever e rodar uma aplicação em ARX. Ela lista as mensagens passadas pelo AutoCAD para aplicações em ARX e mostra como essas aplicações respondem as mensagens. Considera também o registro de novos comandos, como carregar e descarregar uma aplicação e algo mais.
Estrutura de uma Aplicação em ARX
O AutoCAD chama o ARX através do módulo acrxEntryPoint ( ), que substitui o main do C ou ADS. A função acrxEntryPoint ( ) serve não somente como a entrada de pontos para a comunicação com uma aplicação do ARX do AutoCAD, mas também como um caminho para aplicações do ARX passar mensagens e retornar status para o AutoCAD.
extern "C"
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt); msg Representa a mensagem enviada
pkt Pacote de dados
AppRetCode Contem o status retornado do AutoCAD
Dentro da definição do acrxEntryPoint ( ) deve-se escrever um switch para decifrar as mensagens do AutoCAD. O código abaixo mostra o esqueleto:
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt) { switch(msg) { case AcRx::kInitAppMsg: break; case AcRx::kUnloadAppMsg: break; ...
default: break; } return AcRx::kRetOK; }
Mensagens Enviadas do AutoCAD para as Aplicações ARX
kInitAppMsg . kUnloadAppMsg kOleUnloadAppMsg kLoadDwgMsg kUnloadDwgMsg kDependencyMsg kNoDependencyMsg kInvkSubrMsg kEndMsg kPreQuitMsg kQuitMsg kSaveMsg kCfgMsg kEndMsgkCfgMsgkQuitMsgkSaveMsg
O processo das mensagens é praticamente todo feito em uma só direção, do AutoCAD para o aplicativo em ARX.
Registrando Novos Comandos
Command Stack
Os comandos do AutoCAD são armazenados em grupos no command stack, que é definido pela classe AcEdCommandStack. O command stack é criado para a sessão do AutoCAD e é um comando nativo adicionado ao AutoCAD. A macro acedRegCommands ( ) da o acesso para o command stack.
Pode-se adicionar comandos com AcEdCommand::addCommand ( ) e remover grupos com
AcEdCommand::removeGroup( ) ou remover comandos com AcEddCommandStack::removeCmd.
Acad::ErrorStatus
AcEdCommandStack::addCommand (const char* cmdGroupName, const char* cmdGlobalName, const char* cmdLocalName, Adesk::Int32 commandFlags, AcRxFunctionPtr functionAddr);
cmdGroupName Representação ASCII do grupo para adicionar o comando
cmdGlobalName Representação ASCII do nome global do comando para adicionar cmdLocalName Representação ASCII do nome local do comando para adicionar command-Flags Flags associados com o comando
functionAddr Endereço da função para sua execução quando invocado pelo AutoCAD
virtual Acad::ErrorStatus
AcEdCommandStack::removeCmd
(const char* cmdGroupName, const char* cmdGlobalName) = 0; virtual Acad::ErrorStatus
AcEdCommandStack::removeGroup (const char* groupName);
Quando um comando é invocado, o command stack é procurado pelo group name e então pelo
command name dentro do group. Essa procura não é feita em uma ordem lógica, porém o usuário, se
quiser, pode ter controle sobre ela.
Lookup Order
Quando um comando é invocado, o comando Stack é procurado pelo nome do grupo e depois pelo nome do comando. Geralmente, o primeiro o primeiro grupo registrado será o primeiro a ser pesquisado, mas podemos saber qual orem irá seguir. Para especificarmos o primeiro grupo que desejamos que seja pesquisado, podemos usar o comando abaixo:
AcEdCommandStack::popGroupToTop()
Caso não haja necessidade de traduzir o nome do comando local, o nome global pode ser usado para ambas situações.
Comandos Transparentes
Um comando pode ser transparente (ACRX_CMD_TRANSPARENT) ou modal (ACRX_CMD_MODAL). Um comando transparente pode ser invocado quando o usuário utilizando o prompt com outra ação. Já o modal só pode se invocado quando não houver outro comando na linha de prompt.
Querrying Commands
A biblioteca AcEd oferece classes para iteração através do comando Stack e par procurar comandos específicos. Todavia esse questionamento é executado pelo AutoCAD e nós usamos essas funções.
Exemplo: Implementa funções que são chamadas quando a aplicação é carregada (load) e
descarregada (unload) 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(); } void unloadApp() { acedRegCmds->removeGroup("ASDK_DICTIONARY_COMMANDS"); deleteAcRxClass(AsdkMyClass::desc()); }
Carregando uma Aplicação ARX
Métodos para carregar um aplicativo ARX:
Fornecer o aplicativo com aspectos que permitam ser carregados pelo AutoCAD
Especificar o aplicativo no arquivo inicial acad.rx
Utilizar AcRxDynamicLinker::loadModule( )
Usar o quadro de diálogo APPLOAD definido no bonus loadapp.arx
Usar a função arxload do AutoLISP
Usar a função ads_arxload( ) do ARX ou ADS Comando ARX no prompt do AutoCAD
Descarregando uma Aplicação ARX
Métodos para descarregar um aplicativo ARX:
Utilizar AcRxDynamicLinker::unloadModule( )
Usar o quadro de diálogo APPLOAD definido no bonus loadapp.arx
Usar a função arxunload do AutoLISP
Usar a função ads_arxunload( ) do ARX ou ADS
Comando ARX no prompt do AutoCAD
Comando ARX
A partir do comando ARX na linha de comando, tem-se o seguinte na liha de prompt:
?/Load/Unload/Commands/Options: Entre uma opção ou pressione ENTER ? - Lista as aplicações em ARX carregedas
Load - Carrega os arquivos .arx que foram especificados Unload - Descarrega as aplicações em ARX especificadas
Commands - Mostra todos os nomes de comandos e grupos registrados Options - Apresenta o relatório de alguns ítens do programa
Controle de Memória
Os objetos criados devem ser devidamente liberados da memória. No caso do C++, deve-se usar
AcDbObject::new para criar um objeto e AcDbObject::delete para destruí-lo.
IV.
Operações do Banco de Dados
Essa sessão descreve o protocolo básico do banco de dados incluindo como criar um banco de dados, como ler em um arquivo de desenho, e como salvar o banco de dados. As funções wblock e insert são também descritas aqui.
Banco de Dados Inicial
Quando uma sessão do AutoCAD começa tem-se os seguintes elementos:
Um conjunto de sete symbol tables
Block table (AcDbBlockTable)
Dimension style table (AcDbDimStyleTable) Layer table (AcDbLayerTable)
Linetype table (AcDbLinetypeTable)
Registered applications table (AcDbRegAppTable) Text style table (AcDbTextStyleTable)
User coordinate system table (AcDbUCSTable) Viewport table (AcDbViewportTable)
View table (AcDbViewTable)
Um named object dictionary
Um conjunto fixo de variáveis header
Criando e Populando um Banco de Dados
Usa-se new para criar um banco de dados e delete para destruí-lo. O construtor AcDbDatabase tem um argumento com default de Adesk::kTrue que cria o banco de dados populado com o objeto padrão. Se o argumento for Adesk::kFalse , então o banco de dados é criado vazio e pode ser populado.
Salvando um Banco de Dados
Para salvar o banco de dados: Acad::ErrorStatus
AcDbDatabase::saveAs(char* fileName);
A Operação wblock
A classe AcDbDatabase contém uma função wblock( ) sobrecarregada com três formas:
Criando um novo banco de dados a partir de um já existente
Acad::ErrorStatus
AcDbDatabase::wblock(AcDbDatabase*& newDb);
Criando um novo banco de dados com entidades: Copiando um Named Block
Acad::ErrorStatus
AcDbDatabase::wblock(AcDbDatabase*& newDb, AcDbObjectId recordId);
Criando um novo banco de dados com entidades: Copiando um Array de Entidades
Acad::ErrorStatus
AcDbDatabase::wblock(AcDbDatabase*& newDb, const AcDbObjectIdArray& idArray, const AcGePoint3d* point);
Inserindo um Banco de Dados
As funções AcDbDatabase::insert( ) copiam um banco de dados para o banco de dados que invocou a função, porém se alguns objetos tiverem um ponteiro do tipo ownership no named object
dictionary, é necessário utilizar a função de notificação AcEditorReactor.
Setando os Valores do Banco de Dados Corrente
Color
Se a cor não é especificada por uma entidade, o banco de dados armazena no sistema de variáveis CECOLOR.
Acad::ErrorStatus
AcDbDatabase::setCecolor(const AcCmColor& color); AcCmColor AcDbDatabase::cecolor() const;
Acad::ErrorStatus
AcDbDatabase::setCeltype(AcDbObjectId); AcDbObjectId AcDbDatabase::celtype() const;
Linetype Scale
Acad::ErrorStatus
AcDbDatabase::setLtscale(double); double AcDbDatabase::ltScale() const; Acad::ErrorStatus
AcDbDatabase::setCeltscale(double); double AcDbDatabase::celtscale() const; Acad::ErrorStatus
AcDbDatabase::setPsltscale(Adesk::Boolean) Adesk::Boolean AcDbDatabase::psltscale() const;
Layer
Acad::ErrorStatus
AcDbDatabase::setClayer(AcDbObjectId); AcDbObjectId AcDbDatabase::clayer() const;
Referências Externas
Referências externas (xrefs) são criadas exclusivamente pelo AutoCAD que cria um banco de dados contendo os xrefs. Para que se possa monitorar esse banco de dados deve-se usar as funções da classe
AcEditorReactor: beginAttach( ) otherAttach( ) abortAttach( ) endAttach( ) redirected( ) comandeered( )
void
createDwg()
{
// Cria um novo banco de dados
AcDbDatabase *pDb = new AcDbDatabase; // Obtem o model space block table record AcDbBlockTable *pBtbl; pDb->getBlockTable(pBtbl, AcDb::kForRead); AcDbBlockTableRecord *pBtblRcd; pBtbl->getAt(ACDB_MODEL_SPACE, pBtblRcd, AcDb::kForWrite); pBtbl->close();
// Cria dois circles e acrescenta no banco de dados
AcDbCircle *pCir1 = new AcDbCircle(AcGePoint3d(1,1,1), AcGeVector3d(0,0,1), 1.0),
*pCir2 = new AcDbCircle(AcGePoint3d(4,4,4), AcGeVector3d(0,0,1), 2.0); pBtblRcd->appendAcDbEntity(pCir1); pCir1->close(); pBtblRcd->appendAcDbEntity(pCir2); pCir2->close(); pBtblRcd->close(); pDb->saveAs("test1.dwg"); delete pDb; } void readDwg()
{
AcDbDatabase *pDb = new AcDbDatabase; pDb->readDwgFile("test1.dwg");
// abre o model space block table record AcDbBlockTable *pBlkTbl; pDb->getBlockTable(pBlkTbl, AcDb::kForRead); AcDbBlockTableRecord *pBlkTblRcd; pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForRead); pBlkTbl->close(); AcDbBlockTableRecordIterator *pBlkTblRcdItr; pBlkTblRcd->newIterator(pBlkTblRcdItr); AcDbEntity *pEnt;
for (pBlkTblRcdItr->start(); !pBlkTblRcdItr->done(); pBlkTblRcdItr->step()) { pBlkTblRcdItr->getEntity(pEnt, AcDb::kForRead); ads_printf("classname: %s\n", (pEnt->isA())->name()); pEnt->close(); } pBlkTblRcd->close(); delete pBlkTblRcdItr; delete pDb; }
V.
Objetos Banco de Dados
Essa sessão relata todos os objetos banco de dados do AutoCAD, entidades, symbol tables records e dictionaries. Também inclui abrir e fechar comandos, administrar objetos na memória, objetos ownership, e extensão de um objeto ou extension dictionary.
Abrindo e Fechando Objetos
Cada objeto pode ser referenciado de três formas:
Pelo seu handle: enquanto o AutoCAD não é salvo o desenho é armazenado no DWG, assim os
objetos são identificados pelos seus handles;
Pelo seu object ID: depois que o desenho é aberto as informações do desenho estão
armazenadas no AcDbDatabase, assim cada objeto tem no banco de dados um object ID. Esse object Id persiste durante a edição corrente, desde a criação até sua deleção;
Por um ponteiro em C++: As funções de abertura pegam o object ID como um argumento e retornam um ponteiro para um AcDbObject, esse ponteiro é válido até o objeto ser fechado.
DWG
Handle
Abre o Objeto Abre o ObjetoAcDbDatabase
Object ID
C++
Pointer
SAVE WBLOCK Fecha o ObjetoA função para abrir um objeto é: Acad::ErrorStatus
AcDbDatabase::acdbOpenObject(AcDbObject*& obj, AcDbObjectId id,
AcDb::OpenMode mode,
Adesk::Boolean openErasedObject = Adesk::kFalse) A função para mapear um handle para um object ID é:
Acad::ErrorStatus
getAcDbObjectId(AcDbObjectId& retId, Adesk::Boolean createIfNotFound, const AcDbHandle& objHandle, Adesk::UInt32 xRefId=0);
A função para abrir um objeto e requerer seu handle é: AcDbObject* pObject;
AcDbHandle handle;
pObject->getAcDbHandle(handle);
Um ads_name é equivalente para um AcDbObjectId, pode-se mudar usando-se: AcdbGetAdsName (ads_name& objName, AcDbObjectId objId);
AcdbGetObjectId (AcDbObjectId& objId, ads_name objName);
Geralmente, obtém-se um objeto através de uma seleção, e então o retorno é um ads_name que precisa ser trocado para um AcDbObjectId e ser aberto:
AcDbEntity*
selectEntity(AcDbObjectId& eId, AcDb::OpenMode openMode) {
ads_name en; ads_point pt;
ads_entsel("\nSelect an entity: ", en, pt); // muda ads_name para um object Id acdbGetObjectId(eId, en);
AcDbEntity * pEnt;
acdbOpenObject(pEnt, eId, openMode); return pEnt;
}
Pode-se abrir um objeto de três modos:
kForRead;
kForWrite;
kForNotify;
Pode acontecer vários erros se caso o objeto for aberto de uma forma errada ou se o objeto já estiver aberto.
Deletando Objetos
Quando se cria uma instância de um AcDbObject com o intento de adicionar no banco de dados, deve se usar AcDbObject::new. Quando um objeto é primeiro criado e não foi adicionado no banco de dados, pode-se deletá-lo. Do contrário, se o objeto já tiver sido adicionado no banco de dados, não se pode deletá-lo. O AutoCAD administra a deleção de todos os objetos residentes no banco de dados.
Ownership
Com exceção dos objetos raízes, symbol tables e named object dictionary, os demais objetos têm um dono:
Block table records possui as entidades;
Cada symbol table possui um particular tipo de symbol table record
Um AcDbDictionary pode possuir um AcDbObject;
Qualquer AcDbObject pode ter um extension dictionary; um objeto possui seu extension
dictionary;
Adicionando Dados Específicos no Objeto
Pode-se utilizar das seguintes formas para adicionar dados em uma aplicação:
Dados extendidos: consiste numa lista linkada de resbufs usada pelo aplicativo. ;
Xrecords;
Extension Dictionary de qualquer objeto: pode conter um arbitrário conjunto de objetos AcDbObject;
Objetos customizados que podem guardar dados.
Apagando Objetos
Qualquer objeto no banco de dados pode ser apagado com a seguinte função: Acad::ErrorStatus
AcDbObject::erase(Adesk::Boolean Erasing = Adesk::kTrue);
Quando um objeto do banco de dados é apagada, informações sobre ele são removidas do dictionary. Já quando uma entidade é apagada, ela é apagada no block table record.. Não é permitido abrir e apagar um objeto com AcDbOpenObject(), se isso for feito haverá uma mensagem de erro.Quando um objeto é apagado ele não é arquivado no arquivo DWG ou no DXF.
Objeto Filing
O Objeto Filing é usado nos seguintes casos:
Escrevendo e lendo arquivos DWG e DXF;
Na comunicação entre AutoCAD, AutoLISP, ADS e ARX;
No UNDO, INSERT, XREF e COPY;
Na paginação.
O AcDbObject tem duas funções membros para arquivar externamente: dwgout() e dxfout(), e duas funções membros para arquivar internamente: dwgin() e dxfin(). Essas funções são chamadas pelo AutoCAD.
VI.
Entidades
Descrição dos objetos com representação gráfica denominados Entidades. Listando as propriedades comuns das entidades.
Definição de Entidades
Uma entidade é um objeto que possui um banco de dados e também, uma representação gráfica como, lines, circles, text e outros. Um usuário pode ver uma entidade no desenho e manipulá-la
Ownership
Entidades no banco de dados normalmente pertencem a um AcDbBlockTableRecord. O block table quando é recém criado pelo banco de dados tem dois predefinidos records, MODEL_SPACE e
PAPER_SPACE. Adicionais records são adicionados sempre que o usuário cria novos block records.
A estrutura ownership para entidades do banco de dados é a seguinte: AcRxObject AcDbObject AcDbDictionary AcDbEntity AcDb3dSolid AcDbBlockBegin AcDbBlockEnd AcDbBlockReference † AcDbMInsertBlock † AcDbBody AcDbCurve AcDb2dPolyline † AcDb3dPolyline † AcDbArc AcDbCircle AcDbEllipse AcDbLeader AcDbLine AcDbRay AcDbSpline AcDbXline AcDbDimension AcDb2LineAngularDimension AcDb3PointAngularDimension AcDbAlignedDimension AcDbDiametricDimension
AcDbOrdinateDimension AcDbRadialDimension AcDbRotatedDimension AcDbFace AcDbFaceRecord AcDbFcf AcDbMline AcDbMText AcDbOleFrame AcDbPoint AcDbPolyFaceMesh † AcDbPolygonMesh † AcDbRegion AcDbSequenceEnd AcDbShape AcDbSolid AcDbText AcDbAttribute AcDbAttributeDefinition AcDbTrace AcDbVertex AcDb2dPolylineVertex AcDb3dPolylineVertex AcDbPolyFaceMeshVertex AcDbPolygonMeshVertex AcDbViewport AcDbProxyEntity
Propriedades Comuns das Entidades
Todas as entidades têm propriedades comuns que quando se adiciona para o block table record, automaticamente o AutoCAD (AcDbEntity::setDatabaseDefaults()) define os valores default, isso se a definição não estiver explícita em seu código:
Color
A cor das entidades pode ser um valor numérico de 0 até 256, sendo que as cores padrão são:
A seguinte função seta a cor da entidade e assim ignora o valor default: virtual Acad::ErrorStatus
AcDbEntity::setColorIndex(Adesk::UInt16 color); Adesk::UInt16
AcDbEntity::colorIndex() const;
Linetype
Quando uma entidade é instanciada, sua linetype é do tipo NULL. Quando a entidade é adicionada no banco de dados, se não tiver sido especificado pela entidade, a linetype é setada no valor default que é armazenado no sistema de variáveis CELTYPE.
A função seguinte permite estabelecer uma linetype para uma entidade: virtual Acad::ErrorStatus
Número da cor Nome da cor
1 Vermelho 2 Amarelo 3 Verde 4 Cinza 5 Blue 6 Magenta 7 Branco ou Preto 0 BYBLOCK 256 BYLAYER
AcDbEntity::setLinetype(const char* newVal); virtual Acad::ErrorStatus
AcDbEntity::setLinetype(AcDbObjectId newVal); A função retorna o nome da linetype corrente na entidade: char* AcDbEntity::linetype() const;
A função retorna o object ID para o symbol table record especificando a linetype: AcDbObjectId AcDbEntity::linetypeId() const;
Linetype
Scale
Quando uma entidade é instanciada, sua linetype scale é inicializada para um valor inválido. Quando a entidade é adicionada no banco de dados, se não tiver sido especificado pela entidade, a linetype scale é setada no valor default que é armazenado no sistema de variáveis CELTSCALE.
Linetype Scale Especificada pela Entidade
Acad::ErrorStatus
AcDbEntity::setLinetypeScale(double newVal); double
AcDbEntity::linetypeScale() const;
Regenerando um Desenho
Quando uma entidade é regenerada, sua linetype scale é um produto da entidade linetype scale e também do banco de dados global linetype scale.. Assim a linetype scale é calculada da seguinte forma:
effltscale = ent->linetypeScale() * ent->database()->ltscale();
Visibilidade
Se for especificado que uma entidade é invisível ela será independente do que foi estabelecido pelo banco de dados.
Acad::ErrorStatus
AcDbEntity::setVisibility(AcDb::Visibility newVal); AcDb::Visibility
Layer
Pode-se especificar um layer para toda entidade, se isso não for feito ela terá o layer default 0. Cada layer tem uma série de propriedades associadas frozen/thawed, on/off, locked/unlocked, color,
linetype e viewport. As funções seguintes permitem que o layer seja estabelecido para uma entidade:
Acad::ErrorStatus
AcDbEntity::setLayer(const char* newVal); Acad::ErrorStatus
AcDbEntity::setLayer(AcDbObjectId newVal);
Essa função retorna o nome do layer corrente da entidade: char* AcDbEntity::layer() const;
Essa função retorna o object ID do layer corrente: AcDbObjectId AcDbEntity::layerId() const;
Funções Comuns das Entidades
intersectWith( ) : é usada em operações de interseção;
transformBy( ) : é usada como uma matriz de transformação quando o objeto sofre certas
mudanças;
getTransformedCopy( ) : cria uma cópia e aplica uma transformação no objeto;
getOsnapPoints( ) : retorna o osnap points e seu tipo;
getGripPoints( ) : retorna o grip points que é um conjunto do stretch points getStretchPoints( ) : defaults do para o getGripPoints( )
moveStretchPointsAt( ) : é usado pelo comando STRETCH para mover certos pontos e defaults
para transformBy( );
moveGripPointsAt( ) : é usado pelos grips para mover pontos específicos pontos e defaults para
transformBy( );
worldDraw( ) : cria uma representação gráfica independente da entidade;
vuewportDraw( ) : : cria uma representação gráfica dependente da entidade;
draw( ) : desenha as entidades gráficas;
list( ) : é usada pelo comando LIST e produz um ads_printf( );
getGeomExtents ( ) : retorna as esquinas de uma caixa fechada da entidade;
explode( ) : decompõe uma entidade em um conjunto de entidades elementares;
getSubentPathsAtGsMarker( ) : retorna o caminho da subentidade que corresponde ao dado GS marker;
getGsMarkersAtSubentPath( ) : retorna o GS marker que corresponde ao caminho da
subentidade;
subentPtr( ) : retorna um ponteiro para o caminho da subentidade;
highlight ( ) : torna as subentidades com uma representação na seleção do tipo highlight.
Object Snap
Para adquirir os snap points para os modos específicos usa-se a função getOsnapPoints( ). Os modos existentes são:
kOsModeEnd Endpoint kOsModeMid Midpoint kOsModeCen Center kOsModeNode Node kOsModeQuad Quadrant kOsModeIns Insertion kOsModePerp Perpendicular kOsModeTan Tangent kOsModeNear Nearest
A função é da seguinte forma: virtual Acad::ErrorStatus
AcDbEntity::getOsnapPoints( AcDb::OsnapMode osnapMode, int gsSelectionMark,
const AcGePoint3d& pickPoint,
const AcGePoint3d& lastPoint, const AcGeMatrix3d& viewXform, AcGePoint3dArray& snapPoints, AcDbIntArray& geomIds) const;
Funções de Transformação
A classe AcDbEntity fornece duas funções de transformação: virtual Acad::ErrorStatus
AcDbEntity::transformBy(const AcGeMatrix3d& xform);
Essa função é chamada no Grip Move, ROTATE, SCALE e MIRROR virtual Acad::ErrorStatus
AcDbEntity::getTransformedCopy(const AcGeMatrix3d& xform, AcDbEntity*& ent) const;
Essa função é chamada quando houver a necessidade de criar uma nova entidade, como quando uma entidade é explodida e sofre uma escala não uniforme.
Interseção por Pontos
A função intersectWith( ) retorna os pontos onde uma entidade intercepta outra no desenho. Os tipos de interseção podem ser:
kOnBothOperands (entidade extendida)
kExtendThis
kExtendArg
kExtendBoth
A função intersectWith( ) é uma função sobrecarregada com duas formas, sendo que a Segunda leva um argumento adicional que o plano de projeção para determinar a aparente interseção:
virtual Acad::ErrorStatus
AcDbEntity::intersectWith( const AcDbEntity* ent, AcDb::Intersect intType,
AcGePoint3dArray& points,
int thisGsMarker = 0, int otherGsMarker = 0) const; virtual Acad::ErrorStatus
AcDbEntity::intersectWith( const AcDbEntity* ent, AcDb::Intersect intType,
const AcGePlane& projPlane, AcGePoint3dArray& points,
int thisGsMarker = 0,
int otherGsMarker = 0) const;
GS Markers e Subentidades
Toda entidade para ser desenhada chama as primitivas gráficas, assim como, lines, circles e etc que são contidas no AcGi library. Qualquer classe derivada do AcDbEntity pode associar um GS( sistema gráfico) marker e cada subclasse da entidade controla onde inserir seu GS markers. Onde um usuário seleciona uma entidade, o GS marker é usado para identificar qual parte da entidade foi selecionada.
Explodindo Entidades
Algumas entidades podem ser explodidas em um conjunto de simples elementos, pois a função explode( ) cria um array de objetos derivados de AcDbEntity. Quando um entidade é explodida:
A aparencia visual é constante;
A entidade explodida é apagada do banco de dados;
Uma ou mais entidades são criadas e adicionadas ao banco de dados.
Criando Instancias de Entidades no AutoCAD
Criando uma Simples Entidade: criação de uma line e seu acrescimo no model space block table record AcDbObjectId createLine() { AcGePoint3d startPt(4.0, 2.0, 0.0); AcGePoint3d endPt(10.0, 7.0, 0.0);
AcDbLine *pLine = new AcDbLine(startPt, endPt); AcDbBlockTable *pBlockTable; acdbCurDwg()->getBlockTable(pBlockTable, AcDb::kForRead); AcDbBlockTableRecord *pBlockTableRecord; pBlockTable->getAt(ACDB_MODEL_SPACE,pBlockTableRecord, AcDb::kForWrite); pBlockTable->close(); AcDbObjectId lineId; pBlockTableRecord->appendAcDbEntity(lineId, pLine); pBlockTableRecord->close(); pLine->close(); return lineId; }
Criando um Simples Block Table Record: criação de um novo block table record e seu acrescimo
no block table. void
makeABlock()
{
// Cria e nomeia um novo block table record.
AcDbBlockTableRecord *pBlockTableRec = new AcDbBlockTableRecord(); pBlockTableRec->setName("ASDK-NO-ATTR");
AcDbBlockTable *pBlockTable = NULL;
acdbCurDwg()->getBlockTable(pBlockTable, AcDb::kForWrite); // Adiciona o novo block table record para o block table.
AcDbObjectId blockTableRecordId;
pBlockTable->add(blockTableRecordId, pBlockTableRec); pBlockTable->close();
// Cria e adiciona uma line no block record. AcDbLine *pLine = new AcDbLine(); AcDbObjectId lineId; pLine->setStartPoint(AcGePoint3d(3, 3, 0)); pLine->setEndPoint(AcGePoint3d(6, 6, 0)); pLine->setColorIndex(3); pBlockTableRec->appendAcDbEntity(lineId, pLine); pLine->close(); pBlockTableRec->close(); }
Entidades Complexas
Criando uma Entidade Complexa
void
createPolyline() {
// Seta 4 verteces para a pline AcGePoint3dArray ptArr;
ptArr.setLogicalLength(4); for (int i = 0; i < 4; i++) {
ptArr[i].set((double)(i/2), (double)(i%2), 0.0); }
// Aloca dinamicamente um objeto AcDb2dPolyline, // dando 4 elementos cujo a locação é fornecida em // ptArr. A polyline é fechada e não é curva.
AcDb2dPolyline *pNewPline = new AcDb2dPolyline( AcDb::k2dSimplePoly, ptArr, 0.0, Adesk::kTrue); pNewPline->setColorIndex(3);
// Ponteiro para um BlockTable Object AcDbBlockTable *pBlockTable;
acdbCurDwg()->getBlockTable(pBlockTable, AcDb::kForRead); // Ponteiro para MODEL_SPACE BlockTableRecord
AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE,pBlockTableRecord, AcDb::kForWrite); pBlockTable->close();
// Adiciona a pline para o banco de dados e obtem seu object ID AcDbObjectId plineObjId; pBlockTableRecord->appendAcDbEntity(plineObjId, pNewPline); pBlockTableRecord->close(); // Layer "0" pNewPline->setLayer("0"); pNewPline->close(); }
Acesso ao Sistema de Coordenadas
Funções das entidades setam os valores de suas coordenadas usando World Coordinate System . Tem-se como exceção o caso da clasTem-se AcDb2dPolylineVextex, que usa o valor da Entity Coordinate System.
VII.
Objetos Container
Essa sessão descreve os objetos container usados no banco de dados do AutoCAD: symbol tables, dictionaries, groups e xrecords. Mostra também como utilizá-los , interagi-los e como criá-los.
Comparação entre Symbol Tables e Dictionaries
Symbol tables e dictionaries executam essencialmente a mesma função; eles contem entradas que
são objetos de banco de dados que são acessados utilizando-se uma string chave. Pode-se adicionar outras entradas a esses objetos e também usar iterators para percorrer passos a passo as entradas e conteúdos.
O AutoCAD contem um conjunto fixo de nove symbol tables, que não podem ser criados ou deletados. O que pode ser feito é acrescentar ou mudar as entradas em um symbol tables (records). Sendo que cada symbol table contem somente um tipo particular de objetos.
Os dictionaries fornecem um mecanismo similar para armazenamento e recuperação de objetos com nomes chaves. O AutoCAD cria o named object dictionary sempre que cria um novo desenho, e a partir desse pode se criar outro objetos e adicioná-los no mesmo. Contudo, o mais prático seria adicionar um único objeto no named object dictionary e a partir dele adicionar outros dictionaries. Tipicamente, o objeto possuído é uma classe container assim como um dictionary. O dictionary, por default, contém dois dictionaries: ACAD_GROUP e ACAD_MLINESTYLE.
A classe hierárquica para symbol tables, symbol tables records, dictionaries e iterators é a seguinte: AcRxObject AcDbObject AcDbDictionary AcDbDictionaryIterator (AcRxObject) (AcDbObject)
AcDbSymbolTable AcDbBlockTable AcDbDimStyleTable AcDbLayerTable AcDbLinetypeTable AcDbRegAppTable AcDbTextStyleTable AcDbUCSTable AcDbAbstractViewTable AcDbViewportTable AcDbViewTable AcDbSymbolTableRecord AcDbBlockTableRecord AcDbDimStyleTableRecord AcDbLayerTableRecord AcDbLinetypeTableRecord AcDbRegAppTableRecord AcDbTextStyleTableRecord AcDbUCSTableRecord AcDbAbstractViewTableRecord AcDbViewportTableRecord AcDbViewTableRecord AcDbSymbolTableIterator AcDbBlockTableIterator AcDbBlockTableRecordIterator AcDbDimStyleTableIterator AcDbLayerTableIterator
AcDbLinetypeTableIterator AcDbRegAppTableIterator AcDbTextStyleTableIterator AcDbUCSTableIterator AcDbAbstractViewTableIterator AcDbViewTableIterator AcDbViewportTableIterator
Symbol Tables
O banco de dados do AutoCAD contem as seguintes symbol tables:
Block table (AcDbBlockTable; BLOCK)
Layer table (AcDbLayerTable; LAYER)
Text style table (AcDbTextStyleTable; STYLE)
Linetype table (AcDbLinetypeTable; LTYPE)
View table (AcDbViewTable; VIEW)
UCS table (AcDbUCSTable; UCS)
Viewport table (AcDbViewportTable; VPORT)
Registered applications table (AcDbRegAppTable)
Dimension styles table (AcDbDimStyleTable; DIMSTYLE)
Cada classe symbol table fornece uma função getAt( ) para procurar o record especificado pelo nome. Para sobrecarregar essa função tem-se:
Acad::ErrorStatus
AcDb##BASE_NAME##Table::getAt(const char* pEntryName, AcDb::OpenMode mode,
AcDb##BASE_NAME##TableRecord*& pRecord,
Adesk::Boolean openErasedRecord = Adesk::kFalse) const; Acad::ErrorStatus
AcDb##BASE_NAME##Table::getAt(const char* pEntryName, AcDbObjectId& recordId,
Adesk::Boolean getErasedRecord = Adesk::kFalse) const;
Outra funções pra o symbol tables são: Adesk::Boolean
AcDb##BASE_NAME##Table::has(const char* pName) const; Acad::ErrorStatus
AcDb##BASE_NAME##Table::add(AcDb##BASE_NAME##TableRecord* pRecord);
Acad::ErrorStatus
AcDb##BASE_NAME##Table::add(AcDbObjectId& record Id, AcDb##BASE_NAME##TableRecord*
pRecord);
Block Table
Entidades no banco de dados pertencem ao block table record. O block table contem dois records como default, MODEL_SPACE e PAPER_SPACE, que correspondem a dois espaços de edição.
Layer Table
O layer table contem um layer, layer 0, por default. O usuário pode adicionar outros através do comando LAYER.
Propriedades do Layer
A classe AcDbLayerTableRecord contem funções membro para especificar o número de propriedades que afetaram a entidade.
Frozen/Thawed void AcDbLayerTableRecord::setIsFrozen(Adesk::Boolean); Adesk::Boolean AcDbLayerTableRecord::isFrozen() const; On/Off void AcDbLayerTableRecord::setIsOff(Adesk::Boolean); Adesk::Boolean AcDbLayerTableRecord::isOff() const; Viewport void AcDbLayerTableRecord::setVPDFLT(Adesk::Boolean);
Adesk::Boolean AcDbLayerTableRecord::VPDFLT() const; Locked/Unlocked void AcDbLayerTableRecord::setIsLocked(Adesk::Boolean); Adesk::Boolean AcDbLayerTableRecord::isLocked() const; Color
void AcDbLayerTableRecord::setColor(const AcCmColor &color); AcCmColor AcDbLayerTableRecord::color() const; Linetype void AcDbLayerTableRecord::setLinetypeObjectId(AcDbObjectId); AcDbObjectId AcDbLayerTableRecord::linetypeObjectId() const;
Criando e Modificando um Layer Table Record
O exemplo mostra como criar um novo layer table record(AcDbLayerTableRecord) e setar certos atributos do layer.
void addLayer() { AcDbLayerTable *pLayerTbl; acdbCurDwg()->getLayerTable(pLayerTbl, AcDb::kForWrite); if (!pLayerTbl->has("testlayer")) { AcDbLayerTableRecord *pLayerTblRcd = new AcDbLayerTableRecord; pLayerTblRcd->setName("ASDK_TESTLAYER"); pLayerTblRcd->setIsFrozen(0); // layer para THAWED pLayerTblRcd->setIsOff(0); // layer para ON
pLayerTblRcd->setVPDFLT(0); // viewport default pLayerTblRcd->setIsLocked(0); // un-locked
AcCmColor color;
color.setColorIndex(1); // seta a cor para vermelho pLayerTblRcd->setColor(color);
// Para linetype é necessário fornecer o object id da // linetype record AcDbObjectId ltId; acdbCurDwg()->getLinetypeTable(pLinetypeTbl, AcDb::kForRead); if ((pLinetypeTbl->getAt("DASHED", ltId)) != Acad::eOk) {
ads_printf("\nUnable to find DASHED" " linetype. Using CONTINUOUS"); pLinetypeTbl->getAt("CONTINUOUS", ltId); } pLinetypeTbl->close(); pLayerTblRcd->setLinetypeObjectId(ltId); pLayerTbl->add(pLayerTblRcd); pLayerTblRcd->close(); pLayerTbl->close(); } else {
ads_printf("\nlayer already exists"); }
}
Cada symbol table tem um iterator correspondente que pode ser criado com a função AcDb##BASE_NAME::newIterator( ). AcDb##BASE_NAME##Table::newIterator() function. Acad::ErrorStatus AcDb##BASE_NAME##Table::newIterator( AcDb##BASE_NAME##TableIterator*& pIterator, Adesk::Boolean atBeginning = Adesk::kTrue, Adesk::Boolean skipErased = Adesk::kTrue) const;
A função newIterator( ) cria um objeto que pode ser usado para percorrer através do conteúdo da
table e estabelecer pIterator para apontar para o objeto iterator. É possível se criar um novo iterator, mas não se pode esquecer de deletá-lo antes de fechar o symbol table. A classe AcDbBlockTableRecord retorna um objeto da classe AcDbBlockTableRecordIterator , que permite
percorrer através das entidades contidas no block table record.
Interagindo sobre Tables
O exemplo cria um iterator que percorre pelo symbol table record na linetype table. void
iterateLinetypes()
{
AcDbLinetypeTable *pLinetypeTbl;
acdbCurDwg()->getLinetypeTable(pLinetypeTbl, AcDb::kForRead); // Cria um novo iterator.
AcDbLinetypeTableIterator *pLtIterator; pLinetypeTbl->newIterator(pLtIterator); // Percorre a table
char *pLtName;
for (; !pLtIterator->done(); pLtIterator->step()) {
pLtIterator->getRecord(pLtTableRcd, AcDb::kForRead); pLtTableRcd->getName(pLtName);
pLtTableRcd->close();
ads_printf("\nLinetype name is: %s", pLtName); free(pLtName); } delete pLtIterator; pLinetypeTbl->close(); }
Dictionaries
Para criar um novo dictionary, é necessário criar uma instancia do AcDbDictionary, adicionar no banco de dados e registrar com o objeto. Quando isso acontece o dictionary automaticamente anexa um reactor para a entrada. Com a função setAt( ) adiciona objetos para o dictionary e o banco de dados.
Acad::ErrorStatus
AcDbDictionary::setAt(const char* pSrchKey, AcDbObject* pNewValue,
AcDbObjectId& retObjId);
Groups e o Group Dictionary
Um Group é um objeto container que mantem uma coleção ordenada de entidades no banco de dados, porem ele não tem um ownership link para as entidades que contem. Quando uma entidade é apagada , os groups que a contem são automaticamente removidos. Se a mesma entidade for desapagada, os groups são novamente inseridos.
Algumas funções podem ser usadas para os Groups e não é necessário setar cada elemento, por exemplo: setColor(), setLayer(), setLinetype(), setVisibility(), and setHighlight(). Os Groups devem ser armazenados no GROUP dictionary, que pode ser obtido da seguinte forma:
AcDbDictionary* pGrpDict = acdbCurDwg()->getGroupDictionary( pGroupDict, AcDb::kForWrite);
Criando um Dictionary
O exemplo cria um dictionary(ASDK_DICT) e adiciona para o named object dictionary. Então ele cria dois novos objetos da classe customizada AsdkMyClass e adiciona no dictionary.
void
createDictionary() {
AcDbDictionary *pNamedobj;
acdbCurDwg()->getNamedObjectsDictionary(pNamedobj, AcDb::kForWrite); // Checa a existencia do 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) {
// Cria novos objects para adicionar para o novo dictionary, 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();
}
Interagindo sobre Entradas do Dictionary
A classe iterator para dictionaries é AcDbDictionaryIterator. O exemplo a seguir obtem um
dictionary (ASDK_DICT) do named object dictionary e usa um iterador para percorrer as entradas
do dictionary. void iterateDictionary() { AcDbDictionary *pNamedobj; acdbCurDwg()->getNamedObjectsDictionary(pNamedobj, AcDb::kForRead); // Dá o ponteiro para ASDK_DICT dictionary
AcDbDictionary *pDict;
pNamedobj->getAt("ASDK_DICT", (AcDbObject*&)pDict, AcDb::kForRead); pNamedobj->close();
// Dá o iterador para ASDK_DICT dictionary
AcDbDictionaryIterator* pDictIter= pDict->newIterator(); AsdkMyClass *pMyCl;
Adesk::Int16 val;
for (; !pDictIter->done(); pDictIter->next()) { // Dá o corrente record, o abre para ler
pDictIter->getObject((AcDbObject*&)pMyCl, AcDb::kForRead); pMyCl->getData(val);
pMyCl->close();
ads_printf("\nintval is: %d", val); }
delete pDictIter; pDict->close();
}
Xrecords
Xrecords permite a adição de dados específicos de forma arbitrária e limitada. Essa é uma forma
alternativa de guardar dados mais utilizada em ADS ou AutoLISP.
Definindo Novas Classes
VIII.Derivando um Classe Customizada ARX
Nessa sessão tem-se como utilizar as macros em ARX derivando da classe customizada ARX.
Derivação da Classe Customizada
É possível derivar novas classes das classes já existentes na hierarquia ARX: AcRxObject AcRxService AcDbObject AcDbEntity AcDbCurve AcDbObjectReactor AcDbDatabaseReactor AcDbEntityReactor AcTransactionReactor AcEdJig AcEditorReactor
Classes que não devem derivar: AcDbAttribute
AcDbArc AcDbBlockReference AcDbCircle AcDbFace AcDbLine AcDbMInsertBlock AcDbPoint AcDbShape AcDbSolid AcDbText AcDbTrace
All AcDbXxxDimension classes AcDbViewport
AcDbGroup
All classes derived from AcDbSymbolTable All classes derived from AcDbSymbolTableRecord AcDbBlockBegin AcDbBlockEnd AcDbSequenceEnd AcDb2dPolyline AcDb2dPolylineVertex AcDb3dPolyline AcDb3dPolylineVertex AcDbPolygonMesh AcDbPolygonMeshVertex AcDbPolyFaceMesh AcDbPolyFaceMeshVertex
AcDbFaceRecord
Identificação de Classes Rotina
Toda classe na hierarquia ARX que é derivada de AcRxObject tem uma classe de
descrição do objeto, que é uma instancia de AcRxClass que guarda informações para o
tipo de identificação. Essas classes são criadas na inicialização, quando classes são
registradas com ARX e são adicionadas no dictionary, acrxClassDictionary.
Macro:Classes de Declaração
As macros são usadas numa seção pública das classes de declaração: class myClass : public AcRxObject
{ public: ACRX_DECLARE_MEMBERS(myClass); ... }; Quando expandida:
virtual AcRxClass* isA() const; static AcRxClass* gpDesc; static AcRxClass* desc();
static AsdkPoly* cast(const AcRxObject* inPtr) {
return ((inPtr == 0)
|| !inPtr->isKindOf(AsdkPoly::desc())) ? 0 : (AsdkPoly*)inPtr;
};
static void rxInit();
Para implementar uma classe customizada, tem-se tres macros:
ACRX_NO_CONS_DEFINE_MEMBERS(CLASS_NAME, PARENT_CLASS)
Usa-se para classes abstratas e qualquer outra classe que não deve ser instanciada.
ACRX_CONS_DEFINE_MEMBERS(CLASS_NAME, PARENT_CLASS, VERNO)
Usa-se para classes transientes que podem ser instanciadas, mas não escritas em arquivo.
ACRX_DXF_DEFINE_MEMBERS(CLASS_NAME,PARENT_CLASS,
PROXY_FLAGS, DXF_NAME, APP)
Usa-se para classes que podem ser escritas, ou lidas de arquivos DWG e DXF. Cada uma dessas classes define:
Classe de descrição do objeto;
Classe inicialização (função);
A função desc( ) para a classe;
A função virtual isA( ) que a classe deverá sobrecarregar.
Classe de Inicialização ( Função de Inicialização)
A função da classe de inicialização para cada classe é rxInit( ). Uma aplicação que define uma classe customizada invoca essa função durante a inicialização da rotina.
Essa função é definida automaticamente por cada das tres macros
ACRX_XXX_DEFINE_MEMBERS( ) e executa as seguintes tarefas:
Registra a classe customizada;
Cria a classe que descreve o objeto e armazena no dicitonary;
IX.
Derivando de AcDbObject
Essa sessão descreve como derivar uma classe customizada de AcDbObject. Fornece detalhes sobre os arquivos, sobre os quatro tipos de objetos referênciados, sobre o undo e o redo.
Overview
Quando se utiliza subclasses de AcDbObject, há um número de funções virtuais que podem ser sobrecarregadas.
AcDbObject: Funções para Sobrecarregar Essencialmente
virtual Acad::ErrorStatus
dwgInFields(AcDbDwgFiler* filer); virtual Acad::ErrorStatus
dwgOutFields(AcDbDwgFiler* filer) const; virtual Acad::ErrorStatus
dxfInFields(AcDbDxfFiler* filer); virtual Acad::ErrorStatus
dxfOutFields(AcDbDxfFiler* filer) const;
<Destructor>
AcDbObject: Funções para Sobrecarregar Frequentemente
virtual Acad::ErrorStatus audit(AcDbAuditInfo*);
virtual Acad::ErrorStatus subClose(); virtual Acad::ErrorStatus
deepClone(AcDbObject* pOwnerObject, AcDbObject*& pClonedObject, AcDbIdMapping& idMap,
Adesk::Boolean isPrimary = Adesk::kTrue) const; virtual Acad::ErrorStatus
wblockClone(AcRxObject* pOwnerObject, AcDbObject*& pClonedObject, AcDbIdMapping& idMap,
Adesk::Boolean isPrimary = Adesk::kTrue) const;
AcDbObject: Funções para Sobrecarregar Eventualmente