How to use a filter for Multileader text?

How to use a filter for Multileader text?

Anonymous
Not applicable
2,023 Views
2 Replies
Message 1 of 3

How to use a filter for Multileader text?

Anonymous
Not applicable

 

I have been looking for answers everywhere but I cannot find much on filters for multileaders. I figured it should be like Mtext but multileader but my code does not pick up any multileaders in my draft. The following code looks for Mtext and then Mleader, I separated the filters to try narrow down on where it was all going wrong but I still don't know why it wont pick them up. I have a pic of my test drawing; it deletes the text with numbers and both Mleaders but I am only trying to delete one of them.

 

 

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

namespace DataCollection.Classes.Data
{
    class deleteText
    {
        public static void delete(Database db, Editor ed, BlockTableRecord BtrModelWrite)
        {
////////////////
            TypedValue[] acTypValAr = new TypedValue[4];
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Operator, "<and"), 0);
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "MTEXT"), 1);
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Text, "[~0123456789]"), 2);
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Operator, "and>"), 3);


            // Assign the filter criteria to a SelectionFilter object
            //SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
            SelectionFilter sf = new SelectionFilter(acTypValAr);
            PromptSelectionResult psr = ed.SelectAll(sf);

            //// Request for objects to be selected in the drawing area
            //PromptSelectionResult acSSPrompt;
            //acSSPrompt = ed.GetSelection(acSelFtr);
            //SelectionSet acSSPrompt = selectAll.getSelectionSet(ed);

            if (psr.Status == PromptStatus.OK)
            {
                using (Transaction Trans = db.TransactionManager.StartTransaction())
                {
                    foreach (ObjectId text in psr.Value.GetObjectIds())
                    {
                        //Check to see if the object is a polyline
                        var rxClassPline = RXClass.GetClass(typeof(MText));
                        //Test the object for entity type
                        if (text.ObjectClass.IsDerivedFrom(rxClassPline))
                        {
                            MText hDelete = (MText)Trans.GetObject(text, OpenMode.ForWrite);
                            hDelete.Erase();
                        }
                    }
                    Trans.Commit();
                }
            }

            ////////////////
            acTypValAr = new TypedValue[4];
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Operator, "<and"), 0);
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "MULTILEADER"), 1);
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Text, "[~0123456789]"), 2);
            acTypValAr.SetValue(new TypedValue((int)DxfCode.Operator, "and>"), 3);


            // Assign the filter criteria to a SelectionFilter object
            //SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
            sf = new SelectionFilter(acTypValAr);
            psr = ed.SelectAll(sf);

            //// Request for objects to be selected in the drawing area
            //PromptSelectionResult acSSPrompt;
            //acSSPrompt = ed.GetSelection(acSelFtr);
            //SelectionSet acSSPrompt = selectAll.getSelectionSet(ed);

            if (psr.Status == PromptStatus.OK)
            {
                using (Transaction Trans = db.TransactionManager.StartTransaction())
                {
                    foreach (ObjectId leaders in psr.Value.GetObjectIds())
                    {
                        //Check to see if the object is a polyline
                        var rxClassPline = RXClass.GetClass(typeof(MLeader));
                        //Test the object for entity type
                        if (leaders.ObjectClass.IsDerivedFrom(rxClassPline))
                        {
                            MLeader hDelete = (MLeader)Trans.GetObject(leaders, OpenMode.ForWrite);
                            hDelete.Erase();
                        }
                    }
                    Trans.Commit();
                }
            }
}
    }
}

 

Inkeddocwindow_LI.jpg 

 

 

 

 

 

0 Likes
Accepted solutions (2)
2,024 Views
2 Replies
Replies (2)
Message 2 of 3

_gile
Consultant
Consultant
Accepted solution

Hi,

 

The filter you use in the code you posted will only select MText containing a single non numeric character (e.g. "a", "b", "c", ...).

If you want to select "the text with numbers" it should be:

            var filter = new SelectionFilter(new TypedValue[2]
            {
                new TypedValue(0, "MTEXT"),
                new TypedValue(1, "*[0-9]*")
            });

Note you do not need the "AND" logical grouping which is implicit.

 

In any case, you cannot directly filter MLeader entities using their MText content in a selection filter, you must "post-process" the selection set by opening each selected MLeader to check its contents.

In addition, instead of using Editor.SelectAll, it would be simpler and more efficient to iterate through all the entities in the object space directly, and only open the MTexts and MLeaders to check their contents.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 3

_gile
Consultant
Consultant
Accepted solution

Here's a way to iterate through the whole model space and return only the ObjectId of the MText and MLeader containing a digit

 

        public static ObjectIdCollection GetMTextAndMLeaderContainingDigit(Database db)
        {
            var ids = new ObjectIdCollection();
            using (var tr = new OpenCloseTransaction())
            {
                var modelSpace = (BlockTableRecord)tr.GetObject(
                    SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);
                foreach (ObjectId id in modelSpace)
                {
                    if (id.ObjectClass.DxfName == "MTEXT")
                    {
                        var mtext = (MText)tr.GetObject(id, OpenMode.ForRead);
                        if (mtext.Text.ToCharArray().Any(char.IsDigit))
                        {
                            ids.Add(id);
                        }
                    }
                    if (id.ObjectClass.DxfName == "MULTILEADER")
                    {
                        var mleader = (MLeader)tr.GetObject(id, OpenMode.ForRead);
                        if (mleader.ContentType == ContentType.MTextContent)
                        {
                            var mtext = mleader.MText;
                            if (mtext.Text.ToCharArray().Any(char.IsDigit))
                            {
                                ids.Add(id);
                            }
                        }
                    }
                }
            }
            return ids;
        }

If you prefer let the user select objects on screen, you can handle the Editor.SelectionAdded event to remove the undesired entities from the selection (as a selection filter does).

 

        public static PromptSelectionResult SelectMTextAndMLeaderContainingDigit(Editor ed)
        {
            ed.SelectionAdded += SelectionAdded;
            var psr = ed.GetSelection();
            ed.SelectionAdded -= SelectionAdded;
            return psr;
        }

        private static void SelectionAdded(object sender, SelectionAddedEventArgs e)
        {
            using (var tr = new OpenCloseTransaction())
            {
                for (int i = 0; i < e.AddedObjects.Count; i++)
                {
                    ObjectId id = e.AddedObjects[i].ObjectId;
                    if (id.ObjectClass.DxfName == "MTEXT")
                    {
                        var mtext = (MText)tr.GetObject(id, OpenMode.ForRead);
                        if (!mtext.Text.ToCharArray().Any(char.IsDigit))
                        {
                            e.Remove(i);
                        }
                    }
                    else if (id.ObjectClass.DxfName == "MULTILEADER")
                    {
                        var mleader = (MLeader)tr.GetObject(id, OpenMode.ForRead);
                        if (!(mleader.ContentType == ContentType.MTextContent &&
                            mleader.MText.Text.ToCharArray().Any(char.IsDigit)))
                        {
                            e.Remove(i);
                        }
                    }
                    else
                    {
                        e.Remove(i);
                    }
                }
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub