Close

Relief for ODA Team in Ukraine

Learn more
ODA Drawings SDK
Example of Working with Extended Data

This example demonstrates working with extended data for getting, setting, modifying, clearing, transforming, and printing a sequence of tagged data for a registered application and a specified object of a database. This example uses a console menu for the following operations: printing whole extended data [W], printing the current sequence [P], clearing the sequence [C], modifying the current sequence [M], getting the sequence for the registered application [G], setting the sequence for the registered application [S], transforming the extended data [T], printing the list of accessible applications [L], registering an external application [R], and unregistering an existing application [U].

Extended data is associated with an external application that must be registered in the database. The registered application table object and registered application record objects store information about the external application which can use the extended data technology in the database. The registered application can attach, get, or set the extended data of an object. The object of a database stores the extended data, but it does not use the data. Programmatically, extended data is a sequence of tagged data that contains a group code and a data value. Objects of the database has the xData() method for getting the extended data associated with a registered application and the setXData() method for setting extended data for a registered application. Therefore, this example has multiple functionality: working with registered applications, working with extended data attached to an object, and working with a sequence of tagged data.

The example implements four specific functions:

  • PrintXDataSequence() — Prints a sequence of tagged data.
  • ClearXDataSequence() — Deletes all tagged data of a sequence.
  • ModifyXDataSequence() — Modifies a sequence and tagged data in the sequence.
  • ModifyXData() — Works with extended data of the specified object.

The PrintXDataSequence() function does not return a value and requires a smart pointer to an existing sequence of resbuf-instances representing the extended data. This function uses the PrintRbSequence() function and passes to it the obtained smart pointer to the sequence as the first argument and the pointer to the AboutXData() function obtained as the second argument. The PrintRbSequence() function displays information about all resbuf-instances of the passed sequence. The AboutXData() requires a pointer to the resbuf-instance and returns short or whole information about the group code and data value as a string value.

The ClearXDataSequence() function does not return a value and requires a reference to the smart pointer which refers to an existing sequence of resbuf-instances representing the extended data. This function uses the ClearRbSequence() function and passes to it the obtained smart pointer to the sequence as the first argument. The ClearRbSequence() function deletes all resbuf-instances and clears the sequence.

The ModifyXDataSequence() function does not return a value and requires a reference to the smart pointer which refers to an existing sequence of resbuf-instances representing the extended data. This function uses the ModifyRbSequence() function and passes to it the obtained smart pointer to the sequence as the first argument, pointer to the AboutXData() function as the second argument, pointer to the EntryXData() function as the third argument, and pointer to the IsXDataMarker() function as the forth argument. The ModifyRbSequence() function modifies the properties of resbuf-instances and their sequence. The AboutXData() function requires a pointer to an existing resbuf-instance and returns short or whole information about it as a string value. The EntryXData() function requires a pointer to an existing resbuf-instance and either requests a group code and data value or only a data value for the specified resbuf-instance, subject to the value of the second argument. The IsXDataMarker() function checks whether the resbuf-instance is a specific marker that cannot be modified or deleted when the sequence has been edited.


void PrintXDataSequence(OdResBufPtr pXData)
{
  PrintRbSequence(pXData, AboutXData);
}

void ClearXDataSequence(OdResBufPtr& pXData)
{
  ClearRbSequence(pXData);
}

void ModifyXDataSequence(OdResBufPtr& pXData)
{
  ModifyRbSequence(pXData, AboutXData, EntryXData, IsXDataMarker);
}

The ModifyXData() function requires a smart pointer to an existing object whose extended data is being edited and implements a console menu for the listed operations. The function organizes a loop that requests an operation code and uses the switch statement to select whether the case must be performed. The function processes user actions in the loop until the user selects the [Q] operation. The function uses the PrintXDataSequence(), ClearXDataSequence(), and ModifyXDataSequence() functions. The function also uses the EntryRecordName() function for entering an application name, checking whether the name is correct, and for checking whether the name is registered in the table of applications. The EntryRecordName() function returns the entered name as a value of the OdString type when the name is correct for the specified options, or it returns an empty string when the name is incorrect or is in conflict with other names. The ModifyXData() function gets a smart pointer to the database using the database() method of the passed object and gets a smart pointer to the registered application table object using the getRegAppTableId() method of the database object. Before the loop, the function creates an iterator, named itAppReg, using the newIterator() method of the registered application table object, declares the smart pointer to the registered application table object, named pRegApps, declares the smart pointer to the registered application record object, named pRegApp, declares the smart pointer to the resbuf-object for storing the start of the current editable sequence, named pXData, declares the OdString variable which stores the selected registered application for operations with extended data, named sAppName, declares the OdString variable for entering a name, named sName, and creates the three-dimensional transformation matrix for transforming operations with extended data, named vMatrix. The ModifyXData() function displays information about the selected object, selected application, and current sequence.

When the user selects [W], the ModifyXData() function prints the whole extended data attached to the specified object. The function uses the xData() method without arguments for getting the sequence of whole tagged data representing the extended data and the PrintXDataSequence() function for printing the obtained sequence of resbuf-instances.

When the user selects [P], the ModifyXData() function prints the current editable sequence of resbuf-instances using the PrintXDataSequence() function. The function passes the smart pointer being stored in the pXData variable.

When the user selects [C], the ModifyXData() function clears the current editable sequence of resbuf-instances using the ClearXDataSequence() function and sets the name of the selected registered application to an empty string.

When the user selects [M], the ModifyXData() function modifies the current editable sequence of resbuf-instances using the ModifyXDataSequence() function. The function checks whether the current sequence is empty. If the smart pointer of the pXData variable is NULL (the sequence is empty), the function creates a new resbuf-instance with the kDxfRegAppName data type (1001) that defines the start marker of the sequence for extended data associated with the registered application. The function uses the newRb() method for creating a new resbuf-instance that is the static pseudo-constructor and initializes this group code using the sAppName variable that stores the name of the selected registered application. If the selected application name is empty (the registered application is not selected), the function gets the name of the predefined application using the getRegAppAcadId() method of the database object and the getName() method of the obtained registered application record object. After that, the ModifyXData() function uses the ModifyXDataSequence() function and passes to it the smart pointer to the sequence of resbuf-instances for modification.

When the user selects [G], the ModifyXData() function gets the sequence of resbuf-instances associated with the selected registered application. The function requests the name of the registered application whose extended data must be obtained using the EntryRecordName() function. This application becomes selected. The name must exist in the table of registered applications, therefore the function passes the kMustExist value as the second argument for checking. If the entered name is correct and exists in the table, the function clears the current editable sequence of resbuf-instances using the ClearXDataSequence() function, assigns the entered name as the selected application name using the sAppName variable, gets the extended data associated with the selected registered application using the xData() method and saves the smart pointer to the obtained sequence of resbuf-instances as the current editable sequence using the pXData variable. After that, the function goes to the [P] operation for printing the current editable sequence of resbuf-instances.

When the user selects [S], the ModifyXData() function sets the current editable sequence of resbuf-instances as the extended data of the selected registered application. The function checks whether the current editable sequence contains resbuf-instances. If the smart pointer to the sequence is not NULL (the sequence is not empty), the function uses the setXData() method and passes to it the pXData pointer to the current editable sequence of resbuf-instances. The function uses the try…catch statement to catch exceptions when the extended data is set for the object. When the sequence is empty or an exception occurs, the function displays an error message and breaks to the console menu.

When the user selects [T], the ModifyXData() function transforms the extended data using the three-dimensional transformation matrix. The function declares a variable of the OdGeMatrix3d type for storing the transformation matrix and uses the EntryMatrix3d() function for entering its coefficients. After entry, the function uses the xDataTransformBy() method and passes to it the modified transformation matrix. To display the result of the transformation, the function uses the xData() method without arguments for getting the sequence of whole extended data and the PrintXDataSequence() function for printing the obtained sequence of resbuf-instances. The function uses the try…catch statement to catch exceptions when the extended data is transformed. When an exception occurs, the function displays an error message and breaks to the console menu.

When the user selects [L], the ModifyXData() function prints the list of names accessed in the table of registered applications. The function uses the iterator for traversing through the registered application table, getRecord() method of the Iterator object for getting the pointer to each registered application record object, and the getName() method for displaying the name of each registered application record object to which the iterator refers. The function initializes the arguments of the start() and step() methods using default values:  True – beginning with the first record to the next record, and True – only unerased records.

When the user selects [R], the ModifyXData() function requests the name of a new registered application record object using the EntryRecordName() function. The name must be absent from the table because the table cannot contain duplicate records, therefore the function passes the kMustAbsent value as the second argument for checking the new name. If the entered name is correct and absent from the table, the function creates a new registered application record object using its static pseudo-constructor. Then, the function sets the specified name for the created registered application record object using its setName() method and adds the new registered application in the table using the add() method of the registered application table object. The function uses the try…catch statement to catch exceptions when the object is added. If the addition is successful, the function goes to the [L] operation for printing the registered application list. When an exception occurs, the function displays an error message and breaks to the console menu.

When the user selects [U], the ModifyXData() function requests the name of the existing registered application record object to be unregistered using the EntryRecordName() function. The name must exist in the table, therefore the function passes the kMustExist value as the second argument for checking the entered name. If the entered name is correct and exists in the table, the function gets a smart pointer to the corresponding registered application record object using the getAt() method of the registered application table object and opens it in write mode. If the getAt() method returns a pointer to the specified registered application record object, the function calls the erase() method of the registered application record object and passes to it a True value as an argument. If the result is zero, the deletion is successful, and the function breaks to the console menu. If the result is non-zero, the function displays an error message using the getErrorDescription() method of the host object.

When the user selects [Q], the function ends the loop and returns to the calling function.

The ModifyXData() function has the following implementation:


#include "..\Common\DemoMain.h"
#include "Ge\GeMatrix3d.h"
#include "DemoRb.h"
#include "DemoXData.h"
#include "DbRegAppTable.h"
#include "DbRegAppTableRecord.h"
#include <iostream>
using namespace std;

OdGeMatrix3d EntryMatrix3d(const OdGeMatrix3d& matrix);

void ModifyXData(OdDbObjectPtr pObject)
{
  if(pObject.isNull())
  {
    wcout << "\nError: An object is not selected for working with XData\n";
    return;
  }

  wchar_t ch = L'\0';
  OdString sName, sAppName;
  OdResult result;
  OdResBufPtr pXData;
  OdGeMatrix3d vMatrix;

  OdDbRegAppTablePtr pRegApps = pObject->database()->getRegAppTableId().safeOpenObject(OdDb::kForWrite);
  OdDbSymbolTableIteratorPtr itRegApp = pRegApps->newIterator();
  OdDbRegAppTableRecordPtr pRegApp;

  wcout << L"\nStart modifying of the extended data\n";

  do {
    switch(ch)
    {
      case L'T':          // Transform the XData
      case L't':
        vMatrix = EntryMatrix3d(vMatrix);
        try {
          pObject->xDataTransformBy(vMatrix);
        }
        catch(OdError& e) {  wcout << L"\nError: " << e.code() << L" - " << e.description() << L"\n";   break;  }


      case L'W':          // Whole extended data
      case L'w':
        PrintXDataSequence(pObject->xData());
        break;


      case L'S':          // Set the XData sequence for the object
      case L's':
        if(!pXData.isNull())
          try {
            pObject->setXData( pXData );
            wcout << L"\nXData is set successfully\n";
          }
          catch(OdError& e) {  wcout << L"\nError: " << e.code() << L" - " << e.description() << L"\n";  }
        else wcout << L"Error: An empty XData can not be set\n";
        break;


      case L'G':          // Get the XData sequence for an application
      case L'g':
        wcout << L"\nEntry the name of the application to be selected:>" ;
        if((sName = EntryRecordName(pRegApps, kMustExist)).isEmpty()) break;
        ClearXDataSequence(pXData);
        
        pXData = pObject->xData((sAppName = sName));


      case L'P':          // Print the XData sequence
      case L'p':
        PrintXDataSequence(pXData);
        break;


      case L'C':          // Clear the XData sequence
      case L'c':
        ClearXDataSequence(pXData);
        sAppName = L"";
        break;


      case L'M':          // Modify the XData sequence
      case L'm':
        if(pXData.isNull())
        {
          if(sAppName.isEmpty())
          {
            pRegApp = pObject->database()->getRegAppAcadId().safeOpenObject();
            sAppName = pRegApp->getName();
          }
          pXData = OdResBuf::newRb(OdResBuf::kDxfRegAppName, sAppName);
        }
        ModifyXDataSequence(pXData);
        break;


      case L'R':          // Registry an external application
      case L'r':
        wcout << L"\nEntry the name of the application to be registered:>";
        if((sName = EntryRecordName(pRegApps, kMustAbsent)).isEmpty()) break;

        pRegApp = OdDbRegAppTableRecord::createObject();
        
        try {
          pRegApp->setName(sName);     
          pRegApps->add(pRegApp);
        }
        catch(OdError& e)
        {
          wcout << L"\nError: " << e.code() << L" - " << e.description() << L"\n";
          pRegApp->erase();
          break;
        }


      case L'L':          // List of available applications
      case L'l':
        wcout << L"\nList of available applications:\n"; 
        for(itRegApp->start() ; !itRegApp->done() ; itRegApp->step())
        {
          wcout << "\"" << itRegApp->getRecord()->getName() << L"\"\n";
        }
        break;


      case L'U':          // Unregistry an external application
      case L'u':
        wcout << L"\nEntry the name of the application to be unregistered:>" ;
        if((sName = EntryRecordName(pRegApps, kMustExist)).isEmpty()) break;

        pRegApp = pRegApps->getAt(sName, OdDb::kForWrite, false);

        result = pRegApp->erase(true);

        if(result) wcout << L"\nError: " << result << L" - " 
                         << pRegApp->database()->appServices()->getErrorDescription(result) << L"\n"; 
        break;

      case L'\0':         // Skip an action
        break;

      default:
        wcout << L"Incorrect operation\n";
    }
    wcout << L"\nSelected object: " << pObject->handle().ascii() << L"-" << pObject->isA()->name();
    wcout << L"\nSelected application: " << ((sAppName.isEmpty()) ? L"not selected" : sAppName)
          << L", sequence " << ((pXData.isNull()) ? L"is empty" : L"has codes");
    wcout << L"\nW. Whole extended data";
    wcout << L"\nT. Transform the XData";
    wcout << L"\nG. Get the XData sequence";
    wcout << L"\nS. Set the XData sequence";
    wcout << L"\nP. Print the XData sequence";
    wcout << L"\nC. Clear the XData sequence";
    wcout << L"\nM. Modify the XData sequence";
    wcout << L"\nL. List of available applications";
    wcout << L"\nR. Registry an external application";
    wcout << L"\nU. Unregistry an external application";
    wcout << L"\nQ. Quit";
    wcout << L"\nSelect operation:>";
    wcin >> ch;
  }
  while(ch != L'Q' && ch != L'q');

  wcout << L"\nStop modifying of the extended data\n";
}

Testing gives the following results:


Start modifying of the extended data

Selected object: 10-AcDbObject
Selected application: not selected, sequence is empty

W. Whole extended data
T. Transform the XData
G. Get the XData sequence
S. Set the XData sequence
P. Print the XData sequence
C. Clear the XData sequence
M. Modify the XData sequence
L. List of available applications
R. Registry an external application
U. Unregistry an external application
Q. Quit
Select operation:>

When the operation is W-"Whole extended data":


Group code sequence is empty

When the operation is L-"List of available applications":


List of available applications:
"ACAD"

When the operation is R-"Register an external application":


Entry the name of the application to be registered:>ODA
List of available applications:
"ACAD"
"ODA"

When the operation is M-"Modify the XData sequence":


Start modifying of the resbuf-sequence

Resbuf-sequence contains:
1. [1001,AppName] = "ACAD"

P. Print all tagged data
A. Add a new tagged data
I. Insert new tagged data
D. Delete the tagged data
M. Modify the tagged data
m. Modify only data value
C. Clear whole tagged data
Q. Quit
Select operation:>A

Accessible group codes:
1000 - Arbitrary string
1002 - Block brace - { or }
1003 - Layer name
1004 - Binary chunk
1005 - Handle
1010 - 3D Point
1011 - 3D Position
1012 - 3D Displacement
1013 - 3D Direction
1040 - Real value
1041 - Distance
1042 - Scale factor
1070 - Short integer
1071 - Long integer
0 - Quit
Entry group code:>1012
Entry X-coordinate:>2.5
Entry Y-coordinate:>0.8
Entry Z-coordinate:>3.6

Select operation:>A

Accessible group codes:
1000 - Arbitrary string
1002 - Block brace - { or }
1003 - Layer name
1004 - Binary chunk
1005 - Handle
1010 - 3D Point
1011 - 3D Position
1012 - 3D Displacement
1013 - 3D Direction
1040 - Real value
1041 - Distance
1042 - Scale factor
1070 - Short integer
1071 - Long integer
0 - Quit
Entry group code:>1040
Double value:>3.5

Select operation:>P

Resbuf-sequence contains:
1. [1001,AppName] = "ACAD"
2. [1012,3D Displacement] = (2.5,0.8,3.6)
3. [1041,Distance] = 3.5

Select operation:>m

Specify the index to be modified:>3
Tagged data: [1041] = 3.5
Double value:>1.2
Tagged data is set to: [1041] = 1.2

Select operation:>I

Specify the index to be inserted:>1
Accessible group codes:
1000 - Arbitrary string
1002 - Block brace - { or }
1003 - Layer name
1004 - Binary chunk
1005 - Handle
1010 - 3D Point
1011 - 3D Position
1012 - 3D Displacement
1013 - 3D Direction
1040 - Real value
1041 - Distance
1042 - Scale factor
1070 - Short integer
1071 - Long integer
0 - Quit
Entry group code:>1000
String:>Text Data

Select operation:>D

Specify the index to be deleted:>1
Error: Group code is the marker that can not be deleted

Select operation:>Q

Stop modifying of the resbuf-sequence

When the operation is P-"Print the XData sequence":


Resbuf-sequence contains:
[1001] = "ACAD"
[1000] = "Text Data"
[1012] = (2.5,0.8,3.6)
[1041] = 1.2

When the operation is S-"Set the XData sequence":


XData is set successfully

When the operation is G-"Get the XData sequence":


Entry the name of the application to be selected:>ODA
Resbuf-sequence is empty
Selected application: ODA, sequence is empty

When the operation is M-"Modify the XData sequence":


Start modifying of the resbuf-sequence

Resbuf-sequence contains:
1. [1001,AppName] = "ODA"

P. Print all tagged data
A. Add a new tagged data
I. Insert new tagged data
D. Delete the tagged data
M. Modify the tagged data
m. Modify only data value
C. Clear whole tagged data
Q. Quit
Select operation:>A

Accessible group codes:
1000 - Arbitrary string
1002 - Block brace - { or }
1003 - Layer name
1004 - Binary chunk
1005 - Handle
1010 - 3D Point
1011 - 3D Position
1012 - 3D Displacement
1013 - 3D Direction
1040 - Real value
1041 - Distance
1042 - Scale factor
1070 - Short integer
1071 - Long integer
0 - Quit
Entry group code:>1011
Entry X-coordinate:>0.1
Entry Y-coordinate:>3.0
Entry Z-coordinate:>6.5

Select operation:>A

Accessible group codes:
1000 - Arbitrary string
1002 - Block brace - { or }
1003 - Layer name
1004 - Binary chunk
1005 - Handle
1010 - 3D Point
1011 - 3D Position
1012 - 3D Displacement
1013 - 3D Direction
1040 - Real value
1041 - Distance
1042 - Scale factor
1070 - Short integer
1071 - Long integer
0 - Quit
Entry group code:>1040
Double value:>10.0

Select operation:>A

Accessible group codes:
1000 - Arbitrary string
1002 - Block brace - { or }
1003 - Layer name
1004 - Binary chunk
1005 - Handle
1010 - 3D Point
1011 - 3D Position
1012 - 3D Displacement
1013 - 3D Direction
1040 - Real value
1041 - Distance
1042 - Scale factor
1070 - Short integer
1071 - Long integer
0 - Quit
Entry group code:>1000
String:>ODA Data

Select operation:>Q

Stop modifying of the resbuf-sequence

When the operation is P-"Print the XData sequence":


Resbuf-sequence:
[1001] = "ODA"
[1011] = (0.1,3,6.5)
[1040] = 10
[1000] = "ODA Data"

When the operation is S-"Set the XData sequence":


XData is set successfully

When the operation is C-"Clear the XData sequence":


Selected application: Not selected, sequence is empty

When the operation is W-"Whole extended data":


Resbuf-sequence:
[1001] = "ACAD"
[1000] = "Text Data"
[1012] = (2.5,0.8,3.6)
[1041] = 1.2
[1001] = "ODA"
[1011] = (0.1,3,6.5)
[1040] = 10
[1000] = "ODA Data"

When the operation is T-"Transform the XData":


Current matrix:
1       0       0       0
0       1       0       0
0       0       1       0
0       0       0       1

Entry row index [0...3]:>0
Entry column index [0...3]:>0
Entry cell factor:>3

Entry row index [0...3]:>1
Entry column index [0...3]:>1
Entry cell factor:>2

Entry row index [0...3]:>2
Entry column index [0...3]:>3
Entry cell factor:>-6

Entry row index [0...3]:>0
Entry column index [0...3]:>3
Entry cell factor:>-3

Modified matrix:
3       0       0       -3
0       2       0       0
0       0       1       -6
0       0       0       1
Entry any key to continue [or S-save&quit]:>s

Resbuf-sequence contains:
[1001] = "ACAD"
[1000] = "Text Data"
[1012] = (2.5,0.8,3.6)
[1041] = 1.2
[1001] = "ODA"
[1011] = (-2.7,6,0.5)
[1040] = 10
[1000] = "ODA Data"

When the operation is G-"Get the XData sequence":


Entry the name of the application to be selected:>ODA

Resbuf-sequence contains:
[1001] = "ODA"
[1011] = (-2.7,6,0.5)
[1040] = 10
[1000] = "ODA Data"

When the operation is U-"Unregistry an external application":


Entry the name of the application to be unregistered:>ODA

When the operation is S-"Set the XData sequence":


Error: 126 - Invalid RegApp

When the operation is W-"Whole extended data":


Resbuf-sequence contains:
[1001] = "ACAD"
[1000] = "Text Data"
[1012] = (2.5,0.8,3.6)
[1041] = 1.2

Use the Q-"Quit" operation to exit:


Stop modifying of the extended data

See Also

Working with Extended Data

Example of Entering and Displaying the Group Code and Data Value for XData

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