Implementing the Grip Point Functions

AutoCAD entities have grip points that appear when the user selects an entity with the pointing device. The getGripPoints() function returns the grip points that have been defined for an entity. The moveGripPointsAt() function performs the entity modifications that result from a grip edit.

With stretch mode in grip editing, you can stretch an object by moving selected grips to new locations. AutoCAD calls the moveGripPointsAt() function when the user is in stretch mode. For certain entities, however, some grips move the object rather than stretching it. These grips include grips on text objects, blocks, midpoints of lines, centers of circles, centers of ellipses, and point objects. In these cases, the moveGripPointsAt() function calls transformBy().

Note: The default implementation of the AcDbEntity::moveGripPointsAt() function is to invoke the transformBy() function.

When the user is in grip, move, rotate, scale, or mirror modes, AutoCAD calls the transformBy() function, described in the "Entities" section.

If you want the user to be able to edit your entity using grips, you need to override the subGetGripPoints() and subMoveGripPointsAt() functions. The entity defines its grip points and how to interpret the user-supplied offset.

The following excerpt shows how the custom AsdkPoly class implements these functions. The object defined by this class has a grip point at each vertex and a grip point at its center. These grip points are returned by the subGetGripPoints() function. If the user selects a grip point when in grip stretch mode, AutoCAD invokes the moveGripPointsAt() function. This invokes your custom entity’s subMoveGripPointsAt(), passing in an array of the indexes for the selected grip points and a 3D vector specifying how much the user moved the pointing device. If the user has selected a vertex grip point, the polygon is stretched uniformly by the specified offset. If the user picked the center grip point, the polygon is simply translated by an amount equal to the offset. (This value is passed to the transformBy() function, as shown here.)

Acad::ErrorStatus 
 AsdkPoly::subGetGripPoints( 
     AcGePoint3dArray& gripPoints, 
     AcDbIntArray& osnapModes, 
     AcDbIntArray& geomIds) const 
 { 
     assertReadEnabled(); 
     Acad::ErrorStatus es; 
     if ((es = getVertices3d(gripPoints)) != Acad::eOk) { 
         return es; 
     } 
  
     // Remove the duplicate point at the start/end and add 
     // center as the last point. 
     // 
     gripPoints.removeAt(gripPoints.length() - 1); 
     AcGePoint3d center; 
     getCenter(center); 
     gripPoints.append(center); 
     return es; 
 }
Acad::ErrorStatus 
 AsdkPoly::subMoveGripPointsAt( 
     const AcDbIntArray& indices, 
     const AcGeVector3d& offset) 
 { 
     if (indices.length()== 0 || offset.isZeroLength()) 
         return Acad::eOk; //that's easy :-) 
  
     if (mDragDataFlags & kCloneMeForDraggingCalled) { 
         mDragDataFlags |= kUseDragCache; 
     } else 
         // Only if we're not dragging do we want to make an undo 
         // recording and check if the object's open for write. 
         // 
         assertWriteEnabled(); 
  
     //if there more than one hot vertex or there's one and it 
     // is the center then simply transform 
     if (indices.length()>1 || indices[0] == mNumSides) 
         return transformBy(AcGeMatrix3d::translation(offset)); 
          
     AcGeVector3d off(offset); 
     //calculate the offset vector of the startpoint 
     //from the offset vector on a vertex 
     double rotateBy = 2.0 * 3.14159265358979323846 / 
       nNumSides * indices[0]; 
     AcGePoint3d cent; 
     getCenter(cent); 
     off.transformBy(AcGeMatrix3d::rotation(-rotateBy,
      normal(),cent)); 
     acdbWcs2Ecs(asDblArray(off),asDblArray(off),asDblArray(normal()),
  Adesk::kTrue); 
     if (mDragDataFlags & kUseDragCache){ 
         mDragCenter = mCenter; 
         mDragPlaneNormal = mPlaneNormal; 
         mDragStartPoint = mStartPoint + AcGeVector2d(off.x,off.y); 
         mDragElevation = mElevation + off.z; 
     }else{ 
         mStartPoint = mStartPoint + AcGeVector2d(off.x,off.y); 
         mElevation = mElevation + off.z; 
     } 
     return Acad::eOk; 
 }