Recreating the "Shrink Wrap Linework" command in C#

Recreating the "Shrink Wrap Linework" command in C#

dalexanderSP3WJ
Enthusiast Enthusiast
2,345 Views
10 Replies
Message 1 of 11

Recreating the "Shrink Wrap Linework" command in C#

dalexanderSP3WJ
Enthusiast
Enthusiast

Greetings everyone, 

 

I am trying to programmatically create a "profile" or "Shrink Wrap Outline" around a collection of Curve objects (only Arcs, Lines, and Polylines). I have not seen any C-Sharp documentation or support on this topic, though I have found the command written in LISP, which is not really helpful.

 

Im really only concerned with creating the outline around the curves objects, and don't care much about "islands" that exist inside of the outline. 

 

Here are two links that describe exactly what I am trying to recreate in C# in more detail:

https://knowledge.autodesk.com/support/autocad-architecture/learn-explore/caas/CloudHelp/cloudhelp/2...

 

http://files.carlsonsw.com/mirror/manuals/Carlson_2021/source/General/Draw/ShrinkWrap_Entities/Shrin...

 

A great thank you to anyone who can help!

0 Likes
Accepted solutions (2)
2,346 Views
10 Replies
Replies (10)
Message 2 of 11

_gile
Consultant
Consultant
Accepted solution

Hi,

You should get some inspiration from this reply.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 11

dalexanderSP3WJ
Enthusiast
Enthusiast
You have saved the day once again!! Thank you so much!
0 Likes
Message 4 of 11

dalexanderSP3WJ
Enthusiast
Enthusiast

@_gile In the post you referenced, your are returning an IEnumerable<Polyline> object, could you point me to some documentation that shows how to display the final "Shrinkwrap" Polyline in the editor?

0 Likes
Message 5 of 11

dalexanderSP3WJ
Enthusiast
Enthusiast

@_gile Here is the command I am trying to write for more context

 

[CommandMethod("ShrinkWrap", CommandFlags.Session)]
public void ShrinkWrapLinework()
{
    Initializer.init(this);
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    try 
    {
        PromptPointOptions ptOpts1 = new PromptPointOptions("\nSelect the first corner of Crossing Window: ");
        PromptPointResult ptRes1 = ed.GetPoint(ptOpts1);
        PromptPointOptions ptOpts2 = new PromptPointOptions("\nSelect the second corner of Crossing Window: ");
        PromptPointResult ptRes2 = ed.GetPoint(ptOpts2);
        if (ptRes1.Status == PromptStatus.OK &&
            ptRes2.Status == PromptStatus.OK)
        {
            Point3d p1 = ptRes1.Value;
            Point3d p2 = ptRes2.Value;

            PromptSelectionResult windowSelection = ed.SelectCrossingWindow(p1, p2);
            SelectionSet ss = windowSelection.Value;

            if (ss != null)
            {
                Tools.HandleTransaction(doc, (Transaction trans, BlockTableRecord btr) =>
                {
                    List<Polyline> plineList = new List<Polyline>();
                    foreach (SelectedObject selObj in ss)
                    {
                        DBObject foundObj = trans.GetObject(selObj.ObjectId, OpenMode.ForWrite) as DBObject;
                        if (foundObj.GetType() == typeof(Polyline))
                        {
                            using (Polyline pline = (Polyline)foundObj)
                            {
                                plineList.Add(pline);
                            }
                        }
                    }
                    
                    // ShrinkWrap the Polylines
                    IEnumerable<Polyline> plineCollection = plineList;
                    plineCollection = ObjectExtensions.ShrinkWrapPolylines(plineCollection);

                    foreach (Polyline pline in plineCollection)
                    {
                        pline.SetDatabaseDefaults();
                        pline.Thickness = 2;
                        pline.Color = Color.FromRgb(255, 0, 0);
                    }
                }, OpenMode.ForWrite);
            }
        }
    }
    catch (System.Exception ex)
    {
        Tools.Log("Shrinkwrap Error: \n" + ex.Message);
    }
}

I am getting a an "Unhandled Memory" Exception when I try to re-set the plineCollection variable. I have also added the code you pointed me to in the original post in a separate class for brevity. 

0 Likes
Message 6 of 11

_gile
Consultant
Consultant
Accepted solution

The 'Union' method of the code in the referenced post returns an IEnumerable<Polyline>. The calling method is responsible to add these polylines to a Database or Dispose of them.

 

About the the command you are trying to write:

  • Why do you set the CommandFags.Session?
  • After each prompt for user input, you should check the PromptResult.Status value and stop the execution if it's different from PromptStatus.OK.
  • You should use a SelectionFilter to ensure all entities in the selection set are closed polylines.
  • You do not need to convert the List<Polyline> into an IEnumerable<Polyline> because List<T> implements IEnumerable<T>.

 

Try something like this:

[CommandMethod("ShrinkWrap")]
public static void ShrinkWrapLinework()
{
    var doc = Application.DocumentManager.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;

    var pointResult = ed.GetPoint("\nSelect the first corner of Crossing Window: ");
    if (pointResult.Status != PromptStatus.OK)
        return;
    var pt1 = pointResult.Value;

    pointResult = ed.GetCorner("\nSelect the second corner of Crossing Window: ", pt1);
    if (pointResult.Status != PromptStatus.OK)
        return;
    var pt2 = pointResult.Value;

    var filter = new SelectionFilter(new[]
        {
            new TypedValue(0, "LWPOLYLINE"),
            new TypedValue(-4, "&"),
            new TypedValue(70, 1)
        });
    var selection = ed.SelectCrossingWindow(pt1, pt2, filter);
    if (selection.Status != PromptStatus.OK)
        return;

    using (var tr = db.TransactionManager.StartOpenCloseTransaction())
    {
        var source = new List<Polyline>();
        foreach (ObjectId id in selection.Value.GetObjectIds())
        {
            source.Add((Polyline)tr.GetObject(id, OpenMode.ForRead));
        }
        var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

        // Add the ShrinkWrap Polylines to the current space
        foreach (var pline in ObjectExtensions.ShrinkWrapPolylines(source))
        {
            pline.Thickness = 2;
            pline.ColorIndex = 1;
            curSpace.AppendEntity(pline);
            tr.AddNewlyCreatedDBObject(pline, true);
        }
        tr.Commit();
    }
}

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 11

dalexanderSP3WJ
Enthusiast
Enthusiast
I set CommandFlags.Session thinking that this allows the subsequent command thats written to be accessed throughout the entire AutoCAD Session instead of just the current document. However I just copied and pasted your code and it worked fine without CommandFlags.Session, so I really didn't understand what it actually does.

I am very thankful for your hard work and thorough explanations, I extend my gratitude once again.
0 Likes
Message 8 of 11

_gile
Consultant
Consultant

@dalexanderSP3WJ  a écrit :
I set CommandFlags.Session thinking that this allows the subsequent command thats written to be accessed throughout the entire AutoCAD Session instead of just the current document.

The CommandFlags.Session is used to run the command in Application context instead of Document context (as modeless UI).

It is required when the command switches between different Documents (e.g. open an existing document or add a new one to the active document collection).

When a command is decored with this flag, you need to Lock the document before editing its Database.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 11

dalexanderSP3WJ
Enthusiast
Enthusiast
Thank you for the clarification, I appreciate it.
0 Likes
Message 10 of 11

m.bakkerC8KLN
Contributor
Contributor

Hi Gile, 

 

The ObjectExtensions.ShrinkWarpPolylines doesn't exist in the current content. Can you help me solve this error?

 

0 Likes
Message 11 of 11

_gile
Consultant
Consultant

@m.bakkerC8KLN wrote:

Hi Gile, 

 

The ObjectExtensions.ShrinkWarpPolylines doesn't exist in the current content. Can you help me solve this error?

 


You should ask @dalexanderSP3WJ

This came from his code, not mine.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes