< optimize code >Is there any way to speed up the excavation?

< optimize code >Is there any way to speed up the excavation?

463017170
Advocate Advocate
1,066 Views
10 Replies
Message 1 of 11

< optimize code >Is there any way to speed up the excavation?

463017170
Advocate
Advocate

 

static void MyGroupMyCommand () {
	ads_name en1;  ads_point p;
	Acad::ErrorStatus es;
	double L=100;
	double K=10;
	double Space =280;

	if (acedEntSel(L"\nSelect main ARC: ", en1, p) == RTNORM )
	{
			AcDbObjectId id1, id2;
			acdbGetObjectId(id1, en1); 
			AcDbObjectPointer<AcDbCurve> pEnt(id1, AcDb::kForWrite);	
			if (pEnt.openStatus() == Acad::eOk ) {
				double startParam,endParam,startDist,endDist,dTmpParam1;
				AcGePoint3d startPoint,endPoint,TempPoint;
				AcGeVector3d zDir,xDir,yDir,nDir,mDir,lDir; 
				AcGePoint3dArray pts1;
				es = pEnt->getStartParam(startParam);		 
				es = pEnt->getStartPoint(startPoint);		 
				es = pEnt->getEndPoint(endPoint);			 
				es = pEnt->getEndParam(endParam);
				es = pEnt->getFirstDeriv(startParam,zDir);	 
				es = pEnt->getDistAtParam(startParam, startDist);
				es = pEnt->getDistAtParam(endParam, endDist);

				AcGeMatrix3d curMat;
				pEnt->getEcs(curMat);
				yDir = AcGeVector3d(0,0,1).transformBy(curMat);
				xDir = yDir.crossProduct(zDir);

				AcGeMatrix3d transMat;
				xDir = xDir.normalize();
				yDir = yDir.normalize();
				zDir = zDir.normalize();
				transMat.setCoordSystem(startPoint,yDir,xDir,zDir);

				AcDbObjectPointer<AcDbPolyline> Orectangle;
				Orectangle.create();
				Orectangle->addVertexAt(0,AcGePoint2d(-L/2,K));
				Orectangle->addVertexAt(1,AcGePoint2d(+L/2,K));
				Orectangle->addVertexAt(2,AcGePoint2d(+L/2,0));
				Orectangle->addVertexAt(3,AcGePoint2d(-L/2,0));
				Orectangle->setClosed(Adesk::kTrue);		 

				Orectangle->transformBy(transMat);
				//PostToModelSpace(Orectangle);

				AcDbVoidPtrArray OArr,OgnArr;
				OArr.append(Orectangle);        
				OgnArr.setPhysicalLength(1);
				es = AcDbRegion::createFromCurves(OArr,OgnArr);

				AcDbRegion *oRegion=AcDbRegion::cast((AcRxObject*)OgnArr[0]);
				AcDbObjectPointer<AcDb3dSolid> OSolid;

				OSolid.create();
				es = OSolid->extrudeAlongPath(oRegion,pEnt);
				oRegion->erase();

				OSolid->setColorIndex(4);
				AcDbObjectId OSolidId = PostToModelSpace(OSolid);


				double len= endDist - startDist;
				int nn =int (len / Space);
				double startlen= (len - nn* Space)* 0.5;

				TempPoint=startPoint;

				for (int k = 0; k < nn+1; k++)
				{
					es = pEnt->getParamAtDist(startlen+(k * 300),dTmpParam1);
					es = pEnt->getPointAtParam(dTmpParam1,TempPoint);
					es = pEnt->getFirstDeriv(dTmpParam1,nDir);
					es = pEnt->getSecondDeriv(dTmpParam1,mDir);	
					nDir = nDir.normalize();
					mDir = mDir.normalize();
					lDir = nDir.crossProduct(mDir);

					AcGeMatrix3d MtransMat;
					MtransMat.setCoordSystem(TempPoint,lDir,mDir*-1,nDir);

					AcGeMatrix3d mat;  
					AcGeVector3d vec;

					AcDbObjectPointer<AcDb3dSolid> LsSolid1;LsSolid1.create();
					LsSolid1->createFrustum(K*4, 6, 6, 6);
					mat.setToRotation(1.5707963268,AcGeVector3d::kXAxis,AcGePoint3d::kOrigin);  
					LsSolid1->transformBy(mat);
					vec = AcGeVector3d (L/2-10,0,0);
					mat.setToTranslation(vec);  
					LsSolid1->transformBy(mat);
					LsSolid1->transformBy(MtransMat);


					AcDbObjectPointer<AcDb3dSolid> LsSolid2;LsSolid2.create();
					LsSolid2->createFrustum(K*4, 6, 6, 6);
					mat.setToRotation(1.5707963268,AcGeVector3d::kXAxis,AcGePoint3d::kOrigin);  
					LsSolid2->transformBy(mat);
					vec = AcGeVector3d (10-L/2,0,0);
					mat.setToTranslation(vec);  
					LsSolid2->transformBy(mat);
					LsSolid2->transformBy(MtransMat);

					AcDbObjectPointer<AcDb3dSolid>OSolid(OSolidId,AcDb::kForWrite);
					OSolid->booleanOper(AcDb::kBoolSubtract,LsSolid1);
					assert(LsSolid1->isNull());LsSolid1->erase();LsSolid1->close();
					OSolid->booleanOper(AcDb::kBoolSubtract,LsSolid2);
					assert(LsSolid2->isNull());LsSolid2->erase();LsSolid2->close();

		      }
		}
	}
}

 

0 Likes
1,067 Views
10 Replies
Replies (10)
Message 2 of 11

daniel_cadext
Advisor
Advisor

maybe use a transaction? Not sure if that would help

Python for AutoCAD, Python wrappers for ARX https://github.com/CEXT-Dan/PyRx
0 Likes
Message 3 of 11

tbrammer
Advisor
Advisor

I have three suggestions to optimize. But they won't yield a considerable performance boost:

 

1.) Only open objects kForWrite if you really need to modify them:

 

AcDbObjectPointer<AcDbCurve> pEnt(id1, AcDb::kForRead); // Opening kForRead is enough

 

 

2.) You can move

AcDbObjectPointer<AcDb3dSolid> LsSolid1, LsSolid2; outside of the for loop:

 

AcDbObjectPointer<AcDb3dSolid> LsSolid1; LsSolid1.create();
AcDbObjectPointer<AcDb3dSolid> LsSolid2; LsSolid2.create(); // moved outside the for-loop
for (int k = 0; k < nn + 1; k++)
}
  ...
{

 

You don't append them to the database so you don't need to erase()and close() them.

// assert(LsSolid2->isNull()); LsSolid2->erase(); LsSolid2->close();

 

3.) If you want to apply three transformation matrices to an entity it is more efficient to calculate a final transformation matrix M=m3*m2*m1 and transform once with entity->transformBy(M) than transforming with m1,m2 and m3 individually:

 

LsSolid1->createFrustum(K * 4, 6, 6, 6);
mat.setToRotation(1.5707963268, AcGeVector3d::kXAxis, AcGePoint3d::kOrigin);
AcGeMatrix3d MatFinal = mat;	// Calculate a final transformation matrix
vec = AcGeVector3d(L / 2 - 10, 0, 0);
mat.setToTranslation(vec);
MatFinal = MtransMat * mat * MatFinal;
LsSolid1->transformBy(MatFinal); // and transform once with MatFinal

LsSolid2->createFrustum(K * 4, 6, 6, 6);
mat.setToRotation(1.5707963268, AcGeVector3d::kXAxis, AcGePoint3d::kOrigin);
MatFinal = mat;			// Calculate a final transformation matrix
vec = AcGeVector3d(10 - L / 2, 0, 0);
mat.setToTranslation(vec);
MatFinal = MtransMat * mat * MatFinal;
LsSolid2->transformBy(MatFinal); // and transform once with MatFinal

 

 

Note: Your calculation of lDir, nDir, mDir is OK for arcs. But in general mDir is not perpendicular to nDir - i.e. if your curve is a spline. This calculation works as long as mDir is not null:

 

lDir = nDir.crossProduct(mDir);
lDir.normalize();
mDir = nDir.crossProduct(lDir); // mDir is not always perpendicular to nDir!
nDir.normalize();
mDir.normalize();

 

 


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

0 Likes
Message 4 of 11

463017170
Advocate
Advocate

booleanOper    This is slow

0 Likes
Message 5 of 11

tbrammer
Advisor
Advisor

Yes, booleanOper() is the call that takes the most time. But if you want a boolean subtraction to be performed on a 3DSOLID there is no alternative.
It might help to make sure that the cylinders that you subtract "clearly" pierce the surfaces of the 3DSOLID at both ends. So make them "long enough". If the ends of the cylinders are close to the bounding surface of the 3DSOLID the calculation might require greater accuracy internally.

 

If the region that you extrude along the path is always a rectangle sized X * Z you might try this:

  • Create an AcDbSweptSurface using sweeping just a line with length X along the path.
  • Subtract the cylinders with  AcDbSurface::booleanSubtract (AcDb3dSolid*, AcDbSurface*&) 
    The cylinders should "clearly" pierce the surface. So make them "long enough".
  • Thicken the surface with AcDbSurface::thicken(Z,...).

This might run faster because the boolean operation involves less calculations for a surface than for a 3DSOLID.

 


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

0 Likes
Message 6 of 11

463017170
Advocate
Advocate

Do not understand, can write an example, thank you!

0 Likes
Message 7 of 11

tbrammer
Advisor
Advisor

Regarding my 1st suggestion: Looking at your code I see that you are already making the cylinders "long enough". The length K*4 makes sure that they pierce the solid, which is K thick. So just forget this one.

 

Regarding my 2nd suggestion: 

Currently you create an AcDb3dSolid by extruding a rectangle and subtract cylinders from it.

My idea is to create an AcDbSweptSurface by sweeping a line, subtract the cylinder from it and finally create the AcDb3dSolid by thicken() the AcDbSweptSurface

Sample Code:

#include <dbsweptsurf.h>

void cmdOptimizeCommandSurf() {
	ads_name en1;  ads_point p;
	Acad::ErrorStatus es;
	double L = 100;
	double K = 10;
	double Space = 280;

	if (acedEntSel(L"\nSelect main ARC: ", en1, p) == RTNORM)
	{
		AcDbObjectId id1, id2;
		acdbGetObjectId(id1, en1);
		AcDbObjectPointer<AcDbCurve> pEnt(id1, AcDb::kForRead); // Opening kForRead is enough
		if (pEnt.openStatus() == Acad::eOk) {
			double startParam, endParam, startDist, endDist, dTmpParam1;
			AcGePoint3d startPoint, endPoint, TempPoint;
			AcGeVector3d zDir, xDir, yDir, nDir, mDir, lDir;
			AcGePoint3dArray pts1;
			es = pEnt->getStartParam(startParam);
			es = pEnt->getStartPoint(startPoint);
			es = pEnt->getEndPoint(endPoint);
			es = pEnt->getEndParam(endParam);
			es = pEnt->getFirstDeriv(startParam, zDir);
			es = pEnt->getDistAtParam(startParam, startDist);
			es = pEnt->getDistAtParam(endParam, endDist);

			AcGeMatrix3d curMat;
			pEnt->getEcs(curMat);
			yDir = AcGeVector3d(0, 0, 1).transformBy(curMat);
			xDir = yDir.crossProduct(zDir);

			AcGeMatrix3d transMat;
			xDir = xDir.normalize();
			yDir = yDir.normalize();
			zDir = zDir.normalize();
			transMat.setCoordSystem(startPoint, yDir, xDir, zDir);

			AcDbObjectPointer<AcDbPolyline> Oline;
			Oline.create();
			Oline->addVertexAt(0, AcGePoint2d(-L / 2, 0));
			Oline->addVertexAt(1, AcGePoint2d(+L / 2, 0));
			Oline->transformBy(transMat);

			AcDbSweptSurface *sweptSurface = new AcDbSweptSurface;
			AcDbSweepOptions sweepOptions;
			es = sweptSurface->createSweptSurface(Oline, pEnt, sweepOptions);
			AcDbSurface *surface = sweptSurface, *pNewSurface=nullptr;

			AcDbDatabase* pDB = acdbHostApplicationServices()->workingDatabase();

			double len = endDist - startDist;
			int nn = int(len / Space);
			double startlen = (len - nn * Space) * 0.5;

			TempPoint = startPoint;

			AcDbObjectPointer<AcDb3dSolid> LsSolid2; LsSolid2.create(); // moved outside the for-loop
			AcDbObjectPointer<AcDb3dSolid> LsSolid1; LsSolid1.create(); // moved outside the for-loop

			for (int k = 0; k < nn + 1; k++)
			{
				es = pEnt->getParamAtDist(startlen + (k * 300), dTmpParam1);
				es = pEnt->getPointAtParam(dTmpParam1, TempPoint);
				es = pEnt->getFirstDeriv(dTmpParam1, nDir);
				es = pEnt->getSecondDeriv(dTmpParam1, mDir);
				lDir = nDir.crossProduct(mDir);
				lDir.normalize();
				mDir = nDir.crossProduct(lDir); // mDir is not always perpendicular to nDir!
				nDir.normalize();
				mDir.normalize();

				AcGeMatrix3d MtransMat, MatFinal;
				MtransMat.setCoordSystem(TempPoint, lDir, mDir * -1, nDir);

				AcGeMatrix3d mat;
				AcGeVector3d vec;

				LsSolid1->createFrustum(K * 4, 6, 6, 6);
				mat.setToRotation(1.5707963268, AcGeVector3d::kXAxis, AcGePoint3d::kOrigin);
				MatFinal = mat;					// Calculate a final transformation matrix
				vec = AcGeVector3d(L / 2 - 10, 0, 0);
				mat.setToTranslation(vec);
				MatFinal = MtransMat * mat * MatFinal;
				LsSolid1->transformBy(MatFinal); // and transform once with MatFinal

				LsSolid2->createFrustum(K * 4, 6, 6, 6);
				mat.setToRotation(1.5707963268, AcGeVector3d::kXAxis, AcGePoint3d::kOrigin);
				MatFinal = mat;					// Calculate a final transformation matrix
				vec = AcGeVector3d(10 - L / 2, 0, 0);
				mat.setToTranslation(vec);
				MatFinal = MtransMat * mat * MatFinal;
				LsSolid2->transformBy(MatFinal); // and transform once with MatFinal

				es = surface->booleanSubtract(LsSolid1, pNewSurface);
				if (!es && pNewSurface) {
					delete surface;
					surface = pNewSurface;
					pNewSurface = nullptr;
				}
				es = surface->booleanSubtract(LsSolid2, pNewSurface);
				if (!es && pNewSurface) {
					delete surface;
					surface = pNewSurface;
					pNewSurface = nullptr;
				}
			}

			// Create the solid 
			AcDb3dSolid* pSolid = nullptr;
			bool bBothSides = false;
			es = surface->thicken(K, bBothSides, pSolid);
			delete surface; surface = nullptr;

			AcDbObjectId OSolidId;
			if (!es)
			{
				pSolid->setColorIndex(4);
				es = postToDb(pDB, pSolid, OSolidId);
			}
		}
	}
}

 

 


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

0 Likes
Message 8 of 11

tbrammer
Advisor
Advisor

One more thing regarding your code sample:

I just noticed that you have two identically named object pointers OSolid: One outside of the for-loop and one inside:

AcDbObjectPointer<AcDb3dSolid> OSolid;
...
AcDbObjectId OSolidId = PostToModelSpace(OSolid); // keep OSolid open here...

for (int k = 0; k < nn+1; k++) {
    ...
    AcDbObjectPointer<AcDb3dSolid> OSolid(OSolidId,AcDb::kForWrite); //...and remove this!
    ...
}

 

It would improve the performance to remove the OSolid object inside the loop and make sure that  PostToModelSpace(OSolid)does not close OSolid

This will simply keep the AcDb3dSolid open for write after it is posted to the model space instead of open/close it in each loop. The destructor of the outer OSolid will close the AcDb3dSolid as soon as it goes out of scope. 

 


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

0 Likes
Message 9 of 11

463017170
Advocate
Advocate

 Thank you very much!

0 Likes
Message 10 of 11

463017170
Advocate
Advocate
				LsSolid2->createFrustum(K * 4, 6, 6, 6);
				mat.setToRotation(1.5707963268, AcGeVector3d::kXAxis, AcGePoint3d::kOrigin);
				MatFinal = mat;					// Calculate a final transformation matrix
				vec = AcGeVector3d(10 - L / 2, 0, 0);
				mat.setToTranslation(vec);
				MatFinal = MtransMat * mat * MatFinal;
				LsSolid2->transformBy(MatFinal); // and transform once with MatFinal

How can this be calculated at one time

0 Likes
Message 11 of 11

tbrammer
Advisor
Advisor

What do you mean? The calculation of MatFinal?
This is matrix multiplication. 


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

0 Likes