I am trying to rotate a block using basepoint as center of block. I have written below code to calculate center of block and then used rotate method to transform. Rotation is happening but not at same position, the position of block is getting changed which I don't want. I am struggling with this for few days but no luck, I don't have much background of AutoCAD APIs, any help is appreciated.
using (var transaction = Database.TransactionManager.StartTransaction())
{
BlockReference reference = (BlockReference)transaction.GetObject(additionalBlockRef.ObjectId, OpenMode.ForRead);
BlockTableRecord record = (BlockTableRecord)transaction.GetObject(reference.BlockTableRecord, OpenMode.ForRead);
Point3d refPos = reference.Position; //current position of inserted block ref.
Point3d pmin = reference.Bounds.Value.MinPoint; //bounding box of entities.
Point3d pmax = reference.Bounds.Value.MaxPoint;
Point3d newPos = (Point3d)(pmin + (pmax - pmin) / 2); //center point of displayed graphics.
Matrix3d mat = Matrix3d.Rotation(ConvertDegreesToRadians(180),
Vector3d.ZAxis.TransformBy(Document.Editor.CurrentUserCoordinateSystem),
newPos.TransformBy(Document.Editor.CurrentUserCoordinateSystem));
reference.RecordGraphicsModified(true);
Entity entity = (Entity)transaction.GetObject(additionalBlockRef.ObjectId, OpenMode.ForRead) as Entity;
if (entity != null)
{
entity.UpgradeOpen();
entity.TransformBy(mat);
entity.DowngradeOpen();
}
transaction.TransactionManager.QueueForGraphicsFlush();
transaction.Commit();
}
Hi,
This seems to work.
using (var transaction = db.TransactionManager.StartTransaction())
{
var blockReference = (BlockReference)transaction.GetObject(blockReferenceId, OpenMode.ForWrite);
var blockDefinition = (BlockTableRecord)transaction.GetObject(blockReference.BlockTableRecord, OpenMode.ForRead);
var extents = blockDefinition
.Cast<ObjectId>()
.Select(id => (Entity)transaction.GetObject(id, OpenMode.ForRead))
.Aggregate(new Extents3d(), (ext, ent) => { ext.AddExtents(ent.GeometricExtents); return ext; });
var center = (extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2.0);
center = center.TransformBy(blockReference.BlockTransform);
blockReference.TransformBy(Matrix3d.Rotation(Math.PI, blockReference.Normal, center));
transaction.Commit();
}
Thanks for your quick response !
I am not getting desired results with this code. This has same problem as code I posted. when rotation of 180 degree happens, position of block is changed towards bottom. I want block to just rotate without changing its position.
Adding screenshot of actual result and expected result. I am trying to apply transformation to first block in screenshot.
Sorry, I did not get what it means by providing Block reference. I am already doing that in code. Is there anything else expected ? Here additionalBlockRef I am passing as argument, is a Blockreference that I need to rotate.
private void transform1(BlockReference additionalBlockRef)
{
using (var transaction = Database.TransactionManager.StartTransaction())
{
var blockReference = (BlockReference)transaction.GetObject(additionalBlockRef.Id, OpenMode.ForWrite);
var blockDefinition = (BlockTableRecord)transaction.GetObject(blockReference.BlockTableRecord, OpenMode.ForRead);
var extents = blockDefinition
.Cast<ObjectId>()
.Select(id => (Entity)transaction.GetObject(id, OpenMode.ForRead)).Where(item => item.Id == additionalBlockRef.Id)
.Aggregate(new Extents3d(), (ext, ent) => { ext.AddExtents(ent.GeometricExtents); return ext; });
var center = extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2.0;
center = center.TransformBy(blockReference.BlockTransform);
blockReference.TransformBy(Matrix3d.Rotation(ConvertDegreesToRadians(180), blockReference.Normal, center));
transaction.Commit();
}
}
You're passing a BlockReference to this method:
private void transform1(BlockReference additionalBlockRef)
why do you need to open a new transaction and open one more time the same block reference?
var blockReference = (BlockReference)transaction.GetObject(additionalBlockRef.Id, OpenMode.ForWrite);
I removed the transaction and used the Blockreference passed to method. Still same result.
private void transform2(BlockReference additionalBlockRef)
{
var extents = additionalBlockRef.GeometricExtents;
var center = extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2.0;
center = center.TransformBy(additionalBlockRef.BlockTransform);
additionalBlockRef.TransformBy(Matrix3d.Rotation(ConvertDegreesToRadians(180), additionalBlockRef.Normal, center));
}
This does work:
[CommandMethod("TEST")]
public static void Test()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var options = new PromptEntityOptions("\nSelect block to rotate: ");
options.SetRejectMessage("\nSelected object is not a block.");
options.AddAllowedClass(typeof(BlockReference), true);
var result = ed.GetEntity(options);
if (result.Status != PromptStatus.OK)
return;
var blockReferenceId = result.ObjectId;
using (var transaction = db.TransactionManager.StartTransaction())
{
var blockReference = (BlockReference)transaction.GetObject(blockReferenceId, OpenMode.ForWrite);
var extents = blockReference.GeometricExtents;
var center = (extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2.0);
blockReference.TransformBy(Matrix3d.Rotation(Math.PI, blockReference.Normal, center));
transaction.Commit();
}
}
Thank You for your quick response ! Yes I see your code works.
I think issue with my code could be - Blockreference that I am passing to Transform method is not committed to Database yet. Actually I am using EntityJig class and creating bunch of blockreferences in a transaction. I have not committed the transaction yet and I am trying to rotate using transform. Could that be an issue ??
Only after running jig (which create bunch of blockreferences and then apply rotation using transform on them), I try to commit transaction. Refer code below :
If yes, then is there a way I can rotate the blockreferences before I commit that to database ?
// Run the jig
var jig = new MultiBlockReferenceJig(opts);
List<BlockReference> allResultingBlocks = jig.Run(editor);
if (allResultingBlocks?.Count > 0)
{
// Commit changes if user accepted, otherwise discard
transaction.Commit();
var resultingBlockRefIds = allResultingBlocks.Select(br => br.Id).ToList();
foreach (var blockRef in allResultingBlocks)
{
//always dispose an object after creation
blockRef.Dispose();
}
return resultingBlockRefIds;
}
Seeing the pictures you provided, the issue seems to be due to the way you compute the "center" of a block reference using its geometric extents. It looks like the extents only take in account the width of the block reference (RACK_WIDTH dynamic property) as if it height (RACK_DEPTH dynamic property) was equal to 0.
I debugged and saw that center is being calculated properly with code you shared.
When I use the same code you sent, Its working for blocks that are created already but its not working for blocks that are being created but transaction not committed. For example, in code below, parameter additionalBlockRef is a blockreference for which transaction is not committed yet. Can this be a problem ?
Otherwise I am using same code thats working for You.
private void transform2(BlockReference additionalBlockRef)
{
using (var transaction = Database.TransactionManager.StartTransaction())
{
var blockReference = (BlockReference)transaction.GetObject(additionalBlockRef.ObjectId, OpenMode.ForWrite);
var extents = blockReference.GeometricExtents;
var center = extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2.0;
blockReference.TransformBy(Matrix3d.Rotation(Math.PI, blockReference.Normal, center));
transaction.Commit();
}
}
No,
You can transform the block reference before adding to the Database and transaction.
[CommandMethod("TEST")]
public static void Test()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
// prompt the user to specify the block name
var promptResult = ed.GetString("\nEnter the block name: ");
if (promptResult.Status != PromptStatus.OK)
return;
string blockName = promptResult.StringResult;
using (var transaction = db.TransactionManager.StartTransaction())
{
// check if the block table has a block with thie specified name
var blockTable = (BlockTable)transaction.GetObject(db.BlockTableId, OpenMode.ForRead);
if (!blockTable.Has(blockName))
{
ed.WriteMessage($"\nBlock '{blockName}' not found.");
return;
}
// prompt the user to specify the insertion point
var promptPointOptions = new PromptPointOptions("\nSpecifiy the insertion point: ");
var promptPointResult = ed.GetPoint(promptPointOptions);
if (promptPointResult.Status != PromptStatus.OK)
return;
// create a new block reference
var blockReference = new BlockReference(promptPointResult.Value, blockTable[blockName]);
blockReference.TransformBy(ed.CurrentUserCoordinateSystem);
// compute the center of the block reference
var extents = blockReference.GeometricExtents;
var center = extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2;
// rotate the block reference around its center
blockReference.TransformBy(Matrix3d.Rotation(Math.PI, blockReference.Normal, center));
// add the block reference to the database and transaction.
var curSpace = (BlockTableRecord)transaction.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
curSpace.AppendEntity(blockReference);
transaction.AddNewlyCreatedDBObject(blockReference, true);
db.TransactionManager.QueueForGraphicsFlush();
transaction.Commit();
}
}
I''ll throw in my two cents (which is untested) and could be made in ignorance
We have many existing drawings (dwg files) and if insertion point is changed to center , then it could impact existing drawings ..right ? Blocks may display/position differently in existing drawings than we want ?
Can't find what you're looking for? Ask the community or share your knowledge.