Drawings SDK Developer Guide > Working with .dwg Files > Working with Entities > Working with Specific Entitites > Working with Shapes > Example of Working with the Shape Object
Example of Working with the Shape Object

This example demonstrates working with a shape object for displaying and modifying its properties. This example uses a console menu that represents the following operations: getting and setting the position [C], normal [N], thickness [T], oblique angle [O], rotation angle [R], width scale factor [W], height scale factor [F], shape code [I], shape name [L], obtaining and associating with a text style [S], binding to a .shx file [B], displaying the object properties, general properties, specific properties [P], and modifying the general entity properties [M].

The example uses the following header files, examples, and functions implemented in them:


#include "..\Common\DemoMain.h"
#include "DbShape.h"
#include <iostream>
using namespace std;

// Example of Entering and Displaying for 3D Point Objects
bool EntryPoint3d(OdGePoint3d& point);
OdString AboutPoint3d(const OdGePoint3d& point);

// Example of Entering and Displaying for 3D Vector Objects
bool EntryVector3d(OdGeVector3d& vector);
OdString AboutVector3d(const OdGeVector3d& vector);

// Example of Binding to a Shape File
OdDbObjectId BindToSHXFile(OdDbDatabase* pDb, OdString shxFileName, bool bStatus);

// Example of Entering Characters for String Objects
OdString EntryTextAs(enum enumCheckText = kArbitrary);

// Example of Using the Record–Table and Dictionary Interfaces for Getting Information about Objects
OdString AboutDbObject(OdDbObjectId idObject);

// Example of Using the Record–Table Interface for Selecting Objects
OdDbObjectId EntryTableRecordObject(OdDbObjectId idTable, OdDbObjectId idRecord = OdDbObjectId::kNull);

OdString AboutEntityPlane(OdDbEntity* pEntity);
void PrintEntityProperties(OdDbEntity* pEntity);
void ModifyEntityProperties(OdDbEntity* pEntity);

The PrintShapeProperties() function requires a pointer to an existing shape object and displays its properties. The function gets the specific properties using the position(), normal(), thickness(), oblique(), rotation(), widthFactor(), size(), styleId(), shapeNumber(), and name() methods. The function uses the AboutPoint3d() function for converting the position coordinates to a string value and the AboutVector3d() function for converting the coordinates of the normal to a string value. The AboutPoint3d() and AboutVector3d() functions require an instance of the three-dimensional point or three-dimensional vector to be converted as an argument and return a string containing the X,Y,Z coordinates. The shape is a planar entity, and the function gets and displays the coefficients of the plane using the AboutEntityPlane() function.

The PrintShapeProperties() function has the following implementation:


void PrintShapeProperties(OdDbShape* pShape)
{
  wcout << L"\n  Code = " << pShape->shapeNumber()
        << L"\n  Name = \"" << pShape->name() << L"\""
        << L"\n  Normal = " << AboutVector3d(pShape->normal())
        << L"\n  Position = " << AboutPoint3d(pShape->position())
        << L"\n  Thickness = " << pShape->thickness()
        << L"\n  Oblique angle = " << pShape->oblique() << L" radians"
        << L"\n  Rotation angle = " << pShape->rotation() << L" radians"
        << L"\n  Width scale factor = " << pShape->widthFactor() 
        << L"\n  Height scale factor = " << pShape->size()
        << L"\n  Associated Style = " << AboutDbObject(pShape->styleId())
        << L"\n  " << AboutEntityPlane(pText);
}

The ModifyShapeProperties() function requires a pointer to an existing shape object and implements the console menu for the listed operations. The function organizes a loop that inquires about the 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 EntryPoint3d() function for entering coordinates of a three-dimensional point and the EntryVector3d() function for entering coordinates of a three-dimensional vector. The EntryPoint3d() and EntryVector3d() functions require a reference to an instance of the three-dimensional point or three-dimensional vector to be modified as an argument and return True when the passed instance is modified successfully, or False when the user cancels entry.

When the user selects [P], the function displays the common object properties using the PrintObjectProperties() function, general entity properties using the PrintEntityProperties() function, and specific shape properties using the PrintShapeProperties() function. When the user selects the [p] operation, the function displays only specific shape properties.

When the user selects [C], the function gets the position of the shape using the position() method, calls the EntryPoint3d() function for entry of its coordinates, and sets the returned point as the new position using the setPosition() method if entry is successful.

When the user selects [N], the function gets the normal to the plane of the shape using the normal() method, calls the EntryVector3d() function for entry of its coordinates, and sets the returned vector as a new normal using the setNormal() method if entry is successful.

When the user selects [T], the function gets the current thickness using the thickness() method and requests a double value. If an entered value is incorrect, the function displays an error message and breaks to the console menu. If an entered value is correct, the function sets the new thickness using the setThickness() method.

When the user selects [O], the function gets the current oblique angle using the oblique() method and requests a double value in the range ±2PI. If an entered value is incorrect, the function displays an error message and breaks to the console menu. If an entered value is correct, the function sets the new oblique angle using the setOblique() method.

When the user selects [R], the function gets the current rotation angle using the rotation() method and requests a double value in the range ±2PI. If an entered value is incorrect, the function displays an error message and breaks to the console menu. If an entered value is correct, the function sets the new rotation angle using the setRotation() method.

When the user selects [W], the function gets the current width scale factor using the widthFactor() method and requests a positive non-zero double value. If an entered value is incorrect or is negative, the function displays an error message and breaks to the console menu. If an entered value is correct, the function sets the new width scale factor using the setWidthFactor() method.

When the user selects [F], the function gets the current height scale factor using the size() method and requests a positive non-zero double value. If an entered value is incorrect or is negative, the function displays an error message and breaks to the console menu. If an entered value is correct, the function sets the new height scale factor using the setSize() method.

When the user selects [I], the function gets the current code of the shape using the shapeNumber() method and requests an integer value which is a new code. If an entered value is correct, the function sets the new shape code using the setShapeNumber() method and displays the shape code and shape name.

When the user selects [L], the function requests a non-empty string which is the new name using the EntryTextAs() function and passes to it the kNonEmpty value as an argument to verify the value to be entered. The EntryTextAs() organizes the entry of the string, trims leading and trailing spaces after entry, and checks whether the string is non-empty. If an entered string is correct, the function sets the new shape name using the setName() method and displays the shape name and shape code.

When the user selects [S], the function gets the object ID of the current text style assigned to the shape entity using the styleId() method and calls the EntryTableRecordObject() function for selecting another text style. The EntryTableRecordObject() function requires the object ID of the text style table object and the text style record object as arguments and returns the object ID of the text style record object specified by the user or the same object ID when the user cancels entry. To get the text style table, the function uses the getTextStyleTableId() method of the database object and the database() method of the shape object. The EntryTableRecordObject() function organizes its own console menu for selecting the named record object (text style). After selection, the ModifyShapeProperties() function checks whether the ID is not kNull, and then, calls the setStyleId() method and passes to it the returned object ID to associate the shape with the text style.

When the user selects [B], the function inquires about the name of the .shx file using the EntryFileName() function. The EntryFileName() function gets the kMustExist value as the first argument because the .shx file must exist to be associated; the function also gets a False value as the second argument to specify any filename. The EntryFileName() function checks the entered file name and returns the name entered by the user or an empty string if the user cancels entry. If the name is correct, the function calls the BindToSHXFile() function and passes to it the current database as the first argument using the database() method, the obtained file name as the second argument, and True as the third argument. The BindToSHXFile() function checks whether the text style already exists for the specified .shx file or creates a new text style and associates it with the specified .shx file. The BindToSHXFile() function returns the object ID to the text style record object which is associated with the .shx file or OdDb::kNull if errors occur. If binding is successful, the function sets the returned ID for the shape entity using the setStyleId() method and displays the result using the styleId() method and the AboutDbObject() function which displays information about the text style.

When the user selects [M], the function calls the ModifyEntityProperties() function and passes to it the pointer to the shape object for modifying its general entity properties. After modification, the function displays all shape properties using the [P] operation.

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

The ModifyShapeProperties() function has the following implementation:


void ModifyShapeProperties(OdDbShape* pShape)
{
  wchar_t ch = L'\0';
  double value;
  OdInt16 number;
  OdString name;
  OdGePoint3d point;
  OdGeVector3d vector;
  OdDbObjectId idStyle;

  wcout << L"\n\nStart modifying of the shape properties";

  do {
    switch(ch)
    {
      case L'M':          // Modify the general properties
      case L'm':
        ModifyEntityProperties(pShape);


      case L'P':          // Print the whole properties
        wcout << L"\nH=" << pShape->handle().ascii();
        wcout << L"\n  ------ Common Object Properties";
        PrintObjectProperties(pShape);
        wcout << L"\n  ------ General Entity Properties";
        PrintEntityProperties(pShape);


      case L'p':          // Print the specific properties
        wcout << L"\n  ------ Specific Shape Properties";
        PrintShapeProperties(pShape);
        wcout << L"\n";        
        break;


      case L'N':          // Set the normal
      case L'n':
        wcout << L"Entry the normal";
        vector = pShape->normal();
        
        if(EntryVector3d(vector))
        {
          pShape->setNormal(vector);
          wcout << L"Normal is set to " << AboutVector3d(pShape->normal()) << L"\n";
        }
        break;


      case L'C':          // Set the position
      case L'c':
        wcout << L"Entry the position";
        point = pShape->position();
        
        if(EntryPoint3d(point))
        {
          pShape->setPosition(point);
          wcout << L"Position is set to " << AboutPoint3d(pShape->position()) << L"\n";
        }
        break;


      case L'T':          // Set the thickness
      case L't':
        wcout << L"\nCurrent thickness = " << pShape->thickness()
              << L"\nEntry a new thickness [t>0-along normal|t<0-opposite normal]:>";
        wcin >> value;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          pShape->setThickness(value);
          wcout << L"Thickness is set to: " << pShape->thickness() << L"\n";
        }
        else { wcin.clear();  wcin.sync();  wcout << L"Error: Invalid entered value\n"; }
        break;


      case L'O':          // Set the oblique angle
      case L'o':
        wcout << L"\nCurrent oblique angle = " << pShape->oblique()
              << L"\nEntry a new angle [-2PI...2PI]:>";
        wcin >> value;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          pShape->setOblique(value);
          wcout << L"Oblique angle is set to: " << pShape->oblique() << L" radians\n";
        }
        else { wcin.clear();  wcin.sync();  wcout << L"Error: Invalid entered value\n"; }
        break;


      case L'R':          // Set the rotation angle
      case L'r':
        wcout << L"\nCurrent rotation angle = " << pShape->rotation()
              << L"\nEntry a new angle [-2PI...2PI]:>";
        wcin >> value;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          pShape->setRotation(value);
          wcout << L"Rotation angle is set to: " << pShape->rotation() << L" radians\n";
        }
        else { wcin.clear();  wcin.sync();  wcout << L"Error: Invalid entered value\n"; }
        break;


      case L'W':          // Set the width scale factor
      case L'w':
        wcout << L"\nCurrent width scale factor = " << pShape->widthFactor()
              << L"\nEntry a new factor [f > 0]:>";
        wcin >> value;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          if(value > 0)
          {
            pShape->setWidthFactor(value);
            wcout << L"Width scale factor is set to: " << pShape->widthFactor() << L"\n";
          }
          else wcout << L"Error: Width scale factor must be a positive non-zero double value\n";
        }
        else { wcin.clear();  wcin.sync();  wcout << L"Error: Invalid entered value\n"; }
        break;


      case L'F':          // Set the height scale factor
      case L'f':
        wcout << L"\nCurrent height scale factor = " << pShape->size()
              << L"\nEntry a new factor (shape size) [f > 0]:>";
        wcin >> value;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          if(value > 0)
          {
            pShape->setSize(value);
            wcout << L"Height scale factor is set to: " << pShape->size() << L"\n";
          }
          else wcout << L"Error: Height scale factor must be a positive non-zero double value\n";
        }
        else { wcin.clear();  wcin.sync();  wcout << L"Error: Invalid entered value\n"; }
        break;


      case L'I':          // Set the shape code
      case L'i':
        wcout << L"\nCurrent shape code = " << pShape->shapeNumber()
              << L"\nEntry a new code:>";
        wcin >> number;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          pShape->setShapeNumber(number);
          wcout << L"Shape code is set to: " << pShape->shapeNumber() << L" (\"" << pShape->name() << L"\")\n";
        }
        else { wcin.clear();  wcin.sync();  wcout << L"Error: Invalid entered value\n"; }
        break;


      case L'L':          // Set the shape name (label)
      case L'l':
        wcout << L"\nShape name (label):>";
        if((name = EntryTextAs(kNonEmpty)).isEmpty()) break;

        pShape->setName(name);
        wcout << L"Shape name is set to: \"" << pShape->name() << L"\" (" << pShape->shapeNumber() << L")\n";
        break;


      case L'S':          // Set the text style
      case L's':
        idStyle = EntryTableRecordObject(pShape->database()->getTextStyleTableId(), pShape->styleId());

        if(!idStyle.isNull())
        {
          pShape->setStyleId(idStyle);
          wcout << L"Style is set to: " << AboutDbObject(pShape->styleId()) << L"\n";
        }
        else wcout << L"Entry is canceled\n";
        break;


      case L'B':          // Bind to the shx-file
      case L'b':
        wcout << L"\nEntry a shx-file name:>";
        if((name = EntryFileName(kMustExist, false)).isEmpty()) break;

        if((idStyle = BindToSHXFile(pShape->database(), name, true)).isNull()) break;

        pShape->setStyleId(idStyle);
        wcout << L"Shape is bound to: " << AboutDbObject(pShape->styleId()) 
              << L" associated with shx-file\n";
        break;


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

      default:
        wcout << L"Error: Incorrect operation\n";
    }
    wcout << L"\nN. Set the normal";
    wcout << L"\nC. Set the position";
    wcout << L"\nT. Set the thickness";
    wcout << L"\nS. Set the text style";
    wcout << L"\nI. Set the shape code";
    wcout << L"\nL. Set the name (label)";
    wcout << L"\nB. Bind to the shx-file";
    wcout << L"\nO. Set the oblique angle";
    wcout << L"\nR. Set the rotation angle";
    wcout << L"\nW. Set the width scale factor";
    wcout << L"\nF. Set the height scale factor";
    wcout << L"\nP. Print the whole properties";
    wcout << L"\np. Print the specific properties";
    wcout << L"\nM. Modify the general properties";
    wcout << L"\nQ. Quit";
    wcout << L"\nSelect operation:>";
    wcin >> ch;
  }
  while(ch != L'Q' && ch != L'q');

  wcout << L"Stop modifying of the shape properties\n";
}

Testing gives the following results:


Start modifying of the shape properties

N. Set the normal
C. Set the position
T. Set the thickness
S. Set the text style
I. Set the shape code
L. Set the name (label)
B. Bind to the shx-file
O. Set the oblique angle
R. Set the rotation angle
W. Set the width scale factor
F. Set the height scale factor
P. Print the whole properties
p. Print the specific properties
M. Modify the general properties
Q. Quit
Select operation:>

When the operation is p-"Print the specific properties":


------ Specific Shape Properties
Code = 0
Name = ""
Normal = (0,0,1)
Position = (0,0,0)
Thickness = 0
Oblique angle = 0 radians
Rotation angle = 0 radians
Width scale factor = 1
Height scale factor = 1
Associated Style = [Db:kNull]
Entity Plane = (0 * X + 0 * Y + 1 * Z + 0)

When the operation is C-"Set the position":


Entry the position
Current coordinates: (0,0,0)
Entry X-coordinate:>2.5
Entry Y-coordinate:>3.1
Entry Z-coordinate:>0.5
Position is set to (2.5,3.1,0.5)

When the operation is N-"Set the normal":


Entry the normal
Current directions: (0,0,1)
Entry X-direction:>1.3
Entry Y-direction:>0.5
Entry Z-direction:>0.1
Normal is set to (0.930949,0.358057,0.0716115)

When the operation is T-"Set the thickness":


Current thickness = 0
Entry a new thickness [t>0-along normal|t<0-opposite normal]:>1.8
Thickness is set to: 1.8

When the operation is O-"Set the oblique angle":


Current oblique angle = 0
Entry a new angle [-2PI...2PI]:>0.105
Oblique angle is set to: 0.105 radians

When the operation is R-"Set the rotation angle":


Current rotation angle = 0
Entry a new angle [-2PI...2PI]:>0.352
Rotation angle is set to: 0.352 radians

When the operation is W-"Set the width scale factor":


Current width scale factor = 1
Entry a new factor [f > 0]:>1.5
Width scale factor is set to: 1.5

When the operation is F-"Set the height scale factor":


Current height scale factor = 1
Entry a new factor (shape size) [f >= 0]:>2.1
Height scale factor is set to: 2.1

When the operation is I-"Set the shape code":


Current shape code = 0
Entry a new code:>65
Shape code is set to: 65 ("")

When the operation is S-"Set the text style":


Select the TextStyle object:
11-"Standard"
Current: [Db:kNull]
Entry the name to be selected (or [?]-null/[:]-quit):>Standard
Style is set to: [11-"Standard"-TextStyle]

When the operation is p-"Print the specific properties":


------ Specific Shape Properties
Code = 65
Name = ""
Normal = (0.930949,0.358057,0.0716115)
Position = (-0.639172,2.4327,3.12785)
Thickness = 1.8
Oblique angle = 0.105 radians
Rotation angle = 0.352 radians
Width scale factor = 1.5
Height scale factor = 2.1
Associated Style = [11-"Standard"-TextStyle]
Entity Plane = (0.930949 * X + 0.358057 * Y + 0.0716115 * Z + -3.47316)

When the operation is B-"Bind to the shx-file":


Entry a shx-file name:>my.shx
Shape is bound to: [41-"my"-TextStyle] associated with shx-file

When the operation is L-"Set the name (label)":


Shape name (label):>CE
Shape name is set to: "CE" (132)

When the operation is P-"Print all properties":


H=40
  ------ Common Object Properties
  Type: AcDbShape
  Status: unerased,resident,modified,forRead,forWrite
  Database: c:\test.dwg
  ------ General Entity Properties
  Block: [1F-"*Model_Space"-Block]
  Layer: [10-"0"-Layer]
  Material: [3C-"ByLayer"-Material]
  Linetype: [15-"ByLayer"-Linetype]
  Lineweight: [kLnWtByLayer]
  Transparency: [byLayer]
  Visual style: [Db:kNull]
  PlotStyleName: ByLayer
  Linetype scale: 1
  Color: [byLayer], Index = 256
  State: Planar, Visible, Cast Shadows, Receive Shadows
  ------ Specific Shape Properties
  Code = 132
  Name = "CE"
  Normal = (0.930949,0.358057,0.0716115)
  Position = (-0.639172,2.4327,3.12785)
  Thickness = 1.8
  Oblique angle = 0.105 radians
  Rotation angle = 0.352 radians
  Width scale factor = 1.5
  Height scale factor = 2.1
  Associated Style = [41-"my"-TextStyle]
  Entity Plane = (0.930949 * X + 0.358057 * Y + 0.0716115 * Z + -3.47316)

Use the Q-"Quit" operation to exit:


Stop modifying of the shape properties

See Also

Working with Shapes

Example of Binding to a Shape File

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