How do I create a loop with PromptEntityResult

How do I create a loop with PromptEntityResult

sonny3g
Collaborator Collaborator
1,752 Views
9 Replies
Message 1 of 10

How do I create a loop with PromptEntityResult

sonny3g
Collaborator
Collaborator

How do I get this to loop until I either hit ESC or actually select a block?

 

// Setting entity prompt, reject message and allowed class type.
PromptEntityOptions opts1 = new PromptEntityOptions("");
opts1.Message = "\nSelect a TGDraw conveyor bed to get the elevation dimension: ";
opts1.SetRejectMessage("\nMust be a valid TGDraw block, try again: ");
opts1.AddAllowedClass(typeof(BlockReference), true);
PromptEntityResult ent1 = ed.GetEntity(opts1);
if (ent1.Status == PromptStatus.Cancel) return;

// reads the selected block and extracts properties and attributes
BlkStrct elevation = new BlkStrct();
elevation = ReadBlock(ent1.ObjectId);
string bname = elevation.blkName.Substring(0, 3);
if (!BlockFilter("bed filter", bname))
{
   return;
}

 

I know it has to be simple, but I am not seeing the solution.

Thanks for your help.

Sonny

Scott G. Sawdy
scott.sawdy@bluecoyotecad.com
0 Likes
Accepted solutions (1)
1,753 Views
9 Replies
Replies (9)
Message 2 of 10

_gile
Consultant
Consultant
Accepted solution

Hi,

 

            var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;

            var peo = new PromptEntityOptions("\nSelect block: ");
            peo.SetRejectMessage("\nMust be a block.");
            peo.AddAllowedClass(typeof(BlockReference), true);
while (true) { var per = ed.GetEntity(peo); if (per.Status == PromptStatus.Cancel) return; // exit the function if (per.Status != PromptStatus.OK) break; // quit the loop // do your stuff with the selected bloc }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 10

sonny3g
Collaborator
Collaborator

Thanks Giles.  I was trying to use do and was getting nowhere fast.  Using the while loop instead, with some slight modifications, did the trick for me.

Modified code:

 

            try
            {
                // Setting entity prompt, reject message and allowed class type.
                PromptEntityOptions opts1 = new PromptEntityOptions("");
                PromptEntityResult ent1;
                BlkStrct elevation = new BlkStrct();
                opts1.Message = "\nSelect a TGDraw conveyor bed to get the elevation dimension: ";
                opts1.SetRejectMessage("\nMust be a valid TGDraw block, try again: ");
                opts1.AddAllowedClass(typeof(BlockReference), true);
                while (true)
                {
                    ent1 = ed.GetEntity(opts1);
                    if (ent1.Status == PromptStatus.Cancel) return; // exit the function
                    // reads the selected block and extracts properties and attributes
                    elevation = ReadBlock(ent1.ObjectId);
                    string bname = elevation.blkName.Substring(0, 3);
                    if (!BlockFilter("bed filter", bname))
                    {
                        System.Windows.Forms.MessageBox.Show("\nMust be a valid TGDraw block, try again: ");
                    }
                    else
                    {
                        break;
                    }
                }
Scott G. Sawdy
scott.sawdy@bluecoyotecad.com
0 Likes
Message 4 of 10

nghia_pt
Contributor
Contributor

Hi _gile,

I cannot use methode SendStringToExcute in a loop. Thanks for your help.

This is my code :

 

 

for (int i =0;i<2;i++)
         {
            var entityOptions = new PromptSelectionOptions();
            entityOptions.MessageForAdding = "\nSelect polylines";
            var promptSelectionResult = Editor.GetSelection(entityOptions);
            if (promptSelectionResult.Status != PromptStatus.OK)
            {
               return;
            }

            _selectedCurves = promptSelectionResult.GetObject<Curve>();

            using (Transaction trans = Database.TransactionManager.StartTransaction())
            {
               try
               {
                  var polylines = _selectedCurves.JoinAllCurves().Select(x => x.GetEntityToWrite(trans)).Cast<Polyline>().ToList();
                  polylines.ForEach(x => 
                  {
                     Doc.SendStringToExecute($"_.fillet _p _r {radius} {x.GetHandelName()} ", false, false, false);
                  });
                  trans.Commit();
                  count++;
               }
               catch
               {
               }
            }
         }

 

 

And this is the issue:

nghia_pt_0-1673645306985.png

 

0 Likes
Message 5 of 10

_gile
Consultant
Consultant

Hi,

SenStringToExecute runs asynchronously.

Try using Editor.Command instead.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 6 of 10

nghia_pt
Contributor
Contributor

Thanks for your help,

I try to use Editor.Command:

 

//...
 using (Transaction trans = Database.TransactionManager.StartTransaction())
            {
               try
               {
                  var polylines = _selectedCurves.JoinAllCurves().Select(x => x.GetEntityToWrite(trans)).Cast<Polyline>().ToList();
                  polylines.ForEach(x =>
                  {
                     Editor.Command("_.FILLET", "_Polyline", "_Radius", radius, x.Id, "");
                  });
                  trans.Commit();
                  count++;
               }
               catch
               {
               }
            }
//...

 

I do not use  CommandFlag.Session, but the issue  "eInvalidInput" apear.

 
 

nghia_pt_2-1673670669203.png

 

0 Likes
Message 7 of 10

_gile
Consultant
Consultant

This is probably due to the context in which the method is called. Editor.Command can only be used in document context.
Are you calling this method in application context (i.e. modeless UI or CommandFlags.Session)?
In the case of a modeless UI, you can wrap your method in a command (CommandMethod) that you call from your UI with SendStringToExecute, which will have the effect of automatically switching to the document context and locking the document.
From Kean Walmsley's blog:

"Once again there’s our important rule of thumb when it comes to implementing a modeless UI: rather than manually locking the current document, it’s safer to define a command – which will implicitly lock the current document – and call that from the UI via SendStringToExecute()."

 

Anyway, you should provide more informations about how you call this method.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 10

_gile
Consultant
Consultant

Another way would be to avoid calling an AutoCAD command by using the extension methods below (taken from the GeometryExtensions library).

        /// <summary>
        /// Adds an arc (fillet), when possible, at each vertex.
        /// </summary>
        /// <param name="pline">The instance to which this method applies.</param>
        /// <param name="radius">The arc radius.</param>
        public static void FilletAll(this Polyline pline, double radius)
        {
            int n = pline.Closed ? 0 : 1;
            for (int i = n; i < pline.NumberOfVertices - n; i += 1 + pline.FilletAt(i, radius))
            { }
        }

        /// <summary>
        /// Adds an arc (fillet), when possible, at specified vertex.
        /// </summary>
        /// <param name="pline">The instance to which this method applies.</param>
        /// <param name="index">The vertex index.</param>
        /// <param name="radius">The arc radius.</param>
        /// <returns>1, if the operation succeded; 0, if it failed</returns>
        public static int FilletAt(this Polyline pline, int index, double radius)
        {
            int prev = index == 0 && pline.Closed ? pline.NumberOfVertices - 1 : index - 1;
            if (pline.GetSegmentType(prev) != SegmentType.Line ||
                pline.GetSegmentType(index) != SegmentType.Line)
            {
                return 0;
            }
            LineSegment2d seg1 = pline.GetLineSegment2dAt(prev);
            LineSegment2d seg2 = pline.GetLineSegment2dAt(index);
            Vector2d vec1 = seg1.StartPoint - seg1.EndPoint;
            Vector2d vec2 = seg2.EndPoint - seg2.StartPoint;
            double angle = (Math.PI - vec1.GetAngleTo(vec2)) / 2.0;
            double dist = radius * Math.Tan(angle);
            if (dist == 0.0 || dist > seg1.Length || dist > seg2.Length)
            {
                return 0;
            }
            Point2d pt1 = seg1.EndPoint + vec1.GetNormal() * dist;
            Point2d pt2 = seg2.StartPoint + vec2.GetNormal() * dist;
            double bulge = Math.Tan(angle / 2.0);
            if (Clockwise(seg1.StartPoint, seg1.EndPoint, seg2.EndPoint))
            {
                bulge = -bulge;
            }
            pline.AddVertexAt(index, pt1, bulge, 0.0, 0.0);
            pline.SetPointAt(index + 1, pt2);
            return 1;
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 10

nghia_pt
Contributor
Contributor

Hi _gile,

This is my code:

   public class MultiFilletCmd : ICadCommand
   {
      [CommandMethod("MultiFillet")]
      public override void Execute()
      {
         var doc = Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument;
         var entityOptions = new PromptSelectionOptions();
         entityOptions.MessageForAdding = "\nSelect polylines";

         double radius = doc.GetNumberFromUser("Enter the radius");
         while (true)
         {
            var promptSelectionResult = doc.Editor.GetSelection(entityOptions);

            if (promptSelectionResult.Status == PromptStatus.Cancel)
            {
               return;
            }

            if (promptSelectionResult.Status != PromptStatus.OK)
            {
               break;
            }

            var selectedCurves = promptSelectionResult.GetObject<Curve>();

            using (Transaction trans = doc.Database.TransactionManager.StartTransaction())
            {
               try
               {
                  var polylines = selectedCurves.JoinAllCurves().Select(x => x.GetEntityToWrite(trans)).Cast<Polyline>().ToList();
                  polylines.ForEach(x =>
                  {
                     doc.Editor.Command("_.FILLET", "_Polyline", "_Radius", radius, x.Id, "");
                  });
                  trans.Commit();
               }
               catch
               {
               }
            }
         }
      }
   }

I known your methode "FilletAll". It is very usefull. But I can use for the polyline which has some arc segments. So I try to use Editor.Command to call Fillet command. But, I met "eInvalidInput" issue. I don't know why.

 

0 Likes
Message 10 of 10

nghia_pt
Contributor
Contributor
When I run this code by click to button, this issue apear.
0 Likes