Polyline3d.InsertVertexAt crashes Program

Polyline3d.InsertVertexAt crashes Program

bwang-tecoustics
Collaborator Collaborator
2,792 Views
12 Replies
Message 1 of 13

Polyline3d.InsertVertexAt crashes Program

bwang-tecoustics
Collaborator
Collaborator

I was testing to insert a vertex at a polyline using InsertVertexAt method. But it just crashes every time. Is there anything wrong? The code was copied from a vertex removal code. The removal worked fine. I then try to convert it to add a vertex just 10 units next to the index vertex and failed.

 

        <CommandMethod("R3DV")> _
        Public Shared Sub RemoveVertex()


            Dim doc As Document = Application.DocumentManager.MdiActiveDocument

            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor


            Using oTr As Transaction = db.TransactionManager.StartTransaction

                Dim ids As New ObjectIdCollection

                Dim options As New PromptEntityOptions(vbLf & "Pick a 3DPolyline:")

                options.SetRejectMessage("Select 3DPolyline only" + vbLf)
                options.AddAllowedClass(GetType(Polyline3d), True)

                Dim result As PromptEntityResult = ed.GetEntity(options)

                If result.Status <> PromptStatus.OK Then
                    Return
                End If

                ' Polyline3D object
                Dim oEnt As Polyline3d = TryCast(oTr.GetObject(result.ObjectId, OpenMode.ForRead), Polyline3d)


                ' Find each vertex in 3D Polyline
                For Each oVtId As ObjectId In oEnt

                    Dim oVt As PolylineVertex3d = TryCast(oTr.GetObject(oVtId, OpenMode.ForRead), PolylineVertex3d)

                    Dim oPko As New PromptKeywordOptions(vbLf & "Want to remove vertex at " + oVt.Position.ToString() + "?")
                    oPko.AllowNone = False
                    oPko.Keywords.Add("Yes")
                    oPko.Keywords.Add("No")
                    oPko.Keywords.[Default] = "No"

                    Dim oPkr As PromptResult = ed.GetKeywords(oPko)

                    If oPkr.Status = PromptStatus.OK AndAlso oPkr.StringResult = "Yes" Then
                        ids.Add(oVtId) ' ids stores verteies object id's.
                    End If
                Next

                For Each oVtId As ObjectId In ids

                    Dim oVt As PolylineVertex3d = TryCast(oTr.GetObject(oVtId, OpenMode.ForWrite), PolylineVertex3d)
                    Dim nVtP3d As Point3d = New Point3d(oVt.Position.X + 10, oVt.Position.Y, oVt.Position.Z)
                    Dim nVt As PolylineVertex3d = New PolylineVertex3d(nVtP3d)
                    Try
                        oEnt.InsertVertexAt(oVt, nVt)
                    Catch ex As Autodesk.AutoCAD.Runtime.Exception
                        MsgBox(ex.ToString)
                    End Try

                    'oVt.[Erase]()
                Next

                If ids.Count <> 0 Then

                    oEnt.UpgradeOpen() ' Upgrade open mode from readonly to write.
                    'oTr.AddNewlyCreatedDBObject(nVt, True)
                    oEnt.RecordGraphicsModified(True)
                End If

                oTr.Commit()
            End Using

        End Sub
0 Likes
Accepted solutions (1)
2,793 Views
12 Replies
Replies (12)
Message 2 of 13

ActivistInvestor
Mentor
Mentor

As a general rule, you should first try to identify what is causing the crash by placing the entire method's body inside a Try block, and inside the following Catch block, display the exception in a message box.

 

Your code uses try/catch to trap an exception thrown by InsertVertexAt(), but if the exception is thrown by other code, it will not be caught and you won't find out what code caused it.

 

The other problem is that you are inserting vertices into the polyline while you are iterating over the existing vertices. You can't do that. You have to store all of the new vertices that you're going to insert in a List, and after you exit the For Each/Next loop, then you insert all of the new vertices from the list into the Polyline.

 

 

So, I'll speculate that your problem is either an eNotOpenForWrite because you are inserting vertices into the polyline (e.g., modifying it), before you call UpgradeOpen() to upgrade the polyline's open mode to OpenMode.ForWrite, or the problem is that you're inserting vertices while enumerating over the existing ones within a For Each/Next loop.

 

 

Message 3 of 13

bwang-tecoustics
Collaborator
Collaborator

I made two changes and the code is working now.

1. Move the UpgradeOpen to before the InsertVertexAt.

2. Use InsertVertexAt(ObjectId, PolylineVertex3d) instead of InsertVertexAt(PolylineVertex3d, PolylineVertex3d). Still don't know why the InsertVertexAt(PolylineVertex3d, PolylineVertex3d) doesn't work.

 

        <CommandMethod("R3DV")> _
        Public Shared Sub RemoveVertex()


            Dim doc As Document = Application.DocumentManager.MdiActiveDocument

            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor


            Using oTr As Transaction = db.TransactionManager.StartTransaction

                Dim ids As New ObjectIdCollection

                Dim options As New PromptEntityOptions(vbLf & "Pick a 3DPolyline:")

                options.SetRejectMessage("Select 3DPolyline only" + vbLf)
                options.AddAllowedClass(GetType(Polyline3d), True)

                Dim result As PromptEntityResult = ed.GetEntity(options)

                If result.Status <> PromptStatus.OK Then
                    Return
                End If

                ' Polyline3D object
                Dim oEnt As Polyline3d = TryCast(oTr.GetObject(result.ObjectId, OpenMode.ForRead), Polyline3d)


                ' Find each vertex in 3D Polyline
                For Each oVtId As ObjectId In oEnt

                    Dim oVt As PolylineVertex3d = TryCast(oTr.GetObject(oVtId, OpenMode.ForRead), PolylineVertex3d)

                    Dim oPko As New PromptKeywordOptions(vbLf & "Want to remove vertex at " + oVt.Position.ToString() + "?")
                    oPko.AllowNone = False
                    oPko.Keywords.Add("Yes")
                    oPko.Keywords.Add("No")
                    oPko.Keywords.[Default] = "No"

                    Dim oPkr As PromptResult = ed.GetKeywords(oPko)

                    If oPkr.Status = PromptStatus.OK AndAlso oPkr.StringResult = "Yes" Then
                        ids.Add(oVtId) ' ids stores verteies object id's.
                    End If
                Next

                If ids.Count <> 0 Then

                    oEnt.UpgradeOpen() ' Upgrade open mode from readonly to write.
                    'oTr.AddNewlyCreatedDBObject(nVt, True)
                    oEnt.RecordGraphicsModified(True)
                End If

                For Each oVtId As ObjectId In ids

                    Dim oVt As PolylineVertex3d = TryCast(oTr.GetObject(oVtId, OpenMode.ForWrite), PolylineVertex3d)
                    Dim nVtP3d As Point3d = New Point3d(oVt.Position.X + 10, oVt.Position.Y, oVt.Position.Z)
                    Dim nVt As PolylineVertex3d = New PolylineVertex3d(nVtP3d)
                    Try
                        oEnt.InsertVertexAt(oVt.ObjectId, nVt)
                        'oEnt.InsertVertexAt(oVt, nVt)
                    Catch ex As Autodesk.AutoCAD.Runtime.Exception
                        MsgBox(ex.ToString)
                    End Try

                    'oVt.[Erase]()
                Next

                oTr.Commit()
            End Using

        End Sub
0 Likes
Message 4 of 13

bwang-tecoustics
Collaborator
Collaborator

I'll try next to insert the vertex out of the For each loop.

0 Likes
Message 5 of 13

ActivistInvestor
Mentor
Mentor

@bwang-tecoustics wrote:

I'll try next to insert the vertex out of the For each loop.


The problem is not that. I wasn't looking closely at the code and didn't notice that the second For Each/Next loop is iterating over the ObjectIdCollection, rather than the Polyline itself. That should not be a problem.

 

When you say that InsertVertexAt() doesn't work, is there an exception being thrown?  If there is, you should display the exception on the text console using Editor.WriteMessage(), rather than in a message box, so that you can copy the exception text and paste it into a reply here, because 'not working' isn't very descriptive.

 

Try adding the following line after the call to InsertVertexAt():

 

 


oEnt.InsertVertexAt(oVt.ObjectId, nVt)
nVt.Close()

 

 

 

 

0 Likes
Message 6 of 13

bwang-tecoustics
Collaborator
Collaborator

When I use InsertVertexAt(PolylineVertex3d, PolylineVertex3d), it gives me this:

InsertVertexAt01.png

 

Also, the nVt.Close method is obsolete.

0 Likes
Message 7 of 13

ActivistInvestor
Mentor
Mentor
Accepted solution

@bwang-tecoustics wrote:

When I use InsertVertexAt(PolylineVertex3d, PolylineVertex3d), it gives me this:

 

 

Also, the nVt.Close method is obsolete.


Disregard what the compiler tells you about the Close() method, and use it.

 

The other problem is that your code logic is broken. You test to see if the ObjectIdCollection's Count property is <> 0, and call UpgradeOpen(), but you don't exit the method if the count is 0, and instead, proceed without the UpgradeOpen() call.  The dialog you show an image of is not the dialog you show from the catch block in the code. Showing a dialog or message box could itself be causing a problem. Instead of doing that, write the exception to the command line, using Editor.WriteMessage().

 

I converted your code to C#, corrected the aforementioned errors, and made a few other minor changes (shown in red), and the code runs without any problem:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

namespace ClassLibrary2
{
   public static class InsertVertex3d
   {


      [CommandMethod("R3DV")]
      public static void RemoveVertex()
      {
         Document doc = Application.DocumentManager.MdiActiveDocument;
         Database db = doc.Database;
         Editor ed = doc.Editor;
         using(Transaction oTr = db.TransactionManager.StartOpenCloseTransaction())
         {
            ObjectIdCollection ids = new ObjectIdCollection();
            PromptEntityOptions options = new PromptEntityOptions("\nPick a 3DPolyline:");
            options.SetRejectMessage("Select 3DPolyline only\n");
            options.AddAllowedClass(typeof(Polyline3d), true);
            PromptEntityResult result = ed.GetEntity(options);
            if(result.Status != PromptStatus.OK)
            {
               return;
            }
            // Polyline3D object
            Polyline3d oEnt = oTr.GetObject(result.ObjectId, OpenMode.ForRead) as Polyline3d;
            if(oEnt == null)
            {
               ed.WriteMessage("\nSelected object is not a 3DPOLY");
               return;
            }            
foreach(ObjectId oVtId in oEnt) { PolylineVertex3d oVt = oTr.GetObject(oVtId, OpenMode.ForRead) as PolylineVertex3d; PromptKeywordOptions oPko = new PromptKeywordOptions("\nWant to remove vertex at " + oVt.Position.ToString() + "?"); oPko.AllowNone = false; oPko.Keywords.Add("Yes"); oPko.Keywords.Add("No"); oPko.Keywords.Default = "No"; PromptResult oPkr = ed.GetKeywords(oPko); if(oPkr.Status == PromptStatus.OK && oPkr.StringResult == "Yes") { ids.Add(oVtId); } } if(ids.Count == 0) { return; }
oEnt.UpgradeOpen(); foreach(ObjectId oVtId in ids) { PolylineVertex3d oVt = oTr.GetObject(oVtId, OpenMode.ForWrite) as PolylineVertex3d; Point3d nVtP3d = new Point3d(oVt.Position.X + 10, oVt.Position.Y, oVt.Position.Z); PolylineVertex3d nVt = new PolylineVertex3d(nVtP3d); try { oEnt.InsertVertexAt(oVt.ObjectId, nVt); nVt.Close(); } catch(Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage(ex.ToString()); return; } oEnt.RecordGraphicsModified(true); } oTr.Commit(); } } } }
0 Likes
Message 8 of 13

bwang-tecoustics
Collaborator
Collaborator

Thank you very much.

The reason I didn't post the exception is that the program just crashes everytime and doesn't give itself a chance to show the exception.

0 Likes
Message 9 of 13

bwang-tecoustics
Collaborator
Collaborator

Interesting. Your code just works the same way as mine. If I change your code "oEnt.InsertVertexAt(oVt.ObjectId, nVt);" to "oEnt.InsertVertexAt(oVt, nVt);", my AutoCAD crashes. So, there is a problem with the InsertVertexAt(Polyline3dVertex3d, Polyline3dVertex3d) method. I'll just use the InsertVertexAt(ObjectId, Polyline3dVertex3d) method then.

0 Likes
Message 10 of 13

ActivistInvestor
Mentor
Mentor

@bwang-tecoustics wrote:

Interesting. Your code just works the same way as mine. If I change your code "oEnt.InsertVertexAt(oVt.ObjectId, nVt);" to "oEnt.InsertVertexAt(oVt, nVt);", my AutoCAD crashes. So, there is a problem with the InsertVertexAt(Polyline3dVertex3d, Polyline3dVertex3d) method. I'll just use the InsertVertexAt(ObjectId, Polyline3dVertex3d) method then.


The version of InsertVertexAt() that takes a PolylineVertex3d as the first argument is only for use on new polylines that haven't been added to the database yet.

Message 11 of 13

smx_khang
Contributor
Contributor

This article was from 5 years ago I'm not sure if you're still reading it. (I hope can be useful to someone)
I use AutoCAD 2023. Even when I use the new Polyline, I get a crash.
I have realized that the vertex of the polyline is not allowed to open when calling InsertVertexAt() function.

I succeeded (didn't get any errors) with this code

 

[CommandMethod("Test")]
public void Test()
{
    var ver3d1 = new PolylineVertex3d(Point3d.Origin);
    var ver3d2 = new PolylineVertex3d(new Point3d(1, 1, 0));
    var ver3d3 = new PolylineVertex3d(new Point3d(2, 1, 0));
    var ver3d4 = new PolylineVertex3d(new Point3d(2, 2, 0));

    var db = HostApplicationServices.WorkingDatabase;
    using (var tr = db.TransactionManager.StartTransaction())
    using (var poly = new Polyline3d())
    {
        var btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
        var polId = btr.AppendEntity(poly);
        tr.AddNewlyCreatedDBObject(poly, true);
        poly.AppendVertex(ver3d1);
        poly.AppendVertex(ver3d2);
        poly.AppendVertex(ver3d3);

        ver3d3.Dispose();  // AutoCAD will crashes if ver3d3 opened
        poly.InsertVertexAt(ver3d3, ver3d4);  // Vertex ver3d4 is added before vertex ver3d3.
        tr.Commit();
    }
}

 

 

0 Likes
Message 12 of 13

kerry_w_brown
Advisor
Advisor

@smx_khang 

 

Comment out this line , or remove it

ver3d3.Dispose();  // AutoCAD will crashes if ver3d3 opened

 

Move these lines down so they are just before the tr.commit; statement

        var btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
        var polId = btr.AppendEntity(poly);
        tr.AddNewlyCreatedDBObject(poly, true);

 

Looking at the code logic, I can't understand why you are even using the statement :

poly.InsertVertexAt(ver3d3, ver3d4);

 

. . . unless you just wanted to test what the statement does  . . in which case a more realistic test would have been to make two seperate methods, one to make the poly, another to select and insert the new vertex , perhaps ??

 

Regards,

 

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 13 of 13

smx_khang
Contributor
Contributor

Sorry for the confusing explanation above, @kerry_w_brown .
I was just trying to point out that in certain cases Dispose() is necessary.

Here is a more realistic example of adding a vertex to a polyline. In this case, I need to open Vertex to do some operations on it before adding a vertex to the polyline. If not call Dispose(), AutoCAD will crash.

 

[CommandMethod("TEST")]
public void test()
{
    var res = Application.DocumentManager.MdiActiveDocument.Editor.GetEntity("Select polyline");
    if (res.Status != Autodesk.AutoCAD.EditorInput.PromptStatus.OK)
        return;

    using (var tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
    {
        var newVertex = new PolylineVertex3d(new Point3d(2, 1, 0));
        var poly = tr.GetObject(res.ObjectId, OpenMode.ForWrite) as Polyline3d;

        var pos = poly.GetEnumerator();     // I want to loop thrown all vertices of polyline
        pos.MoveNext(); pos.MoveNext();     // Goto 2nd vertex
        var verid = (ObjectId)pos.Current;  // Get its ID

        var pv3d = verid.GetObject(OpenMode.ForWrite) as PolylineVertex3d;

        // Do something with pv3d....

        // If you don't dispose PolylineVertex3d before attempt to passing it into InsertVertexAt,
        // application will crash. (Or else you should probably use InsertVertexAt(ObjectId, PolylineVertex3d) ). 
        pv3d.Dispose();

        // Safely insert vertex.
        poly.InsertVertexAt(pv3d, newVertex);

        tr.Commit();
    }
}

 

Regards,

0 Likes