Question: Is it possible to return origin, rotation, the x-y- scale factors and offset values from the Matrix3d of MaterialMapper.Transform ?
Answer: Yes ,it is possible to retrieve details from transform matrix of an Entity's material mapper , I have demonstrate below assuming user has selected a 3DFace entity on which Material is applied using MaterialMap command iteractively and adjusted rotation ,offset and scale as per user needs.
Somethink like this as shown in below screenshot.
Note : If AcGiMapper::autoTransform() is set to kObject or kModel, then you will not be able to recover the scale/translation/rotation, as the GS will dynamically compute it based on whatever entity/selection the mapper is applied to.
C++ Code :
static void ASDKMyGroupTestMapper() { Acad::ErrorStatus es; ads_name entres; ads_point ptres; AcGeVector3d scale; AcGeVector3d rotation; AcGeVector3d translate; AcGeMatrix3d mat; /*Select Entity*/ if(RTNORM != acedEntSel(_T("Select 3DFace entity"),entres,ptres)) return; AcDbObjectId objId = AcDbObjectId::kNull; if((es = acdbGetObjectId(objId,entres) ) != Acad::eOk) return; AcDbEntity* pFaceEntity = NULL; if ((es = acdbOpenAcDbEntity(pFaceEntity,objId,AcDb::kForRead) ) != Acad::eOk) return; if(pFaceEntity->isA() == AcDbFace::desc()) { AcDbFace* pFace = AcDbFace::cast(pFaceEntity); AcGiMapper mapper; AcDbMaterial* material = NULL; AcGiMaterialMap materialMap; if((es = acdbOpenObject((AcDbObject*&)material,pFace->materialId(), AcDb::kForRead))!= Acad::eOk) { pFaceEntity->close(); return; } double strength=0.0; AcGiMaterialColor color; /*Get diffuse gives details about Texture in general, and what component to be used to retrieve materialmap can be found from AcDbMaterial::channelFlags*/ material->diffuse(color,materialMap); mat = materialMap.mapper().transform(); if(materialMap.mapper().autoTransform() < 2) { decomposeMatrix(mat,scale,rotation,translate); } pFaceEntity->close(); material->close(); } acutPrintf(_T("n Rotation Angle : %2f n"),rotation.z*(180/M_PI)); acutPrintf(_T("n Scale X : %2f , Scale Y : %2f n"),scale.x,scale.y); /*You may have to negate offset values of Translate vector for correct sign*/ acutPrintf(_T("n Translation Vector: %2f,%2f n"),-translate.x,-translate.y); } static void decomposeMatrix (const AcGeMatrix3d &mat, AcGeVector3d &scale, AcGeVector3d &rotate, AcGeVector3d &translate) { // Scale - assume always positive, and must be non-zero scale.x = 1.0/AcGeVector3d(mat(0,0), mat(0,1), mat(0,2)).length(); scale.y = 1.0/AcGeV
ector3d(mat(1,0), mat(1,1), mat(1,2)).length(); scale.z = 1.0/AcGeVector3d(mat(2,0), mat(2,1), mat(2,2)).length(); if (scale.x == 0.0) scale.x = 1.0; if (scale.y == 0.0) scale.y = 1.0; if (scale.z == 0.0) scale.z = 1.0; // Translation translate = mat.translation(); translate.x *= scale.x; translate.y *= scale.y; translate.z *= scale.z; // Rotation – assume only rotation about the Z axis double acosVal = mat(0,0) / scale.x; if (acosVal > 1.0) acosVal = 1.0; else if (acosVal < -1.0) acosVal = -1.0; double zAngle = acos(acosVal); assert(0.0
C# .NET code :
[CommandMethod("TestMapper")] public void Mappertest() { Document activeDoc = Application.DocumentManager.MdiActiveDocument; Database db = activeDoc.Database; Editor ed = activeDoc.Editor; PromptEntityResult oRes = ed.GetEntity("Select 3dFace"); if (oRes.Status != PromptStatus.OK) return; Vector3d scale = default(Vector3d); Vector3d rotate = default(Vector3d); Vector3d translate = default(Vector3d); using (Transaction oTrans = db.TransactionManager.StartTransaction()) { Face oFace = oTrans.GetObject(oRes.ObjectId, OpenMode.ForRead) as Face; if (oFace != null) { string strMat = oFace.Material; ObjectId nMat = oFace.MaterialId; Material material = oTrans.GetObject(nMat,OpenMode.ForRead) as Material; ChannelFlags cFlasg = material.ChannelFlags; MaterialDiffuseComponent mDC = material.Diffuse; MaterialMap materialMap = mDC.Map; Matrix3d tranform = materialMap.Mapper.Transform; double scaleD = tranform.GetScale(); if (materialMap.Mapper.AutoTransform == AutoTransform.InheritAutoTransform || materialMap.Mapper.AutoTransform == AutoTransform.None) DecomposeMatrix(tranform , ref scale, ref rotate, ref translate); /*You have negate offset value to reflect correct sign*/ ed.WriteMessage("Rotation Angle : " + rotate.Z * (180 / Math.PI) + "n" + "Scale X :" + Math.Round(scale.X) + " Scale Y : " + Math.Round(scale.Y) + "n" + "Translation Vector offset Values :" + -translate.X + "," + -translate.Y); } oTrans.Commit(); } } public void DecomposeMatrix( Matrix3d mat, ref Vector3d scale, ref Vector3d rotate, ref Vector3d translate) { // Scale - assume always positive, and must be non-zero Vector3d v3dOne= new Vector3d(mat[0, 0], mat[0, 1], mat[0, 2]); Vector3d v3dTwo = new Vector3d(mat[1, 0], mat[1, 1], mat[1, 2]); Vector3d v3dThree = new Vector3d(mat[2, 0], mat[2, 1], mat[2, 2]); // scale = new Vector3d(v3dOne.Length, v3dTwo.Length, v3dThree.Length); scale = new Vector3d(1/v3dOne.Length, 1/v3dTwo.Length, 1/v3dThree.Length); if (scale.X == 0) scale = new Vector3d(1.0, scale.Y, scale.Z); if (scale.Y == 0) scale = new Vector3d(scale.X, 1.0, scale.Z); if (scale.Z == 0) scale = new Vector3d(scale.X, scale.Y, 1.0); // Translation translate = mat.Translation; translate = new Vector3d(translate.X * Math.Round(scale.X), translate.Y*Math.Round(scale.Y), translate.Z*Math.Round(scale.Z)); // Rotation – assume only rotation about the Z axis double acosValue = mat[0, 0] / scale.X; if (acosValue > 1.0) acosValue = 1.0; else if (acosValue < -1.0) acosValue = -1.0; double zAngle = Math.Acos(acosValue); Debug.Assert(0.0
Output :
Rotation Angle : 60.0000016696521
Scale X :1 Scale Y : 2
Translation Vector offset Values :12,15


Leave a Reply