I have a task that requires me to automate the export of a DWG to SAT without user interaction. I have to find a visible 3DSolid in the DWG database and select it programatically as users do when they have to export solids manually from the File menu to ACIS SAT format.
I acheived the task but because I am new to AutoCAD it's very ugly and seems inefficient. I'd like to ask for some help to find a nicer .NET solution to this:
First of all, I can find the solid I want using .NET API with this function:
Public Function GetVisible3dSolid(Optional ByVal Visible As Boolean = True) As Object
Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
Using tr As Transaction = db.TransactionManager.StartTransaction()
For i As Long = db.BlockTableId.Handle.Value To db.Handseed.Value - 1
Dim id As ObjectId = ObjectId.Null
Dim h As New Handle(i)
If db.TryGetObjectId(h, id) Then
If id.ObjectClass.Name = "AcDb3dSolid" Then
Dim ent As Entity = CType(tr.GetObject(id, OpenMode.ForRead, True), Entity)
If ent.Visible = Visible Then
tr.Commit()
Return id
End If
End If
End If
Next
tr.Commit()
End Using
Return Nothing
End Function
But I can't find a good .NET solution to how to select this ObjectID in a AcadSelectionSet.
I ended up coding it up in COM: I select AcSelect.acSelectionSetAll and when I loop through the selection I place everything in a removeObjects list EXCEPT the solid I just found above. Then I call RemoveItems on my AcadSelectionSet to remove everything EXCEPT my solid. What I would want ideally is to use AddItems to do the opposite: add my solid as the only selected object and then call Export. Is there a way to do this (if possible using .NET)
Here is my current code:
Public Function ExportDWG2SAT(ByVal lsFullName As String) As Object
Dim ssetObj As AcadSelectionSet
Dim removeObjects As New List(Of AcadEntity)
Dim sImage_Type = "SAT"
ssetObj = m_currentDoc.SelectionSets.Add("SSALL") ' creates named selection set
ssetObj.Select(AcSelect.acSelectionSetAll) 'select everything in the drawing
Dim my3DSolidObj As Object = GetVisible3dSolid()
If Not IsNothing(my3DSolidObj) Then
Dim my3DSolid As ObjectId = CType(my3DSolidObj, ObjectId)
For Each ent As AcadEntity In ssetObj
Select Case ent.ObjectName
Case "AcDb3dSolid"
If ent.ObjectID <> CType(my3DSolid.OldIdPtr, Long) Then
removeObjects.Add(ent)
End If
Case Else
removeObjects.Add(ent)
End Select
Next
Dim removeArr() As AcadEntity = removeObjects.ToArray
ssetObj.RemoveItems(removeArr)
m_currentDoc.Export(lsFullName, sImage_Type, ssetObj)
End If
Return Nothing
End Function
I could not find API method to use Export ,
Try this code instead
Imports Autodesk.AutoCAD.Interop -------------------------------- <CommandMethod("exsat")> _ Public Shared Sub testSolidsSelect() Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim ed As Editor = doc.Editor Dim db As Database = HostApplicationServices.WorkingDatabase Dim tr As Transaction = db.TransactionManager.StartTransaction() Dim sImage_Type = "SAT" Dim satFullName As String = "C:\Test\mySolids.sat" Try ''Dim curlay As String = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("clayer").ToString() Dim curtab As String = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("ctab").ToString() Dim values(4) As TypedValue values(0) = New TypedValue(DxfCode.Operator, "<and") values(1) = New TypedValue(DxfCode.Start, "3dsolid") values(2) = New TypedValue(DxfCode.Visibility, 0) values(3) = New TypedValue(DxfCode.LayoutName, curtab) values(4) = New TypedValue(DxfCode.Operator, "and>") Dim selFilter As New SelectionFilter(values) Dim prompSelRes As PromptSelectionResult = ed.SelectAll(selFilter) If prompSelRes.Status <> PromptStatus.OK Then Return Dim oSset As SelectionSet = prompSelRes.Value ed.WriteMessage(vbLf + "{0}", oSset.Count) ed.SetImpliedSelection(oSset) Dim AcApp As Autodesk.AutoCAD.Interop.AcadApplication = DirectCast(Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication, Autodesk.AutoCAD.Interop.AcadApplication) Dim ThisDrawing As Autodesk.AutoCAD.Interop.AcadDocument = AcApp.ActiveDocument Dim pickSset As AcadSelectionSet = ThisDrawing.PickfirstSelectionSet ThisDrawing.Export(satFullName, sImage_Type, pickSset) pickSset.Clear() pickSset = Nothing ThisDrawing = Nothing AcApp = Nothing ed.Regen() Catch ex As Autodesk.AutoCAD.Runtime.Exception Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(ex.ToString & vbLf & ex.Message) Finally Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("Find file " & satFullName & " to see result") End Try End Sub
Thanks Hallex,
This solution works great if you get the selection from the user and you can use the Editor's SelectionFilter.
My problem is that
A) I can't figure out how to create such a selection filter that can be passed to the COM Select call without getting the user/editor involved:
AcadSelectionSet.Select(AcSelect.acSelectionSetAll, [Point1 as Object], [Point2 as Object], [FilterType as Object], [FilterData as Object])
I imagine I need something like this:
1 2 3 4 5 6 | Dim my3DSolid As ObjectId = CType(my3DSolidObj, ObjectId) Dim FilterType(0) As Int16 Dim FilterData(0) As Object FilterType(0) = 0 FilterData(0) = "3dSolid" ssetObj.Select(AcSelect.acSelectionSetAll, , FilterType, FilterData) |
Unfortunately this will not work: how do I tell it to select my3DSolid? I tried different combinations for lines 4 and 5 including passing the ObjectID, my problem is I can't find a good documentation of how to use this API, a link to that would probably help too.
B) How to do this in .NET, meaning what's the corresponding Select API in .NET and how to use it, again without the Editor.
@Anonymous wrote:
Thanks Hallex,
This solution works great if you get the selection from the user and you can use the Editor's SelectionFilter.
...
B) How to do this in .NET, meaning what's the corresponding Select API in .NET and how to use it, again without the Editor.
?? Selectionsets with .NET are avaialble only through the Editor namespace. You want to use .net but don't want to use the Editor namespace? Just because it says "Editor" does not men it will require user interaction. Did you try Hallex's code? It should do exactly what you are asking for.
My apologies I wasn't precise in my previous response. I did try the code and it fails on the line (17) that checks PromptStatus:
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 32 33 34 35 36 37 38 39 40 | Public Function ExportDWG2SAT(ByVal lsFullName As String) As Object Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim ed As Editor = doc.Editor Dim db As Database = HostApplicationServices.WorkingDatabase Dim tr As Transaction = db.TransactionManager.StartTransaction() Dim oSset As SelectionSet = Nothing Dim sImage_Type = "SAT" Try Dim curtab As String = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("ctab").ToString() Dim values(4) As TypedValue values(0) = New TypedValue(DxfCode.Operator, "<and") values(1) = New TypedValue(DxfCode.Start, "3dsolid") values(2) = New TypedValue(DxfCode.Visibility, 0) values(3) = New TypedValue(DxfCode.LayoutName, curtab) values(4) = New TypedValue(DxfCode.Operator, "and>") Dim selFilter As New SelectionFilter(values) Dim prompSelRes As PromptSelectionResult = ed.SelectAll(selFilter) If prompSelRes.Status <> PromptStatus.OK Then log.Error("prompSelRes.Status: {0}", prompSelRes.Status) Return Nothing End If oSset = prompSelRes.Value ed.WriteMessage(vbLf + "{0}", oSset.Count) ed.SetImpliedSelection(oSset) Dim AcApp As Autodesk.AutoCAD.Interop.AcadApplication = DirectCast(Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication, Autodesk.AutoCAD.Interop.AcadApplication) Dim ThisDrawing As Autodesk.AutoCAD.Interop.AcadDocument = AcApp.ActiveDocument Dim pickSset As AcadSelectionSet = ThisDrawing.PickfirstSelectionSet ThisDrawing.Export(lsFullName, sImage_Type, pickSset) pickSset.Clear() pickSset = Nothing ThisDrawing = Nothing AcApp = Nothing ed.Regen() Catch Return SetApiException(Err.GetException, String.Format("ERROR:134 Can't export '{0}'", lsFullName), DisplayExceptions) End Try Return Nothing End Function |
The problem seems to be line 17. prompSelRes.Status comes back with "Error" and the prompSelRes.Value will be empty and when it hits line 22 it errors out with 'Object reference not set to an instance of an object.'. (obviously this only hits if I take out "Return Nothing", I tried many other iterations with no avail)
Again, your help is very much appreciated and I thank you for your patience I am very new to this.
Dear Hallex,
I use the code in my project,but dont work, but i cant find the result .sat in the specified position
i take out the try -cath,then i meet the error“System.AccessViolationException”;why.could somebody help me
best wishes to you
Can't find what you're looking for? Ask the community or share your knowledge.