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!.
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Solved by ShricharanaB. Go to Solution.
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;
}
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);
}
}
}
}
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();
}
}
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!
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.
@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.
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.