ObjectARX.pdf
Short Description
Download ObjectARX.pdf...
Description
ObjectARX Básico
Página 1 de 104
Esta é a versão em html do arquivo http://www.cadtec.dees.ufmg.br/publico/Regina/ObjectARX%20B% C3%A1sico/ApostilaARX/ObjARX_Apostila.doc. G o o g l e 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 1a 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 Introdução
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 2 de 104
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.
Aplicativos ADS
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 3 de 104
IPC
AutoLISP IPC
AutoCAD
Aplicativos ARX Bibliotecas ARX Classe AcRx O 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 O AcEd fornece classes para definição e registro de novos comandos (“nativos”) no AutoCAD que
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 4 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 5 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 6 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 7 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 8 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 9 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 10 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 11 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 12 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 13 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 14 de 104
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 startPt(4.0, 2.0, 0.0);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 15 de 104
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);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 16 de 104
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:
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 17 de 104
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(); pGroup->close();
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 18 de 104
}
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; ...
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 19 de 104
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.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 20 de 104
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() Global versus Local
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 21 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 22 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 23 de 104
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);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 24 de 104
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; Linetype
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 25 de 104
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( )
Exemplo de Operações no Banco de Dados
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 26 de 104
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()
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 27 de 104
{ 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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 28 de 104
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 Objeto
AcDbDatabase Object ID C++ Pointer SAVE WBLOCK
Fecha o Objeto
A função para abrir um objeto é: Acad::ErrorStatus AcDbDatabase::acdbOpenObject(AcDbObject*& obj, AcDbObjectId id,
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 29 de 104
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;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 30 de 104
} 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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 31 de 104
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.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 32 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 33 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 34 de 104
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: Número da cor 1 2 3 4 5 6 7 0 256
Nome da cor Vermelho Amarelo Verde Cinza Blue Magenta Branco ou Preto BYBLOCK BYLAYER
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 35 de 104
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 AcDbEntity::visibility() const;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 36 de 104
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:
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 37 de 104
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 int
osnapMode,
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:
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 38 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 39 de 104
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"); // Block table.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 40 de 104
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;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 41 de 104
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(); }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 42 de 104
Acesso ao Sistema de Coordenadas Funções das entidades setam os valores de suas coordenadas usando World Coordinate System . Temse como exceção o caso da classe 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)
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 43 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 44 de 104
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;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 45 de 104
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);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 46 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 47 de 104
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"); } } Iterators
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 48 de 104
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 AcDbLinetypeTableRecord *pLtTableRcd;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 49 de 104
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);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 50 de 104
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();
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 51 de 104
} 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();
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 52 de 104
}
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 AcDbAttributeDefinition
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 53 de 104
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
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 54 de 104
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();
Macro:Classes de Implementação http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 55 de 104
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 ACRX_XXX_DEFINE_MEMBERS( ) e executa as seguintes tarefas:
das
tres
macros
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.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 56 de 104
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;
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 virtual Acad::ErrorStatus
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 57 de 104
subErase(Adesk::Boolean erasing); virtual Acad::ErrorStatus subHandOverTo(AcDbObject* newObject); virtual Acad::ErrorStatus subOpen(AcDb::OpenMode); virtual Acad::ErrorStatus subCancel(); virtual Acad::ErrorStatus subSwapIdWith(AcDbObjectId otherId, Adesk::Boolean swapXdata = Adesk::kFalse); AcDbObject: Funções para Sobrecarregar Raramente virtual Acad::ErrorStatus setOwnerId(AcDbObjectId); virtual resbuf* xData(const char* regappName = NULL) const; virtual Acad::ErrorStatus setXData(const resbuf* xdata); virtual void addPersistentReactor(AcDbObjectId objId); virtual Acad::ErrorStatus removePersistentReactor(AcDbObjectId objId); virtual void cancelled(const AcDbObject* dbObj); virtual void copied(const AcDbObject* dbObj, const AcDbObject* newObj); virtual void
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 58 de 104
erased(const AcDbObject* dbObj, Adesk::Boolean pErasing = Adesk::kTrue); virtual void goodbye(const AcDbObject* dbObj); virtual void openedForModify(const AcDbObject* dbObj); virtual void modified(const AcDbObject* dbObj); virtual void modifyUndone(const AcDbObject* dbObj); virtual void modifiedXData(const AcDbObject* dbObj); virtual void unappended(const AcDbObject* dbObj); virtual void objectClosed(const AcDbObjectId objId); virtual void modifiedGraphics(const AcDbEntity* dbEnt); AcRxObject: Funções para Sobrecarregar Raramente virtual AcRxObject* clone() const; virtual void copyFrom(const AcRxObject* pSrc); virtual HRESULT __stdcall QueryInterface ( REFIID riid, void ** ppvObject ); virtual ULONG __stdcall AddRef();
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 59 de 104
virtual ULONG __stdcall Release(); AcDbEntity: Funções para Sobrecarregar virtual Adesk::Boolean worldDraw(AcGiWorldDraw* mode); virtual void viewportDraw(AcGiViewportDraw* mode); virtual Acad::ErrorStatus getGeomExtents(AcDbExtents& extents) const; virtual Acad::ErrorStatus transformBy(const AcGeMatrix3d& xform); virtual Acad::ErrorStatus getTransformedCopy(const AcGeMatrix3d& xform, AcDbEntity*& ent) const; virtual Acad::ErrorStatus getGripPoints(AcGePoint3dArray& gripPoints, AcDbIntArray& osnapModes, AcDbIntArray& geomIds) const; virtual Acad::ErrorStatus moveGripPointsAt(const AcDbIntArray& indices, const AcGeVector3d& offset); AcDbEntity: Funções para Sobrecarregar Usualmente virtual void list() const; virtual Acad::ErrorStatus intersectWith( const AcDbEntity* ent, AcDb::Intersect intType,
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 60 de 104
AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const; virtual Acad::ErrorStatus intersectWith( const AcDbEntity* ent, AcDb::Intersect intType, const AcGePlane& projPlane, AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const; virtual Acad::ErrorStatus getOsnapPoints(AcDb::OsnapMode osnapMode, int gsSelectionMark, const AcGePoint3d& pickPoint, const AcGePoint3d& lastPoint, const AcGeMatrix3d& viewXform, AcGePoint3dArray& snapPoints, AcDbIntArray& geomIds) const; virtual Acad::ErrorStatus getStretchPoints(AcGePoint3dArray&) const; virtual Acad::ErrorStatus moveStretchPointsAt(const AcDbIntArray& indices, const AcGeVector3d& offset); virtual Acad::ErrorStatus explode(AcDbVoidPtrArray& entitySet) const; virtual Acad::ErrorStatus getSubentPathsAtGsMarker(AcDb::SubentType type,
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 61 de 104
int gsMark, const AcGePoint3d& pickPoint, const AcGeMatrix3d& viewXform, int& numPaths, AcDbFullSubentPath* & subentPaths, int numInserts = 0, AcDbObjectId* entAndInsertStack = NULL) const; virtual Acad::ErrorStatus applyPartialUndo(AcDbDwgFiler* undoFiler, AcRxClass* classObj); virtual void subSetDatabaseDefaults(AcDbDatabase* pDb); virtual void getEcs(AcGeMatrix3d& retVal) const; virtual Acad::ErrorStatus getGsMarkersAtSubentPath(const AcDbFullSubentPath& subPath, AcDbIntArray& gsMarkers) const; virtual Acad::ErrorStatus highlight(const AcDbFullSubentPath& subId = kNullSubent) const; virtual Acad::ErrorStatus unhighlight(const AcDbFullSubentPath& subId = kNullSubent) const; virtual AcDbEntity* subentPtr(const AcDbFullSubentPath& id) const; virtual void saveAs(AcGiWorldDraw* mode, AcDb::SaveType st); virtual Adesk::Boolean saveImagesByDefault() const;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 62 de 104
AcDbEntity: Funções para Sobrecarregar Raramente virtual Acad::ErrorStatus setColor(const AcCmColor &color); virtual Acad::ErrorStatus setColorIndex(Adesk::UInt16 color); virtual Acad::ErrorStatus setLinetype(const char* newVal); virtual Acad::ErrorStatus setLinetype(AcDbObjectId newVal); AcDbCurve: Funções para Sobrecarregar virtual Adesk::Boolean isClosed () const; virtual Adesk::Boolean isPeriodic () const; virtual Adesk::Boolean isPlanar () const; virtual Acad::ErrorStatus getPlane (AcGePlane&, AcDb::Planarity&) const; virtual Acad::ErrorStatus getStartParam(double&) const; virtual Acad::ErrorStatus getEndParam (double&) const; virtual Acad::ErrorStatus getStartPoint(AcGePoint3d&) const; virtual Acad::ErrorStatus getEndPoint (AcGePoint3d&) const; virtual Acad::ErrorStatus
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 63 de 104
getPointAtParam(double, AcGePoint3d&) const; virtual Acad::ErrorStatus getParamAtPoint(const AcGePoint3d&, double&)const; virtual Acad::ErrorStatus getDistAtParam (double param, double& dist) const; virtual Acad::ErrorStatus getParamAtDist (double dist, double& param) const; virtual Acad::ErrorStatus getDistAtPoint (const AcGePoint3d&, double&)const; virtual Acad::ErrorStatus getPointAtDist (double, AcGePoint3d&) const; virtual Acad::ErrorStatus getFirstDeriv (double param, AcGeVector3d& firstDeriv) const; virtual Acad::ErrorStatus getFirstDeriv (const AcGePoint3d&, AcGeVector3d& firstDeriv) const; virtual Acad::ErrorStatus getSecondDeriv (double param, AcGeVector3d& secDeriv) const; virtual Acad::ErrorStatus getSecondDeriv (const AcGePoint3d&, AcGeVector3d& secDeriv) const; virtual Acad::ErrorStatus getClosestPointTo(const AcGePoint3d& givenPnt, AcGePoint3d& pointOnCurve, Adesk::Boolean extend
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 64 de 104
= Adesk::kFalse) const; virtual Acad::ErrorStatus getClosestPointTo(const AcGePoint3d& givenPnt, const AcGeVector3d& normal, AcGePoint3d& pointOnCurve, Adesk::Boolean extend = Adesk::kFalse) const; virtual Acad::ErrorStatus getOrthoProjectedCurve(const AcGePlane&, AcDbCurve*& projCrv) const; virtual Acad::ErrorStatus getProjectedCurve(const AcGePlane&, const AcGeVector3d& projDir, AcDbCurve*& projCrv) const; virtual Acad::ErrorStatus getOffsetCurves(double offsetDist, AcDbVoidPtrArray& offsetCurves) const; virtual Acad::ErrorStatus getSpline (AcDbSpline*& spline) const; virtual Acad::ErrorStatus getSplitCurves (const AcGeDoubleArray& params, AcDbVoidPtrArray& curveSegments) const; virtual Acad::ErrorStatus getSplitCurves (const AcGePoint3dArray& points, AcDbVoidPtrArray& curveSegments) const; virtual Acad::ErrorStatus extend(double newParam);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 65 de 104
virtual Acad::ErrorStatus extend(Adesk::Boolean extendStart, const AcGePoint3d& toPoint); virtual Acad::ErrorStatus getArea(double&) const;
Implementando Funções Membro Quando se define uma nova função membro ou se sobrecarrega uma função já existente, a primeira que usualmente deve-se chamar é assertReadEnabled( ), assertWriteEnabled( ), ou assertNotifyEnabled( ) para verificar se o objeto foi aberto da forma certa. Objetos abrem para: Read returns aborts returns
assertReadEnabled( ) assertWriteEnabled( ) assertNotifyEnabled( )
Write returns returns returns
Notify returns aborts returns
Filing A partir da derivação de uma nova classe de AcDbObject, é necessário adicionar aldumas informações o mecanismo de armazenamento do AutoCAD. As quatro funções abaixo são utilizadas para garantir esse armazenamento: Acad::ErrorStatus AcDbObject::dwgOut(AcDbDwgFiler* filer); Acad::ErrorStatus AcDbObject::dwgIn(AcDbDwgFiler* filer); Acad::ErrorStatus AcDbObject::dxfOut(AcDbDxfFiler* filer, Adesk::Boolean allXdFlag, Adesk::uchar* regAppTable) const); Acad::ErrorStatus AcDbObject::dxfIn(AcDbDxfFiler* filer);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 66 de 104
Cada função leva um ponteiro para um arquivo como seu argumento primario. Um AcDbObject escreve e lê dados para um arquivo. O FilerType permite a checagem do tipo de arquivo.
kFileFiler (used for DWG and DXF files) kCopyFiler kUndoFiler kBagFiler (usado com ads_entmake(), ads_entmod(), e ads_entget()) kIdXlateFiler kPageFiler kDeepCloneFiler kWBlockCloneFiler kPurgeFiler
As funções dwgOut( ) e o dwgIn( ) chamam dwgOutFields( ) e dwgInField( ), respectivamente. Com a derivação de AcDbObject, haverá a necessidade de sobrecarregar algumas funções virtuais, que são usadas para armazenagem persistente de objetos, em operações de cópia ou undo:
dwgOutFields( ) dwgInFields( ) dxfOutFields( ) dxfInFields( )
Função dwgOut( ) A função dwgOut( ) que chama dwgOutFields( ), é invocada pelos seguintes comandos:
SAVE (usa kFileFiler) SAVEAS (usa kFileFiler) WBLOCK (usa kWblockCloneFiler e kIdXlateFiler) INSERT, XREF (usa kDeepCloneFiler e kIdXlateFiler) COPY (usa os mesmos arquivos que INSERT) PURGE (usa um kPurgeFiler) Quando um objeto é paginado para fora (uses a kPageFiler) Quando um objeto é modificado (para undo; usa um kUndoFiler)
Função dwgIn( ) A função dwgInt( ) que chama dwgInFields( ), é invocada pelos seguintes comandos:
OPEN (usa kFileFiler) UNDO (usa kUndoFiler) INSERT, COPY, XREF (usa kDeepCloneFiler e kIdXlateFiler) WBLOCK (usa kWblockCloneFiler e kIdXlateFiler) Quando um objeto é paginado para dentro(usa kPageFiler)
Função dxfOut( )
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 67 de 104
A função dxfOut( ) que chama dxfOutFields( ), é invocada pelos seguintes comandos:
DXFOUT ads_entget( )
Função dxfIn( ) A função dxfIn( ) que chama dxfInFields( ), é invocada pelos seguintes comandos:
DXFIN ads_entmod( ) ou ads_entmake( )
Implementando as Funções de Arquivamento DWG Ao implementar as funções dwgOutFields( ) e dwgInField( ) para uma nova classe, deve-se chamar primeiro as funções assertReadEnabled( ) e assertWriteEnabled( ) para garantir que o objeto foi aberto corretamente. AcDbDerivedClass::dwgOutFields( ... ); { assertReadEnabled() myParent::dwgOutFields(); } Exemplo: Acad::ErrorStatus AsdkPoly::dwgOutFields(AcDbDwgFiler* filer) const { assertReadEnabled(); Acad::ErrorStatus es; if ((es = AcDbCurve::dwgOutFields(filer)) != Acad::eOk) { return es; }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 68 de 104
filer->writeItem(mCenter); filer->writeItem(mStartPoint); filer->writeInt32(mNumSides); filer->writeItem(mPlaneNormal); filer->writeItem(mpName); filer->writeItem(mTextStyle); return es; Acad::ErrorStatus AsdkPoly::dwgInFields(AcDbDwgFiler* filer) { assertWriteEnabled(); Acad::ErrorStatus es; if ((es = AcDbCurve::dwgInFields(filer)) != Acad::eOk) { return es; } filer->readItem(&mCenter); filer->readItem(&mStartPoint); filer->readInt32((long*) &mNumSides); filer->readItem(&mPlaneNormal); filer->readItem(&mpName); filer->readItem(&mTextStyle); return es; } Implementando as Funções de Arquivamento DXF Ao implementar as funções dxfOutFields( ) e dxfInField( ) para uma nova classe, deve-se chamar primeiro as funções assertReadEnabled( ) e assertWriteEnabled( ) para garantir que o objeto foi aberto corretamente.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 69 de 104
Group DXF A representação DXF de um objeto é composta de pares grupos de códigos e dados, com cada grupo de códigos mapeando para um específico tipo de dado. Na verdade são, 100 grupos de código seguidos por uma string que é o nome da classe corrente. De 1 6 10 38 60 90 100 102 140 170 210 270 280 300 310 320 330 340 350 360
Para 4 9 17 59 79 99 100 102 149 179 219 279 289 309 319 329 339 349 359 369
Tipo de Dado texto texto Ponto ou vetor real 16-bit inteiro 32-bit inteiro Marca de subclasse texto real 16-bit inteiro 3 reais 16-bit inteiro 8-bit inteiro texto binário handle soft pointer ID hard pointer ID soft owner ID hard owner ID
Objetos Referência Um objeto referência pode ser hard ou soft, ou também referência ownership ou referência pointer:
Referência Hard: Indica que um objeto depende do objeto referenciado para sua própria existência; Referência Soft: Indica que um objeto tem alguns tipos de relacionamento com o objeto referenciado, mas não depende dele para existir; Referência Ownership: Indica como os objetos são armazenados. Considerando que apenas um objeto possui um outro, então se o primeiro é armazenado, ele leva o objeto possuído com ele. Essa referência é usada para escritas não redundantes no banco de dados; Referência Pointer: É usada para expressar qualquer referência arbitrária entre AcDb Objetos, sendo usada para escritas redundantes no banco de dados.
Referências Ownership Para implementar uma hierarquia ownership é necessário fazer uma conexão entre o objeto possuidor
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 70 de 104
e o objeto possuido. Um objeto pode ter apenas um possuidor. Essa conexão é usualmente feita em duas fases:
Especificar o objeto possuidor; Especificar qual o objeto possuido.
O protocolo do AcDbObject sempre especifica o link do objeto possuidor para o possuido. // Setar pOwner para ser o possuidor de pOwned void makeOwner(OwnerDemo* pOwner, AcDbObject* pOwned) { pOwner->setIdData(pOwned->ojectId()); pOwned->setOwnerId(pOwner->objectId()); } No caso de algumas classes containers essa relação já é estabelecida. A função seta o block table record como o possuidor da entidade: blockTableRecord->appendAcDbEntity( ...); Usos do Ownership Quando um objeto é escrito para um arquivo DXF ou DWG, todos os objetos possuidos por ele são tambem copiados. A operação deep clone tambem faz com que todos os objetos possuidos pelo objeto clonado, sejam também clonados. Um hard ownership protege o objeto possuido de ser purgado. Tipos de Ownership Os owner podem ser de dois tipos:
Hard Ownership
Um objeto de banco de dados é um hard owner de seu extension dictionary; O block table é um hard owner do model space e paper space block table records; Extension dictionaries são hard owners de seus elementos.
Soft Ownership
Symbol tables são soft owners de seus elementos ( com exceção do MODEL_SPACE, PAPER_SPACE e layer 0);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 71 de 104
Dictionaries são soft owners de suas entradas.
Referências Pointer Um pointer é um one-way link , ou seja, não há nenhuma informação no objeto referenciado que indique a origem do ponteiro. Um objeto pode apontar ou ser apontado por qualquer número de outros objetos. Hard Pointers Um hard pointer protege um objeto de ser purgado. Tem-se alguns exemplos de hard pointers:
Uma entidade contém um hard pointer para um estilo de dimensionamento; Uma entidade texto contem um hard pointer como referência para um estilo de texto; Uma entidade de dimensionamento contém um hard pointer referênciado para um estilo de dimensionamento; Uma entidade tem um hard pointer para um layer.
Soft Pointers Um soft pointer é um simples ponteiro para um objeto. Ele não protege o objeto referenciado de um purge. Exemplos:
Referências Xdata são soft pointers; Persistent reactors são soft pointers.
Purge O mecanismo purge permite apagar objetos não utilizados no banco de dados. Se um objeto tem um hard owner ou um pointer reference, ele não pode ser apagado. AcDbDatabase::purge(AcDbObjectIdArray &idArray); A função purge( ) retorna o ID dos objetos que podem ser purgados, sendo assim existe um controle sobre os objetos que estão sendo apagados.
Undo e Redo Existem dois caminhos básicos para a aplicação de uma operação Undo. O mecanismo de Undo automático, default, deixa o sistema copiar o estado completo do objeto chamando a função dwgOutFields( ) com o arquivo Undo. Um mecanismo alternativo, é o mecanismo de Undo parcial que requer um maior esforço programacional, porém habilita uma maior interação com as mudanças. Toda função de modificação para a nova classe derivada, deve chamar a função assertWriteEnabled ( ) , que checa se o objeto esta habilitado para ser escrito. Se o parâmetro para o autoUndo é kTrue, o
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 72 de 104
objeto é registrado pelo undo. Quando a modificação do objeto esta completa e o objeto é fechado, o conteudo do arquivo é salvo para um arquivo undo. Quando o comando UNDO é invocado e uma operação de auto undo é executada, o AutoCAD invoca a função dwgInFields( ) no objeto, que lê o conteudo do arquivo undo. Undo Automático A função assertWriteEnabled( ) é da seguinte forma: void assertWriteEnabled( Adesk::Boolean autoUndo = Adesk::kTrue, Adesk::Boolean recordModified = Adesk::kTrue); Quando uma função de modificação chama assertWriteEnabled( ), ela checa se o parâmetro recordModified é kTrue, se for, ela analisa o parâmetro autoUndo que especifica se o undo deve ser executado. Se ele for kTrue (default) o objeto é automáticamente escrito no arquivo do objeto undo. Já se o parâmetro recordModified é kFalse ele não executa o undo. Parcial Undo O parcial undo é uma alternativa de programação para ser implementado em algumas funções de modificação das classes. Se somente uma pequena porção do objeto é tipicamente modificado em uma função membro, o parcial undo pode executar alguns benefícios. Para gravar somente parte de um objeto, basta especificar kFalse para o parâmetro autoUndo e então usar a função undoFiler::writeItem( ) para salvar a informação relevante de um arquivo undo. Se for especificado kFalse para o autoUndo, a função applyPartialUndo( ) é chamada quando o comando UNDO é invocado. A função applyPartialUndo( ) é uma função virtual do AcDbObject que garante que a classe executa as mudanças. undoFiler()->writeItem((long)NewClass::desc());
Redo Quando se desfaz o undo, é gravado também o estado corrente do desenho. Essa recuperação pelo redo requer um trabalho muito grande, porque ele usa o mesmo mecanismo de preenchimento como a operação do undo.
subErase, subOpen, subClose e subCancel As funções erase( ), open( ), close( ), e cancel( ) têm funções virtuais correspondentes começando com o prefixo sub. Elas podem ser sobrecarregadas para fornecer a novas classes derivadas mais funcionalidade. O sistema segue a seguinte forma, sendo que a função erase( ) chama subErase( ): virtual Acad::ErrorStatus
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 73 de 104
subErase(Adesk::Boolean pErasing); Para sobrecarregar uma dessas funções, deve-se seguir alguns passos:
Verificar as condições de dependências dos objetos; Invocar Parent::subErase( ) e examinar os resultados; Executar a ação.
Exemplo de uma Classe Objeto Customizada Arquivo de Cabeçalho class MyClass : public AcDbObject { public: ACRX_DECLARE_MEMBERS(MyClass); MyClass(): mIntval(0) {}; MyClass(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; }; Arquivo Fonte class MyClass : public AcDbObject // Utiliza-se funções para setar e pegar o dado inteiro { public:
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 74 de 104
ACRX_DECLARE_MEMBERS(MyClass); MyClass(): mIntval(0) {}; MyClass(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; }; ACRX_DXF_DEFINE_MEMBERS(MyClass, AcDbObject, 0, MYCLASS, SAMP2); MAKE_ACDBOPENOBJECT_FUNCTION(MyClass); // Pega os valores do dado inteiro Acad::ErrorStatus MyClass::getData(Adesk::Int16& val) { assertReadEnabled(); val = mIntval; return Acad::eOk; } // Seta os valores do dado inteiro Acad::ErrorStatus MyClass::setData(Adesk::Int16 val) { assertWriteEnabled();
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 75 de 104
mIntval = val; return Acad::eOk; } // Arquiva dados no DWG Acad::ErrorStatus MyClass::dwgInFields(AcDbDwgFiler* pFiler) { assertWriteEnabled(); AcDbObject::dwgInFields(pFiler); pFiler->readItem(&mIntval); return pFiler->filerStatus(); } // Lê os dados do arquivo DWG Acad::ErrorStatus MyClass::dwgOutFields(AcDbDwgFiler* pFiler) const { assertReadEnabled(); AcDbObject::dwgOutFields(pFiler); pFiler->writeItem(mIntval); return pFiler->filerStatus(); } // Arquivo DXF Acad::ErrorStatus MyClass::dxfInFields(AcDbDxfFiler* pFiler) { assertWriteEnabled(); Acad::ErrorStatus es;
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 76 de 104
if ((es = AcDbObject::dxfInFields(pFiler))!= Acad::eOk) { return es; } if (!pFiler->atSubclassData("MyClass")) { 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(); } // Arquivo DXF Acad::ErrorStatus MyClass::dxfOutFields(AcDbDxfFiler* pFiler) const { assertReadEnabled(); AcDbObject::dxfOutFields(pFiler); pFiler->writeItem(AcDb::kDxfSubclass, "MyClass"); pFiler->writeItem(AcDb::kDxfInt16, mIntval); return pFiler->filerStatus(); }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 77 de 104
// Cria dois objetos da classe "MyClass" com dois inteiros //e adciona no dicionário. void createDictionary() { AcDbDictionary *pNamedobj; acdbCurDwg()->getNamedObjectsDictionary(pNamedobj, AcDb::kForWrite); 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) { MyClass *pObj1 = new MyClass(1); MyClass *pObj2 = new MyClass(2); AcDbObjectId rId1, rId2; pDict->setAt("OBJ1", pObj1, rId1); pDict->setAt("OBJ2", pObj2, rId2); pObj1->close(); pObj2->close(); pDict->close(); } }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 78 de 104
void iterateDictionary() { AcDbDictionary *pNamedobj; acdbCurDwg()->getNamedObjectsDictionary(pNamedobj, AcDb::kForRead); AcDbDictionary *pDict; pNamedobj->getAt("ASDK_DICT", (AcDbObject*&)pDict, AcDb::kForRead); pNamedobj->close(); AcDbDictionaryIterator* pDictIter= pDict->newIterator(); AsdkMyClass *pMyCl; Adesk::Int16 val; for (; !pDictIter->done(); pDictIter->next()) { pDictIter->getObject((AcDbObject*&)pMyCl, AcDb::kForRead); pMyCl->getData(val); pMyCl->close(); ads_printf("\nintval is: %d", val); } delete pDictIter; pDict->close(); } void initApp() { acedRegCmds->addCommand("ASDK_DICTIONARY_COMMANDS", "ASDK_CREATE", "CREATE", ACRX_CMD_MODAL, createDictionary); acedRegCmds->addCommand("ASDK_DICTIONARY_COMMANDS",
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 79 de 104
"ASDK_ITERATE", "ITERATE", ACRX_CMD_MODAL, iterateDictionary); MyClass::rxInit(); acrxBuildClassHierarchy(); } void unloadApp() { acedRegCmds->removeGroup("ASDK_DICTIONARY_COMMANDS"); deleteAcRxClass(AsdkMyClass::desc()); }
Suporte para Versões de Objetos Vários mecanismos podem ser usados para administrar as versões das classes de objetos customizados:
Renomear as classes para cada nova versão; Manter o número da versão como o primeiro membro da classe; Manter o número da versão como dado extendido (xdata) ou uma extensão do dicionário.
X. Derivando de AcDbEntity
Essa sessão demonstra como derivar uma classe customizada de AcDbEntity. A criação de uma classe de entidade customizada exige a utilização da biblioteca AcGi, operações com object osnap points, grip points e stretch points.
Mostrando a Entidade Para acessar AcGi tem-se algumas funções dentro da classe básica AcDbEntity: virtual Adesk::Boolean
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 80 de 104
AcDbEntity::worldDraw(AcGiWorldDraw *pWd); virtual void AcDbEntity::viewportDraw(AcGiViewportDraw *pVd); virtual void AcDbEntity::saveAs(AcGiWorldDraw *pWd, AcDb::SaveType saveType); O AutoCAD chama as funções worldDraw( ) e viewportDraw( ) para mostra a entidade. Em alguns casos o AutoCAD chama a função saveAs( ), como na representação gráfica do objeto proxy ou quando se salva o desenho para o AutoCAD 12. A função worldDraw( ) deve ser sempre implementada para qualquer classe derivada de AcDbEntity, já as funções viewportDraw( ) e saveAs ( ) são opcionais. Sempre que o AutoCAD necessita regenerar um desenho para mostrar uma entidade, as funções worldDraw( ) e viewportDraw( ) são chamadas da seguinte maneira: if (!entity->worldDraw(pWd)) for (each relevant viewport) entity->viewportDraw(pVd); O objetivo da função worldDraw( ) é construir a parte gráfica da entidade que pode ser especificada independentemente do contexto da visualização. Se qualquer das entidades gráficas tem sua visualização dependente, o worldDraw( ) deve retornar kFalse e o viewportDraw( ) deve ser implementado. A função viewportDraw( ) então constroe a parte de visualização dependente da entidade gráfica. A função AcDbEntity::worldDraw( ) leva um ponteiro para um objeto AcGiWorldDraw, que é uma classe container para o AcGi e objetos como:
Objeto AcGiWorldGeometry, faz o tratamento analítico vetorial do AutoCAD trabalhando com suas entidades primitivas:
Circle Circular arc Polyline Polygon Mesh Shell Text Xline Ray
Objeto AcGiSubEntityTraits, trabalha com um conjunto de atributos gráficos usando algumas funções:
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 81 de 104
Color Layer Linetype Polygon fill type Selection marker
A função AcDbEntity::viewportDraw( ) leva um ponteiro para um objeto AcGiviewportDraw e constroe visualizações para a representação gráfica de uma entidade. O objeto AcGiviewportDraw é também um objeto container para outros objetos como:
Objeto AcGiViewportGeometry, faz o tratamento analítico vetorial do AutoCAD para a visualização trabalhando com suas entidades primitivas:
Objeto AcGiSubEntityTraits, trabalha com um conjunto de atributos gráficos usando algumas funções:
Circle Circular arc Polyline Polygon Mesh Shell Text Xline Ray polylineEye() polygonEye() polylineDc() polygonDc()
Color Layer Linetype Polygon fill type Selection marker
Objeto AcGiViewport, fornece funções para trabalhar com visualização baseada em matrizes e parâmetros.
Sobrecarregando AcDbEntity::saveAs( ) Se a entidade customizada não sobrecarrega AcDbEntity::saveAs( ), o AutoCAD deverá fazer com que a função worldDraw( ) suporte a representação gráfica ou arquivos DWG da versão release 12. A função AcDbEntity::saveAs( ) simplesmente chama a função worldDraw( ). É possível sobrecarregar saveAs( ) se for necessário se ter uma representação gráfica alternativa, ou para salvar entidades
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 82 de 104
gráficas do tipo proxy, ou para arquivos DWG da versão 12, ou até mesmo para ambos os casos. Objetos AcGi Um objeto AcGi assim como o AcGiWorldDraw ou AcGiViewportDraw não deve ser armazenado como uma variável global ou estática, e também não deve se salvar cópias através das funções worldDraw( ) e viewportDraw( ). Tipos de Regeneração O tipo de regeneração viewport AcGiWorldDraw::regenType( ):
é
dado
pelo
AutoCAD
através
da
função
kAcGiStandardDisplay é o modo típico de desenho e é usado quando o usuário entra com o comando REGEN ou edita uma entrada; kAcGiHideOrShadeCommand indica que o comando HIDE ou SHADE foi emitido; kAcGiRenderCommand é usado quando o usuário emite o comando RENDER.
Propriedades das Entidades
Entidades: Se você não atribui valores para cor, layer ou line type, sua entidade customizada deverá receber valores prescritos pelo AutoCAD. Adicionalmente, sua aplicação pode chamar AcDbEntity a função membro assim como AcDbEntity::setColorIndex() para atribuir valores para as propriedades das entidades, mas não de dentro do worldDraw(), viewportDraw(), and saveAs().
Subentidades: Pode-se atribuir valores para cor, layer ou line type chamando as funções AcGiSubEntityTraits das funções worldDraw(), viewportDraw(), and saveAs().
Subprimitiva: As funções primitivas mesh e shell possuem parâmetros que levam você a especificar um conjunto de propriedades. Esse mecanismo requer que você atribua valores para todos os lados ou faces.
Propriedades das Subentidades As propriedades são: Color Layer Linetype Fill type GS marker
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 83 de 104
Antes de chamar o worldDraw() and viewportDraw(), o AutoCAD inicializa a cor, layer, e linetype das subentidades. O fill type corresponde ao tipo de regeneração, e o GS marker é inicializado em zero. Fill Type Existem dois tipos de fill type: kAcGiFillAlways kAcGiFillNever Antes do AutoCAD chamas o worldDraw(), ele atribui o fill type de acordo com o tipo de regeneração. GS Markers Os GS markers são utilizados nas conjunções com as funções ADS ads_ssget() and ads_ssnamex(), permitindo sua aplicação editar ou operar nas seções arbitrárias da sua entidade customizada.
Primitivas Mesh Uma mesh é um eficiente caminho para armazenar uma grade retangular de vértices. A geometria para uma mesh é especificada como o número de linhas ou número de colunas e uma lista de vértices. virtual Adesk::Boolean AcGiWorldGeometry::mesh(const Adesk::UInt32 rows, const Adesk::UInt32 columns, const AcGePoint3d* pVertexList, const AcGiEdgeData* pEdgeData = NULL, const AcGiFaceData* pFaceData = NULL, const AcGiVertexData* pVertexData = NULL) const = 0; Os três últimos parâmetros da função são opcionais. Shell Um shell é uma lista de faces que podem ser conectadas e podem Ter também furos. O shell é especificado pro uma lista de vértices, um número de faces e uma lista das faces.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 84 de 104
virtual Adesk::Boolean AcGiWorldGeometry::shell(const Adesk::UInt32 nbVertex, const AcGePoint3d* pVertexList, const Adesk::UInt32 faceListSize, const Adesk::Int32* pFaceList, const AcGiEdgeData* pEdgeData = NULL, const AcGiFaceData* pFaceData = NULL, const AcGiVertexData* pVertexData = NULL const struct resbuf* pResBuf = NULL) const = 0;
Um vertex negativo indica um furo. Os furos devem estar no mesmo plano das faces. Arc A função circularArc() possui duas formas: 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; Os tipos de arc podem ser três, definidos pelos seguintes valores:
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 85 de 104
kAcGiArcSimple kAcGiArcSector kAcGiArcChord Polyline A função pline() permite uma entidade customizada desenhar primitivas graficas usando um AcDbPolyline como um templante. Essa função suportaq multisegmentos curvos ou retos. virtual Adesk::Boolean pline(const AcDbPolyline& lwBuf, Adesk::UInt32 fromIndex = 0, Adesk::UInt32 numSegs = 0) const; Text Um exemplo nesta seção mostra o uso da classe AcGiTextStyle. Ele desenha um retângulo em torno de um texto que pode ser orientado e localizado em qualquer lugar do espaço. Adesk::Boolean AsdkTextStyleSamp::worldDraw(AcGiWorldDraw* pW) { AcGePoint3d pos(0.0, 0.0, 0.0); AcGeVector3d norm(0.0, 0.0, 1.0); AcGeVector3d dir(-1.0, -0.2, 0.0); char *pStr = "This is a percent, '%%%'."; int len = strlen(pStr); AcGiTextStyle style; AcGeVector3d vec = norm; vec = vec.crossProduct(dir); dir = vec.crossProduct(norm); style.setFileName("txt.shx"); style.setBigFontFileName(""); int status; if (!((status = style.loadStyleRec()) & 1))
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 86 de 104
pStr = "Font not found."; pW->geometry().text(pos, norm, dir, pStr, len, Adesk::kFalse, style); pos.y += 2.0; style.setTrackingPercent(80.0); style.setObliquingAngle(10.0); AcGePoint2d ext = style.extents(pStr, Adesk::kFalse, strlen(pStr), Adesk::kFalse); pW->geometry().text(pos, norm, dir, pStr, len, Adesk::kFalse, style); AcGeMatrix3d textMat; norm.normalize(); dir.normalize(); AcGeVector3d yAxis = norm; yAxis = yAxis.crossProduct(dir); yAxis.normalize(); textMat.setCoordSystem(AcGePoint3d(0.0, 0.0, 0.0), dir, yAxis, norm); double offset = ext.y / 2.0; AcGePoint3d verts[5]; verts[0] = verts[4] = AcGePoint3d(-offset, -offset, 0.0); verts[1] = AcGePoint3d(ext.x + offset, -offset, 0.0); verts[2] = AcGePoint3d(ext.x + offset, ext.y + offset, 0.0); verts[3] = AcGePoint3d(-offset, ext.y + offset, 0.0); for (int i = 0; i < 5; i++) { verts[i].transformBy(textMat); verts[i].x += pos.x; verts[i].y += pos.y; verts[i].z += pos.z; }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 87 de 104
pW->geometry().polyline(5, verts); return Adesk::kTrue; } Tesselation Curvas e superfícies curvadas necessitam ser quebradas em linhas e poligonais. O grau de tessellation determina como a curva será mostrada. As funções deviation() fornecidas pelas classes AcGiWorldDraw e AcGiViewportDraw retornam o desvio. virtual double AcGiWorldDraw::deviation(AcGiDeviationType, const AcGePoint3d&) const = 0; Os tipos de desvio são: KAcGiMaxDevForCircle kAcGiMaxDevForCurve kAcGiMaxDevForBoundary kAcGiMaxDevForIsoline kAcGiMaxDevForFacet Isolines Uma isoline é usada para dar um visual para a shape de um objeto. A função AcGiWorldDraw::isolines() permite uma entidade mostrar o mesmo número de isolines para uma superfície como especificado pelo usuário (um valor interio entre 0 e 2047). Viewports O viewport é definido por uma câmera que é aponmtada para o espaço, com um certo campo de visão. A classe AcGiViewport fornece funções para obter informações sobre o viewpoint, assim como getCameraLocation() e getCameraUpVector(). Ele também fornece funções para obter as várias transformações. Transformações As entidades podem sofrer três tipos de transformações:
As transformações de blocos de entidades A transformação da visualização do viewport A transformação da perspectiva
Funções intrínsecas das entidades
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 88 de 104
Object Snap Points É necessário sobrecarregar a função getOsnapPoints() para uma entidade customizada suportar o object snap modes. O AutoCAD invoca esta função para adquirir os snap points para o modo corrente. O exemplo seguinte mostra como a classe AsdkPoly implementa a função getOsnapPoints(): Acad::ErrorStatus AsdkPoly::getOsnapPoints( AcDb::OsnapMode int
osnapMode,
gsSelectionMark,
const AcGePoint3d&
pickPoint,
const AcGePoint3d&
lastPoint,
const AcGeMatrix3d& viewXform, AcGePoint3dArray& AcDbIntArray&
snapPoints, /*geomIds*/) const
{ assertReadEnabled(); Acad::ErrorStatus es = Acad::eOk; if (gsSelectionMark == 0) return Acad::eOk; if ( osnapMode != AcDb::kOsModeEnd && osnapMode != AcDb::kOsModeMid && osnapMode != AcDb::kOsModeNear && osnapMode != AcDb::kOsModePerp && osnapMode != AcDb::kOsModeCen && osnapMode != AcDb::kOsModeIns) { return Acad::eOk; }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 89 de 104
if (gsSelectionMark == (mNumSides + 1)) { if (osnapMode == AcDb::kOsModeIns) snapPoints.append(mCenter); else if (osnapMode == AcDb::kOsModeCen) snapPoints.append(mCenter); return es; } int startIndex = gsSelectionMark - 1; AcGePoint3dArray vertexArray; if ((es = getVertices(vertexArray)) != Acad::eOk) { return es; } AcGeLineSeg3d lnsg(vertexArray[startIndex], vertexArray[startIndex + 1]); AcGePoint3d pt; AcGeLine3d line, perpLine; AcGeVector3d vec; AcGeVector3d viewDir(viewXform(Z, 0), viewXform(Z, 1), viewXform(Z, 2)); switch (osnapMode) { case AcDb::kOsModeEnd: snapPoints.append(vertexArray[startIndex]); snapPoints.append(vertexArray[startIndex + 1]); break; case AcDb::kOsModeMid: pt.set( ((vertexArray[startIndex])[X]
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 90 de 104
+ (vertexArray[startIndex + 1])[X]) * 0.5, ((vertexArray[startIndex])[Y] + (vertexArray[startIndex + 1])[Y]) * 0.5, ((vertexArray[startIndex])[Z] + (vertexArray[startIndex + 1])[Z]) * 0.5); snapPoints.append(pt); break; case AcDb::kOsModeNear: pt = lnsg.projClosestPointTo(pickPoint, viewDir); snapPoints.append(pt); break; case AcDb::kOsModePerp: vec = vertexArray[startIndex + 1] - vertexArray[startIndex]; vec.normalize(); line.set(vertexArray[startIndex], vec); pt = line.closestPointTo(lastPoint); snapPoints.append(pt); break; case AcDb::kOsModeCen: snapPoints.append(mCenter); break; default: return Acad::eOk; } return es; }
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 91 de 104
Grip Points As entidades do AutoCAD possuem grip points que aparecem quando o usuáriuo seleciona uma entidade. A função getGripPoints() returna os grip points que foram definidos por uma entidade. virtual Acad::ErrorStatus AcDbEntity::getGripPoints( AcGePoint3dArray& gripPoints, AcDbIntArray&
osnapModes,
AcDbIntArray&
geomIds) const;
virtual Acad::ErrorStatus AcDbEntity::moveGripPointsAt( const AcDbIntArray& indices, const AcGeVector3d& offset); Stretch Points O conjuntg de stretch points para uma entidade é um subconjunto dos grip points. Quando o usuário invoca o comando STRETCH, a função getStretchPoints() é usada para retornar os stretch points definidos pela entidade selecionada. A implementação para AcDbEntity::getStretchPoints() e AcDbEntity::moveStretchPointsAt() é para invocar seu getGripPoints() and moveGripPointsAt(). virtual Acad::ErrorStatus AcDbEntity::getStretchPoints( AcGePoint3dArray& stretchPoints) const; virtual Acad::ErrorStatus AcDbEntity::moveStretchPointsAt( const AcDbIntArray& indices, const AcGeVector3d& offset). Funções de Transformação A classe AcDbEntity oferece duas funções de transformação. A primeira, transformBy(), aplica uma matriz para uma entidade. A segunda, getTransformedCopy(), desabilita uma entidade para retornar uma cópia dela mesma com a transformação aplicada. Interseção com outras entidades Quando você implementa intersectWith() para sua entidade customizada, assegure-se que esta função não é implementada para todas as entidades do AutoCAD Release 12.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 92 de 104
virtual Acad::ErrorStatus intersectWith(const AcDbEntity* ent, AcDb::Intersect intType, AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const; virtual Acad::ErrorStatus intersectWith(const AcDbEntity* ent, AcDb::Intersect intType, const AcGePlane& projPlane, AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const; A primeira forma do intersectWith() testa uma simples interseção de duas entidades. A Segunda forma calcula a interseção da projeção no plano. Interseção de uma Entidade Customizada com Outra Entidade O ARX é uma arquitetura aberta onde aplicações múltiplas podem implementar suas próprias entidades customizadas. É possível que aplicações múltiplas sejam carregadas no mesmo momento da sessão do AutoCAD, onde o usuário seleciona sua entidade customizada em uma operação que involva sua interseção com outra entidade customizada na qual você não está ciente. Os seguintes itens poderão ajudá-lo a implementar a função intersectWith() de sua entidade customizada.
Cada entidade customizada é esperada para poder cruzar com uma entidade nativa. Se a função intersectWith() da sua entidade customizada é chamada com outra entidade não é nativa, você precisará explodir sua entidade customizada em entidades nativas.
Explodindo uma entidade Você tem que sobrecarregar a função explode() de uma entidade customizada para utilizar os comandos BHATCH e EXPLODE
Tópicos Especializados XI. Objetos Proxy
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 93 de 104
Este capítulo descreve objetos proxi e as condições de sua criação. Ele também discute encontro de usuário com PROXIES , o display de entidades proxy, e a edição de proxy entidades.
Objetos Proxy Definidos O objeto proxy é um objeto que o AutoCAD cria na memória como um portador de um conjunto de dados para um objeto customizado ARX. O AutoCAD cria automaticamente objetos proxy quando a aplicação que define o objeto não é carregada. Proxies são criados por objetos e entidades. O AutoCAD utiliza objetos proxy para fornecer o acesso a leitura de dados em um objeto customizado derivado de AcDbObject ou AcDbEntity. Os objetos Proxy também fornecem o controle de edição para alguns dados, com o argumento da macro ACRX_DXF_DEFINE_MEMBERS no PROXY_FLAGS. A classe do objeto proxy AcDbProxyObject é derivada de AcDbObject, e a classe de entidade proxy AcDbProxyEntity é derivada de AcDbEntity. Ambas as classes são classes básicas abstratas e não podem ser instansiadas e são incluidas no ARX API. Os objetos proxy convertem novamente para o objeto customizado original, sempre que a aplicação é carregada. Em certas circunstâncias, os proxies são escritos para arquivos, mas proxy objects usualmente existem na memoria. Os objetos proxy são criados pelo AutoCAD quando ele lê um arquivo contendo objetos customizados que não podem ser instanciados, isto acontece quando a applicação não é carregada. Porém, durante a seçõa de desenho do AutoCAD, a aplicação pode ser carregada e então, o AutoCAD converte os objetos proxy em objetos customizados. O usuário é notificado da criação do objeto proxy por uma mensagem do AutoCAD. Caso o usuário queira mais detalhes, basta emitir o comando List e clicar sobre a entidade. O usuário pode controlar o proxy quando a classe é criada com a macro ACRX_DXF_DEFINE_MEMBERS. As opções para o PROXY_FLAGS, e seus valores associados são: kNoOperation 0 kEraseAllowed 0x1 kTransformAllowed 0x2 kColorChangeAllowed 0x4 kLayerChangeAllowed 0x8 kLinetypeChangeAllowed 0x10 kLinetypeScaleChangeAllowed 0x20
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 94 de 104
kVisibilityChangeAllowed 0x40 kAllAllowedBits 0x7F
XII. Notificação
Este capítulo descreve como você pode criar reatores que respondam para tipos diferentes de eventos e registrar os reatores com objetos apropriados para receber notificação.
Visão Geral Quando um envento ocorre no sistema, certos objetos, chamados notificadores, automaticamente retransmitem o evento para outros objetos. Os objetos que recebem os eventos são chamados reatores. Um reator deve ser explicitamente adicionado para uma lista de reatores notificados antes que ele possa receber eventos do notificador. Um notificador dado pode Ter um número de reatores em sua lista de reatores. Uma definição da classe de reatores inclui várias funções de notificação. Quando um evento ocorre, o notificador automaticamente invoca a função de notificação correspondente de cada reator na sua lista de reatores. Para usar um reactor na sua aplicação, siga os seguintes passos gerais: 1. Derive uma nova classe de reatores e implemente as funções de notificação para os eventos em que o seu retator responderá; 2. Instansie o reator; 3. Adicione o reator para a lista de reatores do notificador.
Quando você terminar de usar o reator, siga os seguintes passos: 1. Remova o reator da lista de reatores; 2. Delete o reator.
Classes de Reatores As classes de reatores são derivadas do AcRxObject, não AcDbObject. Pelo motivo destes reatores não serem objetos de objetos de banco de dados, eles não possuem object IDs. A hierarquia para as classes de reatores é a seguinte: AcRxObject
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 95 de 104
AcRxDLinkerReactor AcEditorReactor AcDbDatabaseReactor AcTransactionReactor AcDbObjectReactor AcDbEntityReactor
Tipos de Objetos Reatores
Reator Transiente: É usado somente para monitorar eventos que acontecem nos objetos de banco de dados. Eles podem também monitorar eventos no banco de dados, interação de usuários e outros sistemas de eventos.
Reatores Persistentes: É usado ao involver um objeto de banco de dados como um reator, esses objetos podem receber assim como enviar notificações.
Usando Reatores Para utilizar um reator transiente, derive uma nova classe a partir de uma das seguintes classes basicas: AcRxDLinkerReactor AcEditorReactor AcDbDatabaseReactor AcTransactionReactor AcDbObjectReactor AcDbEntityReactor Cada classe parente contém um conjunto de funções de notificação virtual que pode ser implementada pela sua nova classe derivada. Como por exemplo, as funções da classe AcDbObjectReactor: cancelled() copied() erased()
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 96 de 104
goodbye() openedForModify() modified() subObjModified() modifyUndone() modifiedXData() unappended() reappended() objectClosed()
XIII. Administrando Transações
Este capítulo descreve o modelo de transaçãoque pode ser usado para operar nos objetos AcDb. Neste modelo, operações múltiplas em objetos múltiplos são agrupados juntamente em uma operação chamada uma transação. As transações podem ser aninhadas e podem ser finalizadas ou abortadas na atuação do usuário. Este modelo pode ser usado na conjunção com o regular abrir e fechar do objeto.
Visão Geral O modelo de transação encapsula operações múltiplas em objetos múltiplos definindo assim uma operação denominada transação. Dentro de uma transação, o usuário pode obter ponteiros de object IDs, que são válidas até a transação ser finalizada ou abortada pelo usuário. Se a transação é finalizada com sucesso, as operações no objeto são realizadas. Se a transação é abortada, as operações do objeto são canceladas. Esse mecanismo é bastante simplificado em relação ao mecanismo de abrir e fechar objetos, e ainda apresenta algumas vantagens. O mecanismo de abrir e fechar é adequada para operações simples em objetos ou em pequenos grupos de objetos. Contudo esse mecanismo apresenta algumas restrições que podem levar a um conjunto de erros. Se um objeto é aberto para leitura, o usuário não poderá abrí-lo para escrita ao mesmo tempo. Com isso o mecanismo de transição pode ser mais eficiente, permitindo a obtenção do ponteiro do objeto a partir do object ID de uma forma particular. Outra desvantagem é que ao abrir e fechar o mesmo objeto enumeras vezes, algumas operações são associadas ao fechar o objeto aumento o arquivo undo e disparando uma série de notificações. Porém ao utilizar o mecanismo de transação essas operações serão realizadas somente uma vez, ao finalizar a transação.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 97 de 104
Administrador da Transação O administrador de transação é um objeto administrador global, similar a um editor, instancia de AcTransactionManager e é mantido no registro do sistema e não pode ser deletado. O usuário pode obtê-lo através da macro: #define actrTransactionManager \ AcTransactionManager::cast( acrxSysRegistry()->at(AC_TRANSACTION_MANAGER_OBJ)) O administrador deve ser usado para iniciar, finalizar ou abortar transações. Ele pode também fornecer informações assim como o número de transações ativas em qualquer momento e uma lista de todos os objetos cujo os ponteiros foram obtidos em todas as transações.
Aninhando Transações As transações podem ser aninhadas, pode-se começar uma transação dentro de outra e finalizar ou abortar a transação recente. O administrador de transações mantém as transações em pilhas, com a mais recente transação no topo da pilha. Quando o usuário começa uma nova transação usando AcTransactionManager::startTransaction(), a nova transação é adicionada no topo da pilha e um ponteiro é retornado para ele. Quando é chamado AcTransactionManager::endTransaction() ou AcTransactionManager::abortTransaction(), a transação do topo é finalizada ou abortada. Se a transação mais externa for abortada, todas as operações de todos os objetos são canceladas.
Os Limites das transações O limite de uma transação é o tempo entre o início e o final ou aborto da transação, o usuário é responsável por esses limites. Uma forma inteligente de utilizar uma transação é dentro de uma função que será invocada por um comando registrado, porém se caos um comando for finalizado com uma transação aberta, o AutoCAD irá abortar. Alguns comandos não devem ser transacionados: ARX NEW QUIT SAVE UNDO DXFIN OPEN RECOVER SCRIPT XREF INSERT PURGE REDO U
Obtendo Ponteiros para Objetos na Transação Ambas AcTransactionManager::getObject() e AcTransaction::getObject() podem ser usadas para
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 98 de 104
obter ponteiros para objetos a partir de object Ids, esses ponteiros são associados a mais recente transação. Ambas funções retornam um ponteiro para leitura, escrita ou notificação. Nesse caso nunca deve-se chamar close(), essa função é usada quando o ponteiro é obtido através da função acdbOpenObject() ou quando o objeto foi novamente criado. Não é recomendado introduzir o mecanismo de transação quando se está usando o mecanismo de abrir e fechar. Porém o contrário é perfeitamente possível. Quando a mais recente transação é finalizada, o administrador de trasações dispara a notificação endCalledOnOutermostTransaction() e começa o processo de armazenamento das operações no banco de dados.
Undo e as Transações O modelo de transação usa o mecanismo de Undo do AutoCAD e AcDbObject::cancel() na implementação de AcTransactionManager::abortTransaction(). Isso requer que nenhuma operação utilizando subcomandos do AutoCAD sejam utilizadas na transação, como por exemplo, PEDIT e SPLINEDIT.
Transações e Geração Gráfica Para desenhar entidades associadas com as AcTransactionManager::queueForGraphicsFlush() e
transações
pode-se
utilizar
as
funções
AcTransactionManager::flushGraphics(), antes de enviá-las para o banco de dados do AutoCAD. Pode-se também usar a função AcDbEntity::draw() para desenhar entidades individualmente.
Reatores da Transação O administrador da transação tem uma lista de reatores através dos quais ele notifica o usuário dos relevantes eventos para a transação: virtual void transactionStarted (int& numTransactions); virtual void transactionEnded (int& numTransactions); virtual void transactionAborted (int& numTransactions); virtual void endCalledOnOutermostTransaction (int& numTransactions);
XIV. Deep Cloning
Este capítulo descreve as funções “deep clone”, que copiam um objeto ou qualquer objeto possuído pelo objeto copiado.
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 99 de 104
Deep Clone básico A função deep clone copia um objeto e suas referências “ownership”. Qualquer apontador de referências é ignorado. A função wblock clone copia hard owners e hard pointers e ignora as referências soft. As relações entre objetos são armazenadas no objeto como um dado membro de classe AcDbObjectId. Existem quatro tipos de relações entre objetos que estão no quadro abaixo. Estas relações caracterizam qual o tipo de comportamento seus dados irão seguir, isso será devidamente guardado usando-se o “object ID”, dentro da classe AcDbObjectId.
Deep
Wblock
clone
clone
Hard owner Soft owner Hard pointer Soft pointer
A função AcRxObject::clone ( ) clona objetos simples. A função AcDbObject::deepClone () clona o objeto e qualquer outro objeto possuído por esse objeto e também traduz as referências do objeto clonado. Basicamente o processo de clonagem dos objetos é feito de forma bastante simples. As operações deep clone e wblock clone arquivam o objeto para cloná-lo. Primeiramente um novo objeto é criado, que virá a ser o clone. Depois o objeto original é armazenado para a memória usando dwgOut ( ). Finalmente, o dado é armazenado no novo objeto usando-se dwgIn ( ). O ID map é um mecanismo para guardar o caminho de uma operação clone, ele consiste de pares de objetos ID:
Key ID – objeto de origem Value ID - objeto clonado ou objeto de destino
O ID map também contém pares de ID adicionais de objetos não clonados que são necessários para tradução do ID. As operações deep clone e wblock clone consistem de duas etapas: clonagem e tradução. O passo da clonagem acontece quando dwgOut ( ) e dwgIn ( ) são chamados e copiados. Nesse momento quando o deep clone ( ) é chamado em um objeto, o AutoCAD averigua se o objeto clonado possui qualquer outro objeto. Já o segundo passo é o da tradução, que usa o ID map para “linkar” novamente todos os objetos com suas novas relações.
Típica utilização do AcDbDatabase::deepCloneObjects ( )
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 100 de 104
void cloneSameOwnerObjects() { // Etapa 1: Obter os objetos para serem clonados ads_name sset; if (ads_ssget(NULL, NULL, NULL, NULL, sset) != RTNORM) { ads_printf("\nNothing selected"); return; } // Etapa 2: Adiciona os objetos ID’s para uma lista de objetos para serem clonados long length; ads_sslength(sset, &length); AcDbObjectIdArray objList; AcDbObjectId ownerId = AcDbObjectId::kNull; for (int i = 0; i < length; i++) { ads_name ent; ads_ssname(sset, i, ent); AcDbObjectId objId; acdbGetObjectId(objId, ent); AcDbObject *pObj; acdbOpenObject(pObj, objId, AcDb::kForRead); if (pObj->ownerId() == ownerId) objList.append(objId); else if (i == 0) { ownerId = pObj->ownerId(); objList.append(objId);
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 101 de 104
} pObj->close(); } ads_ssfree(sset); // Etapa 3: Pega o objeto ID desejado para o objeto clonado // Model Space AcDbBlockTable *pBlockTable; acdbCurDwg()->getBlockTable(pBlockTable, AcDb::kForRead); AcDbObjectId modelSpaceId; pBlockTable->getAt(ACDB_MODEL_SPACE, modelSpaceId); pBlockTable->close(); // Etapa 4: Cria um novo map ID AcDbIdMapping idMap; // Etapa 5: Chama deepCloneObjects( ) acdbCurDwg()->deepCloneObjects(objList, modelSpaceId, idMap); // Etapa 6: Printando os objetos ID dos novos objetos clonados AcDbIdMappingIter iter(idMap); for (iter.start(); !iter.done(); iter.next()) { AcDbIdPair idPair; iter.getMap(idPair); if (!idPair.isCloned()) continue; ads_printf("\nObjectId is: %Ld", idPair.value().asOldId()); } }
Clonando objetos de diferentes donos
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 102 de 104
Para se clonar objetos de diferentes donos, deve-se dividir os objetos ID em grupos de cada dono e devem pertencer ao mesmo banco de dados.
Implementando deepClone ( ) para Classes Customizadas As funções deepClone ( ) e wblockClone ( ) podem ser sobrecarregadas para objetos e entidades customizadas. Comandos do AutoCAD que usam as funções deepClone ( ) ou wblockClone ( )
COPY ARRAY MIRROR BLOCK INSERT WBLOCK XREF BIND XBIND EXPLODE
Named Object Dictionary O Named Object Dictionary tem soft ownership nas suas entradas. Então essas não são clonadas pelo wblockClone ( ). Tem-se aqui um caso especial de clonagem, no qual deve-se usar beginDeepCloneXlation ( ).
Sobrecarregando a Função deepClone ( ) Tem-se dois estágios:
Clonando: Pode ser sobrecarregado
Criar um novo objeto do mesmo tipo do antigo Adicionar o novo objeto para seu objeto possuidor Chamar dwgOut ( ) no objeto original usando AcDbDeepCloneFiler Rever o arquivo e então chamar dwgIn ( ) no novo objeto Chamar setObjectIdsInFlux ( ) em cada novo objeto antes de adicioná-lo no objeto ID map Adicionar a nova informação para o idMap. Clona o objeto possuído
Traduzindo: Deve ser controlado apenas através do ID map
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 103 de 104
Sobrecarregando a Função wblockClone ( ) Quando uma operação wblock é executada, o AutoCAD constroe um banco de dados novo para o novo desenho, que contem o named object dictionary , todos os symbol tables, e as variáveis. A função wblockClone ( ) usa um arquivo da classe AcDbWblockCloneFiler, que retorna uma lista de hard pointer e hard owner conectados no objeto primário. Antes deve-se chamar WblockClone ( ) nesses subobjetos. Todos os objetos possuídos são clonados durante o WblockClone ( ). Insert A operação insert é um especial caso do deep clone. O objeto não é copiado para um banco de dados, em vez disso ele é movido para um novo banco de dados. Funções de Notificação do Editor Reator A classe AcEditorReactor fornece quatro funções de notificação que retornam o controle para a aplicação de certos pontos na operação deep clone. As seguintes funções são chamadas durante todas as operações de deep clone e wblock clone:
beginDeepClone ( ) beginDeepCloneXlation ( ) abortDeepClone ( ) endDeepClone ( )
XV. Extensão do Protocolo
Usando o protocolo de extensão em ARX pode-se adicionar funcionalidade para as classes em tempo de execução.
Definição Protocolo extendido é um mecanismo para adicionar funcionalidade as classes ARX, essa associação é feita através das classes descritoras dos objetos. Essas classes descrevem a classe e incluem um array de ponteiros para qualquer objeto que extenda a funcionalidade desta classe. Uma classe ARX pode Ter qualquer número protocolos extendidos associados com ele.
Implementação Existem dois passos básicos para a implementação do protocolo extendido:
Declarar e definir as classes do protocolo que incluem a funcionalidade adicional, utilizando a sintaxe do C++ para derivar novas classes. Para cada classe, pode-se implementar as funções que constituem o protocolo extendido.
Registrar as classes do protocolo com a aplicação, e associa-los com as classes ARX : Inicializar a nova classe aparente (protocolo) e adicionar para a classe hierárquica
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
ObjectARX Básico
Página 104 de 104
AsdkEntTemperature::rxInit(); acrxBuildClassHierarchy();
Criar um objeto de cada classe e adicionar os objetos a classe descritora, com por exemplo:
pDefaultTemp = new AsdkDefaultTemperature(); pRegionTemp = new AsdkRegionTemperature(); pCircleTemp = new AsdkCircleTemperature(); AcDbEntity::desc()->addX(AsdkEntTemperature::desc(), pDefaultTemp); AcDbRegion::desc()->addX(AsdkEntTemperature::desc(), pRegionTemp); AcDbCircle::desc()->addX(AsdkEntTemperature::desc(), pCircleTemp); Descarregando o Aplicativo Quando a aplicação é descarregada, você necessita remover quaiquer comandos que foram adicionados na inicialização. Na adição, você poderá remover a classe do protocolo da classe ARX e deletar a classe descritora do objeto.
Centro de Apoio, Desenvolvimento Tecnológico e Ensino da Computação Gráfica Escola de Engenharia da UFMG Departamento de Engenharia de Estruturas
http://webcache.googleusercontent.com/search?q=cache:qGHSQZUGc-EJ:www.cadtec... 14/4/2010
View more...
Comments