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

How to get transformation matrix of a nested block in WCS instead of OCS?

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
ShricharanaB
426 Views, 7 Replies

How to get transformation matrix of a nested block in WCS instead of OCS?

Hi,

 

I'm trying to insert a block (Block_2) with the position and orientation being the same as another block (Block_1) . The block (Block_2) will be inserted in model space no matter the nesting of the block (Block_1)

If the Block_1 is nested (lets say in Block_3) , BlockRef.BlockTransform returns the transformation matrix in OCS, and because of this the new block is being inserted in the wrong position.

 

How to convert this transformation matrix from OCS to WCS? 

 

Thanks in advance for any help!.

Labels (3)
7 REPLIES 7
Message 2 of 8
_gile
in reply to: ShricharanaB

Hi,

If you get the nested block with Editor.GetNestedEntity, the PromptNestedEntityResult provides a GetContainers method you can use to compute the transformation Matrix.

        private static Matrix3d GetTransformation(PromptNestedEntityResult promptResult)
        {
            var xform = Matrix3d.Identity;
            using (var tr = new OpenCloseTransaction())
            {
                if (promptResult.ObjectId.ObjectClass.Name == "AcDbAttribute")
                {
                    var attRef = (AttributeReference)tr.GetObject(promptResult.ObjectId, OpenMode.ForRead);
                    var owner = (BlockReference)tr.GetObject(attRef.OwnerId, OpenMode.ForRead);
                    xform = owner.BlockTransform;
                }
                foreach (ObjectId id in promptResult.GetContainers())
                {
                    var container = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                    xform = container.BlockTransform * xform;
                }
            }
            return xform;
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 8
ShricharanaB
in reply to: _gile

Hi Gile, 

 

Thank you for the reply. 

(Edit: Found out issue was something else. The below code works.)

I'm using editor.SelectAll with "INSERT" filter to get the blocks and iterating through each block and the blocks nested in them as I need to attach the block_2 to Block_1 wherever it exists. I'm using a recursive method to do this for each block in the selection set. I tried the below but it added the blocks somewhere unintended. 

 

void mainMethod()
	{
		//getting database selection etc... 		
		foreach (SelectedObject sObj in ss)
		{
			BlockReference blockRef = (BlockReference)trans.GetObject(sObj.ObjectId, OpenMode.ForRead);
			RecusrsiveAttachBlock(blockRef, trans, Matrix3d.Identity);    
		}
	}

	void RecusrsiveAttachBlock(BlockReference blockRef, Transaction trans, Matrix3d parentTransform){
	{
		string blockName = blockRef.IsDynamicBlock ? ((BlockTableRecord)blockRef.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)).Name : blockRef.Name;
		if (ContainsString(BlockNames, blockName))
		{
			Matrix3d blockTransformationMatrix = parentTransform * blockRef.BlockTransform;
			//creating new block reference and setting block transform to blockTransformationMatrix	etc...
		}
		else
		{
			BlockTableRecord btr = (BlockTableRecord)trans.GetObject(blockRef.BlockTableRecord, OpenMode.ForRead);			
			parentTransform = parentTransform * blockRef.BlockTransform;
			foreach (ObjectId objID in btr)
			{
				Entity entity = trans.GetObject(objID, OpenMode.ForRead) as Entity;
				
				
				if (entity is BlockReference)
				{                        
					BlockReference br = trans.GetObject(objID, OpenMode.ForRead) as BlockReference;
					RecusrsiveAttachBlock(br, trans, parentTransform);
				}
			}
		}
		
	}

 

 

Message 4 of 8
_gile
in reply to: ShricharanaB

This one seems to work fine with a selected block reference.

        static IEnumerable<Matrix3d> GetNestedBlockTransform(BlockReference br, Matrix3d xform, string nestedBlockName)
        {
            xform *= br.BlockTransform;
            string blockName = ((BlockTableRecord)br.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)).Name;
            if (blockName == nestedBlockName)
            {
                yield return xform;
            }
            else
            {
                var btr = (BlockTableRecord)br.BlockTableRecord.GetObject(OpenMode.ForRead);
                var nestedBrs = btr
                    .Cast<ObjectId>()
                    .Where(id => id.ObjectClass.Name == "AcDbBlockReference")
                    .Select(id => (BlockReference)id.GetObject(OpenMode.ForRead));
                foreach (var nestedBr in nestedBrs)
                {
                    foreach (var matrix in GetNestedBlockTransform(nestedBr, xform, nestedBlockName))
                    {
                        yield return matrix;
                    }
                }
            }
        }

 A testing command:

        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var filter = new SelectionFilter(new[] { new TypedValue(0, "INSERT") });
            var selection = ed.GetSelection(filter);
            if (selection.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(blockToInsertName))
                {
                    foreach (var id in selection.Value.GetObjectIds())
                    {
                        var source = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                        var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        foreach (var xform in GetNestedBlockTransform(source, Matrix3d.Identity, nestedBlockName))
                        {
                            var br = new BlockReference(Point3d.Origin, bt[blockToInsertName]);
                            br.TransformBy(xform);
                            curSpace.AppendEntity(br);
                            tr.AddNewlyCreatedDBObject(br, true);
                        }
                    }

                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 8
ShricharanaB
in reply to: ShricharanaB

Hi, 

 

I found the issue. The method I posted above works. I was using rotation after calculating the transform, for which I was providing Blockref.Position as base point which should have been transformationMatrix.CoordinateSystem3d.Origin . This was rotating the object with wrong base point and placing it somewhere else as a result. 

 

Thank you!

Message 6 of 8
ShricharanaB
in reply to: _gile

Thank you for providing the snippet!

It will come in handy as I won't have to track and multiply the transformation matrices in recursive loops. 

Message 7 of 8
_gile
in reply to: ShricharanaB


@ShricharanaB  a écrit :

Thank you for providing the snippet!

It will come in handy as I won't have to track and multiply the transformation matrices in recursive loops. 


The GetNestedBlockTransform function is recursive.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 8
ShricharanaB
in reply to: _gile

Sorry, what I meant to say was that I won't have to handle the transformation matrix multiplication, or conversion to WCS, in loops I create to iterate through all blocks and nested blocks. I can just call the GetNestedBlockTransform() and it'll handle that. 

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

Post to forums  

Forma Design Contest


AutoCAD Beta