Drawings SDK Developer Guide > Working with .dwg Files > Working with Entities > Creating a Custom Entity > Implementing Grip Point Functions
Implementing Grip Point Functions

Custom entities have grip points that appear when the user selects an entity object with a pointing device. The subGetGripPoints() function must fill in the OdGePoint3dArray array of grip points that have been defined for a custom entity. The subMoveGripPointsAt() function performs the entity modifications that result from a grip edit.


virtual OdResult OdDbEntity::subGetGripPoints( OdGePoint3dArray& gripPoints ) const;
virtual OdResult OdDbEntity::subMoveGripPointsAt( const OdGePoint3dArray& gripPoints, const OdIntArray& indices ) const;

The entity defines its grip points and how to interpret the user-supplied action. To edit a custom entity using grips, you must override the subGetGripPoints() and subMoveGripPointsAt() functions. Grip points are added to a special array using the subGetGripPoints function, with each point indicating the order in which it was added beginning with zero (the first point = 0, second point = 1, third point = 2, and so on). Additional points in the array are realized by the append() function of the Array object.

For example, the smiley entity implements the following:


OdResult AsdkSmiley::subGetGripPoints(OdGePoint3dArray& gripPoints) const
{
   assertReadEnabled();
                                              // indices
   // Grip points to face
   OdGePoint3d center( center() );
   OdGeVector3d xoff( radius(), 0, 0 ),
                yoff( 0, radius(), 0 );

   gripPoints.append( center );               // 0
   gripPoints.append( center + xoff );        // 1
   gripPoints.append( center + yoff );        // 2
   gripPoints.append( center - xoff );        // 3
   gripPoints.append( center - yoff );        // 4

   // Grip points to mouth
   gripPoints.append( mouthLeft() );          // 5
   gripPoints.append( mouthRight() );         // 6
   gripPoints.append( mouthBottom() );        // 7
   gripPoints.append( OdGeLineSeg3d(mouthLeft(),mouthRight()).midPoint() );  // 8
   
   // Grip points to eye
   xoff.x = yoff.y = meyesize;
   
   // Left eye
   center = leftEyeCenter();
   gripPoints.append( center );               // 9
   gripPoints.append( center + xoff );        // 10
   gripPoints.append( center + yoff );        // 11
   gripPoints.append( center - xoff );        // 12
   gripPoints.append( center - yoff );        // 13
   
   // Right eye
   center = rightEyeCenter();
   gripPoints.append( center );               // 14
   gripPoints.append( center + xoff );        // 15
   gripPoints.append( center + yoff );        // 16
   gripPoints.append( center - xoff );        // 17
   gripPoints.append( center - yoff );        // 18

   return eOk;
}

The subMoveGripPointsAt function is used to modify the points of the array. Grip editing in stretch mode allows you to stretch an object by moving selected grips to new locations. The custom object calls the subMoveGripPointsAt() function when the user is in stretch mode. For certain entities, however, some grips move the object rather than stretching it. These grips include grip points of text objects, blocks, midpoints of lines, centers of circles, centers of ellipses, and point objects. In these cases, the subMoveGripPointsAt() function calls the transformBy() function. The subMoveGripPointsAt() function is used to invoke the transformBy() function. If the subMoveGripPointsAt() function is not overridden in the custom entity, the transformBy() function is called.

The subMoveGripPointsAt() function uses a switch operator to check which grip point is being edited. The first function parameter indicates the array of grip points that was created using the subGetGripPoints() function. The second function parameter indicates the array of grip indices that the user edited in stretch mode. Indices of points that have changed position are located in this array. The new position of grip points is stored in the grip points array. You can select a single grip point, but generally you may want to select multiple grip points. The following example illustrates selecting multiple grip points.


OdResult AsdkSmiley::subMoveGripPointsAt(const OdGePoint3dArray& gripPoints, const OdIntArray& indices)
{
   assertWriteEnabled();

   int  idx, count = indices.length();
   OdGePoint3d idxpoint;

   for( int i = 0; i < count ; i++ )                           // A few grip points can be selected concurrently
   {
      idx = indices[i];
      idxpoint = gripPoints[idx];

      if( idx == 0 )                                           // Move the smiley center
      {
         setCenter( idxpoint );
      }
      else if( idx >= 1 && idx <= 4 )                          // Stretch the smiley radius
      {
         scaleRadius( idxpoint.distanceTo( center() ));
      }
      else if( idx == 5 )                                      // Stretch the left edge of mouth
      {
         setMouth( idxpoint, mouthBottom(), mouthRight() );
         ensureRadiusMouth();
      }
      else if( idx == 6 )                                      // Stretch the right edge of mouth
      {
         setMouth( mouthLeft(), mouthBottom(), idxpoint );
         ensureRadiusMouth();
      }
      else if( idx == 7 )                                      // Stretch the bottom edge of mouth
      {
         setMouth( mouthLeft(), idxpoint, mouthRight() );
         ensureRadiusMouth();
      }
      else if( idx == 8 )                                      // Move the mouth
      { 
         moveMouthToPoint( idxpoint );
         ensureRadiusMouth();
      }
      else if( idx == 9 || idx == 14 )                         // Move the center of eyes
      {
         setEyesApart( (idxpoint.x - center().x) * 2 );        // Apart >= 2*eyeSize

         if( eyesApart() < 2 * eyeSize() ) setEyesApart( 2 * eyeSize() );

         setEyesHeight( idxpoint.y - center().y );             // Height >= eyeSize

         if( eyesHeight() < eyeSize() ) setEyesHeight( eyeSize() );
         
         ensureRadiusEyes();
      }
      else if((idx >= 10 && idx <= 13) || 
              (idx >= 15 && idx <= 18))                        // Stretch the radius of eyes
      {
         setEyeSize( idxpoint.distanceTo( (idx < 14) ? leftEyeCenter() : rightEyeCenter() ) );
         
         if ( 2 * eyeSize() > eyesApart() ) setEyeSize( eyesApart() / 2 );
         
         ensureRadiusEyes();
      };
   }
   return  eOk;
}

void AsdkSmiley::moveMouthToPoint(const  OdGePoint3d point)
{
   OdGePoint3d middle( OdGeLineSeg3d(mouthLeft(), mouthRight()).midPoint() );
   OdGeVector3d offset( point.x - middle.x, point.y - middle.y, point.z - middle.z );
   setMouth( mouthLeft() + offset, mouthBottom() + offset, mouthRight() + offset );
}

void AsdkSmiley::ensureRadiusMouth()
{
   double  d;
   OdGePoint3d center( center() );   
   if( (d = center.distanceTo( mouthLeft() )) > radius() / 1.1) setRadius( 1.1 * d );
   if( (d = center.distanceTo( mouthRight() )) > radius() / 1.1) setRadius( 1.1 * d );
   if( (d = center.distanceTo( mouthBottom() )) > radius() / 1.1) setRadius( 1.1 * d );
}

void AsdkSmiley::ensureRadiusEyes()
{
   double  d = center().distanceTo(leftEyeCenter()) + eyeSize();
   if (d > radius() / 1.1) setRadius( 1.1 * d );
}

See Also

Creating a Custom Entity

Implementing Snap Point Functions

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