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

How to rotate a block using center as a basepoint

15 REPLIES 15
Reply
Message 1 of 16
rohit_c_sharma
636 Views, 15 Replies

How to rotate a block using center as a basepoint

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();                                                     
            }

 

15 REPLIES 15
Message 2 of 16
_gile
in reply to: rohit_c_sharma

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();
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 16
rohit_c_sharma
in reply to: _gile

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.

Actual resultActual result

Expected resultExpected result

 

Message 4 of 16
_gile
in reply to: rohit_c_sharma

You should provide the block reference.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 16
rohit_c_sharma
in reply to: _gile

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();
            }
        }

 

Message 6 of 16
_gile
in reply to: rohit_c_sharma

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);


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 16
rohit_c_sharma
in reply to: _gile

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));
        }

Screenshot 2024-04-23 211925.png 

Message 8 of 16
_gile
in reply to: rohit_c_sharma

The issue seems to be due to your block.

Could you attach a dwg file with this block?



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 16

Attached dwt file. 

Message 10 of 16
_gile
in reply to: rohit_c_sharma

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();
    }
}



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 16
rohit_c_sharma
in reply to: _gile

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;
                }

 

 

Message 12 of 16
_gile
in reply to: rohit_c_sharma

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.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 13 of 16
rohit_c_sharma
in reply to: _gile

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();
                }
        }

 

 

 

Message 14 of 16
_gile
in reply to: rohit_c_sharma

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();
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 15 of 16
BKSpurgeon
in reply to: rohit_c_sharma

I''ll throw in my two cents (which is untested) and could be made in ignorance

 

  • It is unclear why the 'center' is being calculated via the geometric extents. another option: if it's a block that you control then you can define the "centre" via the block definition.
  • If you can do that, then simply rotate around the insertion point: 

 

 

Message 16 of 16
rohit_c_sharma
in reply to: BKSpurgeon

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.

Post to forums  

Technology Administrators


Autodesk Design & Make Report