Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Creating Custom Applications

DWGdirect Teigha provides the facilities for creating dynamically loaded custom modules , and custom objects derived from DWGdirect Teigha classes.

Creating a Custom Module

To create a custom module, the user should create a subclass of OdRxModule , as in the following example:

...

Naming Convention for Custom Modules

The naming rule for the shared library containing the subclass of OdRxModule , should be named is < application name >.drx, where < module name > is the same module name that is used to define the custom object classes in this context.

...

DWGdirect clients should use the supplied smart pointer classes when accessing database objects. In the above example, OdDbDatabasePtr is a smart pointer class that wraps a reference to an OdDbDatabase object. All database classes have corresponding smart pointer classes with the "Ptr" suffix attached. For example, for example a smart pointer to an OdDbCircle is an OdDbCirclePtr. When used properly, the DWGdirect smart pointer classes guarantee the proper management of heap objects both, in normal execution cases , and as well as in cases where exceptions transfer control out of the current scope.

...

Accessing System Header Variables

Header variables can be accessed You can access header variables directly from an instance of OdDbDatabase, for example.

Example:

Code Block
pDb->setLTSCALE(1.2);
std::cout << "  LTSCALE: " << pDb->getLTSCALE() << std::endl;

In the general case, all header variable access functions are in the form OdDbDatabase::getVARNAME() and OdDbDatabase::setVARNAME().

Accessing Table Entries

Table data is retrieved by opening To retrieve table data, open the table object , and then using use an iterator to step through the table entries. The following function iterates through the Layers table and prints the name of each layer, assuming pDb is a valid database , and os is an output stream.

...

Entities are owned by blocks (OdDbBlockTableRecord), so a block must first be opened before its entities can be accessed. Therefore, you must open the block first to access its entities. The following code iterates through all entities in all blocks of a drawing , and calls the dumpEntity() function for each entity:

...

The starting point for accessing objects in a database is the main dictionary object. The following example prints the object hierarchy starting from the main dictionary , and recurses into any sub dictionaries that it finds found subdictionaries (it does not traverse the entire object hierarchy).

...

Code Block
dumpObject(pDb->getNamedObjectsDictionaryId(), 
           "Named Objects Dictionary", 
           pDb, 
           os, 
           "  ");

Items To retrive items in a dictionary can also be retrieved by item name, using use the OdDbDictionary::getAt() function. The following code segment retrieves the entry called "ACAD_LAYOUT" from the specified dictionary (, if it exists):

Code Block
OdDbDictionaryPtr pDic = 
  pDb->getNamedObjectsDictionaryId().openObject(OdDb::kForRead);
if (pDic)
{
  OdDbDictionaryPtr pLayoutDic = 
    pDic->getAt("ACAD_LAYOUT", OdDb::kForRead);
  if (pLayoutDic)
  {
    // Do something with the layout dictionary
  }
}

Note that the : The layout dictionary ID can be accessed directly from a database by calling OdDbDatabase::getLayoutDictionaryId().

...

The base class for all objects that require runtime type identification is OdRxObject (this is - the base class for all database objects , and many other auxiliary classes used by that Teigha ). Instances uses. You can create instances of OdRxObject can be created by calling the static OdRxClass::createObject() function. For example, the

Example:

The following code segment creates a dictionary object:

Code Block
OdDbDictionaryPtr pDic;
pDic = OdDbDictionary::createObject();

An object created in using this fashion method does not belong to a database when it is first created--it must be explicitly added . The client must explicitly add it to a database by the client. The following code segment creates a new dictionary and , an xrecord, and adds the new objects the main dictionary. As the following example demonstrates, an OdDbObjectID is assigned to an object when the object is added to a database , and this OdDbObjectID is normally returned by the function that added the object (OdDbDictionary::setAt in this case).

Code Block
void DbFiller::addCustomObjects(OdDbDatabase* pDb)
{
  //Open the main dictionary
  OdDbDictionaryPtr pMain = 
    pDb->getNamedObjectsDictionaryId().safeOpenObject(OdDb::kForWrite);

  // Create the new dictionary.
  OdDbDictionaryPtr pOdtDic = OdDbDictionary::createObject();
  
  // Add new dictionary to the main dictionary.
  OdDbObjectId dicId = pMain->setAt("DWGDIRECT_OBJECTS", pOdtDic);
  
  // Create a new xrecord object.
  OdDbXrecordPtr pXRec = OdDbXrecord::createObject();

  // Add the xrecord the owning dictionary.
  OdDbObjectId xrId = pOdtDic->setAt("PROPERTIES_1", pXRec);
  
  OdResBufPtr pRb, temp;
  temp = pRb = OdResBuf::newRb(1000);
  temp->setString("Sample XRecord Data");
  
  temp = appendXDataPair(temp, 40);
  temp->setDouble(3.14159);
  
  temp = appendXDataPair(temp, 70);
  temp->setInt16(312);
  
  pXRec->setFromRbChain(pRb);
} //end DbFiller::addCustomObjects

In general, the following steps must be performed to To add an object to a database, perform the following steps:

  1. Open the parent object for

...

  1. writing. The parent is the object that will own the newly created object within the database hierarchy

...

  1. .

  2. Create the new object.

  3. Set the minimal number of properties required to add the object to the database:
    Table entries

...

  1. must have a name before

...

  1. adding them to the database.
    Entities

...

  1. can be added to a database without setting any properties.
    Objects

...

  1. can be added to a database without setting any properties.

  2. Add the new object to its parent, getting back the new Object ID for this object. Adding the object to a database does not change its open status

...

  1. . The object remains open for writing after it was added to a database.

  2. Set the remaining properties for the new object.
    Note

...

  1. : Some properties can only be set on a database resident object

...

  1. . As a general rule, it is

...

  1. easier to set all remaining properties (other than those specified

...

  1. above) after the object

...

  1. was added to the database.

  2. Close the object and its parent. This happens implicitly when the smart pointers used to open and create the objects are destroyed. Alternatively,

...

  1. you can

...

  1. explicitly destroy them by calling the OdSmartPtr::release() method on the appropriate smart pointer objects.

Creating New Table Objects

Table objects can be added To add table objects to a database by doing , do the following:

  1. Open the table to which the new object will be added, in OdDb::kForWrite mode.

  2. Create the new table entry.

  3. Set the name of the entry, and any other desired properties.

  4. Add the new entry to the open table object.

  5. Close the table entry and table objects (this is done automatically when the smart pointers holding references to these objects go out of scope).

...

Example:

The following function adds a new layer to a database:

...

Entities are owned by OdDbBlockTableRecord objects. An entity can be created and added To create an entity and add it to a block as follows, do the following:

  • Open the OdDbBlockTableRecord to which you want to add the new entity will be added, in OdDb::kForWrite mode.

  • Create the new entity.

  • Add the new entity to the open OdDbBlockTableRecord object.

  • Set If necessary, set the properties for the newly created entity, if necessary.

  • Close the OdDbBlockTableRecord object and the new entity (this . This is automatically done automatically when the smart pointers holding references to these objects go out of scope).

The following example adds an OdDbBlockReference entity to a specified block:

Code Block
OdDbObjectId DbFiller::addInsert(
  OdDbDatabase* pDb,            // owning database
  OdDbBlockTableRecord* pBlock, // block to which insert will be added
  const OdDbObjectId& blockId,  // ID of block to be inserted
  double xscale,                // X scale for insertion
  double yscale)                // X scale for insertion
{
  OdDbObjectId brefId;
  
  // Create the new insert entity.
  OdDbBlockReferencePtr pBlkRef = OdDbBlockReference::createObject();
  // Add the entity to the parent block.
  brefId = pBlock->appendOdDbEntity(pBlkRef);

  // Set the remaining entity properties.
  pBlkRef->setBlockTableRecord(blockId);
  pBlkRef->setScaleFactors(OdGeScale3d(xscale, yscale, 1.0));
  pBlkRef->setPosition(OdGePoint3d(6, 6, 0));
  return brefId;
} // end DbFiller::addInsert

Other entities (, such as circles , and lines , etc.) can be added in a similar manner.

...

Applications that process entity data from a database require a means functionalities to identify each entity by its type , and perform type-specific processing on the entity. Teigha uses a mechanism called protocal protocol extension to provide this functionality. Protocol extension allows a client application to create a new class and associate an a class instance of this class with a particular class of database objects. Then this The new class instance may be retrieved from a generalization of the class with which it was registered, providing an effective means of dispatching by type.

As an example, consider the protocol extension classes defined in ExProtocolExtension.h and ExProtocolExtension.cpp. The purpose of these classes is to dump the contents of the entities in a database, based on entity type. The implementation can be broken up split into the following steps.

Create the Parent Dispatching Class

The following class is the parent class for our entity dumpers:

...

Create One or More Child Dispatching Classes

The following code defines a class for dumping OdDb2dPolyline entities. It overrides the OdDbEntity_Dumper::dump() function in order to dump the data specific to this entity.

...

Code Block
void ExProtocolExtension::initialize()
{
  // Register OdDbEntity_Dumper with DWGdirect
  OdDbEntity_Dumper::rxInit();
  m_pDumpers = new Dumpers;
  m_pDumpers->addXs();
  
}//  end ExProtocolExtension::initialize()

And the The Dumpers::addXs() functions function does the following:

Code Block
  void addXs()
  {
    OdDbEntity::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_entityDumper);
    OdDbRegion::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_regionDumper);
    OdDbPolyline::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_polylineDumper);
    OdDb2dPolyline::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_2dPolylineDumper);
    OdDb3dPolyline::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_3dPolylineDumper);
    OdDbPolyFaceMesh::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_polyFaceMeshDumper);
    OdDbPolygonMesh::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_polygonMesh);
    OdDbBlockReference::desc()->addX(
    OdDbEntity_Dumper::desc(), &m_blockReference);
    OdDbMInsertBlock::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_mInsertBlock);
    OdDbSpline::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_splineDumper);
    OdDbEllipse::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_ellipseDumper);
    OdDbSolid::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_solidDumper);
    OdDbTrace::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_traceDumper);
    OdDb3dSolid::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_3DSolidDumper);
    OdDbProxyEntity::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_proxyEntityDumper);
    OdDbHatch::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_hatchDumper);
    OdDbCircle::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_circleDumper);
    OdDbMText::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_mTextDumper);
    OdDbText::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_textDumper);
    OdDbMline::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_mlineDumper);
    OdDbRasterImage::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_imageDumper);
    OdDbArcAlignedText::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_arcAlignedTextDumper);
    OdDbOle2Frame::desc()->addX(
      OdDbEntity_Dumper::desc(), &m_ole2FrameDumper);
  } // end addXs

All dumpers are registered for the OdDbEntity_Dumper class, so that the dumpers associated with a particular instance of OdDbEntity can be retrieved in a consistent manner (always by retrieving the dumper registered with OdDbEntity_Dumper).

Retrieve and Call the Registered Dispatching Class

The following function retrieves the custom dispatching class associated with a particular OdDbEntity instance , and calls the virtual dump() method to display the contents of this entity.

...

The OdDbEntity class defines a virtual OdDbEntity::worldDraw() function, which is used for vectorization. Each class derived from OdDbEntity overrides this function in order to perform custom vectorization. This function provides a convenient method for extracting the geometric representation of an entity in a generic manner.

For example, a client application can extract the vector data associated with an unsupported OdDbEntity descendant can be easily extracted by a client application by deriving a new class from OdGiWorldGeometry (see the OdGiWorldGeometryDumper class from OdReadEx as an example) , and then passing an instance of this class to OdDbEntity::worldDraw() to receive the vector geometry and attributes from the entity. See For the complete implemention of this class, see GiWorldDrawDumper.h and GiWorldDrawDumper.cpp within the OdReadEx sample folder for the complete implemention of this class.

The following code is a protocol extension class for OdDbEntity , that uses the sample OdGiWorldGeometryDumper class to print the vector information contained in an OdEntity:

...