Kean Walmsley


  • About the Author
    Kean on Google+

July 2014

Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    








« A 2nd Photo Scene Editor/Photofly Competition | Main | Previewing the contents of the clipboard in an AutoCAD palette using .NET »

October 19, 2010

Changing the relative draw-order of AutoCAD objects based on their layer

Terry Dotson has – once again – generously offered an application to be an ADN Plugin of the Month. This little tool, called DrawOrderByLayer, allows you to modify the draw-order of objects in an AutoCAD drawing according to the layer they’re on. I don’t expect this to go live for another month or so (I still have plans for November’s plugin), but I did want to post it in order to give people the chance to provide feedback.

Here’s basically how it works…

You have layers containing geometry – in this case I’ve created circular solid hatches on layers named by their respective colours:

Hatches ready for ordering by layer Loading the DLL and launching the DOBYLAYS command shows a simple dialog:

Our DrawOrderByLayer dialog Once you’ve ticked/checked the layers you care about and have moved them into an appropriate relative order, clicking OK selects the objects on each layer and uses the DrawOrderTable to bring them to the top. In our case we have asked for Red, Yellow, Green and Blue to be brought to the the top (Red being the topmost of them):

The ordered layers I’ve made a few cosmetic changes to Terry’s code, but it’s mostly his. There may well be further changes prior to the eventually posting – I’m wondering if it’s worth streamlining the DrawOrderTable calls, for instance – but I (and, I’m sure, Terry, also) would appreciate any feedback people would like to provide, in the meantime.

Here’s the main VB.NET file:

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.Runtime

Imports DrawOrderByLayer.DemandLoading

 

Public Class Commands

 

  Implements IExtensionApplication

 

  ' AutoCAD fires the Initialize Sub when the assembly is loaded,

  ' so we check to see if the command is registered by looking for

  ' the existance of the Registry keys.  If not found, we attempt

  ' to add them so the command will automatically load in future

  ' sessions.  This means it only needs to be NETLOADed once.

 

  Public Sub Initialize() Implements IExtensionApplication.Initialize

    RegistryUpdate.RegisterForDemandLoading()

  End Sub

 

  Public Sub Terminate() Implements IExtensionApplication.Terminate

    ' Only fires when AutoCAD is shutting down

  End Sub

 

  <CommandMethod("ADNPLUGINS", "REMOVEDO", CommandFlags.Modal)> _

  Public Shared Sub RemoveDrawOrderByLayer()

    RegistryUpdate.UnregisterForDemandLoading()

  End Sub

 

  ' Establish our command name to use to start the tool.  It

  ' dimensions an instance of the form and displays it with

  ' AutoCAD's ShowModalDialog.  Don't use Windows Form.Show!

 

  <CommandMethod("ADNPLUGINS", "DOBYLAY", CommandFlags.Modal)> _

  Public Shared Sub OrderByLayer()

    Using dlg As New OrderDialog()

      Application.ShowModalDialog(dlg)

    End Using

  End Sub

 

End Class

Here’s the dialog implementation file:

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.DatabaseServices

Imports Autodesk.AutoCAD.EditorInput

Imports Autodesk.AutoCAD.Runtime

 

Public Class OrderDialog

 

  'Related System Variables

  '  DRAWORDERCTL: Controls the display order of overlapping objects.

  '    Improves editing speed in large drawings

  '  SORTENTS: Controls object sorting in support of draw order for

  '    several operations.

 

  Private Sub MainForm_Load( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles MyBase.Load

 

    ' Populate layer list with layers (in order created)

 

    Dim db As Database = _

      Application.DocumentManager.MdiActiveDocument.Database

 

    Using tr As Transaction = _

      db.TransactionManager.StartTransaction

      Dim lt As LayerTable = _

        tr.GetObject(db.LayerTableId, OpenMode.ForRead)

      For Each id As ObjectId In lt

        Dim ltr As LayerTableRecord = _

          tr.GetObject(id, OpenMode.ForRead)

        If ltr.IsDependent = False Then

          LayLst.Items.Add(ltr.Name)

        End If

      Next

      tr.Commit() ' Cheaper to commit than abort

    End Using

 

  End Sub

 

  Private Sub Accept_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles Accept.Click

 

    If LayLst.CheckedItems.Count > 0 Then

 

      ' Build list of layers from those checked, then reverse it

 

      Dim revLst As New List(Of String)

      For Each TxtStr As String In LayLst.CheckedItems

        revLst.Add(TxtStr)

      Next

      revLst.Reverse()

 

      ' Get modelspace objects on each layer and pass to

      ' DrawOrderTable.MoveToTop()

 

      Dim doc As Document = _

        Application.DocumentManager.MdiActiveDocument

      Dim db As Database = doc.Database

      Dim ed As Editor = doc.Editor

 

      Using tr As Transaction = _

        db.TransactionManager.StartTransaction

        Dim bt As BlockTable = _

          tr.GetObject(db.BlockTableId, OpenMode.ForWrite)

        Dim btr As BlockTableRecord = _

          tr.GetObject( _

            bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)

        Dim dot As DrawOrderTable = _

          tr.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite)

        Using pm As New ProgressMeter

          pm.Start("Processing: ")

          pm.SetLimit(LayLst.CheckedItems.Count)

          For Each lay As String In revLst

            Dim psr As PromptSelectionResult

            Dim tvs(0) As TypedValue

            tvs(0) = New TypedValue(DxfCode.LayerName, lay)

            Dim sf As New SelectionFilter(tvs)

            psr = ed.SelectAll(sf)

            If psr.Value IsNot Nothing Then

              dot.MoveToTop( _

                New ObjectIdCollection(psr.Value.GetObjectIds))

            End If

            pm.MeterProgress()

            System.Windows.Forms.Application.DoEvents()

          Next

          pm.Stop()

        End Using

        tr.Commit()

      End Using

      ed.Regen()

    End If

    Me.Close()

  End Sub

 

  Private Sub Cancel_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles Cancel.Click

 

    Me.Close()

  End Sub

 

  Private Sub LayInv_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles LayInv.Click

 

    For AI As Integer = 0 To LayLst.Items.Count - 1

      LayLst.SetItemChecked(AI, Not LayLst.GetItemChecked(AI))

    Next

  End Sub

 

  Private Sub LaySrt_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles LaySrt.Click

 

    LayLst.Sorted = True

    LayLst.Sorted = False

  End Sub

 

  Private Sub MovUpp_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles MovUpp.Click

 

    If LayLst.SelectedIndex > 0 Then

      Dim OldChk As Boolean = _

        LayLst.GetItemChecked(LayLst.SelectedIndex - 1)

      LayLst.Items.Insert( _

        LayLst.SelectedIndex + 1, _

        LayLst.Items(LayLst.SelectedIndex - 1))

      LayLst.Items.RemoveAt( _

        LayLst.SelectedIndex - 1)

      LayLst.SetItemChecked( _

        LayLst.SelectedIndex + 1, OldChk)

    End If

  End Sub

 

  Private Sub MovDnn_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles MovDnn.Click

 

    If LayLst.SelectedIndex < LayLst.Items.Count - 1 Then

      Dim OldChk As Boolean = _

        LayLst.GetItemChecked(LayLst.SelectedIndex + 1)

      LayLst.Items.Insert( _

        LayLst.SelectedIndex, LayLst.Items(LayLst.SelectedIndex + 1))

      LayLst.Items.RemoveAt( _

        LayLst.SelectedIndex + 1)

      LayLst.SetItemChecked( _

        LayLst.SelectedIndex - 1, OldChk)

    End If

  End Sub

 

  Private Sub SelAll_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles SelAll.Click

 

    For I As Int16 = 0 To LayLst.Items.Count - 1

      LayLst.SetItemChecked(I, True)

    Next

  End Sub

 

  Private Sub SelNon_Click( _

    ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles SelNon.Click

 

    For I As Int16 = 0 To LayLst.Items.Count - 1

      LayLst.SetItemChecked(I, False)

    Next

  End Sub

 

End Class

And here’s the project. Thanks for providing this sample, Terry!

blog comments powered by Disqus

10 Random Posts