Delete the text in group A1, increase the arc length and add the text to group A1?

Delete the text in group A1, increase the arc length and add the text to group A1?

463017170
Advocate Advocate
1,014 Views
4 Replies
Message 1 of 5

Delete the text in group A1, increase the arc length and add the text to group A1?

463017170
Advocate
Advocate

Can you help me see what the problem is? thank you!

1 . Delete the text in group A1,

2. increase text the arc length ,

3. add the text to group A1(Similar to the group on the right)

 

 

static void MSDDMyGroupMyCommand0 () {
	ads_name ent;
	ads_point pt;
	if (RTNORM != acedEntSel(_T("\n选择对象: "),ent,pt))
	{
		return;
	}
	AcDbObjectId objId;
	acdbGetObjectId(objId,ent);
	AcDbEntityPointer pEnt(objId,AcDb::kForRead);
	Acad::ErrorStatus es=pEnt.openStatus();
	if (Acad::eOk != es)
	{
		acutPrintf(_T("\nFailed to open object,es=%s"),acadErrorStatusText(es));
		return;
	}

	const AcDbVoidPtrArray *pReactors=pEnt->reactors();
	if (pReactors==NULL || pReactors->length()<1)
	{
		acutPrintf(_T("\nThe object has no groups!"));
		return;
	}
	AcDbObjectIdArray entIds;
	for (int i=0;i<pReactors->length();i++)
	{
		void* pSomething = pReactors->at(i);
		if (pSomething==NULL) continue;
		if (!acdbIsPersistentReactor(pSomething)) continue;
		AcDbObjectId persReactorId=acdbPersistentReactorObjectId(pSomething);
		AcDbObjectPointer<AcDbGroup> pGroup(persReactorId,AcDb::kForRead);
		pGroup->allEntityIds(entIds);		
	}

	for (int i=0;i<entIds.length();i++)
	{
		AcDbEntity *pEnt = NULL;
		if (acdbOpenObject(pEnt, entIds.at(i), AcDb::kForWrite) == Acad::eOk)
		{
		if (pEnt->isKindOf(AcDbText::desc()))
		{
			pEnt->erase();
		}
		else
		{
			pEnt->close();
			AcDbCurve* pEnt;
			double PaPtCen;
			AcGePoint3d PtCen;
	
	
			acdbOpenObject(pEnt, entIds.at(i), AcDb::kForRead);
			double startParam, endParam, startDist, endDist;
	
			pEnt->getStartParam(startParam);  
			pEnt->getEndParam(endParam);      
			pEnt->getDistAtParam(startParam, startDist); 
			pEnt->getDistAtParam(endParam, endDist); 
			double Clength = endDist - startDist;   
			pEnt->getParamAtDist(Clength * 0.5,PaPtCen);  
			pEnt->getPointAtParam(PaPtCen,PtCen); 

			WCHAR s[20];
			_swprintf(s, L"L=%0.0f", Clength);

			AcDbText  *text = new AcDbText(PtCen,s,AcDbObjectId::kNull,80,0);
			text->setColorIndex(50);
			text->setWidthFactor(0.7);
	
			text->setHorizontalMode(AcDb::TextHorzMode::kTextCenter);
			text->setAlignmentPoint(PtCen);
			text->setJustification(AcDbText::kTextAlignmentMiddleCenter );

			AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
			AcDbBlockTableRecordPointer pBTR(pDb->currentSpaceId(), AcDb::kForWrite); 
			if (text && Acad::eOk == pBTR.openStatus())  {pBTR->appendAcDbEntity(text); text->close();}
	

		}

		}
		pEnt->close();
	}
}

 

0 Likes
Accepted solutions (2)
1,015 Views
4 Replies
Replies (4)
Message 2 of 5

tbrammer
Advisor
Advisor
Accepted solution

The main problem is AcDbEntityPointer pEnt(objId, AcDb::kForRead);

This will keep the entity open for read until pEnt goes out of scope - which is when the function returns.

It isn't possible to open an entity for write if it is already opened for read. So your call

acdbOpenObject(pEnt, entIds.at(i), AcDb::kForWrite) fails and return eWasOpenForRead.

pEnt remains NULL or uninitialized and pEnt->close() crashes.

 

Here is the fixed version with some comments marked "//tb:" and recommendations:

static void MSDDMyGroupMyCommand0() {
	ads_name ent;
	ads_point pt;
	if (RTNORM != acedEntSel(_T("\n选择对象: "), ent, pt))
		return;
	AcDbObjectId objId;
	acdbGetObjectId(objId, ent);
	AcDbEntityPointer pEntPtr(objId, AcDb::kForRead); //tb: renamed to avoid confusion with pEnt below
	Acad::ErrorStatus es = pEntPtr.openStatus();
	if (Acad::eOk != es)
	{
		acutPrintf(_T("\nFailed to open object,es=%s"), acadErrorStatusText(es));
		return;
	}

	const AcDbVoidPtrArray* pReactors = pEntPtr->reactors();
	if (pReactors == NULL || pReactors->length() < 1)
	{
		acutPrintf(_T("\nThe object has no groups!"));
		return;
	}
	AcDbObjectIdArray entIds;
	for (int i = 0; i < pReactors->length(); i++)
	{
		void* pSomething = pReactors->at(i);
		if (pSomething == NULL) continue;
		if (!acdbIsPersistentReactor(pSomething)) continue;
		AcDbObjectId persReactorId = acdbPersistentReactorObjectId(pSomething);
		AcDbObjectPointer<AcDbGroup> pGroup(persReactorId, AcDb::kForRead);
		pGroup->allEntityIds(entIds); 
	}
	//tb: You are using AcDbEntityPointer pEnt above and 
	// AcDbEntity* pEnt; below. I would suggest to choose different names!
	// The problem is, that the AcDbEntityPointer pEnt keeps the entity open for read 
	// until it goes out of scope.
	// This causes that you can't open AcDbEntity* pEnt for write.
	pEntPtr->close(); //tb: close it here explicitly.

	for (int i = 0; i < entIds.length(); i++)
	{
		AcDbEntity* pEnt = NULL; //tb: Confusing! NOT the same as AcDbEntityPointer pEnt above!
		//tb: It is always a good idea to store the Acad::ErrorStatus.
		// It gives important information if something goes wrong.
		// You should only open objects for write, if you really need to modify them.
		Acad::ErrorStatus es = acdbOpenObject(pEnt, entIds.at(i), AcDb::kForRead); //tb: Write->Read
		if (es == Acad::eOk)
		{
			if (pEnt->isKindOf(AcDbText::desc()))
			{
				//tb: Here we need write acces. So we upgradeOpen() the entity.
				es = pEnt->upgradeOpen();
				if (es==Acad::eOk)
					pEnt->erase();
			}
			else
			{
				double PaPtCen;
				AcGePoint3d PtCen;
				WCHAR s[20];

				// pEnt->close();
				//tb: no need to reopen the entity. 
				// The 3rd usage of the variable name pEnt gave extra confusion!
				AcDbCurve* pCurve = AcDbCurve::cast(pEnt); 
				if (pCurve) // AcDbCurve::cast(pEnt) returns NULL if it isn't an AcDbCurve
				{
					double startParam, endParam, startDist, endDist;
					pCurve->getStartParam(startParam);
					pCurve->getEndParam(endParam);
					pCurve->getDistAtParam(startParam, startDist);
					pCurve->getDistAtParam(endParam, endDist);
					double Clength = endDist - startDist;
					pCurve->getParamAtDist(Clength * 0.5, PaPtCen);
					pCurve->getPointAtParam(PaPtCen, PtCen);
					_swprintf(s, L"L=%0.0f", Clength);

					AcDbText* text = new AcDbText(PtCen, s, AcDbObjectId::kNull, 80, 0);
					text->setColorIndex(50);
					text->setWidthFactor(0.7);

					text->setHorizontalMode(AcDb::TextHorzMode::kTextCenter);
					text->setAlignmentPoint(PtCen);
					text->setJustification(AcDbText::kTextAlignmentMiddleCenter);

					AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
					AcDbBlockTableRecordPointer pBTR(pDb->currentSpaceId(), AcDb::kForWrite);
					if (text && Acad::eOk == pBTR.openStatus()) { 
						pBTR->appendAcDbEntity(text); text->close(); 
					}
				}
			}
			pEnt->close(); //tb: moved here.
		}
		//pEnt->close(); //tb: only close what you have opened!
	}
}

 

 
 

 

 


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 3 of 5

463017170
Advocate
Advocate

Thank you for your help!

0 Likes
Message 4 of 5

463017170
Advocate
Advocate

Text length (L =?) Didn't join the group

0 Likes
Message 5 of 5

tbrammer
Advisor
Advisor
Accepted solution

What do you mean? Do you want the new AcDbText entities to be members of the group?

Than you just have to append their objectids to the group.

 

	AcDbObjectIdArray entIds, newTextIds; //tb: store text ids in newTextIds
	AcDbObjectId groupId; //tb: Store the group id here
	for (int i = 0; i < pReactors->length(); i++)	{
		void* pSomething = pReactors->at(i);
		if (pSomething == NULL) continue;
		if (!acdbIsPersistentReactor(pSomething)) continue;
		AcDbObjectId persReactorId = acdbPersistentReactorObjectId(pSomething);
		AcDbObjectPointer<AcDbGroup> pGroup(persReactorId, AcDb::kForRead);
		if (pGroup.object()) //tb: Better check. There might be other persistent reactors
		{
			groupId = pGroup->objectId(); //tb: Store group id for later
			pGroup->allEntityIds(entIds);
		}
	}
...
					if (text && Acad::eOk == pBTR.openStatus()) { 
						es = pBTR->appendAcDbEntity(text); 
						if (es == Acad::eOk)	{
							newTextIds.append(text->objectId()); //tb: Store the id
							text->close();
						}
						else
							delete text;
					}

...

	if (!newTextIds.isEmpty())	{ //tb: Append the new text entities to the group.
		AcDbGroup* group;
		if ((es = acdbOpenObject(group, groupId, AcDb::kForWrite)) == Acad::eOk) {
			group->append(newTextIds);
			group->close();
		}
	}
 
 

 

 


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes