ObjectARX
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

AcDb3DSolid transform eCannotScaleNonUniformly

6 REPLIES 6
Reply
Message 1 of 7
sandip.chaudhari8FDDH
505 Views, 6 Replies

AcDb3DSolid transform eCannotScaleNonUniformly

 

Trying to apply transformations to newly created object of AcDb3dSolid as in below code snippet, facing error Acad::eCannotScaleNonUniformly :

 

 

 

 

AcDb3dSolid* pSolid = new AcDb3dSolid();
pSolid->createBox(2.5625040964374133, 1.2500013503361456, 2.5000043091562860);



AcGePoint3d pt(1008.0336829062500, 6759.0490120937502, 64.845924312500003);



AcGeVector3d lengthNormal(0.0018969969674422047, -0.0018969969674422047, 0.99999640139603041);
AcGeVector3d widthNormal(-0.70710423613727291, 0.70710423613727291, 0.0026829971016416282);
AcGeVector3d heightNormal(-0.70710678118654757, -0.70710678118654757, 0.0000000000000000);



AcGeMatrix3d xform;



xform.setToAlignCoordSys(AcGePoint3d::kOrigin,
                                AcGeVector3d::kXAxis,
                                AcGeVector3d::kYAxis,
                                AcGeVector3d::kZAxis,
                                pt, lengthNormal, widthNormal, heightNormal);

Acad::ErrorStatus es = pSolid->transformBy(xform);    //Acad::eCannotScaleNonUniformly

 

 

 

Working Transform  :
0.0000000000000000, -0.70520723594475043, -0.70900123721412855, 1010.4860633561000
0.0000000000000000, 0.70900123721412867, -0.70520723594475043, 6756.5701507752001
1.0000000000000000, 0.0000000000000000, 0.0000000000000000, 64.841999999999999
0.0000000000000000, 0.0000000000000000, 0.0000000000000000, 1.0000000000000000

 


Non-working transform:
0.0018970007614240092, -0.70710423613007445, -0.70710678118654757, 1008.0336867812500
-0.0018970007614240092, 0.70710423613007445, -0.70710678118654757, 6759.0490157187496
0.99999640138163604, 0.0026830008959601273, 0.0000000000000000, 64.845921750000002
0.0000000000000000, 0.0000000000000000, 0.0000000000000000, 1.0000000000000000

 

 

Above transform are sample transform coming from other system, if it possible to correct matrix , so it will atleast give approximate results instead of error
How to resolve this issue ?

6 REPLIES 6
Message 2 of 7

Preview

Message 3 of 7

Try the function makeUniform(mat) below. It makes mat uniform while preserving as much of it's properties as possible:

AcGeMatrix3d &makeUniformNoRounding(AcGeMatrix3d &mat);

// Make mat uniform
// Preserves:
//	+ direction of the Z-axis
//	+ ZX-plane
//  + "average" length of the base vectors
//  + all elements m[i][3] und m[3][j]
AcGeMatrix3d &makeUniform(AcGeMatrix3d &mat)
{
	// set values to 0 / 1 that only differ by 1e-12 from 0 / 1
	int i, j;
	double *dval;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			dval = &(mat(i, j));
			if (fabs(*dval) < 1e-12)
				*dval = 0.0;
			else if (fabs(*dval - 1.0) < 1e-6)
				*dval = 1.0;
		}
		dval = &(mat(i, 3));
		if (fabs(*dval) < 1e-12)
			*dval = 0.0;
	}
	makeUniformNoRounding(mat);
	return mat;
}

bool approx(const double &x1, const double &x2, const double &tol)
{
	int	exp1, exp2;
	double mant1 = frexp(x1, &exp1);
	double mant2 = frexp(x2, &exp2);

	if (abs(exp1 - exp2) > 1)
		return FALSE;	// exp1 > 2*exp2 or exp2 > 2*exp1
	else if (exp1 > exp2)
		mant2 *= 2;	// to same exponent
	else if (exp2 > exp1)
		mant1 *= 2;

	return (fabs(mant1 - mant2) < tol);
}

AcGeMatrix3d &makeUniformNoRounding(AcGeMatrix3d &mat)
{
	AcGePoint3d origin;
	AcGeVector3d eX, eY, eZ;
	mat.getCoordSystem(origin, eX, eY, eZ);
	bool bSetKoSys = false;
	double	spXY = eX.dotProduct(eY),
		spZX = eZ.dotProduct(eX),
		spYZ = eY.dotProduct(eZ);

	// make pairwise perpendicular
	if (spXY != 0.0 || spZX != 0.0 || spYZ != 0.0)
	{
		// keep eZ
		AcGeVector3d eZnorm(eZ), eYnorm;
		eZnorm.normalize();
		eX -= eZnorm * eX.dotProduct(eZnorm); 

		// eX must be perpendicular to eY and eZ
		eYnorm = eX.crossProduct(eZnorm).normalize();
		double lY = eY.dotProduct(eYnorm); 
		eY = lY * eYnorm;
		bSetKoSys = true;
	}
	
	double	slX = eX.dotProduct(eX), // = eX.lengthSqrd()
		slY = eY.dotProduct(eY),
		slZ = eZ.dotProduct(eZ);

	// make same length
	if (!approx(slX, slY, 1e-12) || !approx(slX, slZ, 1e-12))
	{
		double lav = sqrt((slX + slY + slZ) / 3.0); // average length
		eX.normalize(); eX *= lav;
		eY.normalize(); eY *= lav;
		eZ.normalize(); eZ *= lav;
		bSetKoSys = true;
	}

	if (bSetKoSys)
		mat.setCoordSystem(origin, eX, eY, eZ);

	return mat;
}

 


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

Message 4 of 7
ynapeu
in reply to: tbrammer

The length of the AcGeVector3d, are different.

lenghtNormal = 0.99999999999999989

withNormal     = 0.99999999999999999

heightNormal  = 1.0000000000000000

use

lengthNormal = heightNormal.crossProduct(widthNormal);
widthNormal = lengthNormal.crossProduct(heightNormal);
heightNormal = widthNormal.crossProduct(lengthNormal);

and you get eOk

Message 5 of 7

Is there a solution to this problem as i am getting the same and in similar situation?

@tbrammer Do you have this code for .NET as well?

 

thanks

Message 6 of 7

@ynapeu Seems your solution worked for me. Should I do it for all the times or only for the case where I am getting this exception?

Message 7 of 7
tbrammer
in reply to: salman_abeed

I think the best way is to check the matrix first with 

Adesk::Boolean AcGeMatrix3d::isUniScaledOrtho(const AcGeTol& tol = AcGeContext::gTol()

I suppose that you don't need to change the matrix if it returns true.

Otherwise you should use the function to make it uniform.


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

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost