Batch Export from .prt to .stl

Hi! I am fairly new to journaling in NX and this forum and website have been a fantastic source of knowledge and has provided excellent guidance thus far. Thank you! However, I have run into an issue when trying to batch export my .prt files to .stl files.

I am looking to export ~100 .prt files to the .stl format and have not been able to so far. I have been referencing this link: http://www.nxjournaling.com/content/exporting-stl-files but I cannot get it to work for 1 file let alone the whole batch.

I was hoping someone could provide some guidance or tips so that I can get this working.

Thanks a lot in advance.

What do you want to export from the part file?
All the bodies?
One or more user selected bodies?
A particular body or bodies in a part file based on layer, name, group, etc?

Also, what version of NX are you using?

Hi, thanks for the speedy response. I am looking to export all the bodies in the file.
I am using NX 7.5

Thanks!
J

Try the following journal. It will collect all the solid bodies in the work part and export them to an .STL file.

Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF

Module Module1

Dim theSession As Session = Session.GetSession()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim lw As ListingWindow = theSession.ListingWindow

Sub Main()

If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If

Dim workPart As Part = theSession.Parts.Work
lw.Open()

Const undoMarkName As String = "export solids to STL"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, undoMarkName)

Dim theSolids As New List(Of Body)

'collect the solid bodies in the work part
For Each temp As Body In workPart.Bodies
If temp.IsSolidBody Then
theSolids.Add(temp)
End If
Next

Try
ExportSTL(workPart.FullPath, theSolids, 0.003, 0.003)
Catch ex As NXException
lw.WriteLine("NX Error: " & ex.Message)
Catch ex As Exception
lw.WriteLine("Error: " & ex.Message)
End Try

lw.Close()

End Sub

Sub ExportSTL(ByVal FileName As String, ByVal theObjects As List(Of Body), ByVal triangleTolerance As Double, ByVal adjacencyTolerance As Double)

Dim NumErrors As Integer
Dim FileHandle As IntPtr
Dim InfoError() As UFStd.StlError
Dim Header, FileBaseName As String
'Dim numNegated As Integer
'Dim Negated() As Tag

'Negated = Nothing
InfoError = Nothing

FileName = IO.Path.ChangeExtension(FileName, ".stl")

FileBaseName = IO.Path.GetFileName(FileName)
Header = "Header: " & FileBaseName

theUfSession.Std.OpenBinaryStlFile(FileName, False, Header, FileHandle)

theUfSession.Ui.SetPrompt("Creating file ... " & FileBaseName & " ...")

For Each temp As Body In theObjects
If temp.IsSolidBody Then
theUfSession.Std.PutSolidInStlFile(FileHandle, Tag.Null, temp.Tag, 0.0, 0.0, triangleTolerance, NumErrors, InfoError)
End If
Next

theUfSession.Std.CloseStlFile(FileHandle)

theUfSession.Ui.SetStatus("File ... " & FileBaseName & " generated ...")

End Sub

Public Function GetUnloadOption(ByVal dummy As String) As Integer

'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately

End Function

End Module

This is fantastic. Thank you. I can get it to work for one part now. However, when I try to implement this code for all the files in a directory with the code below (borrowed from your website, thank you) I get an error that List is not defined in the "Dim theSolids As New List(Of Body)" line. Any ideas? Thank you for all your help.


Option Strict Off
Imports System
Imports System.IO
Imports System.Collections
Imports System.Windows.Forms

Imports NXOpen
Imports NXOpenUI
Imports NXOpen.UF

Module Cycle_Files_and_Folders_b
Dim theSession As Session = Session.GetSession
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim LW As ListingWindow = theSession.ListingWindow

Dim workPart As Part = theSession.Parts.Work
Dim displayPart As Part = theSession.Parts.Display
Dim initialPart As Part = theSession.Parts.Display

Dim nTotalPartFiles As Integer = 0

Sub Main()

Dim strOutputFolder As String
LW.Open()
Try

Dim FolderBrowserDialog1 As New FolderBrowserDialog
' Change the .SelectedPath property to the default location
With FolderBrowserDialog1
' Desktop is the root folder in the dialog.
.RootFolder = Environment.SpecialFolder.Desktop
' Change the following line to default to a given path
.SelectedPath = "C:\"
' Prompt the user with a custom message.
.Description = "Select the directory to scan"
If .ShowDialog = DialogResult.OK Then
' Display the selected folder if the user clicked on the OK button.
'msgbox(.SelectedPath)
strOutputFolder = .SelectedPath
Else
'user pressed "cancel", exit the journal
Exit Sub
End If
End With

LW.WriteLine("Cycle All Parts in a Folder Tree")
LW.WriteLine("Start Time: " & CType(TimeOfDay(), String))
LW.WriteLine("")

processParts(strOutputFolder, False)

LW.WriteLine("")
LW.WriteLine("Total Part Files Scanned: " & nTotalPartFiles)
LW.WriteLine("Stop Time: " & CType(TimeOfDay(), String))

Catch ex As NXException
LW.WriteLine("Cycle Files and Folders Error: " & ex.Message)
Exit Sub
End Try
End Sub

'***************************************************************************
'Process All Parts in a Directory

Sub processParts(ByVal directoryPath As String, ByVal includeSubDirs As Boolean)

Try
Dim nPartFiles As Integer = 0
Dim part1 As Part
Dim files() As String

If includeSubDirs Then
files = Directory.GetFiles(directoryPath, "*.prt", SearchOption.AllDirectories)
Else
files = Directory.GetFiles(directoryPath, "*.prt", SearchOption.TopDirectoryOnly)
End If
For Each fileName As String In files
nPartFiles += 1
nTotalPartFiles += 1
LW.WriteLine(" " & nPartFiles & " " & Path.GetFileName(fileName))

If (IsNothing(initialPart)) OrElse (initialPart.FullPath <> fileName) Then
part1 = theSession.Parts.OpenDisplay(fileName, Nothing)
Else
'LW.WriteLine("initial part equals display part: " & initialPart.Equals(displayPart).ToString)
part1 = displayPart
End If

displayPart = theSession.Parts.Display
workPart = theSession.Parts.Display

'do something
'write your own subroutines and/or functions to process the part and call them from here

Const undoMarkName As String = "export solids to STL"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, undoMarkName)

Dim theSolids As New List(Of Body)

'collect the solid bodies in the work part
For Each temp As Body In workPart.Bodies
If temp.IsSolidBody Then
theSolids.Add(temp)
End If
Next

Try
ExportSTL(workPart.FullPath, theSolids, 0.003, 0.003)
Catch ex As NXException
LW.WriteLine("NX Error: " & ex.Message)
Catch ex As Exception
LW.WriteLine("Error: " & ex.Message)
End Try

'close file unless this file was initially open
If (IsNothing(initialPart)) OrElse (initialPart.FullPath <> fileName) Then
'part1.Save(BasePart.SaveComponents.True, BasePart.CloseAfterSave.True)
part1.Close(BasePart.CloseWholeTree.False, BasePart.CloseModified.UseResponses, Nothing)
part1 = Nothing
workPart = Nothing
displayPart = Nothing
End If

If Not IsNothing(initialPart) Then
Dim partLoadStatus1 As PartLoadStatus
Dim status1 As PartCollection.SdpsStatus
status1 = theSession.Parts.SetDisplay(initialPart, False, False, partLoadStatus1)

displayPart = theSession.Parts.Display
partLoadStatus1.Dispose()
theSession.Parts.SetWork(displayPart)
workPart = theSession.Parts.Work
End If

Next fileName
Catch ex As Exception
LW.WriteLine("Part Scan Error: " & ex.Message)
End Try

End Sub

'***************************************************************************
Sub ExportSTL(ByVal FileName As String, ByVal theObjects As List(Of Body), ByVal triangleTolerance As Double, ByVal adjacencyTolerance As Double)

Dim NumErrors As Integer
Dim FileHandle As IntPtr
Dim InfoError() As UFStd.StlError
Dim Header, FileBaseName As String
'Dim numNegated As Integer
'Dim Negated() As Tag

'Negated = Nothing
InfoError = Nothing

FileName = IO.Path.ChangeExtension(FileName, ".stl")

FileBaseName = IO.Path.GetFileName(FileName)
Header = "Header: " & FileBaseName

theUfSession.Std.OpenBinaryStlFile(FileName, False, Header, FileHandle)

theUfSession.Ui.SetPrompt("Creating file ... " & FileBaseName & " ...")

For Each temp As Body In theObjects
If temp.IsSolidBody Then
theUfSession.Std.PutSolidInStlFile(FileHandle, Tag.Null, temp.Tag, 0.0, 0.0, triangleTolerance, NumErrors, InfoError)
End If
Next

theUfSession.Std.CloseStlFile(FileHandle)

theUfSession.Ui.SetStatus("File ... " & FileBaseName & " generated ...")

End Sub

'***********************************************************************

Public Function GetUnloadOption(ByVal dummy As String) As Integer

'Unloads the image when the NX session terminates
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination

End Function

End Module

This is a namespace issue. The compiler is looking for the type: List and cannot find it. The List type is found in System.Collections.Generic.

Change the 4th line of the journal from:

Imports System.Collections

to:

Imports System.Collections.Generic

Alternately, you could add the qualification to the list declaration:

Dim theSolids As New Generic.List(Of Body)

Pick one method or the other, but you don't have to do both.

Thank you so much.

A++

This code is very helpful. I'm just wondering if someone could tell me how to export an XT file at the same time? I found this http://nxjournaling.com/content/export-parasolid and surely its on a few lines... I just don't know exactly what I'm doing.

For what its worth, there is only 1 solid body in each of my parts that I wish to export as both STL and XT.

Thank you

What is the code for choosing only the displayed bodies

One way is to use the .AskVisibleObjects method which will return all the visible objects in the specified view. You could then sort through the returned objects looking for solid bodies. This method may not return objects that are "off screen" even though they are not hidden and their layer is turned on. If this behavior is not desired, an alternative is to loop through the body collection looking for bodies whose layer is turned on and that is not hidden.

Thanks for responding so fast, I am new to journals so I have been working on it all day. What would the desired code look like if I ONLY wanted the solids that are visible?

Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF

Module Module1

Dim theSession As Session = Session.GetSession()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim lw As ListingWindow = theSession.ListingWindow

Sub Main()

If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If

Dim workPart As Part = theSession.Parts.Work
lw.Open()
'------------------------
' Undo Section
'------------------------
Const undoMarkName As String = "export solids to STL"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, undoMarkName)
'------------------------
' Declaring Variables
'------------------------
Dim theSolids As New List(Of Body)
'------------------------
'collect the solid bodies in the work part
'------------------------
For Each temp As Body In workPart.Bodies
If temp.IsSolidBody Then
theSolids.Add(temp)
End If
Next

Try
ExportSTL(workPart.FullPath, theSolids, 0.00127, 0.00127)
Catch ex As NXException
lw.WriteLine("NX Error: " & ex.Message)
Catch ex As Exception
lw.WriteLine("Error: " & ex.Message)
End Try

lw.Close()

End Sub

Sub ExportSTL(ByVal FileName As String, ByVal theObjects As List(Of Body), ByVal triangleTolerance As Double, ByVal adjacencyTolerance As Double)

Dim NumErrors As Integer
Dim FileHandle As IntPtr
Dim InfoError() As UFStd.StlError
Dim Header, FileBaseName As String
'Dim numNegated As Integer
'Dim Negated() As Tag

'Negated = Nothing
InfoError = Nothing

FileName = IO.Path.ChangeExtension(FileName, ".stl")

FileBaseName = IO.Path.GetFileName(FileName)
Header = "Header: " & FileBaseName

theUfSession.Std.OpenBinaryStlFile(FileName, False, Header, FileHandle)

theUfSession.Ui.SetPrompt("Creating file ... " & FileBaseName & " ...")

For Each temp As Body In theObjects
If temp.IsSolidBody Then
theUfSession.Std.PutSolidInStlFile(FileHandle, Tag.Null, temp.Tag, 0.00127, 0.00127, triangleTolerance, NumErrors, InfoError)
End If
Next

theUfSession.Std.CloseStlFile(FileHandle)

theUfSession.Ui.SetStatus("File ... " & FileBaseName & " generated ...")

End Sub

Public Function GetUnloadOption(ByVal dummy As String) As Integer

'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately

End Function

End Module

Try replacing this for loop:

For Each temp As Body In workPart.Bodies
If temp.IsSolidBody Then
theSolids.Add(temp)
End If
Next

with this for loop:

For Each tempBody As Body In workPart.Bodies
'skip sheet bodies
If tempBody.IsSheetBody Then
Continue For
End If

'skip hidden bodies
If tempBody.IsBlanked Then
Continue For
End If

'skip bodies on an invisible layer
If workPart.Layers.GetState(tempBody.Layer) = Layer.State.Hidden Then
Continue For
End If

'if we make it to here, we have a solid body that is visible
theSolids.Add(tempBody)
Next

This worked perfectly! You are the best!

Thank you for this code, it is really good but I only need the bodies that are visible (not the ones that are hidden or on another layer).
Please help?

How could this be modified to export each body in a work part to individual .STLs? Another one of our engineers has about 40 bodies in a part that need to be printed. I've been using NX for a while, but have never really needed to automate anything like this, so I'm at a loss. Right now, the need is for NX 8.5, but eventually we'll be doing this in NX 10.

Thanks in advance.

Try the version below, I modified the export function to export to individual stl files. The code was written and tested in NX 9, but I'm pretty sure it will work with NX 8.5 and 10 as well.

Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF

Module Module2

Dim theSession As Session = Session.GetSession()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim lw As ListingWindow = theSession.ListingWindow

Sub Main()

If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If

Dim workPart As Part = theSession.Parts.Work
lw.Open()

Const undoMarkName As String = "export solids to STL"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, undoMarkName)

Dim theSolids As New List(Of Body)

'collect the solid bodies in the work part
For Each temp As Body In workPart.Bodies
If temp.IsSolidBody Then
theSolids.Add(temp)
End If
Next

Try
ExportSTLFiles(workPart.FullPath, theSolids, 0.003, 0.003)
Catch ex As NXException
lw.WriteLine("NX Error: " & ex.Message)
Catch ex As Exception
lw.WriteLine("Error: " & ex.Message)
End Try

lw.Close()

End Sub

Sub ExportSTL(ByVal FileName As String, ByVal theObjects As List(Of Body), ByVal triangleTolerance As Double, ByVal adjacencyTolerance As Double)

Dim NumErrors As Integer
Dim FileHandle As IntPtr
Dim InfoError() As UFStd.StlError
Dim Header, FileBaseName As String
'Dim numNegated As Integer
'Dim Negated() As Tag

'Negated = Nothing
InfoError = Nothing

FileName = IO.Path.ChangeExtension(FileName, ".stl")

FileBaseName = IO.Path.GetFileName(FileName)
Header = "Header: " & FileBaseName

theUfSession.Std.OpenBinaryStlFile(FileName, False, Header, FileHandle)

theUfSession.Ui.SetPrompt("Creating file ... " & FileBaseName & " ...")

For Each temp As Body In theObjects
If temp.IsSolidBody Then
theUfSession.Std.PutSolidInStlFile(FileHandle, Tag.Null, temp.Tag, 0.0, 0.0, triangleTolerance, NumErrors, InfoError)
End If
Next

theUfSession.Std.CloseStlFile(FileHandle)

theUfSession.Ui.SetStatus("File ... " & FileBaseName & " generated ...")

End Sub

Sub ExportSTLFiles(ByVal FileName As String, ByVal theObjects As List(Of Body), ByVal triangleTolerance As Double, ByVal adjacencyTolerance As Double)

Dim NumErrors As Integer
Dim InfoError() As UFStd.StlError
Dim Header, FileBaseName As String
'Dim numNegated As Integer
'Dim Negated() As Tag

'Negated = Nothing
InfoError = Nothing

Dim parentFolder As String = IO.Path.GetDirectoryName(FileName)
Dim fileNameNoExt As String = IO.Path.GetFileNameWithoutExtension(FileName)

'FileName = IO.Path.ChangeExtension(FileName, ".stl")
Dim suffix As Integer = 1
For Each temp As Body In theObjects

Dim FileHandle As IntPtr

Dim fileNameWithSuffix As String = fileNameNoExt & "_" & suffix.ToString & ".stl"

FileBaseName = IO.Path.GetFileName(FileName)
Header = "Header: " & FileBaseName

theUfSession.Std.OpenBinaryStlFile(IO.Path.Combine(parentFolder, fileNameWithSuffix), False, Header, FileHandle)

theUfSession.Ui.SetPrompt("Creating file ... " & FileBaseName & " ...")

theUfSession.Std.PutSolidInStlFile(FileHandle, Tag.Null, temp.Tag, 0.0, 0.0, triangleTolerance, NumErrors, InfoError)

theUfSession.Std.CloseStlFile(FileHandle)

theUfSession.Ui.SetStatus("File ... " & FileBaseName & " generated ...")

suffix += 1

Next

End Sub

Public Function GetUnloadOption(ByVal dummy As String) As Integer

'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately

End Function

End Module

I just realized that I never thanked you for this. It worked out really nicely. Thanks again.

Glad to help. When I don't hear back, I assume that "no news is good news"; but a quick "that worked" is encouraging to the code author and it gives other viewers confidence that the code works and is worth downloading.

I am a newbie to NX Journaling and this forum has helped me to take baby steps in NX Automation. I found this site very useful and Informative. A Big Thanks to the Contributors for their valuable Suggestions and Contributions. I went through the Code for Exporting Solids to STL, but I wish to have sheet Bodies also to be exported to STL format. I Tried Using theUfSession.Std.PutSheetsInStlFile(---Arguments--),and trying to extract the face information for the particular sheetBodies, but in vain. I am getting a lot of namespace issues and errors. Request anyone to modify the code for exporting sheetbodies also.

Thanks

Hey guys. I'm a little new to NX Journaling as well. This code works great, but it grabs all of the bodies that are in the part file. I want to just export the body(bodies) on one specific layer. How do I need to change the code to only get the bodies I'm looking for?

Zachary Buckler

Try this to export from layer 1
'collect the solid bodies in the work part
For Each temp As Body In workPart.Bodies
If temp.IsSolidBody andalso temp.Layer = 1 Then
theSolids.Add(temp)
End If
Next