Пример #1
0
bool ArxEntityHelper::GetEntitiesColor( const AcDbObjectIdArray& objIds, AcArray<Adesk::UInt16>& colors )
{
    AcTransaction* pTrans = actrTransactionManager->startTransaction();
    if( pTrans == 0 ) return false;

    bool ret = true;  // 默认返回true
    int len = objIds.length();
    for( int i = 0; i < len; i++ )
    {
        AcDbObject* pObj;
        if( Acad::eOk != pTrans->getObject( pObj, objIds[i], AcDb::kForRead ) )
        {
            actrTransactionManager->abortTransaction();
            ret = false;
            colors.removeAll(); // 清空
            break;
        }
        AcDbEntity* pEnt = AcDbEntity::cast( pObj );
        if( pEnt == 0 )
        {
            actrTransactionManager->abortTransaction();
            ret = false;
            colors.removeAll(); // 清空
            break;
        }
        Adesk::UInt16 ci = pEnt->colorIndex();
        colors.append( ci ); // 记录原有的颜色
    }
    actrTransactionManager->endTransaction();
    return ret;
}
Пример #2
0
void ContourColorDlg::OnBnClickedOk()
{
    UpdateData( TRUE );

    // 获取图层名称
    CString layer;
    if( !GetLayer( layer ) )
    {
        MessageBox( _T( "没有选择包含等值线的图层" ) );
        return;
    }

    AcGeDoubleArray zValues;
    AcArray<COLORREF> colors;
    int n = m_colorList.GetItemCount();
    for( int i = 0; i < n; i++ )
    {
        ColorListItemData* pData = ( ColorListItemData* )m_colorList.GetItemData( i );
        zValues.append( pData->z );
        colors.append( pData->rgb );
    }
    // 删除最后一个z值
    zValues.removeLast();

    // 删除color list上的附加数据
    DeleteColorListItemDatas();

    // 获取图层上的等值线信息图元
    AcDbObjectId objId = GetContourInfoOnLayer( layer );
    SetContourInfo( objId, zValues, colors, m_bFillColor );

    // 获取边界坐标数据
    AcGePoint3dArray bounds;
    GetBoundaryPoints( bounds );
    if( bounds.isEmpty() )
    {
        MessageBox( _T( "请添加一个闭合的井田边界" ) );
        return;
    }

    // 获取点集数据
    AcGePoint3dArray datas;
    GetContourDatas( objId, datas );

    //assert((colors.length()-zValues.length()) == 1);
    // 绘制填充
    DrawFill( layer, bounds,  datas, zValues, colors, m_bFillColor );

    OnOK();
}
Пример #3
0
void
AsdkDocReactor::documentToBeDestroyed(AcApDocument *pDoc)
{
    if (pDoc == NULL) {
        // This isn't supposed to happen...
        assert(pDoc!=NULL);
        // But in production, just log it and keep going...
        bumpCount(/*NOXLATE*/"#NULL_DOC_DESTROYED", Adesk::kTrue);
        return;
    }
    int i = lookupDoc(pDoc);
    // The current document being destroyed?
    if (pDoc == curDocGlobals.doc) {
        // If Anything is still active in the document being destroyed,
        // log it as done now.
        if (curDocGlobals.lispRcd != NULL) {
            recordElapsedCmdTime(curDocGlobals.lispRcd, curDocGlobals.lispStartTime);
            curDocGlobals.lispRcd = NULL;
        }
        recordCommandDuration(NULL);
        curDocGlobals.doc = NULL;
    }
    // Remove the document data
     docData.removeAt(i);
}
Пример #4
0
static COLORREF GetColorRGB( const AcArray<COLORREF>& colors, int i )
{
    if( colors.isEmpty() )
        return RGB( 255, 255, 255 );
    else
        return colors[i];
}
Пример #5
0
int lookupDoc(AcApDocument* pDoc) {
    // NULL documents are not acceptable here...
    if (pDoc == NULL)
        return -1;

    int i;
    for (i = 0; i < docData.length(); i++) {
        if (docData[i].doc == pDoc)
            return i;
    }

    // Not Found.
    //
    // If AcApDocManagerReactor::documentCreated() were sent
    // before AcApDocumentReactor::documentToBeActivated,
    // this wouldn't be necessary!
    addDoc(pDoc);
    return docData.length()-1;
}
Пример #6
0
	virtual Acad::ErrorStatus   getOsnapInfo(
		AcDbEntity*			pickedObject,
		Adesk::GsMarker		gsSelectionMark,
		const AcGePoint3d&		pickPoint,
		const AcGePoint3d&		lastPoint,
		const AcGeMatrix3d&	viewXform,
		AcArray<AcGePoint3d>&	snapPoints,
		AcArray<int>&			geomIdsForPts,
		AcArray<AcGeCurve3d*>& snapCurves,
		AcArray<int>&			geomIdsForLines)
	{
		// Generic curve function for all AcDbCurves (except AcDbPolylines)

		// Protocol Extension insures that the following assertion is always
		// true, but check in non-prod versions just to be safe.
		assert( pickedObject->isKindOf( AcDbCurve::desc() ));

		// but in production, a hard cast is fastest
		AcDbCurve *pCurve = (AcDbCurve*)pickedObject;

		double startParam, endParam;
		AcGePoint3d pt;

		Acad::ErrorStatus es;
		es=pCurve->getStartParam( startParam);
		es=pCurve->getEndParam( endParam );
		es=pCurve->getPointAtParam( startParam + ((endParam - startParam) / 3), pt );
		assert( Acad::eOk == es);
		snapPoints.append( pt );
		es=pCurve->getPointAtParam( startParam + ((endParam - startParam) * 2 / 3), pt );
		assert(Acad::eOk==es);
		snapPoints.append( pt );
		if ( pCurve->isClosed() )
		{
			es=pCurve->getStartPoint( pt );
			assert(Acad::eOk==es);
			snapPoints.append( pt );
		}
		return Acad::eOk;
	}
Пример #7
0
void LineFrameBuilder::buildFramePoints(AcArray<AcGePoint3d>& arrayPoints, AcDbObjectPointer<AcDbEntity>& lineObject, int granularity)
{
	acutPrintf(_T("Building the points using LineFrameBuilder  ...\n"));
	_pLine = AcDbLine::cast(lineObject);
	arrayPoints.append(_pLine->startPoint());
	
	double length;
	_pLine->getDistAtPoint(_pLine->endPoint(), length);
	
	acutPrintf(_T("The length and other params: %f, %d, %d  ...\n"), length, ((int) length)/granularity, granularity);
	for (int i = 1; i< ((int) length)/granularity; i++)
	{
		
		AcGePoint3d newPoint;
		_pLine->getPointAtDist(i*granularity, newPoint);
		arrayPoints.append(newPoint); 
	}

	arrayPoints.append(_pLine->endPoint());

	acutPrintf(_T("Built the points using LineFrameBuilder  ...\n"));


}
Пример #8
0
static void DrawFill( const CString& layer, AcGePoint3dArray& bound, const AcGePoint3dArray& pts, const AcGeDoubleArray& zValues, const AcArray<COLORREF>& colors, BOOL bFillColor )
{
    // 删除图层上的所有等值线填充图元
    AcDbObjectIdArray objIds;
    ContourHelper::GetContourGEOnLayer( layer, _T( "ContourFill" ), objIds );
    ArxEntityHelper::EraseObjects2( objIds, true );

    if( bFillColor && colors.length() > zValues.length() )
    {
        // 临时切换图层, 如果图层不存在, 则新建图层
        LayerSwitch ls( layer, true );

        // 绘制等值线填充
        ContourHelper::DrawCountourFill( bound, pts, zValues, colors );
    }
}
Пример #9
0
void recordCommandDuration(const char* pszCmdStr)
{
    if (curDocGlobals.doc == NULL)
        return;

    // Verify that the command ending is the one on the top of the stack in the current
    // document.  If not, go fish through other documents.  If we are still empty handed,
    // give up.
    AsdkCommandRecord* curCmdRcd = NULL;
    if (pszCmdStr != NULL)
        curCmdRcd = (AsdkCommandRecord*) sessionStats->at(pszCmdStr);
    else if (curDocGlobals.cmdIndex > 0)
        curCmdRcd = curDocGlobals.cmdRcd[curDocGlobals.cmdIndex-1];
    bool swappedCurDoc = false;

    if ((curDocGlobals.cmdIndex <= 0) ||
        (curCmdRcd != curDocGlobals.cmdRcd[curDocGlobals.cmdIndex-1])) {
        bool foundDoc = false;
        int i = 0;
        for (; !foundDoc && (i < docData.length()); i++) {
            foundDoc = (docData[i].cmdIndex > 0) &&
                (docData[i].cmdRcd[docData[i].cmdIndex - 1] == curCmdRcd);
        }
        if (foundDoc)
            docData[i - 1].recordAndPop();
    } else {
        if (curDocGlobals.cmdIndex > 0)
            curDocGlobals.recordAndPop();
        int i = lookupDoc(curDocGlobals.doc);
        assert(i >= 0);
        docData[i] = curDocGlobals;
    }
    // Active command stack has been fully popped and we have a pending
    // statistics file update?
    if (bStatsFileUpdatePending && ::updateCumulativeStats())
        /* We have completed an operation such as SAVE or WBLOCK since
           this lisp expression began, and this is a convenient time to
           at least try to update the
           stats file with the current counts.  This must be marked pending
           and done after command completion because cmdRcd[] points to a
           CommandRecord object in *sessionStats which is deleted in
           updateCumulativeStats()called below.  updateCumulativeStats
           will return kFalse if any documents have any active command
           or LISP expressions, in which case, this will have to wait.
           JMC, WCA 7/15/98 */
         bStatsFileUpdatePending = Adesk::kFalse;
}
Пример #10
0
Adesk::Boolean updateCumulativeStats()
{
    // If anything is going on in any document, now is NOT a good
    // time to accumulate stats, because each command/LISP expression
    // in progress has pointers into session stats.
    // This could be fixed with more recoding than I have time to do
    // now.  WCA 7/15/98
    for (int i = docData.length() - 1; i >= 0; i--) {
        // Make sure our info is up to date.
        if (docData[i].doc == curDocGlobals.doc)
            docData[i] = curDocGlobals;
        if ((docData[i].cmdIndex > 0) ||
            (docData[i].lispRcd != NULL))
            return Adesk::kFalse;
    }

    if (!readCumulativeStats()) {
        acutPrintf("\nWarning: Could not find Command Statistics file.\n");
        acutPrintf("Will try to create it.\n");
    }

    AcRxDictionaryIterator* iter;

    // Loop over current session stats, and merge them into cumulative stats.
    for (iter = sessionStats->newIterator(); !iter->done(); iter->next()) {
        AsdkCommandRecord* sessionCmdRcd = (AsdkCommandRecord*) iter->object();
        AsdkCommandRecord* cumulativeCmdRcd = (AsdkCommandRecord*)
                                          cumulativeStats->at(iter->key());
        if (!cumulativeCmdRcd)
            // First time, add it.
            cumulativeStats->atPut(iter->key(),
                                   new AsdkCommandRecord(sessionCmdRcd->count,
                                                     sessionCmdRcd->elapsedTime));
        else {
            // Not the first time, so bump it.
            cumulativeCmdRcd->count += sessionCmdRcd->count;
            cumulativeCmdRcd->elapsedTime += sessionCmdRcd->elapsedTime;
        }
    }

    delete iter;

    // Now that it has been added in, wipe out the current session Stats;
    delete sessionStats;
    sessionStats = initStatDictionary();

    // Open the cumulative stat file, creating it if necessary.
    char statFilePath[MAX_PATH_LENGTH];
    
    int ret = cmdcount_findfile(statFileName, statFilePath,true);
    assert(ret==RTNORM);//this should always succeed

    // Open the file
    FILE* statFile = fopen(statFilePath, /*NOXLATE*/"w");

    if (statFile == NULL) {
        // Bad permission in our chosen directory.  Give up.
        acedAlert("Warning: Could not create Command Statistics file.");
        return Adesk::kTrue;
    }

    // Print version number of STATFILE
    fprintf(statFile, "v%04.1f\n", STAT_FILENAME_VERSION);

    // Print create date of STATFILE
    if (!*createDate) {
        fprintf(statFile, "Created:               ");
        printCurrentDateTime(statFile);
        fprintf(statFile, "\n");
    } else
        fprintf(statFile, "%s\n", createDate);

    // Print date last modified for STATFILE
    fprintf(statFile, "Last Modified:         ");
    printCurrentDateTime(statFile);
    fprintf(statFile, "\n");
    
    resbuf tempRes;
    // Print LOGINNAME
    if (acedGetVar(/*NOXLATE*/"LOGINNAME", &tempRes) != RTNORM) {
        sprintf(abort_msg, "%.*s Command\nStatistics Gatherer\nFailure 1",
                PRODUCTL, getProductName());
        acrx_abort(abort_msg);
    }
    fprintf(statFile, /*NOXLATE*/"LOGINNAME:             %s\n", tempRes.resval.rstring);
    acdbFree (tempRes.resval.rstring) ;
    // Print ACAD serial number
    if (acedGetVar(/*NOXLATE*/"_PKSER", &tempRes) != RTNORM) {
        sprintf(abort_msg, "%.*s Command\nStatistics Gatherer\nFailure 1",
                PRODUCTL, getProductName());
        acrx_abort(abort_msg);
    }
    fprintf(statFile, /*NOXLATE*/"%.*s Serial Number: %s\n", PRODUCTL, getProductName(),
                            tempRes.resval.rstring);
    acdbFree (tempRes.resval.rstring) ;

    // Print ACAD version
    if (acedGetVar(/*NOXLATE*/"_VERNUM", &tempRes) != RTNORM) {
        sprintf(abort_msg, "%.*s Command\nStatistics Gatherer\nFailure 1",
                PRODUCTL, getProductName());
        acrx_abort(abort_msg);
    }
    fprintf(statFile, /*NOXLATE*/"%.*s version:       %s\n", PRODUCTL, getProductName(),
                        tempRes.resval.rstring);
    acdbFree (tempRes.resval.rstring) ;


    for (iter = cumulativeStats->newIterator(AcRx::kDictSorted); !iter->done(); iter->next()) {
        // Write out the command string.
        fprintf(statFile, "%s", iter->key());

        // Try for reasonable text alignment, such as allowing 24 chars
        // for the command name.  But have at least 1 space as a delimiter.
        int nbrOfSpaces = 24 - strlen(iter->key());
        do
            fprintf(statFile, " ");
        while (--nbrOfSpaces > 0);

        // Now the count and elapsed time in seconds (assume 1 billion seconds
        // maximum, which should exceed a typical beta survey period).
        fprintf(statFile, "%7i   %12.2f\n",
                ((AsdkCommandRecord*) iter->object())->count,
                ((AsdkCommandRecord*) iter->object())->elapsedTime);
    }

    fclose(statFile);

    delete iter;
    return Adesk::kTrue;
}
Пример #11
0
static void addDoc(AcApDocument* pDoc) {

    AsdkCmdCountDocData newData;
    newData.doc = pDoc;
    docData.append(newData);
}
Пример #12
0
// commandStats:  Print out current Session and Cumulative Stats
void initStats()
{
    cmdr   = new AsdkCommandReactor();
    statFileName[0] = EOS;

    // Define dictionary to delete all its entries when it is deleted.
    sessionStats = initStatDictionary();
    acedEditor->addReactor(cmdr);
    acedRegCmds->addCommand(/*NOXLATE*/"ASDK_COMMAND_STATS",
                            /*NOXLATE*/"ASDK_CMDSTAT",
                            "CMDSTAT",
                            ACRX_CMD_MODAL,
                            &commandStats);
    acedRegCmds->addCommand(/*NOXLATE*/"ASDK_COMMAND_STATS",
                            /*NOXLATE*/"ASDK_CMDCOUNT",
                            "CMDCOUNT",
                            ACRX_CMD_MODAL,
                            &cmdCommandCount);

    bStatsFileUpdatePending = Adesk::kFalse;

    // Initialize Global struct array
    docData.setLogicalLength(0);

    // Fill array from existing documents
    AcApDocumentIterator* pDocIter = acDocManager->newAcApDocumentIterator();

    for (;!pDocIter->done(); pDocIter->step())
        // add an entry for the document, if some other notification hasn't
        // already done so.
        lookupDoc(pDocIter->document());

    delete pDocIter;

    // Establish current document, if there is one yet.
    if ((docData.length() > 0) && (acDocManager->curDocument() != NULL))
        curDocGlobals = docData[lookupDoc(acDocManager->curDocument())];
    else
        curDocGlobals.doc = NULL;

    pDocReactor = new AsdkDocReactor;
    acDocManager->addReactor(pDocReactor);


    resbuf tempRes;
    int i, j;
    // set the statFileName to be <LOGINNAME>.txt
    // remove blanks and tabs from LOGINNAME, so we have a more 
    // reasonable statFileName.
    if (acedGetVar(/*NOXLATE*/"LOGINNAME", &tempRes) != RTNORM) {
        sprintf(abort_msg, "%.*s Command\nStatistics Gatherer\nFailure 1",
                PRODUCTL, getProductName());
        acrx_abort(abort_msg);
    }
    strcpy(statFileName, tempRes.resval.rstring);
    acdbFree (tempRes.resval.rstring) ;
    for (i = 0, j = 0;
         (statFileName[i] != EOS) && (j < LOGINNAME_LENGTH);
         i++) {
        if ((statFileName[i] != ' ') && (statFileName[i] != '\t')) {
            statFileName[j] = statFileName[i];
            j++;
        }
    }
    statFileName[j] = EOS;
    strcat(statFileName, /*NOXLATE*/".txt");
}
Пример #13
0
	virtual Acad::ErrorStatus   getOsnapInfo(
		AcDbEntity*			pickedObject,
		Adesk::GsMarker		gsSelectionMark,
		const AcGePoint3d&		pickPoint,
		const AcGePoint3d&		lastPoint,
		const AcGeMatrix3d&	viewXform,
		AcArray<AcGePoint3d>&	snapPoints,
		AcArray<int>&			geomIdsForPts,
		AcArray<AcGeCurve3d*>& snapCurves,
		AcArray<int>&			geomIdsForLines)
	{
		// Specialised implementation for AcDbPolylines:
		//  Parametrisation of AcDbPolylines is different: each whole numbered paramater appears
		//  at a vertex, so we cannot simply divide by three to get the correct parameter.

		// Protocol Extension insures that the following assertion is always
		// true, but check in non-prod versions just to be safe.
		assert( pickedObject->isKindOf( AcDbPolyline::desc() ));

		// but in production, a hard cast is fastest
		AcDbPolyline *pPline = (AcDbPolyline*)pickedObject;

		Acad::ErrorStatus es;

		if ( bSnapToSegments )
		{
			// Snap to a third of each of the segments
			unsigned int numSegs = pPline->numVerts() - 1;
			AcGeLineSeg3d segLn;
			AcGeCircArc3d segArc;
			double startParam, endParam, newParam, dist;
			AcGePoint3d pt;

			for ( unsigned int idx = 0; idx < numSegs; idx++ )
			{
				switch( pPline->segType( idx ))
				{
				case AcDbPolyline::kLine:
					es=pPline->getLineSegAt( idx, segLn );
					startParam = segLn.paramOf( segLn.startPoint() );
					endParam = segLn.paramOf( segLn.endPoint() );
					snapPoints.append(segLn.evalPoint( startParam + ((endParam - startParam) / 3 )));
					snapPoints.append(segLn.evalPoint( startParam + ((endParam - startParam) * 2 / 3 )));
					break;
				case AcDbPolyline::kArc:
					es=pPline->getArcSegAt( idx, segArc );
					startParam = segArc.paramOf( segArc.startPoint() );
					endParam = segArc.paramOf( segArc.endPoint() );
					dist = segArc.length( startParam, endParam );
					newParam = segArc.paramAtLength( startParam, dist / 3 );
					snapPoints.append( segArc.evalPoint( newParam ));
					newParam = segArc.paramAtLength( startParam, dist * 2 / 3 );
					snapPoints.append( segArc.evalPoint( newParam ));
					break;
				default:
					break;
				}
			}
		}
		else {
			double endParam;
			AcGePoint3d pt;
			double dist;

			es=pPline->getEndParam( endParam );
			es=pPline->getDistAtParam( endParam, dist );
			es=pPline->getPointAtDist( dist / 3, pt );
			assert(Acad::eOk==es);
			snapPoints.append( pt );
			es=pPline->getPointAtDist( dist * 2 / 3, pt );
			assert(Acad::eOk==es);
			snapPoints.append( pt );
			if ( pPline->isClosed() )
			{
				es=pPline->getStartPoint( pt );
				snapPoints.append( pt );
			}
		}
		return Acad::eOk;
	}
Пример #14
0
//
// This is where we take advantage of quite a bit of information
// provide by this big function to display multiline tooltip
// (new feature in Acad 2002) under the cursor aperture.
//
// It gets even more interesting when you mix it with OSNAP info.
//
// Have fun!
//
Acad::ErrorStatus 
CSampleIPM::monitorInputPoint(
	 bool& bAppendToTooltipStr,
     char*& pAdditionalTooltipString,
     AcGiViewportDraw* pDrawContext,
     AcApDocument* pDocument,
     bool pointComputed,
     int history,
     const AcGePoint3d& lastPoint,
     const AcGePoint3d& rawPoint,
     const AcGePoint3d& grippedPoint,
     const AcGePoint3d& cartesianSnappedPoint,
     const AcGePoint3d& osnappedPoint,
     AcDb::OsnapMask osnapMask,
     const AcArray<AcDbCustomOsnapMode*>& customOsnapModes,
     AcDb::OsnapMask osnapOverrides,
     const AcArray<AcDbCustomOsnapMode*>& customOsnapOverrides,
     const AcArray<AcDbObjectId>& apertureEntities,
     const AcArray< AcDbObjectIdArray,
     AcArrayObjectCopyReallocator< AcDbObjectIdArray > >& nestedApertureEntities,
     const AcArray<int>& gsSelectionMark,
     const AcArray<AcDbObjectId>& keyPointEntities,
     const AcArray< AcDbObjectIdArray,
     AcArrayObjectCopyReallocator< AcDbObjectIdArray > >& nestedKeyPointEntities,
     const AcArray<int>& keyPointGsSelectionMark,
     const AcArray<AcGeCurve3d*>& alignmentPaths,
     const AcGePoint3d& computedPoint,
     const char* pTooltipString)
{
	char mtooltipStr[1024],
		 tempStr[100];
	mtooltipStr[0] = '\0';

	Acad::ErrorStatus es;
	AcDbEntity* pEnt;
	AcDbObjectId highlightId = AcDbObjectId::kNull;

	if (pointComputed)
	{
		//
		// Analyze the aperture entities.
		//
		if (apertureEntities.length() > 0)
		{
			if(strlen(mtooltipStr) > 0)
				strcpy(mtooltipStr, "\nEntities under the cursor aperture:");
			else
				strcpy(mtooltipStr, "Entities under the cursor aperture:");

			for (int i = 0; i < apertureEntities.length(); ++i)
			{
				if (Acad::eOk != (es = acdbOpenAcDbEntity(pEnt, apertureEntities[i], AcDb::kForRead)))
					continue;

					sprintf(tempStr, "\n  %s%s%d%s", pEnt->isA()->name(), " <Object ID: ", pEnt->objectId(), ">");
					strcat(mtooltipStr, tempStr);
					pEnt->close();

					// Analyze the nested aperture entities.
					AcDbObjectIdArray nestedIds = nestedApertureEntities[i];
					int length = nestedIds.length();
					if (length > 1)
					{
						// There is a nested entitiy: get it.
						AcDbEntity* pEnt2;
						if (Acad::eOk == (es = acdbOpenAcDbEntity(pEnt2, nestedIds[length - 1], AcDb::kForRead))) {
							sprintf(tempStr, "\n  nested: %s", pEnt2->isA()->name());
							strcat(mtooltipStr, tempStr);
							pEnt2->close();
						}
					}
			}
			highlightId = apertureEntities[0];
		}

		//
		// Analyze OSNAP.
		//

		if (history && Acad::eOsnapped)
		{
			char osnapInfo[500];
			osnapInfo[0] = '\0';

			switch (osnapMask)
			{
			case AcDb::kOsMaskEnd:
				strcpy(osnapInfo, "\nOsnap:\n  end");
				break;
			case AcDb::kOsMaskMid:
				strcpy(osnapInfo, "\nOsnap:\n  mid");
				break;
			case AcDb::kOsMaskCen:
				strcpy(osnapInfo, "\nOsnap:\n  center");
				break;
			case AcDb::kOsMaskNode:
				strcpy(osnapInfo, "\nOsnap:\n  node");
				break;
			case AcDb::kOsMaskQuad:
				strcpy(osnapInfo, "\nOsnap:\n  quadrant");
				break;
			case AcDb::kOsMaskInt:
				strcpy(osnapInfo, "\nOsnap:\n  intersection");
				break;
			case AcDb::kOsMaskIns:
				strcpy(osnapInfo, "\nOsnap:\n  insert");
				break;
			case AcDb::kOsMaskPerp:
				strcpy(osnapInfo, "\nOsnap:\n  perpendicular");
				break;
			case AcDb::kOsMaskTan:
				strcpy(osnapInfo, "\nOsnap:\n  tangent");
				break;
			case AcDb::kOsMaskNear:
				strcpy(osnapInfo, "\nOsnap:\n  near");
				break;
			case AcDb::kOsMaskQuick:
				strcpy(osnapInfo, "\nOsnap:\n  quick");
				break;
			case AcDb::kOsMaskApint:
				strcpy(osnapInfo, "\nOsnap:\n  apint");
				break;
			case AcDb::kOsMaskImmediate:
				strcpy(osnapInfo, "\nOsnap:\n  immediate");
				break;

			case AcDb::kOsMaskAllowTan:
				strcpy(osnapInfo, "\nOsnap:\n  allowTan");
				break;
			case AcDb::kOsMaskDisablePerp:
				strcpy(osnapInfo, "\nOsnap:\n  DisablePerp");
				break;
			case AcDb::kOsMaskRelCartesian:
				strcpy(osnapInfo, "\nOsnap:\n  RelCartesian");
				break;
			case AcDb::kOsMaskRelPolar:
				strcpy(osnapInfo, "\nOsnap:\n  RelPolar");
				break;
			}
			if (strlen(osnapInfo))
			{
				if (keyPointEntities.length())
				{
					strcat(osnapInfo, "\nKey entities:");
					for (int i=0; i<keyPointEntities.length(); ++i)
					{
						if (Acad::eOk != (es = acdbOpenAcDbEntity(pEnt, keyPointEntities[i], AcDb::kForRead)))
							continue;

						sprintf(tempStr, "\n    %s", pEnt->isA()->name());
						strcat(osnapInfo, tempStr);
						pEnt->close();
					}
				}
			}
			strcat(mtooltipStr, osnapInfo);
		}
	}

	//
	// Do highlighting, only the top level entity is highlighted.
	//
	static AcDbObjectId oldHighlightId = AcDbObjectId::kNull;
	if(highlightId != oldHighlightId)
	{
		if (AcDbObjectId::kNull != oldHighlightId)
		{
			es = acdbOpenAcDbEntity(pEnt, oldHighlightId, AcDb::kForRead);
			if (es == Acad::eOk)
			{
				es = pEnt->unhighlight();
				pEnt->close();
				oldHighlightId = AcDbObjectId::kNull;
			}
		}
		es = acdbOpenAcDbEntity(pEnt, highlightId, AcDb::kForRead);
		if (es == Acad::eOk)
		{
			es = pEnt->highlight();
			pEnt->close();
			oldHighlightId = highlightId;
		}
	}

	// Turn on additional tooltip.
	bAppendToTooltipStr = true;
	pAdditionalTooltipString = mtooltipStr;
	return Acad::eOk;
}