Select Object While Executing Command Programmatically

ahmedshawkey95
Advocate
Advocate

Select Object While Executing Command Programmatically

ahmedshawkey95
Advocate
Advocate

Hello All,

I'm trying to execute a built-in command "DIMBREAK" that requires to selecting dimensions then selecting the intersected object. The problem occurs when I tried to pass the intersected objected Id (BlockReference Id), AutoCAD writes <Bad Entity name: 114C0550>. Although when I select the block reference manually, it works properly.

ahmedshawkey95_1-1601910718891.png

 

Could you help me to know what's missing in the following code?

        [CommandMethod("BreakDimensionsWithBlock", CommandFlags.UsePickSet)]
        public static void BreakDimWithBlock()
        {
            Document doc =
                Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            // Ask the user to select a block
            try
            {
                SelectionSet brokenDimSelectionSet = null;
                SelectionSet blocksSelectionSet = null;
                using (var tr = db.TransactionManager.StartTransaction())
                {
                    BlockTableRecord spaceBtr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    ObjectIdCollection dimensionsIds = new ObjectIdCollection();
                    foreach (var id in spaceBtr)
                    {
                        if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(Dimension))))
                            dimensionsIds.Add(id);
                    }

                    if (dimensionsIds.Count < 1)
                    {
                        ed.WriteMessage("The current space doesn't contain any dimensions");
                        return;
                    }
                    ObjectId[] idArray = new ObjectId[dimensionsIds.Count];
                    dimensionsIds.CopyTo(idArray, 0);
                    brokenDimSelectionSet = SelectionSet.FromObjectIds(idArray);

                    PromptEntityOptions peo = new PromptEntityOptions("\nSelect a block that will break dimensions:") { AllowNone = false };
                    peo.SetRejectMessage("\nMust select a block.");
                    peo.AddAllowedClass(typeof(BlockReference), false);
                    PromptEntityResult per = ed.GetEntity(peo);
                    if (per.Status != PromptStatus.OK)
                        return;

                    var blockRef = tr.GetObject(per.ObjectId, OpenMode.ForWrite) as BlockReference;
                    BlockTableRecord btr = blockRef.IsDynamicBlock ?
                        (BlockTableRecord)tr.GetObject(blockRef.DynamicBlockTableRecord, OpenMode.ForRead) :
                        (BlockTableRecord)tr.GetObject(blockRef.BlockTableRecord, OpenMode.ForWrite);

                    var allBlocksIds = btr.GetBlockReferenceIds(true, true);
                    foreach (ObjectId blockRefId in btr.GetAnonymousBlockIds())//for dynamic blocks
                        allBlocksIds.Add(blockRefId);

                    ObjectId[] blocksIdArray = new ObjectId[allBlocksIds.Count];
                    allBlocksIds.CopyTo(blocksIdArray, 0);
                    blocksSelectionSet = SelectionSet.FromObjectIds(blocksIdArray);
                    tr.Commit();
                }
                //Application.DocumentManager.MdiActiveDocument.SendStringToExecute($"DIMBREAK Multiple {blocksSelectionSet} {blockRef.Id}", false, false, false);
                //ed.Command("_.DIMBREAK", "_Multiple", brokenDimSelectionSet, "", blocksSelectionSet);//AutoCad throws InvalidInput Exception
                foreach (ObjectId blockRefId in blocksSelectionSet.GetObjectIds())
                {
                    ed.Command("_.DIMBREAK", "_Multiple", brokenDimSelectionSet, "", blockRefId, "");//AutoCad says <Bad Entity Name> ! Is blockRefId invalid?
                }
            }
            catch (Autodesk.AutoCAD.Runtime.Exception e)
            {
                // Something went wrong
                ed.WriteMessage(e.ToString());
            }
        }
0 Likes
Reply
3,287 Views
10 Replies
Replies (10)

norman.yuan
Mentor
Mentor

When calling Editor.Command(), the entity reference or references passed into the command should be SelectionSet, not individual ObjectId. So, in your calling to command "BreakDim", you pass following parameters:

 

1. "_.BREAKDIM" - command;

2. "_Multiple" - instead of breaking dimension one by one, allow multiple selection;

3. brokenDimSelectionset - all dimension IDs as a SelectionSet;

4. "" - end of multiple selection;

5. blokRefId - instead of default breaking option of "Auto", select entity that breaks dimension. Here is where the code is wrong. See explanation later;

6. "" - end of breaking entity selection and the command execution is done.

 

The code error occurs at parameter 5, which is to select an breaking entity. Event the command only expects single entity being selected here, you still need to pass the entity ID as SelectionSet (with Count=1). So, this code works for me:

 

foreach (var blockRefId in blocksSelectionSet.GetObjectIds())
{
var ss = SelectionSet.FromObjectId(new ObjectId[]{ blockRefId });      ed.Command("_.DIMBREAK""m", brokenDimSelectionSet, "", ss, ""); }

However, if you have too many block references to loop through, you might hit the 128 SelectionSet limit during the foreach... loop. See this was mentioned in this link (in the article's comment).

 

So, you might as well do this (creating the selectionset for the breaking block reference inside the scope of the "BreakDim" command). This might prevent you from hit the 128 limit, but I am not sure on this, just a wild guess:

 

foreach (var blockRefId in blocksSelectionSet.GetObjectIds())
{
    ed.Command("_.DIMBREAK""m", brokenDimSelectionSet, ""
SelectionSet.FromObjectIds(new ObjectId[] { blockRefId }), ""); }

 

I did try the code and it worked with my Acad2021. HTH.

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes

ahmedshawkey95
Advocate
Advocate

@norman.yuan Thanks for your quick and valuable reply as usual. I already tried to do what you suggested above by sending SelectionSet that contains one item in the fifth parameter, but AutoCAD neglects this parameter and use the default value "Auto" instead of using the passed block. 

Does this command is using internally the selection point on the selected object? Or is there any other smarter way to break dimensions instead of executing DIMBREAK command? 

 

ahmedshawkey95_0-1602015441720.png

 

 

0 Likes

norman.yuan
Mentor
Mentor

Well, when the command goes to the step of asking you to select entity that breaks dim, you would either select an entity (supply a selectionset with one entity in it by code), or press enter (not supply a selectionset, instead, use "" for enter) for the option of [Auto]. In my previous reply, the code worked for me. To prove it, you can watch the attached video clip. I used all your code, except for the final foreach (ObjectId blockRefId in ....){...} that wraps the Editor.Command() call. Again, it worked with my Acad2021 and the simple sample drawing, where 3 dimesions are to be break by block references.

 

There is no API exposed to break dimension, I think. So, Editor.Command() as my code demonstrated is the way to go.
 

Norman Yuan

Drive CAD With Code

EESignature

ahmedshawkey95
Advocate
Advocate

@norman.yuan Thanks again for your clear reply and video but it seems that your drawing contains 3 block references of the same BlockTableRecord that's why it can't prove that AutoCAD considered the selected block because it will generate the same output if the default value ("Auto") is used.

In other words, if you want to test if AutoCAD considers the fifth command parameter, you may add a different entity(such as rectangle or circle) or block (but with different block definition) that intersects dimension and if the new entity doesn't break the dimension then we can make sure that it works properly.

 

 

0 Likes

norman.yuan
Mentor
Mentor

Well, I strictly followed your code: the code ask user to pick a block reference and then obtain the block definition, then through the definition, find all block references of THAT Block DEFINITION (let's not consider dynamic block references, for simplicity). So, I am a bit confused as what exactly your situation is and how it is different from what your code tells.

 

Nonetheless, I just tried to use different block references to break different dimension, as your latest reply suggested. Firstly, here is the code:

 

public static void BreakAllDims()
        {
            Document doc =
                Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            // Ask the user to select a block
            try
            {
                SelectionSet brokenDimSelectionSet = null;
                SelectionSet blocksSelectionSet = null;
                using (var tr = db.TransactionManager.StartTransaction())
                {
                    BlockTableRecord spaceBtr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    ObjectIdCollection dimensionsIds = new ObjectIdCollection();
                    foreach (var id in spaceBtr)
                    {
                        if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(Dimension))))
                            dimensionsIds.Add(id);
                    }

                    if (dimensionsIds.Count < 1)
                    {
                        ed.WriteMessage("The current space doesn't contain any dimensions");
                        return;
                    }
                    ObjectId[] idArray = new ObjectId[dimensionsIds.Count];
                    dimensionsIds.CopyTo(idArray, 0);
                    brokenDimSelectionSet = SelectionSet.FromObjectIds(idArray);

                    //Select all block references in current space
                    var layoutName = ((Layout)tr.GetObject(spaceBtr.LayoutId, OpenMode.ForRead)).LayoutName;
                    var vals = new TypedValue[]
                    {
                        new TypedValue((int)DxfCode.Start, "INSERT"),
                        new TypedValue((int)DxfCode.LayoutName, layoutName)
                    };
                    var res = ed.SelectAll(new SelectionFilter(vals));
                    if (res.Status== PromptStatus.OK)
                    {
                        blocksSelectionSet = SelectionSet.FromObjectIds(res.Value.GetObjectIds());
                    }
                    
                    tr.Commit();
                }

                if (blocksSelectionSet != null)
                {
                    foreach (var blkId in blocksSelectionSet.GetObjectIds())
                    {
                        ed.Command("_.DIMBREAK", "m", brokenDimSelectionSet, "", SelectionSet.FromObjectIds(new ObjectId[] { blkId }), "");
                    }
                }

            }
            catch (Autodesk.AutoCAD.Runtime.Exception e)
            {
                // Something went wrong
                ed.WriteMessage(e.ToString());
            }
        }

 

 

See video clip below on the code runs in debugging.

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes

ahmedshawkey95
Advocate
Advocate

The command target is to allow selecting only one block definition that will be used to break all dimensions with the references of this block only but not to break the dimensions with any other entity or block.

 

The problem is that the output of executing the following command leads to the same the output if you used Auto instead of the fifth parameter

 

ed.Command("_.DIMBREAK", "m", brokenDimSelectionSet, "",  SelectionSet.FromObjectIds(new ObjectId[] { blockRefId }), "");

 

 This means that the dimensions are broken not only with the passed block reference but also with all intersected entities and blocks that's why I think that Autocad neglects the fifth parameter and uses Auto instead.

In your above command, if you draw a circle or rectangle that intersects dimension, it will break the dimensions although you didn't pass it to the command.

 

0 Likes

lena.talkhina
Alumni
Alumni

Hello @ahmedshawkey95 !

Just a kindly reminder, our community is support based and when you receive a solution, we would like you to accept it by clicking the green button "Accept as a solution" under the post. It will help others to find the answer on the same question.

Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям! | Do you find the posts helpful? "LIKE" these posts!
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.



Лена Талхина/Lena Talkhina
Менеджер Сообщества - Русский/Community Manager - Russian

0 Likes

norman.yuan
Mentor
Mentor

Ok, I got what you are saying, after testing by adding different entities that overlap with dimensions (breaking dimensions, that is).

 

It seems that the passed block reference Id does not affect the outcome and the [Auto] option is always used, so that all dimensions are broken at all the breaking entities.

 

I tried to call the "DIMBREAK" in different options (breaking dimension one at a time, or breaking many dimensions with [Muiltiple] option) and the passed breaking entity (block reference, in your case) has no effect and dimension always be broken by [Auto].

 

I am at the end of my wisdom on this😓😁

 

Norman Yuan

Drive CAD With Code

EESignature

ahmedshawkey95
Advocate
Advocate

Hi @lena.talkhina,

Sure, I'll do this once I find a solution.

ahmedshawkey95
Advocate
Advocate

Thanks for your effort and time, I was forced to do workarounds such as copying the dimensions and the selected block references to a new space then breaking them then returning the dimensions to the original location.

 

I greatly appreciate the assistance you have provided me.

0 Likes