Author Topic: Boundary Calculation  (Read 719 times)

0 Members and 1 Guest are viewing this topic.

poncelet

  • Newt
  • Posts: 51
Boundary Calculation
« on: April 30, 2012, 05:11:15 pm »
Hi people,
Ok here we go. This is a good old VBA function i wrote to calculate a boundary by clicking a point. It works even if not all entities are visible in modelspace (better than boundary command). Well it seems sendstringtoexecute is useless. I would appreciate any directions to do the same with .NET.

Code - vb.net: [Select]
  1.    Function calculateBoundary(ByVal PointInside As Object) As AcadEntity
  2.        Dim ent1 As AcadEntity
  3.        Dim ent2 As AcadEntity
  4.        ThisDrawing.SendCommand("-bhatch a r y  p s " & PointInside(0) & "," & PointInside(1) & "  ")
  5.        ent1 = ThisDrawing.ModelSpace.Item(ThisDrawing.ModelSpace.Count - 1)
  6.        ent2 = ThisDrawing.ModelSpace.Item(ThisDrawing.ModelSpace.Count - 2)
  7.        If ent1.ObjectName = "AcDbHatch" And ent2.ObjectName = "AcDbPolyline" Then
  8.            Call delete(ent1)
  9.            Return ent2
  10.        ElseIf ent1.ObjectName = "AcDbHatch" And ent2.ObjectName = "AcDbRegion" Then
  11.            MsgBox("Could not create boundary." & vbLf & "Please check if an spline is part of the boundary entities.")
  12.            Call delete(ent1)
  13.            Call delete(ent2)
  14.            Return Nothing
  15.        Else
  16.            MsgBox("Could not calculate the boundary." & vbLf & "Please try again.")
  17.            Return Nothing
  18.        End If
  19.    End Function
Ce que femme veut, Dieu le veut.

kaefer

  • Swamp Rat
  • Posts: 538
Re: Boundary Calculation
« Reply #1 on: April 30, 2012, 06:22:30 pm »
Well it seems sendstringtoexecute is useless.

In other words, it does what it is supposed to do, but because execution is stayed until the current command finishes, you can't react to the changes effected to the database?  If you insist on doing things the old way, nothing stops you from using SendCommand(), as appropriate from an application context (CommandFlags.Session), and if necessary with DocumentLock in place. The traditionalist would prefer EntLast() and EntNext() to these newfangled indexers too, see Autodesk.AutoCAD.Internal.Utils.

Since rel. 2011, one can also use the Editor.TraceBoundary() method.

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #2 on: May 01, 2012, 04:43:48 am »
Well i started an application with COM references but for compatibility reasons i started replacing the code with .NET. The funny thing is that even with a .NET application not all versions of Autocad are compatible. Also i can't use Traceboundary as i'm using an older API version
Ce que femme veut, Dieu le veut.

kaefer

  • Swamp Rat
  • Posts: 538
Re: Boundary Calculation
« Reply #3 on: May 01, 2012, 01:38:07 pm »
Well i started an application with COM references but for compatibility reasons i started replacing the code with .NET.

That's just as well, since the occasional call into COM can be perfectly handled by late binding. And away go all the reference dependencies on specific versions. The pre-C#-4.0 approach would then look like something as this:

Code - C#: [Select]
  1. public class test
  2. {
  3.    Document doc;
  4.    Database db;
  5.    Editor ed;
  6.  
  7.    public test()
  8.    {
  9.        doc = acadApp.DocumentManager.MdiActiveDocument;
  10.        db = doc.Database;
  11.        ed = doc.Editor;
  12.    }
  13.    void Command(string arg)
  14.    {
  15.        object ActiveDocument = doc.AcadDocument;
  16.        object[] data = { arg };
  17.        ActiveDocument.GetType().InvokeMember(
  18.          "SendCommand",
  19.          System.Reflection.BindingFlags.InvokeMethod,
  20.          null, ActiveDocument, data
  21.        );
  22.    }
  23.    ...
and then further on

Code - C#: [Select]
  1.            // please do remember that there may be users not on an english version
  2.            Command(String.Format(
  3.                "_-bhatch _a _y _r _y  _p _s {0},{1} \n", pt.X, pt.Y ));
« Last Edit: May 01, 2012, 01:43:52 pm by kaefer »

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #4 on: May 01, 2012, 02:00:05 pm »
Give me an address to send you flowers and sweets  :-)
Ce que femme veut, Dieu le veut.

fixo

  • Swamp Rat
  • Posts: 782
  • Pietari, Venäjä
Re: Boundary Calculation
« Reply #5 on: May 02, 2012, 10:32:17 am »
Or the same for interactive point
Code: [Select]
        [DllImport("acad.exe", CharSet = CharSet.Auto,

     CallingConvention = CallingConvention.Cdecl,

     EntryPoint = "?acedPostCommand@@YAHPB_W@Z"

    )]

        extern static private int acedPostCommand(string strExpr);
        [CommandMethod("bha")]
        public static void TestBhatch()
        {
            acedPostCommand("_-bhatch _a _y _r _y  _p _s  \n");
        }

~'J'~
\\\"Always drink upstream from the herd."\\\ - Will Rogers, was died in 1935 plane crash

--> Donate to TheSwamp <--

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #6 on: May 02, 2012, 11:06:13 am »
Does this work with a modeless form?
Ce que femme veut, Dieu le veut.

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #7 on: May 02, 2012, 03:04:22 pm »
Ok this is the .NET version. Thanks again for your help.
Code - vb.net: [Select]
  1.    Function CalculateBoundary(ByVal PointInside As Point3d) As ObjectId
  2.  
  3.        Dim eBefore As Integer
  4.        Dim eAfter As Integer
  5.  
  6.        Using dLock As DocumentLock = doc.LockDocument
  7.            Using trans As Transaction = db.TransactionManager.StartTransaction
  8.                Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead)
  9.                Dim btr As BlockTableRecord = trans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
  10.                eBefore = btr.AcadObject.count()
  11.            End Using
  12.  
  13.            Command("-bhatch a r y  p s " & PointInside(0) & "," & PointInside(1) & "  ")
  14.  
  15.            Using trans As Transaction = db.TransactionManager.StartTransaction
  16.                Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead)
  17.                Dim btr As BlockTableRecord = trans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
  18.                eAfter = btr.AcadObject.count()
  19.  
  20.                If eBefore = eAfter Then
  21.                    MsgBox("Could not calculate the boundary." & vbLf & "Please try again.")
  22.                    Return Nothing
  23.                End If
  24.  
  25.                If Utils.EntLast.ObjectClass.DxfName = "HATCH" Then
  26.                    Using tr As Transaction = db.TransactionManager.StartTransaction
  27.                        Dim h As Hatch = tr.GetObject(Utils.EntLast, OpenMode.ForWrite)
  28.                        h.Erase()
  29.                        tr.Commit()
  30.                    End Using
  31.                End If
  32.  
  33.                Select Case True
  34.                    Case Utils.EntLast.ObjectClass.DxfName = "LWPOLYLINE"
  35.                        trans.Commit()
  36.                        Return Utils.EntLast
  37.  
  38.                    Case Utils.EntLast.ObjectClass.DxfName = "REGION"
  39.                        Using tr As Transaction = db.TransactionManager.StartTransaction
  40.                            Dim r As Region = tr.GetObject(Utils.EntLast, OpenMode.ForWrite)
  41.                            r.Erase()
  42.                            tr.Commit()
  43.                            trans.Commit()
  44.                        End Using
  45.                        MsgBox("Could not create boundary." & vbLf & "Please check if an spline is part of the boundary entities.")
  46.                End Select
  47.  
  48.            End Using
  49.        End Using
  50.  
  51.        Return Nothing
  52.  
  53.    End Function
  54.  

Should i make eBefore and eAfter long type?
« Last Edit: May 02, 2012, 03:11:59 pm by poncelet »
Ce que femme veut, Dieu le veut.

TT

  • Swamp Rat
  • Posts: 814
Re: Boundary Calculation
« Reply #8 on: May 02, 2012, 04:35:55 pm »
Rather than using EntLast(), you can handle the database's ObjectAppended event to capture the Ids of newly-appended objects in a list. The use of the Count property of the AcadBlock AciveX object should be avoided if at all possible, as the underlying implementation must actually iterate over every non-erased object in the block, to produce the count.

Ok this is the .NET version. Thanks again for your help.
Code - vb.net: [Select]
  1.    Function CalculateBoundary(ByVal PointInside As Point3d) As ObjectId
  2.  
  3.        Dim eBefore As Integer
  4.        Dim eAfter As Integer
  5.  
  6.        Using dLock As DocumentLock = doc.LockDocument
  7.            Using trans As Transaction = db.TransactionManager.StartTransaction
  8.                Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead)
  9.                Dim btr As BlockTableRecord = trans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
  10.                eBefore = btr.AcadObject.count()
  11.            End Using
  12.  
  13.            Command("-bhatch a r y  p s " & PointInside(0) & "," & PointInside(1) & "  ")
  14.  
  15.            Using trans As Transaction = db.TransactionManager.StartTransaction
  16.                Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead)
  17.                Dim btr As BlockTableRecord = trans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
  18.                eAfter = btr.AcadObject.count()
  19.  
  20.                If eBefore = eAfter Then
  21.                    MsgBox("Could not calculate the boundary." & vbLf & "Please try again.")
  22.                    Return Nothing
  23.                End If
  24.  
  25.                If Utils.EntLast.ObjectClass.DxfName = "HATCH" Then
  26.                    Using tr As Transaction = db.TransactionManager.StartTransaction
  27.                        Dim h As Hatch = tr.GetObject(Utils.EntLast, OpenMode.ForWrite)
  28.                        h.Erase()
  29.                        tr.Commit()
  30.                    End Using
  31.                End If
  32.  
  33.                Select Case True
  34.                    Case Utils.EntLast.ObjectClass.DxfName = "LWPOLYLINE"
  35.                        trans.Commit()
  36.                        Return Utils.EntLast
  37.  
  38.                    Case Utils.EntLast.ObjectClass.DxfName = "REGION"
  39.                        Using tr As Transaction = db.TransactionManager.StartTransaction
  40.                            Dim r As Region = tr.GetObject(Utils.EntLast, OpenMode.ForWrite)
  41.                            r.Erase()
  42.                            tr.Commit()
  43.                            trans.Commit()
  44.                        End Using
  45.                        MsgBox("Could not create boundary." & vbLf & "Please check if an spline is part of the boundary entities.")
  46.                End Select
  47.  
  48.            End Using
  49.        End Using
  50.  
  51.        Return Nothing
  52.  
  53.    End Function
  54.  

Should i make eBefore and eAfter long type?

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #9 on: May 03, 2012, 04:31:09 am »
Yeah i see. The event will trigger twice after the
Quote
Command("-bhatch a r y  p s " & PointInside(0) & "," & PointInside(1) & "  ")
?
Ce que femme veut, Dieu le veut.

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #10 on: May 03, 2012, 06:13:54 am »
Master something like this?
Code - vb.net: [Select]
  1. Imports Autodesk.AutoCAD.Geometry
  2. Imports Autodesk.AutoCAD.DatabaseServices
  3. Imports Autodesk.AutoCAD.ApplicationServices
  4. Imports Autodesk.AutoCAD.Internal
  5. Imports Orion.Commands
  6.  
  7. Public Class OrionBoundary
  8.  
  9.    Private _EntityCreated As String
  10.  
  11.    Public Function CalculateBoundary(ByVal PointInside As Point3d) As ObjectId
  12.  
  13.        Using dLock As DocumentLock = doc.LockDocument
  14.  
  15.            AddHandler db.ObjectAppended, AddressOf Me.EntityAppended
  16.  
  17.            Command("-bhatch a r y  p s " & PointInside(0) & "," & PointInside(1) & "  ")
  18.  
  19.            RemoveHandler db.ObjectAppended, AddressOf Me.EntityAppended
  20.  
  21.            Using trans As Transaction = db.TransactionManager.StartTransaction
  22.  
  23.                If _EntityCreated = String.Empty Then
  24.                    MsgBox("Could not calculate the boundary." & vbLf & "Please try again.")
  25.                    Return Nothing
  26.                Else
  27.                    'delete the hatch
  28.                    Using tr As Transaction = db.TransactionManager.StartTransaction
  29.                        Dim h As Hatch = tr.GetObject(Utils.EntLast, OpenMode.ForWrite)
  30.                        h.Erase()
  31.                        tr.Commit()
  32.                    End Using
  33.                End If
  34.  
  35.                Select Case True
  36.                    Case _EntityCreated = "LWPOLYLINE"
  37.                        trans.Commit()
  38.                        Return Utils.EntLast
  39.  
  40.                    Case _EntityCreated = "REGION"
  41.                        Using tr As Transaction = db.TransactionManager.StartTransaction
  42.                            Dim r As Region = tr.GetObject(Utils.EntLast, OpenMode.ForWrite)
  43.                            r.Erase()
  44.                            tr.Commit()
  45.                            trans.Commit()
  46.                        End Using
  47.                        MsgBox("Could not create boundary." & vbLf & "Please check if an spline or an ellipse is part of the boundary entities.")
  48.                        Return Nothing
  49.                End Select
  50.  
  51.            End Using
  52.        End Using
  53.  
  54.  
  55.    End Function
  56.  
  57.    Private Sub EntityAppended(ByVal sender As Object, ByVal e As ObjectEventArgs)
  58.  
  59.        Select Case True
  60.            Case e.DBObject.ObjectId.ObjectClass.DxfName = "LWPOLYLINE"
  61.                _EntityCreated = "LWPOLYLINE"
  62.            Case e.DBObject.ObjectId.ObjectClass.DxfName = "REGION"
  63.                _EntityCreated = "REGION"
  64.        End Select
  65.  
  66.    End Sub
  67.  
  68.    Private Sub Command(ByVal arg As String)
  69.        Dim ActiveDocument As Object = doc.AcadDocument
  70.        Dim data As Object() = {arg}
  71.        ActiveDocument.[GetType]().InvokeMember("SendCommand", System.Reflection.BindingFlags.InvokeMethod, Nothing, ActiveDocument, data)
  72.    End Sub
  73.  
  74. End Class
  75.  
« Last Edit: May 03, 2012, 06:33:25 am by poncelet »
Ce que femme veut, Dieu le veut.

TT

  • Swamp Rat
  • Posts: 814
Re: Boundary Calculation
« Reply #11 on: May 03, 2012, 08:08:15 am »
Yes. But for this purpose, your class and all members should be static/shared. You don't need to create an instance of it then, you would just call the method that gets the boundary.

And, you can just store the ObjectId of the appended region/polyline in a static member from the ObjectAppended event handler, and you don't need to use EntLast() at all.

Lastly, you should use Try/Finally, invoke the command in the Try block, and remove the ObjectAppended event handler in the Finally block.
« Last Edit: May 03, 2012, 08:11:17 am by TheMaster »

poncelet

  • Newt
  • Posts: 51
Re: Boundary Calculation
« Reply #12 on: May 03, 2012, 12:16:31 pm »
Yes. But for this purpose, your class and all members should be static/shared. You don't need to create an instance of it then, you would just call the method that gets the boundary.
I invoke the .CreateBoundary method inside another method of a class named OrionParcel so i avoid shared members to keep tracking what i am doing. Well i don't know if my methodology is right.
Ce que femme veut, Dieu le veut.