Place a block in a specific rectangle

Place a block in a specific rectangle

Anonymous
Not applicable
621 Views
5 Replies
Message 1 of 6

Place a block in a specific rectangle

Anonymous
Not applicable

Hello, 

 

I can place a block using a Point as a position and change his scale using the bellow code  : 

 

                    string blockName = name;
                    BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                    BlockTableRecord blockDef = bt[blockName].GetObject(OpenMode.ForRead) as BlockTableRecord;
                    BlockTableRecord ms = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite) as BlockTableRecord;

                    using (BlockReference blockRef = new BlockReference(position, blockDef.ObjectId))
                    {
                        blockRef.ScaleFactors = new Scale3d(scale);
                        blockRef.Layer = layer;
                        id = ms.AppendEntity(blockRef);
                        myT.AddNewlyCreatedDBObject(blockRef, true);
                    }

 

but i want to place the block in a specific rectangle for which i can recover the extent, means that i need to use just  the extent to place the block in the rectange without using the scale. is that possible an how ? 

 

thank you. 

0 Likes
622 Views
5 Replies
Replies (5)
Message 2 of 6

BKSpurgeon
Collaborator
Collaborator

Personally, and this is a matter of preference, I would strongly recommend you use a transaction to open/close objects - unless performance is a huge concern, this is probably a good way to go. unless you are really careful, it's very easy to potentially forget to close an object. using transactions obviates the need to remember. also please don't forget to commit or abort your transaction when you are done with it otherwise the code will run slower.

 

 

Perhaps try something like this:

 

public class MyCommands
{
           [CommandMethod("PlaceBlockReferenceInRectangle")]
        public static void PlaceBlockReferenceInRectangle()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // set up variablees
                string blockName = "blahblah";

                    // get the extents of the Rectangle
                Extents3d rectangleExtents = GetRectangleExtents(); // get the extents using the rectangle. you will have to substitute your custom code here.
                double xAverage = (rectangleExtents.MinPoint.X + rectangleExtents.MaxPoint.X) / 2.0;
                double yAverage = (rectangleExtents.MinPoint.Y + rectangleExtents.MaxPoint.Y) / 2.0;
                Point3d insertionPointInMiddleOfRectangle = new Point3d(xAverage, yAverage, 0);


                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord ms = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
                BlockTableRecord blockDef = tr.GetObject(bt[blockName], OpenMode.ForRead) as BlockTableRecord;

                    // this should place it
                using (BlockReference blockRef = new BlockReference(insertionPointInMiddleOfRectangle, blockDef.ObjectId))
                {
                    //// omit the scale and all the layer information from this example for simplicity.
                    

                    
                    ms.AppendEntity(blockRef);
                    tr.AddNewlyCreatedDBObject(blockRef, true);
                }


                tr.Commit();
            }
        }

           private static Extents3d GetRectangleExtents()
           {
               // write your custom code here.
               return new Extents3d();
           }
}
0 Likes
Message 3 of 6

_gile
Consultant
Consultant

BKSpurgeon a écrit :

Personally, and this is a matter of preference, I would strongly recommend you use a transaction to open/close objects - unless performance is a huge concern, this is probably a good way to go. unless you are really careful, it's very easy to potentially forget to close an object.

 


The upper code does use a transaction.

 

From this topic:

"The ObjectId.GetObject() style utilizes the normal Transaction object mechanism, but this way gives you a slightly difference access point."



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 6

ActivistInvestor
Mentor
Mentor

@BKSpurgeon wrote:

Personally, and this is a matter of preference, I would strongly recommend you use a transaction to open/close objects - unless performance is a huge concern, this is probably a good way to go. unless you are really careful, it's very easy to potentially forget to close an object. using transactions obviates the need to remember. also please don't forget to commit or abort your transaction when you are done with it otherwise the code will run slower.

  

 


He is using a Transaction.

 

Here is the (simplified) source code for ObjectId.GetObject():

 

 

 

public DBObject GetObject(OpenMode mode)
{
    return this.Database.TransactionManager.TopTransaction.GetObject(this, mode);
}

 

ObjectId.GetObject() is just another way of using the top transaction, if there is one. If there isn't one, an exception is raised.

 

If performance is important in cases where many objects are being opened sequentially, ObjectId.GetObject() is obviously not the best way to do it.

 

It's also not recommended if the calling code needs to work with any kind of transaction.

Message 5 of 6

_gile
Consultant
Consultant

Hi,

 

If the purpose is to insert and scale the block so that is fills a rectangle, you can get some inspiration from this:

 

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

            // get the block name
            var pr = ed.GetString("\nEnter the block name: ");
            if (pr.Status != PromptStatus.OK)
                return;
            var blockName = pr.StringResult;
            if (string.IsNullOrWhiteSpace(blockName))
                return;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                // check if block exists in the block table
                var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (!bt.Has(blockName))
                {
                    ed.WriteMessage($"\nBlock '{blockName}' not found.");
                    return;
                }

                // get the rectangle
                var peo = new PromptEntityOptions("\nSelect a rectangle: ");
                peo.SetRejectMessage("\nSelected object is not a polyline.");
                peo.AddAllowedClass(typeof(Polyline), true);
                var per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK)
                    return;
                var pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                var rectangle = pline.GeometricExtents;

                // insert the block
                var br = new BlockReference(rectangle.MinPoint, bt[blockName]);
                var space = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                space.AppendEntity(br);
                tr.AddNewlyCreatedDBObject(br, true);

                // local functions (C#7, use delegates for prior versions)
                double GetLength(Extents3d extents) =>
                    extents.MaxPoint.X - extents.MinPoint.X;

                double GetWidth(Extents3d extents) =>
                    extents.MaxPoint.Y - extents.MinPoint.Y;

                Point3d GetCenter(Extents3d extents) =>
                    extents.MinPoint + (extents.MaxPoint - extents.MinPoint) / 2.0;

                // scale
                var brExtents = br.GeometricExtents;
                double xScale = GetLength(rectangle) / GetLength(brExtents);
                double yScale = GetWidth(rectangle) / GetWidth(brExtents);
                br.ScaleFactors = new Scale3d(xScale, yScale, 1);
                
                // move
                brExtents = br.GeometricExtents;
                br.TransformBy(Matrix3d.Displacement(GetCenter(rectangle) - GetCenter(brExtents)));
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 6

BKSpurgeon
Collaborator
Collaborator

 

@_gile @ActivistInvestor - thank you both for the clarification. you are both correct - i made a mistake in the above.

 

rgds

 

 

 

 

0 Likes