Close

Relief for ODA Team in Ukraine

Learn more
ODA BimRv SDK
Identifying Elements using an ID

Overview of Element IDs

ODA BimRv SDK uses element IDs (instances of OdBmObjectId) to reference database elements. An element ID is a memory resident placeholder for a database element, and an actual database element pointer can always be obtained from a valid element ID. In general, a user will obtain a database element pointer by explicitly opening the element via the element ID. An opened database element will be closed by the associated smart pointer when the last smart pointer referring to the database element goes out of scope, or it can be explicitly closed by calling the smart pointer's release() function. Thus, database elements need not reside in memory unless they have been explicitly opened. This mechanism provides transparent partial loading functionality — a few key elements can be loaded, and the remaining database elements can be loaded only if necessary when they are opened. This greatly improves the execution speed for applications that need to access only portions of a drawing.

An ID stores a unique identifier of an element across all databases loaded at run-time. An ID exists only during the current run-time session until the database is loaded into memory. The database associates an ID with an element and its handle. When a database is saved into a file, IDs are not saved. The database creates new IDs each time a database is loaded into memory. Programmatically, an ID is a specific structure named OdDbStub and contains a handle associated with an element, smart pointer to an element, pointer to a database, and pointer to an owner.

The OdBmObjectId class implements an ID and represents the interface for getting and modifying an identification value. The OdBmObjectId class does not inherit the standard database functionality; it is a specific structure for associating elements of a database. This class declares a pointer to the specific internal class, named OdDbStub, that contains four members: smart pointer that addresses the referenced element in memory, handle associated with the referenced element, pointer to the database that contains the referenced element, and pointer to an owner that possesses the referenced element.

In the examples below, the pCmdCtx variable stores a pointer to the command context and the m_pDatabase variable stores a pointer to the database element.


OdBmCommandContextPtr pDbCmdCtx(pCmdCtx);
OdBmDatabasePtr m_pDatabase = pDbCmdCtx->database();
OdSmartPtr<OdBmUserIO> pIO = pDbCmdCtx->userIO();
    

Creating an ID

To create an ID, use its constructor. The OdBmObjectId class has a single constructor that creates an ID instance initialized by the kNull value. For example:


// create an ID
OdBmObjectId id;
OdString message;
message.format(L"\nHandle = %llx, Db = %lx", (OdUInt64)id.getHandle(), id.database());
pIO->putString(message);
    

Null ID

The OdBmObjectId class declares a special notation — OdBm::kNull — which defines a null value for an ID instance, denoting an undefined identifier that refers to nothing. An ID that equals kNull is not associated with an element and has a handle equal to zero.

To check whether an ID is null, use the isNull() method which does not have arguments and returns 'true' when an ID is set to kNull or 'false' when an ID is associated with an object. For example:


message.format(L"\nID %s", (id.isNull()) ? L"is kNull" : L"is associated");
pIO->putString(message);
    

To check an ID, you may also use the Not operator which calls the isNull() method and determines its returned value. For example:


id.setNull();
message.format(L"\nisNull() = %d", id.isNull());
pIO->putString(message);    // =1 - kNull,  =0 - not kNull
    

To set an ID to kNull, use the setNull() method which does not have arguments, does not return a value, and sets the ID to kNull. For example:


OdDbBaseDatabase* pIdDb = id.database();
if (pIdDb == NULL)
{
  message.format(L"\nID is not associated with a database");
  pIO->putString(message);
} 
else
{
  message.format(L"\nID is associated with database: %lx", pIdDb);
  pIO->putString(message);
}
    

Getting a Database, Handle, and Element From an ID

To get a database associated with an ID, use the database() method which does not have arguments and returns a pointer to the database element that contains the element associated with the ID, or NULL when the ID is not associated with an element or is set to kNull. For example:


OdDbHandle handle = id.getHandle();
if (handle.isNull())
{
  message.format(L"\nID is not associated with a handle");
  pIO->putString(message);
}
else
{
  message.format(L"\nID is associated with handle = %s", handle.ascii().c_str());
  pIO->putString(message);
}
    

To get a handle associated with an ID and referenced element, use the getHandle() method which does not have arguments and returns the handle assigned to the element associated with the ID or zero when the ID is not associated with an element or is set to kNull. To check the returned handle, use its isNull() method. For example:


message.format(L"\nID %s", (id.isValid()) ? L"is valid" : L"is invalid");
pIO->putString(message);
    

To get an element associated with an ID, use the safeOpenObject() method or openObject() method which requires the open mode as the first argument of the OdBm::OpenMode type, the erase status as the second argument of a boolean type, and returns the smart pointer to the element opened in the specified mode. The main difference between those methods is that openObject() method doesn't check the error code that was returned. safeOpenObject() method checks the returning error code and if error occurs - it generates an exception.

Checking an ID

To check whether an ID is valid, use the isValid() method which does not have arguments and returns 'true' when an ID is valid or 'false' when an ID is invalid. When an element is marked as 'erased', it continues existing in the database, and its ID remains valid. When an element is permanently erased or an ID is kNull, the ID becomes invalid. For example:


OdBmElementPtr pObj = OdBmElement::createObject();
OdBmObjectId id_1;
OdBmObjectId id_2 = pObj->objectId(); // pObj is a pointer to an element
message.format(L"\nObj=%lx, Db=%lx, Handle=%llx, isNull=%d, isValid=%d", id_1.openObject().get(),
  id_1.database(), (OdUInt64)id_1.getHandle(), id_1.isNull(), id_1.isValid());
pIO->putString(message);
message.format(L"\nObj=%lx, Db=%lx, Handle=%llx, isNull=%d, isValid=%d", id_2.openObject().get(),
  id_2.database(), (OdUInt64)id_2.getHandle(), id_2.isNull(), id_2.isValid());
pIO->putString(message);
    

When an ID element is not associated with an element, the handle is set to '-1', the pointer to the database is set to NULL, the pointer to the element is set to NULL, the erase status is 'true', and the ID is invalid and identified as kNull. When an ID element is associated with an element, the handle has an identifier, the pointer to a database is set to the address of an existing database, the pointer to an element is set to the address of an existing instance, the erase status is 'false', and the ID is valid. For example:


OdBmDatabasePtr pDb1 = pDbCmdCtx->database();
OdBmDatabasePtr pDb2 = pDbCmdCtx->database();
OdBmObjectId id1 = pDb1->getOwnerFamilyId();
OdBmObjectId id2 = pDb2->getOwnerFamilyId();
OdBmObjectId id3 = pDb1->getOwnerFamilyContainingGroupId();
OdBmObjectId id4 = pDb2->getOwnerFamilyContainingGroupId();
message.format(L"\n1) %llx", (OdUInt64)id1.getHandle());
pIO->putString(message);
message.format(L"\n2) %llx", (OdUInt64)id2.getHandle());
pIO->putString(message);
message.format(L"\n3) %llx", (OdUInt64)id3.getHandle());
pIO->putString(message);
message.format(L"\n4) %llx", (OdUInt64)id4.getHandle());
pIO->putString(message);
// Compare the same element from different databases
message.format(L"\n(id1 == id2) = %d, (id1 != id2) = %d", (id1 == id2), (id1 != id2));
pIO->putString(message);
message.format(L"\n(id3 == id4) = %d, (id3 != id4) = %d", (id3 == id4), (id3 != id4));
pIO->putString(message);
// Compare the different elements from the same database
message.format(L"\n(id1 == id3) = %d, (id1 != id3) = %d", (id1 == id3), (id1 != id3));
pIO->putString(message);
message.format(L"\n(id2 == id4) = %d, (id2 != id4) = %d", (id2 == id4), (id2 != id4));
pIO->putString(message);
// Compare the different elements from different databases
message.format(L"\n(id1 == id4) = %d, (id1 != id4) = %d", (id1 == id4), (id1 != id4));
pIO->putString(message);
message.format(L"\n(id2 == id3) = %d, (id2 != id3) = %d", (id2 == id3), (id2 != id3));
pIO->putString(message);
/*   Result is following:
  (id1 == id2) = 1, (id1 != id2) = 0
  (id3 == id4) = 1, (id3 != id4) = 0
  (id1 == id3) = 0, (id1 != id3) = 1
  (id2 == id4) = 0, (id2 != id4) = 1
  (id1 == id4) = 0, (id1 != id4) = 1
  (id2 == id3) = 0, (id2 != id3) = 1
*/
    

Comparing an ID

To compare IDs, use the comparison operators that compare the ID elements taking into account the handle and database. For example:


id1 = pDb1->getOwnerFamilyId();
id2 = id1;
 message.format(L"\nH1=%llx, H2=%llx, (ID1==ID2)=%d", (OdUInt64)id1.getHandle(), (OdUInt64)id2.getHandle(), (id1 == id2));
pIO->putString(message);
    

Copying an ID

To copy an ID, use the Assignment operator that copies one ID to another ID. For example:

See Also

Identification of Database Elements

Copyright © 2002 – 2022. Open Design Alliance. All rights reserved.