Continue to Site

Eng-Tips is the largest engineering community on the Internet

Intelligent Work Forums for Engineering Professionals

  • Congratulations KootK on being selected by the Eng-Tips community for having the most helpful posts in the forums last week. Way to Go!

Fully Automatic Dimension Tool - Length, Width and Thickness 5

Status
Not open for further replies.

lj1970

Marine/Ocean
Nov 26, 2023
18
Hello guys,
I am excited to share my latest journal to you all. This time infused with a touch of Lord Voldemort's unique style.
The tool automates the process of analyzing and annotating the dimensions and material thicknesses of parts in a Siemens NX assembly. It is designed specifically to aid engineers and CAD designers like myself in efficiently processing and documenting crucial measurements directly within the NX framework.

Features:
- Component Analysis: The script iterates through all components in the main assembly, including subassemblies, calculating the dimensions of each component. It intelligently handles duplicated components by skipping them.
Based on this sub, created by NXJournaling on 2012.

- Bounding Box Calculation: For the designated body, the script creates a non-aligned bounding box to determine its width, depth, and height. The body doesn't have to be aligned with the absolute coordinate system. The process involves generating a non-aligned minimum bounding box, selecting the first vertex on it, iterating through the edges that share a common point with this vertex, and then accurately measuring these three edges .

Solid Body Requirements:
If the body is on Layer 1, it will be processed.
If on any layer other than Layer 1, it will be skipped.
If multiple bodies are on Layer 1, the script will skip the component.
Dimensions are in millimeters.

- Material Thickness Identification: The script determines the material thickness from a pre-set range of valid thicknesses, adjusting the value according to specific criteria. Refer to the code comments for customization to your environment.

- Dimension Sorting: The script sorts the calculated dimensions to identify the length, width, and material thickness of each component. If the material thickness is indeterminable, the script designates the smallest dimension as the thickness.

- User Interaction: The script includes a form interface for user adjustments to dimensions (additional length and width) and to modify grain direction as required.

- Attribute Assignment: Attributes for length, width, and material thickness are added to each associated component / Part. Refer to the code comments for customization to your environment.

Use Case:
Ideal for mechanical engineers and designers using Siemens NX who need a fast, automated method to document and review dimensions and material thicknesses of components in complex assemblies. This tool is particularly valuable in large-scale projects where manual measurement is impractical.

The code has been tested on versions 2212 and 2306 with Teamcenter 13.
Additionally, a professional version is attached, but feel free to modify and add your personal style.

I have several other publications that you might find beneficial, although I was uncertain if this would be the appropriate forum to share them.

Happy Holidays :)
Enjoy!


Code:
' created by Tamas Woller at 27.12.2023
Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Utilities
Imports NXOpen.Assemblies
Imports System.Drawing
Imports System.Windows.Forms

Module NXJournal
    Dim theSession As Session = Session.GetSession()
    Dim lw As ListingWindow = theSession.ListingWindow
    Dim theUFSession As UFSession = UFSession.GetUFSession()
    Dim theUI As UI = UI.GetUI()
    Dim workPart As Part = theSession.Parts.Work
    Dim Length As Double
    Dim Width As Double
    Dim winFormLocationX As Integer = 317 ' Default X position for Winforms
    Dim winFormLocationY As Integer = 317 ' Default Y position for Winforms

    ' Use a Dictionary to track processed components
    Private ProcessedComponents As New Dictionary(Of String, Boolean)

	Sub Main()
		Dim markId1 As NXOpen.Session.UndoMarkId
		markId1 = theSession.SetUndoMark(NXOpen.Session.MarkVisibility.Visible, "Dimensions Tool")
		lw.Open()

		' Make all components visible
		Dim showhide As Integer = theSession.DisplayManager.ShowByType(DisplayManager.ShowHideType.All, DisplayManager.ShowHideScope.AnyInAssembly)
		workPart.ModelingViews.WorkView.FitAfterShowOrHide(NXOpen.View.ShowOrHideType.ShowOnly)

		Try
			Dim workPart As Part = theSession.Parts.Work
			Dim dispPart As Part = theSession.Parts.Display
			Dim ca As ComponentAssembly = dispPart.ComponentAssembly

			If Not IsNothing(dispPart) Then
				lw.WriteLine("---------------------------------------------- ")
				lw.WriteLine("Lord Voldemort's Dimensions Tool")
				lw.WriteLine(" ")
				lw.WriteLine("The ritual of dimensions begins.")
				lw.WriteLine("Behold, Width, Height, and Material Thickness.")
				lw.WriteLine(" ")
				lw.WriteLine("The Main Assembly reveals itself as: " & dispPart.Name)
				lw.WriteLine(" ")
				ReportComponentChildren(ca.RootComponent)
			Else
				lw.WriteLine("This part is devoid of any components, much like a soul without magic.")
			End If
		Catch e As Exception
			theSession.ListingWindow.WriteLine("Failure? Impossible! " & e.ToString)
		Finally
			' Reset to main assembly
			lw.WriteLine(" ")
			lw.WriteLine("Returning home to the main assembly, like a serpent to its lair.")
			ResetToMainAssembly()
		End Try
	End Sub

	Sub ReportComponentChildren(ByVal comp As Component)
		' List to keep track of components along with their suppressed status
		Dim componentsWithStatus As New List(Of Tuple(Of Component, Boolean))

		' List to keep track of processed component display names for duplicate check
		Dim NameList As New List(Of String)

		' Collect components and their suppressed status
		For Each child As Component In comp.GetChildren()
			' Add component and its suppressed status to the list
			componentsWithStatus.Add(New Tuple(Of Component, Boolean)(child, child.IsSuppressed))
		Next

		' Sort the list so that suppressed components come first
		componentsWithStatus.Sort(Function(x, y) y.Item2.CompareTo(x.Item2))

		' Process sorted components
		For Each tuple As Tuple(Of Component, Boolean) In componentsWithStatus
			Dim child As Component = tuple.Item1
			Dim isSuppressed As Boolean = tuple.Item2

			' Check for duplicate part
			If NameList.Contains(child.DisplayName()) Then
				' Logic for handling duplicate parts
				lw.WriteLine("Another duplicate, unworthy of my attention: " & child.DisplayName())
				Continue For
			Else
				NameList.Add(child.DisplayName()) ' Add new component display name to the list
			End If

			If isSuppressed Then
				lw.WriteLine("A suppressed component hides in the shadows: " & child.DisplayName())
			Else
				lw.WriteLine("-----------------")

				' Retrieve and process the part associated with the child component
				Dim childPart As Part = LoadComponentAndGetPart(child)

				If childPart IsNot Nothing AndAlso childPart.IsFullyLoaded Then
					' Display the part name instead of the component name
					lw.WriteLine("Now, gaze upon the Part: " & childPart.Name)

					ProcessBodies(childPart, child) ' Pass the Part and Component objects
				Else
					lw.WriteLine("This part lacks the magic it needs, it is not fully conjured.")
				End If

				If child.GetChildren.Length <> 0 Then
					' Continue processing subassemblies
					ReportComponentChildren(child)
				End If
			End If
		Next
	End Sub

	' Method to load a component and return the associated part
	Function LoadComponentAndGetPart(ByVal component As Component) As Part
		Dim partLoadStatus As PartLoadStatus = Nothing
		Try
			' Set the work component to load the component
			theSession.Parts.SetWorkComponent(component, PartCollection.RefsetOption.Current, PartCollection.WorkComponentOption.Visible, partLoadStatus)

			' Get the part associated with the component
			If TypeOf component.Prototype Is Part Then
				Return CType(component.Prototype, Part)
			End If
		Catch ex As Exception
			lw.WriteLine("An unexpected disturbance in the dark arts: " & ex.Message)
			Return Nothing
		Finally
			' Dispose of the part load status
			If partLoadStatus IsNot Nothing Then
				partLoadStatus.Dispose()
			End If
		End Try
		Return Nothing
	End Function

Sub ProcessBodies(ByVal part As Part, ByVal comp As Component)
    Dim lw As ListingWindow = theSession.ListingWindow
    Dim nXObject1 As NXOpen.NXObject
    Dim bbWidth, bbDepth, bbHeight, Length, Width, MaterialThickness As Double
    Dim lengthDisplay As String = "" ' Declare lengthDisplay
    Dim widthDisplay As String = ""  ' Declare widthDisplay

	 ' Set the measure manager to consistent unit
	Dim myMeasure As MeasureManager = part.MeasureManager()
	Dim wIconMOseT (0) As Unit
	wIconMOseT (0) = part.UnitCollection.GetBase("Mass")

	' Create a mass properties measurement for the entire part
	Dim mb As MeasureBodies = myMeasure.NewMassProperties(wIconMOseT , 0.99, part.Bodies.ToArray())
	mb.InformationUnit = MeasureBodies.AnalysisUnit.KilogramMilliMeter
	
    ' Check if the part is valid and loaded
    If Not part Is Nothing AndAlso part.IsFullyLoaded Then
        ' Get the list of solid bodies in the part
        Dim bodies As Body() = part.Bodies.ToArray()

        ' Lists to track bodies on Layer 1
        Dim bodiesOnLayer1 As New List(Of Body)

        ' Check bodies and categorize based on layer
        For Each body As Body In bodies
		
            Dim bodyLayer As Integer = body.Layer
            Dim bodyName As String = If(String.IsNullOrEmpty(body.Name), "Unnamed Body", body.Name)

            If bodyLayer = 1 Then
                bodiesOnLayer1.Add(body)
                lw.WriteLine("Found Solid Body: " & bodyName & " on Layer 1")
				lw.WriteLine(" ")
            Else
                lw.WriteLine("A mere illusion: " & bodyName & " on Layer " & bodyLayer.ToString())
				lw.WriteLine("I shall disregard it.")
				lw.WriteLine(" ")
            End If
        Next

        ' Check the number of bodies on Layer 1
        If bodiesOnLayer1.Count > 1 Then
            lw.WriteLine("Too many forms vie for attention on Layer 1")
			lw.WriteLine("I shall choose none.")
			lw.WriteLine(" ")
            Exit Sub
        ElseIf bodiesOnLayer1.Count = 1 Then
            ' Process the single body found on Layer 1
            Dim bodyToProcess As Body = bodiesOnLayer1(0)
            lw.WriteLine("Processing Body: " & bodyToProcess.Name)
            
			Try
				' Calculate and display the center of mass
				Dim accValue(10) As Double
				accValue(0) = 0.999
				Dim massProps(46) As Double
				Dim stats(12) As Double
				theUFSession.Modl.AskMassProps3d(New Tag() {bodyToProcess.Tag}, 1, 1, 4, 0.03, 1, accValue, massProps, stats)

				' Convert the center of mass coordinates to Double
				Dim com_x As Double = massProps(3)
				Dim com_y As Double = massProps(4)
				Dim com_z As Double = massProps(5)

				Dim toolingBoxBuilder1 As NXOpen.Features.ToolingBoxBuilder = workPart.Features.ToolingFeatureCollection.CreateToolingBoxBuilder(Nothing)
				toolingBoxBuilder1.Type = NXOpen.Features.ToolingBoxBuilder.Types.BoundedBlock
				toolingBoxBuilder1.ReferenceCsysType = NXOpen.Features.ToolingBoxBuilder.RefCsysType.SelectedCsys
				toolingBoxBuilder1.XValue.SetFormula("10")
				toolingBoxBuilder1.YValue.SetFormula("10")
				toolingBoxBuilder1.ZValue.SetFormula("10")
				toolingBoxBuilder1.OffsetPositiveX.SetFormula("0")
				toolingBoxBuilder1.OffsetNegativeX.SetFormula("0")
				toolingBoxBuilder1.OffsetPositiveY.SetFormula("0")
				toolingBoxBuilder1.OffsetNegativeY.SetFormula("0")
				toolingBoxBuilder1.OffsetPositiveZ.SetFormula("0")
				toolingBoxBuilder1.OffsetNegativeZ.SetFormula("0")
				toolingBoxBuilder1.RadialOffset.SetFormula("0")
				toolingBoxBuilder1.Clearance.SetFormula("0")
				toolingBoxBuilder1.CsysAssociative = True
				toolingBoxBuilder1.NonAlignedMinimumBox = True
				toolingBoxBuilder1.SingleOffset = False

				Dim selectionIntentRuleOptions1 As NXOpen.SelectionIntentRuleOptions = Nothing
				selectionIntentRuleOptions1 = workPart.ScRuleFactory.CreateRuleOptions()
				selectionIntentRuleOptions1.SetSelectedFromInactive(False)
						
				Dim selectedBody As NXOpen.Body = TryCast(NXOpen.Utilities.NXObjectManager.Get(bodyToProcess.Tag), NXOpen.Body)
				If selectedBody Is Nothing Then
					lw.WriteLine("The tag you dare present does not match any corporeal form.")
					Return
				End If

				' Use the selectedBody for creating the dumb rule
				Dim bodyDumbRule1 As NXOpen.BodyDumbRule = workPart.ScRuleFactory.CreateRuleBodyDumb(New Body() {selectedBody}, True, selectionIntentRuleOptions1)
				selectionIntentRuleOptions1.Dispose()

				Dim scCollector1 As NXOpen.ScCollector = toolingBoxBuilder1.BoundedObject
				Dim rules1(0) As NXOpen.SelectionIntentRule
				rules1(0) = bodyDumbRule1
				scCollector1.ReplaceRules(rules1, False)

				' Use the selectedBody in SetSelectedOccurrences
				Dim selections1(0) As NXOpen.NXObject
				selections1(0) = selectedBody
				Dim deselections1(-1) As NXOpen.NXObject
				toolingBoxBuilder1.SetSelectedOccurrences(selections1, deselections1)

				Dim selectNXObjectList1 As NXOpen.SelectNXObjectList = Nothing
				selectNXObjectList1 = toolingBoxBuilder1.FacetBodies
				Dim objects1(-1) As NXOpen.NXObject
				Dim added1 As Boolean = Nothing
				added1 = selectNXObjectList1.Add(objects1)
				toolingBoxBuilder1.CalculateBoxSize()

				' Set the box position using the center of mass coordinates
				Dim csysorigin1 As NXOpen.Point3d = New NXOpen.Point3d(com_x, com_y, com_z)
				toolingBoxBuilder1.BoxPosition = csysorigin1

				' Commit the tooling box to create the feature
				nXObject1 = toolingBoxBuilder1.Commit()
				
				' Destroy the tooling box builder
				If toolingBoxBuilder1 IsNot Nothing Then
					toolingBoxBuilder1.Destroy()
				End If

				' Access the body of the bounding box feature
				Dim bboxFeature As Features.Feature = TryCast(nXObject1, Features.Feature)
				Dim bboxBody As Body = Nothing
				Dim innerBboxBody As Body = Nothing
				
				If bboxFeature IsNot Nothing Then
					For Each innerBboxBody In bboxFeature.GetBodies()
						'bboxBody = body
						Exit For
					Next
				End If

				If innerBboxBody IsNot Nothing Then
					' Initialize directions and distances arrays
					Dim minCorner(2) As Double
					Dim directions(,) As Double = New Double(2, 2) {}
					Dim distances(2) As Double

					' Get the bounding box of the body
					theUFSession.Modl.AskBoundingBoxExact(innerBboxBody.Tag, Tag.Null, minCorner, directions, distances)

					' Define the minimum corner point and print it
					Dim cornerPoint As Point3d = New Point3d(minCorner(0), minCorner(1), minCorner(2))

					' Initialize a List to store unique vertices
					Dim vertices As New List(Of Point3d)()

					' Iterate through all edges in the body and get vertices
					For Each edge As Edge In innerBboxBody.GetEdges()
						Dim vertex1 As Point3d, vertex2 As Point3d
						edge.GetVertices(vertex1, vertex2)
						If Not vertices.Contains(vertex1) Then vertices.Add(vertex1)
						If Not vertices.Contains(vertex2) Then vertices.Add(vertex2)
					Next

					' Select the first vertex as the starting vertex
					Dim startingVertex As Point3d = vertices(0)

					' Initialize a List to store lengths of edges connected to the starting vertex
					Dim edgeLengths As New List(Of Double)
					Dim edgesAtStartingVertex As Integer = 0

					' Iterate through all edges in the body
					For Each edge As Edge In innerBboxBody.GetEdges()
						Dim vertex1 As Point3d, vertex2 As Point3d
						edge.GetVertices(vertex1, vertex2)
						If IsPointEqual(startingVertex, vertex1) OrElse IsPointEqual(startingVertex, vertex2) Then
							edgesAtStartingVertex += 1
							edgeLengths.Add(edge.GetLength())
						End If
					Next

					' Check if we have at least three edges before accessing the list
					If edgeLengths.Count >= 3 Then
						' Sort the edge lengths
						edgeLengths.Sort()

						' Assign the sorted values
						bbWidth = Math.Round(edgeLengths(0))
						bbDepth = Math.Round(edgeLengths(1))
						bbHeight = Math.Round(edgeLengths(2))

						' Output the dimensions
						lw.WriteLine("Bounding Box Dimensions:")
						lw.WriteLine("Width: " & bbWidth.ToString("F0") & " mm")
						lw.WriteLine("Depth: " & bbDepth.ToString("F0") & " mm")
						lw.WriteLine("Height: " & bbHeight.ToString("F0") & " mm")
						lw.WriteLine(" ")
					Else
						lw.WriteLine("Not enough edges found, like a spell half-cast.")
					End If

					' Valid material thicknesses
					Dim validThicknesses As Double() = {2, 5, 7, 8, 8.5, 12, 12.5, 13, 22, 24, 25} ' Change here to suit your environment
					Dim materialThicknessIdentified As Boolean = False

					' Identify Material Thickness
					If Array.IndexOf(validThicknesses, bbWidth) >= 0 Then
						MaterialThickness = bbWidth
						materialThicknessIdentified = True
					ElseIf Array.IndexOf(validThicknesses, bbDepth) >= 0 Then
						MaterialThickness = bbDepth
						materialThicknessIdentified = True
					ElseIf Array.IndexOf(validThicknesses, bbHeight) >= 0 Then
						MaterialThickness = bbHeight
						materialThicknessIdentified = True
					End If

					If Not materialThicknessIdentified Then
						' Handle case where material thickness is not identified
						MaterialThickness = Math.Min(bbWidth, Math.Min(bbDepth, bbHeight))
						lw.WriteLine("Cannot identify material thickness. Using the smallest dimension instead.")
					End If

					' Determine Length and Width from the remaining dimensions
					Dim remainingDimensions As New List(Of Double) From {bbWidth, bbDepth, bbHeight}
					remainingDimensions.Remove(MaterialThickness)

					' Ensure there are two dimensions left
					If remainingDimensions.Count = 2 Then
						' Assign the larger value to Length and the smaller to Width
						Length = Math.Max(remainingDimensions(0), remainingDimensions(1))
						Width = Math.Min(remainingDimensions(0), remainingDimensions(1))
					Else
						lw.WriteLine("Unable to determine Length and Width accurately.")
					End If
					
					' Delete the bounding box feature
					Dim featureTags(0) As NXOpen.Tag
					featureTags(0) = bboxFeature.Tag
					theUFSession.Modl.DeleteFeature(featureTags)

					Dim myForm As New Form1()
					If myForm.ShowDialog() = DialogResult.OK Then
						' Check the IsGrainDirectionChanged property
						If myForm.IsGrainDirectionChanged Then
							' Flip Length and Width
							Dim temp As Double = Length
							Length = Width
							Width = temp
							lw.WriteLine("Grain direction changed")
						End If

						' Update Length and Width based on LengthExtra and WidthExtra
						lengthDisplay = Length.ToString("F0")
						If myForm.LengthExtra > 0 Then
							Length += myForm.LengthExtra
							lengthDisplay = Length.ToString("F0") & " (" & myForm.LengthExtra.ToString("F0") & ")"
						Else
							'lw.WriteLine("No Extra added to Length")
						End If

						widthDisplay = Width.ToString("F0")
						If myForm.WidthExtra > 0 Then
							Width += myForm.WidthExtra
							widthDisplay = Width.ToString("F0") & " (" & myForm.WidthExtra.ToString("F0") & ")"
						Else
							'lw.WriteLine("No Extra added to Width")
						End If

						' Write the updated dimensions to the listing window
						If Length > 0 And Width > 0 Then
							lw.WriteLine("Length: " & lengthDisplay & " mm")
							lw.WriteLine("Width: " & widthDisplay & " mm")
						Else
							lw.WriteLine("The dimensions evade my grasp.")
						End If
					End If

					' Adjust Material Thickness if necessary - Change here to suit your environment
					Select Case MaterialThickness
						Case 8.5
							MaterialThickness = 8
							lw.WriteLine("Material thickness identified: 8.5mm. Changed to 8mm.")
						Case 12.5
							MaterialThickness = 12
							lw.WriteLine("Material thickness identified: 12.5mm. Changed to 12mm.")
						Case 22
							MaterialThickness = 20
							lw.WriteLine("Material thickness identified: 22mm. Changed to 20mm.")
						Case 25
							MaterialThickness = 24
							lw.WriteLine("Material thickness identified: 25mm. Changed to 24mm.")
					End Select
					lw.WriteLine("Material Thickness: " & MaterialThickness.ToString("F0") & " mm")
					lw.WriteLine(" ")

					' Adding Attributes to the Component as Part - Change here to suit your environment
					AddPartAttribute(comp, "VLength", lengthDisplay)
					lw.WriteLine("Length attribute added")
					AddPartAttribute(comp, "VWidth", widthDisplay)
					lw.WriteLine("Width attribute added")
					AddPartAttribute(comp, "VMaterialThickness", MaterialThickness)
					lw.WriteLine("Material Thickness attribute added")
				Else
					lw.WriteLine("The bounding box, a ghost, it eludes me.")
				End If

			Catch ex As Exception
				lw.WriteLine("An error? A mere setback in my grand design: " & ex.Message)
			Finally
			End Try

        Else
            lw.WriteLine("No solid bodies found on Layer 1")
        End If
    Else
        lw.WriteLine("The part before me is flawed, incomplete in its essence.")
    End If
End Sub
	
	Function IsPointEqual(point1 As Point3d, point2 As Point3d) As Boolean
		Const Tolerance As Double = 0.001
		Return (Math.Abs(point1.X - point2.X) < Tolerance AndAlso 
				Math.Abs(point1.Y - point2.Y) < Tolerance AndAlso 
				Math.Abs(point1.Z - point2.Z) < Tolerance)
	End Function
	
	' Method to reset to the main assembly
	Sub ResetToMainAssembly()
		Dim partLoadStatus2 As PartLoadStatus = Nothing

		Try
			' Reset to main assembly
			theSession.Parts.SetWorkComponent(Nothing, PartCollection.RefsetOption.Current, PartCollection.WorkComponentOption.Visible, partLoadStatus2)
			lw.WriteLine(" ")
			lw.WriteLine("As shadows gather and night befalls, our paths now diverge in silent halls.")
			lw.WriteLine("Remember, the Dark Lord's gaze, ever so watchful, in mystery's maze. ")
			lw.WriteLine("Until we meet in destiny's corridors, obscure and deep,")
			lw.WriteLine("our dark voyage concludes, in secrets we keep.")
			lw.WriteLine(" ")
		Catch ex As Exception
			lw.WriteLine("Failed to return to my dominion: " & ex.Message)
		Finally
			' Dispose the PartLoadStatus object if it's not null
			If partLoadStatus2 IsNot Nothing Then
				partLoadStatus2.Dispose()
			End If
		End Try
	End Sub

	<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
	Partial Class Form1
		Inherits System.Windows.Forms.Form

		Public Property LengthExtra As Double
		Public Property WidthExtra As Double
		Public Property IsGrainDirectionChanged As Boolean

		' Form designer variables
		Private components As System.ComponentModel.IContainer
		Friend WithEvents chkChangeGrainDirection As System.Windows.Forms.CheckBox
		Friend WithEvents txtExtraLength As System.Windows.Forms.TextBox
		Friend WithEvents txtExtraWidth As System.Windows.Forms.TextBox
		Friend WithEvents btnOK As System.Windows.Forms.Button
		'Friend WithEvents btnCancel As System.Windows.Forms.Button
		Friend WithEvents lblExtraLength As System.Windows.Forms.Label
		Friend WithEvents lblExtraWidth As System.Windows.Forms.Label

		<System.Diagnostics.DebuggerNonUserCode()> _
		Protected Overrides Sub Dispose(ByVal disposing As Boolean)
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
			MyBase.Dispose(disposing)
		End Sub

		<System.Diagnostics.DebuggerStepThrough()> _
		Private Sub Form1_Load(sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		    Me.StartPosition = FormStartPosition.Manual
			Me.Location = New System.Drawing.Point(winFormLocationX, winFormLocationY)
		
			' Setting the color properties of the form and its controls
			Me.BackColor = Color.FromArgb(55, 55, 55) ' Set form background color

			' Set colors for buttons
			btnOK.BackColor = Color.FromArgb(50, 50, 50)
			'btnCancel.BackColor = Color.FromArgb(50, 50, 50)

			' Setting the font colors to white
			txtExtraLength.ForeColor = Color.Black
			txtExtraWidth.ForeColor = Color.Black
			btnOK.ForeColor = Color.White
			'btnCancel.ForeColor = Color.White
			lblExtraLength.ForeColor = Color.White
			lblExtraWidth.ForeColor = Color.White
			chkChangeGrainDirection.ForeColor = Color.White
		End Sub
		
		Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
			' Save the location of the form
			winFormLocationX = Me.Location.X
			winFormLocationY = Me.Location.Y
		End Sub
		
		Private Sub InitializeComponent()
			Me.chkChangeGrainDirection = New System.Windows.Forms.CheckBox()
			Me.txtExtraLength = New System.Windows.Forms.TextBox()
			Me.txtExtraWidth = New System.Windows.Forms.TextBox()
			Me.btnOK = New System.Windows.Forms.Button()
			'Me.btnCancel = New System.Windows.Forms.Button()
			Me.lblExtraLength = New System.Windows.Forms.Label()
			Me.lblExtraWidth = New System.Windows.Forms.Label()
			Me.SuspendLayout()
			'
			'chkChangeGrainDirection
			'
			Me.chkChangeGrainDirection.AutoSize = True
			Me.chkChangeGrainDirection.Location = New System.Drawing.Point(30, 17)
			Me.chkChangeGrainDirection.Name = "chkChangeGrainDirection"
			Me.chkChangeGrainDirection.Size = New System.Drawing.Size(200, 17)
			Me.chkChangeGrainDirection.TabIndex = 0
			Me.chkChangeGrainDirection.Text = "Would you like to change Grain Direction?"
			Me.chkChangeGrainDirection.UseVisualStyleBackColor = True
			'
			'lblExtraLength
			'
			Me.lblExtraLength.AutoSize = True
			Me.lblExtraLength.Location = New System.Drawing.Point(30, 55)
			Me.lblExtraLength.Name = "lblExtraLength"
			Me.lblExtraLength.Size = New System.Drawing.Size(100, 13)
			Me.lblExtraLength.Text = "Enter Extra Length:"
			'
			'txtExtraLength
			'
			Me.txtExtraLength.Location = New System.Drawing.Point(220, 50)
			Me.txtExtraLength.Name = "txtExtraLength"
			Me.txtExtraLength.Size = New System.Drawing.Size(100, 20)
			Me.txtExtraLength.TabIndex = 1
			'
			'lblExtraWidth
			'
			Me.lblExtraWidth.AutoSize = True
			Me.lblExtraWidth.Location = New System.Drawing.Point(30, 85)
			Me.lblExtraWidth.Name = "lblExtraWidth"
			Me.lblExtraWidth.Size = New System.Drawing.Size(100, 13)
			Me.lblExtraWidth.Text = "Enter Extra Width:"
			'
			'txtExtraWidth
			'
			Me.txtExtraWidth.Location = New System.Drawing.Point(220, 80)
			Me.txtExtraWidth.Name = "txtExtraWidth"
			Me.txtExtraWidth.Size = New System.Drawing.Size(100, 20)
			Me.txtExtraWidth.TabIndex = 2
			'
			'btnOK
			'
			Me.btnOK.Location = New System.Drawing.Point(152, 130)
			Me.btnOK.Name = "btnOK"
			Me.btnOK.Size = New System.Drawing.Size(75, 23)
			Me.btnOK.TabIndex = 3
			Me.btnOK.Text = "OK"
			Me.btnOK.UseVisualStyleBackColor = True
			'
			'btnCancel
			'
			'Me.btnCancel.Location = New System.Drawing.Point(220, 130)
			'Me.btnCancel.Name = "btnCancel"
			'Me.btnCancel.Size = New System.Drawing.Size(75, 23)
			'Me.btnCancel.TabIndex = 4
			'Me.btnCancel.Text = "Quit"
			'Me.btnCancel.UseVisualStyleBackColor = True
			'
			'Form1
			'
			Me.AcceptButton = Me.btnOK
			'Me.CancelButton = Me.btnCancel
			Me.ClientSize = New System.Drawing.Size(380, 170)
			Me.Controls.Add(Me.chkChangeGrainDirection)
			Me.Controls.Add(Me.lblExtraLength)
			Me.Controls.Add(Me.txtExtraLength)
			Me.Controls.Add(Me.lblExtraWidth)
			Me.Controls.Add(Me.txtExtraWidth)
			Me.Controls.Add(Me.btnOK)
			'Me.Controls.Add(Me.btnCancel)
			Me.Name = "Form1"
			Me.Text = "Dimensions"
			Me.ResumeLayout(False)
			Me.PerformLayout()
		End Sub

		Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
			' Set the IsGrainDirectionChanged based on the checkbox
			Me.IsGrainDirectionChanged = chkChangeGrainDirection.Checked
			' Set the properties based on user input
			If chkChangeGrainDirection.Checked Then
				Me.IsGrainDirectionChanged = True
			End If

			Dim lengthExtraValue As Double
			Dim widthExtraValue As Double

			' Validate and set LengthExtra
			If Not String.IsNullOrWhiteSpace(txtExtraLength.Text) AndAlso Double.TryParse(txtExtraLength.Text, lengthExtraValue) Then
				Me.LengthExtra = lengthExtraValue
			ElseIf Not String.IsNullOrWhiteSpace(txtExtraLength.Text) Then
				MessageBox.Show("Enter a proper lenght number worthy of my time. ", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
				Return
			End If

			' Validate and set WidthExtra
			If Not String.IsNullOrWhiteSpace(txtExtraWidth.Text) AndAlso Double.TryParse(txtExtraWidth.Text, widthExtraValue) Then
				Me.WidthExtra = widthExtraValue
			ElseIf Not String.IsNullOrWhiteSpace(txtExtraWidth.Text) Then
				MessageBox.Show("Enter a proper width number worthy of my time. ", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
				Return
			End If

			Me.DialogResult = DialogResult.OK
			Me.Close()
		End Sub
	End Class	
	
	Sub AddPartAttribute(ByVal comp As Component, ByVal attTitle As String, ByVal attValue As String)
		If comp Is Nothing Then
			lw.WriteLine("A null component? Unacceptable!")
			Exit Sub
		End If

		Try
			Dim objects1(0) As NXObject
			objects1(0) = comp

			Dim attributePropertiesBuilder1 As AttributePropertiesBuilder
			attributePropertiesBuilder1 = theSession.AttributeManager.CreateAttributePropertiesBuilder(workPart, objects1, AttributePropertiesBuilder.OperationType.None)

			attributePropertiesBuilder1.IsArray = False
			attributePropertiesBuilder1.DataType = AttributePropertiesBaseBuilder.DataTypeOptions.String
			attributePropertiesBuilder1.ObjectPicker = AttributePropertiesBaseBuilder.ObjectOptions.ComponentAsPartAttribute
			attributePropertiesBuilder1.Title = attTitle
			attributePropertiesBuilder1.StringValue = attValue

			Dim nXObject1 As NXObject
			nXObject1 = attributePropertiesBuilder1.Commit()

			attributePropertiesBuilder1.Destroy()
		Catch ex As Exception
			lw.WriteLine("A flaw in the enchantment: " & ex.Message)
		End Try
	End Sub

	Public Function GetUnloadOption(dummy As String) As Integer
		GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination
	End Function

End Module
 
UPDATE V1.09: Part-Level Unit Recognition, Measurement Precision Configuration, Nearest Half Rounding for Millimeters, Trim Trailing Zeros, GUI-Based Modification Control, Material Thickness Adjustment and added Configuration Settings

Also, I couldn't sleep and ended up compiling all my codes into a package, including some pictures and explanations on how I use them. This dimension tool is part of this package, and you can download it from GitHub:
Link
 
Hello guys,
I moved the repo, please see the new link below or on NXJournaling as before:
Link
 
And if you prefer not to leave the site, here is the latest code:

Code:
' Written by Tamas Woller - March 2024, V109
' Journal desciption: Iterates through all components in the main assembly, including subassemblies, calculating the dimensions of each component - Length, Width And Material Thickness.
' Shared on NXJournaling.com
' Written in VB.Net
' Tested on Siemens NX 2212 and 2306, Native and Teamcenter 13

' Solid Body Requirements:
' If the body is on Layer 1, it will be processed.
' If on any layer other than Layer 1, it will be skipped.
' If multiple bodies are on Layer 1, the script will skip the component

' ChangeLog:
' V100 - Initial Release - December 2023
' V101 - Improved the handling of NXOpen expressions
' V103 - Part-Level Unit Recognition, Measurement Precision Configuration, Nearest Half Rounding for Millimeters, Trim Trailing Zeros, GUI-Based Modification Control, Material Thickness Adjustment and added Configuration Settings
' V105 - Added "Maybe" to GUI-Based Modification Control
' V107 - Subassemblies (Components with children) skip, Part name output instead Component, added notes and minor changes in Output Window
' V109 - Expressions delete moved from the end to right after bounding box disposal

Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Utilities
Imports NXOpen.Assemblies
Imports System.Drawing
Imports System.Windows.Forms

Module NXJournal
	Dim theSession As Session = Session.GetSession()
	Dim lw As ListingWindow = theSession.ListingWindow
	Dim theUFSession As UFSession = UFSession.GetUFSession()
	Dim theUI As UI = UI.GetUI()
	Dim workPart As Part = theSession.Parts.Work
	Dim Length As Double
	Dim Width As Double
	Dim winFormLocationX As Integer = 317 ' Default X position for GUI
	Dim winFormLocationY As Integer = 317 ' Default Y position for GUI
	Dim formattedWidth As Double
	Dim formattedDepth As Double
	Dim formattedHeight As Double
	Dim unitString As String
	Dim modifications As Boolean


	'------------------------
	' Configuration Settings:
	' Adjust these values accordingly, as the numbers represent the identified material thicknesses. The example below shows the most common thicknesses, with the first seven in inches and the following seven in millimeters. Note, the unit check occurs at the part level, allowing for different units (inch and millimeter) within the same assembly. The code automatically adjusts based on each part's unit.
	Dim validThicknesses As Double() = {0.141, 0.203, 0.25, 0.453, 0.469, 0.709, 0.827, 6, 9, 12, 13, 15, 18, 19}

	'Defines the precision for formatting measurements. "F0" means no decimal places, "F4" formats a number to 4 decimal places (e.g., 15.191832181891 to 15.1918). Values for NX makes sense between F0 to F13.
	Dim decimalFormat As String = "F1"

	'Controls whether to round measurements to the nearest half. Applicable only for millimeters and the decimal places will be forced to 1 by the code. When True, rounds 12.4999787 to 12.5. When False, rounds to the nearest whole number as decimalformat set (e.g. with F1, 12.2535. to 12.0, or with F3, 12.2535 to 12.254). Looks neat, if you use this with trimzeros set to True.
	Dim roundToNearestHalfBLN As Boolean = True

	'' Determines the state of GUI-based modifications. A value of "True" enables user input through the GUI for modifications. A value of "False" bypasses the GUI, allowing the program to run automatically with predefined settings, akin to a "Just Do It" mode - no questions asked. "Maybe" will prompts you at the start of the journal to decide whether to enable modifications. Note, while the code is running, the NX window will not respond. Before starting, set your Model to trimetric view and position your Information Window so it doesn't obstruct your model. You can access the window using Ctrl+Shift+S.
	Dim modificationsQST As String = "Maybe"

	' Controls whether predefined material thickness adjustments are applied. When set to True, material thickness values are automatically adjusted to match predefined standards (e.g., for Laminates, you might model a 12mm Laminate with an extra 1mm for a total of 13mm, but require the output to be 12mm, thus the 13mm is adjusted back to 12mm). You need to include the "13" in the validThicknesses, so the code can identify at first, then adjust as required. To configure predefined values, see code from line 540 - under 'Configuration Settings'. You can add or remove values as needed, but ensure to maintain the format. 
	' Set to False to maintain original material thickness measurements without automatic adjustments. 
	Dim materialthicknessadjust As Boolean = True

	' Controls the trimming of unnecessary trailing zeros in the numerical output. When set to True, trailing zeros after the decimal point are removed for a cleaner display. For example, "12.34000" becomes "12.34", and "15.00" becomes "15". When False, numbers are displayed as formatted according to the specified decimal precision without trimming zeros.
	Dim trimzeros As Boolean = True

	' Quick setting variables for attribute names
	Dim LengthAttribute As String = "DIM_LENGTH"
	Dim WidthAttribute As String = "DIM_WIDTH"
	Dim MaterialThicknessAttribute As String = "MAT_THICKNESS"
	'------------------------


	' Use a Dictionary to track processed components
	Private ProcessedComponents As New Dictionary(Of String, Boolean)

	Sub Main()
		Dim markId1 As NXOpen.Session.UndoMarkId
		markId1 = theSession.SetUndoMark(NXOpen.Session.MarkVisibility.Visible, "Dimensions Tool")
		lw.Open()

		' Make all components visible
		Dim showhide As Integer = theSession.DisplayManager.ShowByType(DisplayManager.ShowHideType.All, DisplayManager.ShowHideScope.AnyInAssembly)
		workPart.ModelingViews.WorkView.FitAfterShowOrHide(NXOpen.View.ShowOrHideType.ShowOnly)

		Try
			Dim workPart As Part = theSession.Parts.Work
			Dim dispPart As Part = theSession.Parts.Display
			Dim ca As ComponentAssembly = dispPart.ComponentAssembly

			' Assume modificationsQST is a String that can have values "True", "False", or anything else for an undecided state
			If modificationsQST IsNot Nothing AndAlso (modificationsQST.Equals("True", StringComparison.OrdinalIgnoreCase) OrElse modificationsQST.Equals("False", StringComparison.OrdinalIgnoreCase)) Then
				' If modificationsQST is a clear "True" or "False", convert it to a Boolean
				modifications = Boolean.Parse(modificationsQST)
			Else
				' If modificationsQST is not clearly "True" or "False", prompt the user
				Dim userResponse As DialogResult = MessageBox.Show("Would you like to modify the dimensions on this assembly?", "Modifications", MessageBoxButtons.YesNoCancel)
				Select Case userResponse
					Case DialogResult.Yes
						' The user wants to make modifications.
						modifications = True
					Case DialogResult.No
						' The user does not want to make modifications.
						modifications = False
					Case DialogResult.Cancel
						' The user has chosen to quit the journal.
						lw.WriteLine("A spell has been cast to abort the operation.")
						Return
				End Select
			End If

			lw.WriteLine("------------------------------------------------------------")
			lw.WriteLine("Lord Voldemort's Dimensions Tool          Version: 1.09 NXJ")
			lw.WriteLine(" ")

			' Extract the number of decimal places from the format string for a clearer message
			Dim decimalPlaces As Integer = GetDecimalPlaces(decimalFormat)
 
			lw.WriteLine("--------------------------------")
			lw.WriteLine("Configuration Settings Overview:")
			lw.WriteLine(" ")
			lw.WriteLine("Numerical Output Configuration:")
			lw.WriteLine(" - Decimal Precision:             " & decimalPlaces.ToString())
			lw.WriteLine(" - Rounding to Nearest Half:      " & If(roundToNearestHalfBLN, "Yes", "No"))
			lw.WriteLine(" - Trimming Trailing Zeros:       " & If(trimzeros, "Yes", "No"))
			lw.WriteLine(" ")
			lw.WriteLine("Additional Changes:")
			lw.WriteLine(" - GUI Modifications Enabled:     " & If(modifications, "Yes", "No"))
 
			Dim validThicknessesStr As String = ""
			For Each thickness As Double In validThicknesses
				If validThicknessesStr <> "" Then
					validThicknessesStr &= ", "
				End If
				validThicknessesStr &= thickness.ToString()
			Next
 
			lw.WriteLine(" - Material Thickness adjustment: " & If(materialthicknessadjust, "Yes", "No"))
			lw.WriteLine(" - Valid material thicknesses:    ")
			lw.WriteLine("   " & validThicknessesStr)
			lw.WriteLine(" ")
			lw.WriteLine("Attribute Names Configuration:")
			lw.WriteLine(" - Length Attribute:              " & LengthAttribute)
			lw.WriteLine(" - Width Attribute:               " & WidthAttribute)
			lw.WriteLine(" - Material Thickness Attribute:  " & MaterialThicknessAttribute)
			lw.WriteLine("-------------------------------")

			If Not IsNothing(dispPart) Then
				lw.WriteLine(" ")
				lw.WriteLine("The Main Assembly reveals itself as: ")
				lw.WriteLine(" - " & dispPart.Name)
				ReportComponentChildren(ca.RootComponent)
			Else
				lw.WriteLine("This part is devoid of any components, much like a soul without magic.")
			End If
		Catch e As Exception
			theSession.ListingWindow.WriteLine("Failure? Impossible! " & e.ToString)
		Finally
			' Reset to main assembly
			'lw.WriteLine(" ")
			'lw.WriteLine("Withdrawing to the main assembly, like a phantom retreating into the void.")
			ResetToMainAssembly()
		End Try
	End Sub

	Sub ReportComponentChildren(ByVal comp As Component)
		' List to keep track of components along with their suppressed status
		Dim componentsWithStatus As New List(Of Tuple(Of Component, Boolean))

		' List to keep track of processed component display names for duplicate check
		Dim NameList As New List(Of String)

		' Collect components and their suppressed status
		For Each child As Component In comp.GetChildren()
			' Add component and its suppressed status to the list
			componentsWithStatus.Add(New Tuple(Of Component, Boolean)(child, child.IsSuppressed))
		Next

		' Sort the list so that suppressed components come first
		componentsWithStatus.Sort(Function(x, y) y.Item2.CompareTo(x.Item2))

		' Process sorted components
		For Each tuple As Tuple(Of Component, Boolean) In componentsWithStatus
			Dim child As Component = tuple.Item1
			Dim isSuppressed As Boolean = tuple.Item2

			' Check for duplicate part
			If NameList.Contains(child.DisplayName()) Then
				' Logic for handling duplicate parts
				Continue For
			Else
				NameList.Add(child.DisplayName()) ' Add new component display name to the list
			End If

			If isSuppressed Then
				Continue For
			Else
				' If the component has children, it's a subassembly; skip processing it directly
				If child.GetChildren().Length > 0 Then
					' It's a subassembly, skip processing it but continue to check its children
					'lw.WriteLine(" ")
					'lw.WriteLine("Encountered a subassembly: " & child.DisplayName() & ", delving deeper...")
					ReportComponentChildren(child)
				Else
					' It's a single part with no children, process it
					lw.WriteLine(" ")
					lw.WriteLine("-----------------------------")

					Dim childPart As Part = LoadComponentAndGetPart(child)
					If childPart IsNot Nothing AndAlso childPart.IsFullyLoaded Then
						' Changed from child.DisplayName() to childPart.Name for part name output
						lw.WriteLine("Processing Overview for Part: ")
						lw.WriteLine(" - " & childPart.Name)
						ProcessBodies(childPart, child) ' Pass the Part and Component objects
					Else
						lw.WriteLine("This part lacks the magic it needs, it is not fully conjured.")
					End If
				End If
			End If
		Next
	End Sub

	Sub ProcessBodies(ByVal part As Part, ByVal comp As Component)
		Dim lw As ListingWindow = theSession.ListingWindow
		Dim nXObject1 As NXOpen.NXObject
		Dim bbWidth, bbDepth, bbHeight, Length, Width, MaterialThickness As Double
		Dim lengthDisplay As String = ""
		Dim widthDisplay As String = ""

		' Capture existing expressions before creating the tooling box
		Dim initialExpressionNames As New List(Of String)
		For Each expr As Expression In part.Expressions
			initialExpressionNames.Add(expr.JournalIdentifier)
		Next

		' Set the measure manager to consistent unit
		Dim myMeasure As MeasureManager = part.MeasureManager()
		Dim wIconMOseT(0) As Unit
		wIconMOseT(0) = part.UnitCollection.GetBase("Length")

		' Create a mass properties measurement for the entire part
		Dim mb As MeasureBodies = myMeasure.NewMassProperties(wIconMOseT, 0.99, part.Bodies.ToArray())

		' Ensure you are operating on the correct part object
		Dim currentPart As Part = comp.Prototype

		' Now, perform the unit check on the currentPart
		If currentPart.PartUnits = BasePart.Units.Inches Then
			unitString = "in"
			lw.WriteLine(" ")
			lw.WriteLine(" - Measurement Unit System: Imperial (Inches)")
			lw.WriteLine(" ")
			mb.InformationUnit = MeasureBodies.AnalysisUnit.PoundInch
		Else
			unitString = "mm"
			lw.WriteLine(" ")
			lw.WriteLine(" - Measurement Unit System: Metric (Millimeters)")
			lw.WriteLine(" ")
			mb.InformationUnit = MeasureBodies.AnalysisUnit.KilogramMilliMeter
		End If

		' Check if the part is valid and loaded
		If Not part Is Nothing AndAlso part.IsFullyLoaded Then
			' Get the list of solid bodies in the part
			Dim bodies As Body() = part.Bodies.ToArray()

			' Lists to track bodies on Layer 1
			Dim bodiesOnLayer1 As New List(Of Body)

			' Check bodies and categorize based on layer
			For Each body As Body In bodies

				Dim bodyLayer As Integer = body.Layer
				Dim bodyName As String = If(String.IsNullOrEmpty(body.Name), "Unnamed Body", body.Name)

				If bodyLayer = 1 Then
					bodiesOnLayer1.Add(body)
					lw.WriteLine(" - Discovery: " & bodyName & " on Layer 1")
				Else
					lw.WriteLine(" - A mere illusion: " & bodyName & " on Layer " & bodyLayer.ToString())
					'lw.WriteLine("   I shall disregard it.")
				End If
			Next

			' Check the number of bodies on Layer 1
			If bodiesOnLayer1.Count > 1 Then
				lw.WriteLine(" ")
				lw.WriteLine("Too many forms vie for attention on Layer 1")
				'lw.WriteLine("I shall choose none.")
				Exit Sub
			ElseIf bodiesOnLayer1.Count = 1 Then
				' Process the single body found on Layer 1
				Dim bodyToProcess As Body = bodiesOnLayer1(0)
				lw.WriteLine(" ")
				lw.WriteLine("Now the magic begins. Proceeding with dimension analysis...")

				Try
					' Calculate and display the center of mass
					Dim accValue(10) As Double
					accValue(0) = 0.999
					Dim massProps(46) As Double
					Dim stats(12) As Double
					theUFSession.Modl.AskMassProps3d(New Tag() {bodyToProcess.Tag}, 1, 1, 4, 0.03, 1, accValue, massProps, stats)

					' Convert the center of mass coordinates to Double
					Dim com_x As Double = massProps(3)
					Dim com_y As Double = massProps(4)
					Dim com_z As Double = massProps(5)

					Dim toolingBoxBuilder1 As NXOpen.Features.ToolingBoxBuilder = workPart.Features.ToolingFeatureCollection.CreateToolingBoxBuilder(Nothing)
					toolingBoxBuilder1.Type = NXOpen.Features.ToolingBoxBuilder.Types.BoundedBlock
					toolingBoxBuilder1.ReferenceCsysType = NXOpen.Features.ToolingBoxBuilder.RefCsysType.SelectedCsys
					toolingBoxBuilder1.XValue.SetFormula("10")
					toolingBoxBuilder1.YValue.SetFormula("10")
					toolingBoxBuilder1.ZValue.SetFormula("10")
					toolingBoxBuilder1.OffsetPositiveX.SetFormula("0")
					toolingBoxBuilder1.OffsetNegativeX.SetFormula("0")
					toolingBoxBuilder1.OffsetPositiveY.SetFormula("0")
					toolingBoxBuilder1.OffsetNegativeY.SetFormula("0")
					toolingBoxBuilder1.OffsetPositiveZ.SetFormula("0")
					toolingBoxBuilder1.OffsetNegativeZ.SetFormula("0")
					toolingBoxBuilder1.RadialOffset.SetFormula("0")
					toolingBoxBuilder1.Clearance.SetFormula("0")
					toolingBoxBuilder1.CsysAssociative = True
					toolingBoxBuilder1.NonAlignedMinimumBox = True
					toolingBoxBuilder1.SingleOffset = False

					Dim selectionIntentRuleOptions1 As NXOpen.SelectionIntentRuleOptions = Nothing
					selectionIntentRuleOptions1 = workPart.ScRuleFactory.CreateRuleOptions()
					selectionIntentRuleOptions1.SetSelectedFromInactive(False)

					Dim selectedBody As NXOpen.Body = TryCast(NXOpen.Utilities.NXObjectManager.Get(bodyToProcess.Tag), NXOpen.Body)
					If selectedBody Is Nothing Then
						lw.WriteLine("The tag you dare present does not match any corporeal form.")
						Return
					End If

					' Use the selectedBody for creating the dumb rule
					Dim bodyDumbRule1 As NXOpen.BodyDumbRule = workPart.ScRuleFactory.CreateRuleBodyDumb(New Body() {selectedBody}, True, selectionIntentRuleOptions1)
					selectionIntentRuleOptions1.Dispose()

					Dim scCollector1 As NXOpen.ScCollector = toolingBoxBuilder1.BoundedObject
					Dim rules1(0) As NXOpen.SelectionIntentRule
					rules1(0) = bodyDumbRule1
					scCollector1.ReplaceRules(rules1, False)

					' Use the selectedBody in SetSelectedOccurrences
					Dim selections1(0) As NXOpen.NXObject
					selections1(0) = selectedBody
					Dim deselections1(-1) As NXOpen.NXObject
					toolingBoxBuilder1.SetSelectedOccurrences(selections1, deselections1)

					Dim selectNXObjectList1 As NXOpen.SelectNXObjectList = Nothing
					selectNXObjectList1 = toolingBoxBuilder1.FacetBodies
					Dim objects1(-1) As NXOpen.NXObject
					Dim added1 As Boolean = Nothing
					added1 = selectNXObjectList1.Add(objects1)
					toolingBoxBuilder1.CalculateBoxSize()

					' Set the box position using the center of mass coordinates
					Dim csysorigin1 As NXOpen.Point3d = New NXOpen.Point3d(com_x, com_y, com_z)
					toolingBoxBuilder1.BoxPosition = csysorigin1

					' Commit the tooling box to create the feature
					nXObject1 = toolingBoxBuilder1.Commit()

					' Destroy the tooling box builder
					If toolingBoxBuilder1 IsNot Nothing Then
						toolingBoxBuilder1.Destroy()
					End If

					' Access the body of the bounding box feature
					Dim bboxFeature As Features.Feature = TryCast(nXObject1, Features.Feature)
					Dim bboxBody As Body = Nothing
					Dim innerBboxBody As Body = Nothing

					If bboxFeature IsNot Nothing Then
						For Each innerBboxBody In bboxFeature.GetBodies()
							'bboxBody = body
							Exit For
						Next
					End If

					If innerBboxBody IsNot Nothing Then
						' Initialize directions and distances arrays
						Dim minCorner(2) As Double
						Dim directions(,) As Double = New Double(2, 2) {}
						Dim distances(2) As Double

						' Get the bounding box of the body
						theUFSession.Modl.AskBoundingBoxExact(innerBboxBody.Tag, Tag.Null, minCorner, directions, distances)

						' Define the minimum corner point
						Dim cornerPoint As Point3d = New Point3d(minCorner(0), minCorner(1), minCorner(2))

						' Initialize a List to store unique vertices
						Dim vertices As New List(Of Point3d)()

						' Iterate through all edges in the body and get vertices
						For Each edge As Edge In innerBboxBody.GetEdges()
							Dim vertex1 As Point3d, vertex2 As Point3d
							edge.GetVertices(vertex1, vertex2)
							If Not vertices.Contains(vertex1) Then vertices.Add(vertex1)
							If Not vertices.Contains(vertex2) Then vertices.Add(vertex2)
						Next

						' Select the first vertex as the starting vertex
						Dim startingVertex As Point3d = vertices(0)

						' Initialize a List to store lengths of edges connected to the starting vertex
						Dim edgeLengths As New List(Of Double)
						Dim edgesAtStartingVertex As Integer = 0

						' Iterate through all edges in the body
						For Each edge As Edge In innerBboxBody.GetEdges()
							Dim vertex1 As Point3d, vertex2 As Point3d
							edge.GetVertices(vertex1, vertex2)
							If IsPointEqual(startingVertex, vertex1) OrElse IsPointEqual(startingVertex, vertex2) Then
								edgesAtStartingVertex += 1
								edgeLengths.Add(edge.GetLength())
							End If
						Next

						' Check if we have at least three edges before accessing the list
						If edgeLengths.Count >= 3 Then
							' Sort the edge lengths
							edgeLengths.Sort()

							' Output the initial (raw) bounding box dimensions before any formatting
							lw.WriteLine("")
							lw.WriteLine("Initial Bounding Box Dimensions:")
							lw.WriteLine(" - Width:  " & edgeLengths(0) & " " & unitString)
							lw.WriteLine(" - Depth:  " & edgeLengths(1) & " " & unitString)
							lw.WriteLine(" - Height: " & edgeLengths(2) & " " & unitString)
							lw.WriteLine(" ")

							' Directly format the edge lengths with rounding and precision applied as needed
							formattedWidth = FormatNumber(edgeLengths(0))
							formattedDepth = FormatNumber(edgeLengths(1))
							formattedHeight = FormatNumber(edgeLengths(2))

						Else
							lw.WriteLine("Not enough edges found, like a spell half-cast.")
						End If

						' Valid material thicknesses check
						Dim materialThicknessIdentified As Boolean = False

						' Identify Material Thickness
						If Array.IndexOf(validThicknesses, formattedWidth) >= 0 Then
							MaterialThickness = formattedWidth
							materialThicknessIdentified = True
							lw.WriteLine("Material thickness identified.")
						ElseIf Array.IndexOf(validThicknesses, formattedDepth) >= 0 Then
							MaterialThickness = formattedDepth
							materialThicknessIdentified = True
							lw.WriteLine("Material thickness identified.")
						ElseIf Array.IndexOf(validThicknesses, formattedHeight) >= 0 Then
							MaterialThickness = formattedHeight
							materialThicknessIdentified = True
							lw.WriteLine("Material thickness identified.")
						End If

						If Not materialThicknessIdentified Then
							' Handle case where material thickness is not identified
							MaterialThickness = Math.Min(formattedWidth, Math.Min(formattedDepth, formattedHeight))
							lw.WriteLine("Cannot identify material thickness. Using the smallest dimension instead.")
						End If

						' Determine Length and Width from the remaining dimensions
						Dim remainingDimensions As New List(Of Double) From {formattedWidth, formattedDepth, formattedHeight}
						remainingDimensions.Remove(MaterialThickness)

						' Ensure there are two dimensions left
						If remainingDimensions.Count = 2 Then
							' Assign the larger value to Length and the smaller to Width
							Length = Math.Max(remainingDimensions(0), remainingDimensions(1))
							Width = Math.Min(remainingDimensions(0), remainingDimensions(1))
						Else
							lw.WriteLine("Unable to determine Length and Width accurately.")
						End If

						' Delete the bounding box feature
						Dim featureTags(0) As NXOpen.Tag
						featureTags(0) = bboxFeature.Tag
						theUFSession.Modl.DeleteFeature(featureTags)

                        ' Identify new expressions after creating the tooling box
                        Dim newExpressions As New List(Of Expression)
                        For Each expr As Expression In part.Expressions
                            If Not initialExpressionNames.Contains(expr.JournalIdentifier) Then
                                newExpressions.Add(expr)
                            End If
                        Next

                        ' First round: delete expressions directly created by the tooling box
                        For Each expr As Expression In newExpressions
                            Try
                                part.Expressions.Delete(expr)
                            Catch deleteEx As NXOpen.NXException
                                ' Ignore the exception and proceed
                            End Try
                        Next

                        ' Second round: delete any remaining new interlinked expressions
                        For Each expr As Expression In part.Expressions
                            If Not initialExpressionNames.Contains(expr.JournalIdentifier) Then
                                Try
                                    part.Expressions.Delete(expr)
                                Catch deleteEx As NXOpen.NXException
                                    ' Log the exception but do not stop the process
                                    lw.WriteLine("Failed to delete expression '" & expr.JournalIdentifier & "': " & deleteEx.Message)
                                End Try
                            End If
                        Next

						' Update Length and Width based on user input or predefined settings
						If modifications Then
							Dim myForm As New Form1()
							If myForm.ShowDialog() = DialogResult.OK Then
								' Check the IsGrainDirectionChanged property
								If myForm.IsGrainDirectionChanged Then
									' Flip Length and Width
									Dim temp As Double = Length
									Length = Width
									Width = temp
									lw.WriteLine(" ")
									lw.WriteLine("The grain direction has been successfully altered.")
								End If

								' Update Length and Width based on LengthScribe and WidthScribe, applying FormatNumber
								' This will apply whether the scribe is positive or negative
								Length += myForm.LengthScribe
								lengthDisplay = FormatNumber(Length)
								If myForm.LengthScribe <> 0 Then
									lengthDisplay &= " (" & myForm.LengthScribe.ToString & ")"
								End If

								Width += myForm.WidthScribe
								widthDisplay = FormatNumber(Width)
								If myForm.WidthScribe <> 0 Then
									widthDisplay &= " (" & myForm.WidthScribe.ToString & ")"
								End If
							End If
						Else
							lengthDisplay = FormatNumber(Length)
							widthDisplay = FormatNumber(Width)
						End If

						' Write the updated dimensions to the listing window
						lw.WriteLine(" ")
						lw.WriteLine("Final Dimensions after Sorting and Rounding:")
						lw.WriteLine(" - Length: " & lengthDisplay & " " & unitString)
						lw.WriteLine(" - Width:  " & widthDisplay & " " & unitString)
						lw.WriteLine(" ")
						lw.WriteLine("Material Thickness Adjustment and Dimension Summary: ")
						lw.WriteLine(" - Original Material Thickness: " & FormatNumber(MaterialThickness) & " " & unitString)

						If materialthicknessadjust Then
							Select Case MaterialThickness


								' ------------------------
								' Adjust Material Thickness Configuration Settings
								' Example: If the code identifies a length of 19 (Case 19), it adjusts the thickness to 18 (MaterialThickness = 18). Between " " will be the output message. Only use numbers here without unit. 
								Case 0.469
									MaterialThickness = 0.453
									lw.WriteLine(" - Adjusted Material Thickness: 0.453" & " " & unitString & " (according to preset adjustments)")
								Case 0.25
									MaterialThickness = 0.203
									lw.WriteLine(" - Adjusted Material Thickness: 0.203" & " " & unitString & " (according to preset adjustments)")
								Case 13
									MaterialThickness = 12
									lw.WriteLine(" - Adjusted Material Thickness: 12" & " " & unitString & " (according to preset adjustments)")
								Case 19
									MaterialThickness = 18
									lw.WriteLine(" - Adjusted Material Thickness: 18" & " " & unitString & " (according to preset adjustments)")
									'------------------------


							End Select
						Else
							'lw.WriteLine("Material thickness remains unadjusted at: " & MaterialThickness & " " & unitString)
							'lw.WriteLine(" ")
						End If

						lw.WriteLine(" ")
						lw.WriteLine("Attributes Successfully Updated:")
						' Adding Attributes to the Component as Part
						AddPartAttribute(comp, LengthAttribute, lengthDisplay)
						'lw.WriteLine(" - Length attribute (" & LengthAttribute & ") set to: " & lengthDisplay)
						lw.WriteLine(" - Length attribute set.")

						AddPartAttribute(comp, WidthAttribute, widthDisplay)
						'lw.WriteLine(" - Width attribute (" & WidthAttribute & ") set to: " & widthDisplay)
						lw.WriteLine(" - Width attribute set.")

						AddPartAttribute(comp, MaterialThicknessAttribute, FormatNumber(MaterialThickness))
						'lw.WriteLine(" - Material Thickness attribute (" & MaterialThicknessAttribute & ") set to: " & FormatNumber(MaterialThickness))
						lw.WriteLine(" - Material Thickness attribute set.")

					Else
						lw.WriteLine("The bounding box, a ghost, it eludes me.")
					End If

				Catch ex As Exception
					lw.WriteLine("An error? A mere setback in my grand design: " & ex.Message)
				Finally
				End Try
			Else
				lw.WriteLine(" - No solid bodies found on Layer 1")
			End If
		Else
			lw.WriteLine("The part before me is flawed, incomplete in its essence.")
		End If
	End Sub

	' Method to load a component and return the associated part
	Function LoadComponentAndGetPart(ByVal component As Component) As Part
		Dim partLoadStatus As PartLoadStatus = Nothing
		Try
			' Set the work component to load the component
			theSession.Parts.SetWorkComponent(component, PartCollection.RefsetOption.Current, PartCollection.WorkComponentOption.Visible, partLoadStatus)

			' Get the part associated with the component
			If TypeOf component.Prototype Is Part Then
				Return CType(component.Prototype, Part)
			End If
		Catch ex As Exception
			lw.WriteLine("An unexpected disturbance in the dark arts: " & ex.Message)
			Return Nothing
		Finally
			' Dispose of the part load status
			If partLoadStatus IsNot Nothing Then
				partLoadStatus.Dispose()
			End If
		End Try
		Return Nothing
	End Function

	' Method to reset to the main assembly
	Sub ResetToMainAssembly()
		Dim partLoadStatus2 As PartLoadStatus = Nothing

		Try
			' Reset to main assembly
			theSession.Parts.SetWorkComponent(Nothing, PartCollection.RefsetOption.Current, PartCollection.WorkComponentOption.Visible, partLoadStatus2)
			lw.WriteLine(" ")
			lw.WriteLine("As shadows gather and night befalls, our paths now diverge in silent halls.")
			lw.WriteLine("Remember, the Dark Lord's gaze, ever so watchful, in mystery's maze. ")
			lw.WriteLine("Until we meet in destiny's corridors, obscure and deep,")
			lw.WriteLine("our dark voyage concludes, in secrets we keep.")
			lw.WriteLine(" ")
		Catch ex As Exception
			lw.WriteLine("Failed to return to my dominion: " & ex.Message)
		Finally
			' Dispose the PartLoadStatus object if it's not null
			If partLoadStatus2 IsNot Nothing Then
				partLoadStatus2.Dispose()
			End If
		End Try
	End Sub

	Sub AddPartAttribute(ByVal comp As Component, ByVal attTitle As String, ByVal attValue As String)
		If comp Is Nothing Then
			lw.WriteLine("A null component? Unacceptable!")
			Exit Sub
		End If

		Try
			Dim objects1(0) As NXObject
			objects1(0) = comp

			Dim attributePropertiesBuilder1 As AttributePropertiesBuilder
			attributePropertiesBuilder1 = theSession.AttributeManager.CreateAttributePropertiesBuilder(workPart, objects1, AttributePropertiesBuilder.OperationType.None)

			attributePropertiesBuilder1.IsArray = False
			attributePropertiesBuilder1.DataType = AttributePropertiesBaseBuilder.DataTypeOptions.String
			attributePropertiesBuilder1.ObjectPicker = AttributePropertiesBaseBuilder.ObjectOptions.ComponentAsPartAttribute
			attributePropertiesBuilder1.Title = attTitle
			attributePropertiesBuilder1.StringValue = attValue

			Dim nXObject1 As NXObject
			nXObject1 = attributePropertiesBuilder1.Commit()

			attributePropertiesBuilder1.Destroy()
		Catch ex As Exception
			lw.WriteLine("A flaw in the enchantment: " & ex.Message)
		End Try
	End Sub

	Function IsPointEqual(point1 As Point3d, point2 As Point3d) As Boolean
		Const Tolerance As Double = 0.001
		Return (Math.Abs(point1.X - point2.X) < Tolerance AndAlso
				Math.Abs(point1.Y - point2.Y) < Tolerance AndAlso
				Math.Abs(point1.Z - point2.Z) < Tolerance)
	End Function

	Function GetDecimalPlaces(format As String) As Integer
		Dim decimalPlaces As Integer = 0
		If format.StartsWith("F") AndAlso Integer.TryParse(format.Substring(1), decimalPlaces) Then
			Return decimalPlaces
		End If
		Return 0 ' Default to 0 if the format is not recognized or no digits are specified
	End Function

	Function RoundToNearestHalf(value As Double) As Double
		Return Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2
	End Function

	Function FormatNumber(value As Double) As String
		Dim formatSpecifier As String = decimalFormat
		Dim result As String

		' Apply rounding to the nearest half if enabled and in millimeters
		If roundToNearestHalfBLN AndAlso unitString = "mm" Then
			value = Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2
			' Force F1 formatting when rounding to the nearest half for consistency
			formatSpecifier = "F1"
		End If

		' Format the value using the specified or adjusted decimal precision
		result = value.ToString(formatSpecifier, System.Globalization.CultureInfo.InvariantCulture)

		' Trim trailing zeros if trimzeros is True
		If trimzeros Then
			' Check if there's a decimal point to avoid trimming integers
			If result.Contains(".") Then
				' Trim unnecessary trailing zeros and the decimal point if it becomes redundant
				result = result.TrimEnd("0"c).TrimEnd("."c)
			End If
		End If

		Return result
	End Function

	' Settings for the GUI - Winforms. Feel free to experiment with these numbers to change colors, box size etc.
	' The default position for the input box set at the beginning of the Journal.
	<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
	Partial Class Form1
		Inherits System.Windows.Forms.Form

		Public Property LengthScribe As Double
		Public Property WidthScribe As Double
		Public Property IsGrainDirectionChanged As Boolean

		' Form designer variables
		Private components As System.ComponentModel.IContainer
		Friend WithEvents chkChangeGrainDirection As System.Windows.Forms.CheckBox
		Friend WithEvents txtScribeLength As System.Windows.Forms.TextBox
		Friend WithEvents txtScribeWidth As System.Windows.Forms.TextBox
		Friend WithEvents btnOK As System.Windows.Forms.Button
		'Friend WithEvents btnCancel As System.Windows.Forms.Button
		Friend WithEvents lblScribeLength As System.Windows.Forms.Label
		Friend WithEvents lblScribeWidth As System.Windows.Forms.Label

		<System.Diagnostics.DebuggerNonUserCode()>
		Protected Overrides Sub Dispose(ByVal disposing As Boolean)
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
			MyBase.Dispose(disposing)
		End Sub

		<System.Diagnostics.DebuggerStepThrough()>
		Private Sub Form1_Load(sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
			Me.StartPosition = FormStartPosition.Manual
			Me.Location = New System.Drawing.Point(winFormLocationX, winFormLocationY)

			' Setting the color properties of the form and its controls
			Me.BackColor = Color.FromArgb(55, 55, 55) ' Set form background color

			' Set colors for buttons
			btnOK.BackColor = Color.FromArgb(50, 50, 50)
			'btnCancel.BackColor = Color.FromArgb(50, 50, 50)

			' Setting the font colors to white
			txtScribeLength.ForeColor = Color.Black
			txtScribeWidth.ForeColor = Color.Black
			btnOK.ForeColor = Color.White
			'btnCancel.ForeColor = Color.White
			lblScribeLength.ForeColor = Color.White
			lblScribeWidth.ForeColor = Color.White
			chkChangeGrainDirection.ForeColor = Color.White
		End Sub

		Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
			' Save the location of the form
			winFormLocationX = Me.Location.X
			winFormLocationY = Me.Location.Y
		End Sub

		Private Sub InitializeComponent()
			Me.chkChangeGrainDirection = New System.Windows.Forms.CheckBox()
			Me.txtScribeLength = New System.Windows.Forms.TextBox()
			Me.txtScribeWidth = New System.Windows.Forms.TextBox()
			Me.btnOK = New System.Windows.Forms.Button()
			'Me.btnCancel = New System.Windows.Forms.Button()
			Me.lblScribeLength = New System.Windows.Forms.Label()
			Me.lblScribeWidth = New System.Windows.Forms.Label()
			Me.SuspendLayout()
			'
			'chkChangeGrainDirection
			'
			Me.chkChangeGrainDirection.AutoSize = True
			Me.chkChangeGrainDirection.Location = New System.Drawing.Point(30, 17)
			Me.chkChangeGrainDirection.Name = "chkChangeGrainDirection"
			Me.chkChangeGrainDirection.Size = New System.Drawing.Size(200, 17)
			Me.chkChangeGrainDirection.TabIndex = 0
			Me.chkChangeGrainDirection.Text = "Would you like to change Grain Direction?"
			Me.chkChangeGrainDirection.UseVisualStyleBackColor = True
			'
			'lblScribeLength
			'
			Me.lblScribeLength.AutoSize = True
			Me.lblScribeLength.Location = New System.Drawing.Point(30, 55)
			Me.lblScribeLength.Name = "lblScribeLength"
			Me.lblScribeLength.Size = New System.Drawing.Size(100, 13)
			Me.lblScribeLength.Text = "Enter Scribe Length:"
			'
			'txtScribeLength
			'
			Me.txtScribeLength.Location = New System.Drawing.Point(220, 50)
			Me.txtScribeLength.Name = "txtScribeLength"
			Me.txtScribeLength.Size = New System.Drawing.Size(100, 20)
			Me.txtScribeLength.TabIndex = 1
			'
			'lblScribeWidth
			'
			Me.lblScribeWidth.AutoSize = True
			Me.lblScribeWidth.Location = New System.Drawing.Point(30, 85)
			Me.lblScribeWidth.Name = "lblScribeWidth"
			Me.lblScribeWidth.Size = New System.Drawing.Size(100, 13)
			Me.lblScribeWidth.Text = "Enter Scribe Width:"
			'
			'txtScribeWidth
			'
			Me.txtScribeWidth.Location = New System.Drawing.Point(220, 80)
			Me.txtScribeWidth.Name = "txtScribeWidth"
			Me.txtScribeWidth.Size = New System.Drawing.Size(100, 20)
			Me.txtScribeWidth.TabIndex = 2
			'
			'btnOK
			'
			Me.btnOK.Location = New System.Drawing.Point(152, 130)
			Me.btnOK.Name = "btnOK"
			Me.btnOK.Size = New System.Drawing.Size(75, 23)
			Me.btnOK.TabIndex = 3
			Me.btnOK.Text = "OK"
			Me.btnOK.UseVisualStyleBackColor = True
			'
			'btnCancel
			'
			'Me.btnCancel.Location = New System.Drawing.Point(220, 130)
			'Me.btnCancel.Name = "btnCancel"
			'Me.btnCancel.Size = New System.Drawing.Size(75, 23)
			'Me.btnCancel.TabIndex = 4
			'Me.btnCancel.Text = "Quit"
			'Me.btnCancel.UseVisualStyleBackColor = True
			'
			'Form1
			'
			Me.AcceptButton = Me.btnOK
			'Me.CancelButton = Me.btnCancel
			Me.ClientSize = New System.Drawing.Size(380, 170)
			Me.Controls.Add(Me.chkChangeGrainDirection)
			Me.Controls.Add(Me.lblScribeLength)
			Me.Controls.Add(Me.txtScribeLength)
			Me.Controls.Add(Me.lblScribeWidth)
			Me.Controls.Add(Me.txtScribeWidth)
			Me.Controls.Add(Me.btnOK)
			'Me.Controls.Add(Me.btnCancel)
			Me.Name = "Form1"
			Me.Text = "Dimensions"
			Me.ResumeLayout(False)
			Me.PerformLayout()
		End Sub

		Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
			' Set the IsGrainDirectionChanged based on the checkbox
			Me.IsGrainDirectionChanged = chkChangeGrainDirection.Checked
			' Set the properties based on user input
			If chkChangeGrainDirection.Checked Then
				Me.IsGrainDirectionChanged = True
			End If

			Dim lengthScribeValue As Double
			Dim widthScribeValue As Double

			' Validate and set LengthScribe
			If Not String.IsNullOrWhiteSpace(txtScribeLength.Text) AndAlso Double.TryParse(txtScribeLength.Text, lengthScribeValue) Then
				Me.LengthScribe = lengthScribeValue
			ElseIf Not String.IsNullOrWhiteSpace(txtScribeLength.Text) Then
				MessageBox.Show("Enter a proper lenght number worthy of my time. ", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
				Return
			End If

			' Validate and set WidthScribe
			If Not String.IsNullOrWhiteSpace(txtScribeWidth.Text) AndAlso Double.TryParse(txtScribeWidth.Text, widthScribeValue) Then
				Me.WidthScribe = widthScribeValue
			ElseIf Not String.IsNullOrWhiteSpace(txtScribeWidth.Text) Then
				MessageBox.Show("Enter a proper width number worthy of my time. ", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
				Return
			End If

			Me.DialogResult = DialogResult.OK
			Me.Close()
		End Sub
	End Class

	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
 
Hello, dear colleague! Your work is awesome and super useful. Thanks a million for sharing it!

I'm planning to write some code of my own, inspired by your masterpiece. But, I've hit a little bump on the road. The code is below. Unlike yours, I’m trying to create a non-aligned minimum body for a selected body in a part file. I’ve gotten that far, but after that... well, let’s just say my brain took a coffee break! 😅

I want to write the dimensions of the bounding box (Width, Length, Height) to the body attributes. But, for the life of me, I can't figure out how to get those dimensions! Any chance you could guide this lost soul in the right direction?


Code:
' ' Written by M-OZCAN - Eylül 2024
'
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpenUI
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Globalization

Module NXJournal
Sub Main (ByVal args() As String) 

Dim theSession As NXOpen.Session = NXOpen.Session.GetSession()
Dim workPart As NXOpen.Part = theSession.Parts.Work

Dim displayPart As NXOpen.Part = theSession.Parts.Display


 Dim body1 As Body
        If SelectBody("select a body", body1) = Selection.Response.Cancel Then
            Return
        End If

        Dim theBodies(0) As Body
        theBodies(0) = body1
'--


Dim nullNXOpen_Features_ToolingBox As NXOpen.Features.ToolingBox = Nothing

Dim toolingBoxBuilder1 As NXOpen.Features.ToolingBoxBuilder = Nothing
toolingBoxBuilder1 = workPart.Features.ToolingFeatureCollection.CreateToolingBoxBuilder(nullNXOpen_Features_ToolingBox)

toolingBoxBuilder1.Type = NXOpen.Features.ToolingBoxBuilder.Types.BoundedBlock

toolingBoxBuilder1.NonAlignedMinimumBox = True


Dim selectionIntentRuleOptions1 As NXOpen.SelectionIntentRuleOptions = Nothing
selectionIntentRuleOptions1 = workPart.ScRuleFactory.CreateRuleOptions()

selectionIntentRuleOptions1.SetSelectedFromInactive(False)



Dim bodies1(0) As NXOpen.Body

bodies1(0) = body1
Dim bodyDumbRule1 As NXOpen.BodyDumbRule = Nothing
bodyDumbRule1 = workPart.ScRuleFactory.CreateRuleBodyDumb(bodies1, True, selectionIntentRuleOptions1)

selectionIntentRuleOptions1.Dispose()
Dim scCollector1 As NXOpen.ScCollector = Nothing
scCollector1 = toolingBoxBuilder1.BoundedObject

Dim rules1(0) As NXOpen.SelectionIntentRule
rules1(0) = bodyDumbRule1
scCollector1.ReplaceRules(rules1, False)

Dim selections1(0) As NXOpen.NXObject
selections1(0) = body1
Dim deselections1(-1) As NXOpen.NXObject
toolingBoxBuilder1.SetSelectedOccurrences(selections1, deselections1)

Dim selectNXObjectList1 As NXOpen.SelectNXObjectList = Nothing
selectNXObjectList1 = toolingBoxBuilder1.FacetBodies

Dim objects1(-1) As NXOpen.NXObject
Dim added1 As Boolean = Nothing
added1 = selectNXObjectList1.Add(objects1)

toolingBoxBuilder1.CalculateBoxSize()

Dim nXObject1 As NXOpen.NXObject = Nothing
nXObject1 = toolingBoxBuilder1.Commit()

Dim expression1 As NXOpen.Expression = toolingBoxBuilder1.OffsetPositiveZ

toolingBoxBuilder1.Destroy()

theSession.CleanUpFacetedFacesAndEdges()



End Sub

Function SelectBody(ByVal prompt As String, ByRef selObj As TaggedObject) As Selection.Response

        Dim theUI As UI = UI.GetUI
        Dim title As String = "Select a solid body"
        Dim includeFeatures As Boolean = False
        Dim keepHighlighted As Boolean = False
        Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
        Dim cursor As Point3d
        Dim scope As Selection.SelectionScope = Selection.SelectionScope.WorkPart
        Dim selectionMask_array(0) As Selection.MaskTriple

        With selectionMask_array(0)
            .Type = UFConstants.UF_solid_type
            .SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_SOLID_BODY
        End With

        Dim resp As Selection.Response = theUI.SelectionManager.SelectTaggedObject(prompt, _
         title, scope, selAction, _
         includeFeatures, keepHighlighted, selectionMask_array, _
         selobj, cursor)
        If resp = Selection.Response.ObjectSelected OrElse resp = Selection.Response.ObjectSelectedByName Then
            Return Selection.Response.Ok
        Else
            Return Selection.Response.Cancel
        End If

    End Function
End Module
 
Hi MrtZcn81!

I'm flattered and I'm glad you like the journal. I know how frustrating coding can be at first. Believe it or not, my very first project - the material journal (the EasyWeight main concept) - took me two weeks to develop (banging my head 1000 times), even though I had a good starting point from NXJournaling. That knowledge eventually became the foundation for my other journals, so don't give it up!

Anyway, this Dimension tool was developed in two smaller parts:

- One for the recursive walkthrough of the assembly structure and solid body filtering
- The other for bounding box creation for selected solid bodies.

I’ve attached my last working checkpoint for you and added the latest features. Since you’re looking for Width, Length, and Height, you can easily modify this version by removing the parts related to Material Thickness identification and adjustments. Instead, use the bounding box formatted values.

formattedWidth
formattedDepth
formattedHeight

and change the related lines where you attribute them (the names can be changed at the beginning of the journal:
AddPartAttribute(comp, LengthAttribute, lengthDisplay)
to
AddPartAttribute(comp, LengthAttribute, formattedDepth)

AddPartAttribute(comp, WidthAttribute, widthDisplay)
to
AddPartAttribute(comp, WidthAttribute, formattedWidth)

and
AddPartAttribute(comp, MaterialThicknessAttribute, FormatNumber(MaterialThickness))
to
AddPartAttribute(comp, MaterialThicknessAttribute, formattedHeight)

Also, if you get stuck, consider using ChatGPT or Claude - the free versions (I didn't mean to advertise anything)! When I started, they were more like a teacher guiding me, but they've since become incredibly useful for coding. Read my comments to understand what each part does, copy paste what you think you should change and provide detailed information about your requirements. The more detailed your question, the better the answer you'll get.

I hope this helps with what you’re trying to achieve!
(Please note that the comments are missing because I added them much later after decided to share it with you all. Check the V109 version - Bounding box details are identical.)

Good luck with your project!

Ps. Don't forget to set up the journal in the Configuration Settings, just as before.

Code:
' Written by Tamas Woller - September 2024, V309
' Journal desciption: Iterates through and calculates the dimensions of each selected solid bodies - Length, Width And Material Thickness and attributes them.
' Shared on NXJournaling.com
' Written in VB.Net
' Tested on Siemens NX 2212

' ChangeLog:
' V100 - Initial Release - December 2023
' V101 - Improved the handling of NXOpen expressions
' V103 - Part-Level Unit Recognition, Measurement Precision Configuration, Nearest Half Rounding for Millimeters, Trim Trailing Zeros, GUI-Based Modification Control, Material Thickness Adjustment and added Configuration Settings
' V105 - Added "Maybe" to GUI-Based Modification Control
' V107 - Subassemblies (Components with children) skip, Part name output instead Component, added notes and minor changes in Output Window
' V109 - Expressions delete moved from the end to right after bounding box disposal
' V309 - Modified version to work with solid bodies instead of componens. 

Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Utilities
Imports System.Drawing
Imports System.Windows.Forms

Module NXJournal
	Dim theSession As Session = Session.GetSession()
	Dim lw As ListingWindow = theSession.ListingWindow
	Dim theUFSession As UFSession = UFSession.GetUFSession()
	Dim theUI As UI = UI.GetUI()
	Dim workPart As Part = theSession.Parts.Work
	Dim displayPart As Part
	Dim mySelectedObjects As New List(Of DisplayableObject)
	Dim winFormLocationX As Integer = 317
	Dim winFormLocationY As Integer = 317
	Dim formattedWidth As Double
	Dim formattedDepth As Double
	Dim formattedHeight As Double
	Dim unitString As String
	Dim modifications As Boolean


	'------------------------
	' Configuration Settings:
	' Adjust these values accordingly, as the numbers represent the identified material thicknesses. The example below shows the most common thicknesses, with the first seven in inches and the following seven in millimeters. Note, the unit check occurs at the part level, allowing for different units (inch and millimeter) within the same assembly. The code automatically adjusts based on each part's unit.
	Dim validThicknesses As Double() = {0.141, 0.203, 0.25, 0.453, 0.469, 0.709, 0.827, 6, 9, 12, 13, 15, 18, 19}

	'Defines the precision for formatting measurements. "F0" means no decimal places, "F4" formats a number to 4 decimal places (e.g., 15.191832181891 to 15.1918). Values for NX makes sense between F0 to F13.
	Dim decimalFormat As String = "F1"

	'Controls whether to round measurements to the nearest half. Applicable only for millimeters and the decimal places will be forced to 1 by the code. When True, rounds 12.4999787 to 12.5. When False, rounds to the nearest whole number as decimalformat set (e.g. with F1, 12.2535. to 12.0, or with F3, 12.2535 to 12.254). Looks neat, if you use this with trimzeros set to True.
	Dim roundToNearestHalfBLN As Boolean = True

	' Determines the state of GUI-based modifications. A value of "True" enables user input through the GUI for modifications. A value of "False" bypasses the GUI, allowing the program to run automatically with predefined settings, akin to a "Just Do It" mode - no questions asked. "Maybe" will prompts you at the start of the journal to decide whether to enable modifications. Note, while the code is running, the NX window will not respond. Before starting, set your Model to trimetric view and position your Information Window so it doesn't obstruct your model. You can access the window using Ctrl+Shift+S.
	Dim modificationsQST As String = "Maybe"

	' Controls whether predefined material thickness adjustments are applied. When set to True, material thickness values are automatically adjusted to match predefined standards (e.g., for Laminates, you might model a 12mm Laminate with an extra 1mm for a total of 13mm, but require the output to be 12mm, thus the 13mm is adjusted back to 12mm). You need to include the "13" in the validThicknesses, so the code can identify at first, then adjust as required. To configure predefined values, see code from line 540 - under 'Configuration Settings'. You can add or remove values as needed, but ensure to maintain the format. 
	' Set to False to maintain original material thickness measurements without automatic adjustments. 
	Dim materialthicknessadjust As Boolean = True

	' Controls the trimming of unnecessary trailing zeros in the numerical output. When set to True, trailing zeros after the decimal point are removed for a cleaner display. For example, "12.34000" becomes "12.34", and "15.00" becomes "15". When False, numbers are displayed as formatted according to the specified decimal precision without trimming zeros.
	Dim trimzeros As Boolean = True

	' Quick setting variables for attribute names
	Dim LengthAttribute As String = "DIM_LENGTH"
	Dim WidthAttribute As String = "DIM_WIDTH"
	Dim MaterialThicknessAttribute As String = "MAT_THICKNESS"
	'------------------------

	
    Sub Main(ByVal args() As String)
		Dim nXObject1 As NXOpen.NXObject
		Dim bbWidth, bbDepth, bbHeight, Length, Width, MaterialThickness As Double
		Dim lengthDisplay As String = ""
		Dim widthDisplay As String = ""
		Dim markId1 As NXOpen.Session.UndoMarkId
		markId1 = theSession.SetUndoMark(NXOpen.Session.MarkVisibility.Visible, "Dimensions Tool")
		lw.Open()

		If modificationsQST IsNot Nothing AndAlso (modificationsQST.Equals("True", StringComparison.OrdinalIgnoreCase) OrElse modificationsQST.Equals("False", StringComparison.OrdinalIgnoreCase)) Then
			modifications = Boolean.Parse(modificationsQST)
		Else
			Dim userResponse As DialogResult = MessageBox.Show("Would you like to modify the dimensions for these Solid Bodies?", "Modifications", MessageBoxButtons.YesNoCancel)
			Select Case userResponse
				Case DialogResult.Yes
					modifications = True
				Case DialogResult.No
					modifications = False
				Case DialogResult.Cancel
					lw.WriteLine(" ")
					lw.WriteLine("The incantation falters, no spell can be cast. But the dark arts wait for none, perhaps next time...")
					Return
			End Select
		End If
		
		lw.WriteLine("------------------------------------------------------------")
		lw.WriteLine("Lord Voldemort's Dimensions Tool          Version: 3.09 NXJ")
		lw.WriteLine("Solid Body Edition ")
		lw.WriteLine(" ")

		Dim decimalPlaces As Integer = GetDecimalPlaces(decimalFormat)

		lw.WriteLine("--------------------------------")
		lw.WriteLine("Configuration Settings Overview:")
		lw.WriteLine(" ")
		lw.WriteLine("Numerical Output Configuration:")
		lw.WriteLine(" - Decimal Precision:             " & decimalPlaces.ToString())
		lw.WriteLine(" - Rounding to Nearest Half:      " & If(roundToNearestHalfBLN, "Yes", "No"))
		lw.WriteLine(" - Trimming Trailing Zeros:       " & If(trimzeros, "Yes", "No"))
		lw.WriteLine(" ")
		lw.WriteLine("Modifications:")
		lw.WriteLine(" - GUI Enabled:                   " & If(modifications, "Yes", "No"))

		Dim validThicknessesStr As String = ""
		For Each thickness As Double In validThicknesses
			If validThicknessesStr <> "" Then
				validThicknessesStr &= ", "
			End If
			validThicknessesStr &= thickness.ToString()
		Next

		lw.WriteLine(" - Material Thickness adjustment: " & If(materialthicknessadjust, "Yes", "No"))
		lw.WriteLine(" - Valid material thicknesses:    ")
		lw.WriteLine("   " & validThicknessesStr)
		lw.WriteLine(" ")
		lw.WriteLine("Attribute Names Configuration:")
		lw.WriteLine(" - Length Attribute:              " & LengthAttribute)
		lw.WriteLine(" - Width Attribute:               " & WidthAttribute)
		lw.WriteLine(" - Material Thickness Attribute:  " & MaterialThicknessAttribute)
		lw.WriteLine(" ")
		
        Try
            theSession = Session.GetSession()
            theUFSession = UFSession.GetUFSession()
            workPart = theSession.Parts.Work
            displayPart = theSession.Parts.Display
            theUI = UI.GetUI()

			If SelectObjects("Hey, select multiple somethings", mySelectedObjects) = Selection.Response.Ok Then
				Dim currentPart As Part = workPart
				Dim myMeasure As MeasureManager = currentPart.MeasureManager()

				Dim wIconMOseT(0) As Unit
				wIconMOseT(0) = currentPart.UnitCollection.GetBase("Length")

				Dim mb As MeasureBodies = myMeasure.NewMassProperties(wIconMOseT, 0.99, currentPart.Bodies.ToArray())

				If currentPart.PartUnits = BasePart.Units.Inches Then
					unitString = "in"
					lw.WriteLine(" - Measurement Unit System: Imperial (Inches)")
					lw.WriteLine("-------------------------------")
					lw.WriteLine(" ")
					mb.InformationUnit = MeasureBodies.AnalysisUnit.PoundInch
				Else
					unitString = "mm"
					lw.WriteLine(" - Measurement Unit System: Metric (Millimeters)")
					mb.InformationUnit = MeasureBodies.AnalysisUnit.KilogramMilliMeter
				End If

				For Each obj As DisplayableObject In mySelectedObjects
					Dim tempComp As Body = TryCast(obj, Body)
					If tempComp Is Nothing Then
						lw.WriteLine(" ")
						lw.WriteLine("The solid body before me is flawed, incomplete in its essence.")
						Continue For
					End If

					Try
						If String.IsNullOrEmpty(tempComp.Name) Then
							lw.WriteLine(" ")
							lw.WriteLine("-----------------------------")
							lw.WriteLine("Processing Overview for an unnamed Solid Body:")
						Else
							lw.WriteLine(" ")
							lw.WriteLine("-----------------------------")
							lw.WriteLine("Processing Overview for Solid Body:")
							lw.WriteLine(" - " & tempComp.Name)
						End If
						
						lw.WriteLine(" ")
						lw.WriteLine("The ritual begins... summoning the dark forces...")
						
						Dim accValue(10) As Double
						accValue(0) = 0.999
						Dim massProps(46) As Double
						Dim stats(12) As Double
						theUFSession.Modl.AskMassProps3d(New Tag() {tempComp.Tag}, 1, 1, 4, 0.03, 1, accValue, massProps, stats)

						Dim com_x As Double = massProps(3)
						Dim com_y As Double = massProps(4)
						Dim com_z As Double = massProps(5)

						Dim toolingBoxBuilder1 As NXOpen.Features.ToolingBoxBuilder = workPart.Features.ToolingFeatureCollection.CreateToolingBoxBuilder(Nothing)
						toolingBoxBuilder1.Type = NXOpen.Features.ToolingBoxBuilder.Types.BoundedBlock
						toolingBoxBuilder1.ReferenceCsysType = NXOpen.Features.ToolingBoxBuilder.RefCsysType.SelectedCsys
						toolingBoxBuilder1.XValue.SetFormula("10")
						toolingBoxBuilder1.YValue.SetFormula("10")
						toolingBoxBuilder1.ZValue.SetFormula("10")
						toolingBoxBuilder1.OffsetPositiveX.SetFormula("0")
						toolingBoxBuilder1.OffsetNegativeX.SetFormula("0")
						toolingBoxBuilder1.OffsetPositiveY.SetFormula("0")
						toolingBoxBuilder1.OffsetNegativeY.SetFormula("0")
						toolingBoxBuilder1.OffsetPositiveZ.SetFormula("0")
						toolingBoxBuilder1.OffsetNegativeZ.SetFormula("0")
						toolingBoxBuilder1.RadialOffset.SetFormula("0")
						toolingBoxBuilder1.Clearance.SetFormula("0")
						toolingBoxBuilder1.CsysAssociative = True
						toolingBoxBuilder1.NonAlignedMinimumBox = True
						toolingBoxBuilder1.SingleOffset = False

						Dim selectionIntentRuleOptions1 As NXOpen.SelectionIntentRuleOptions = Nothing
						selectionIntentRuleOptions1 = workPart.ScRuleFactory.CreateRuleOptions()
						selectionIntentRuleOptions1.SetSelectedFromInactive(False)

						Dim selectedBody As NXOpen.Body = TryCast(NXOpen.Utilities.NXObjectManager.Get(tempComp.Tag), NXOpen.Body)
						If selectedBody Is Nothing Then
							lw.WriteLine("The tag you dare present does not match any corporeal form.")
							Return
						End If

						Dim bodyDumbRule1 As NXOpen.BodyDumbRule = workPart.ScRuleFactory.CreateRuleBodyDumb(New Body() {selectedBody}, True, selectionIntentRuleOptions1)
						selectionIntentRuleOptions1.Dispose()

						Dim scCollector1 As NXOpen.ScCollector = toolingBoxBuilder1.BoundedObject
						Dim rules1(0) As NXOpen.SelectionIntentRule
						rules1(0) = bodyDumbRule1
						scCollector1.ReplaceRules(rules1, False)

						Dim selections1(0) As NXOpen.NXObject
						selections1(0) = selectedBody
						Dim deselections1(-1) As NXOpen.NXObject
						toolingBoxBuilder1.SetSelectedOccurrences(selections1, deselections1)

						Dim selectNXObjectList1 As NXOpen.SelectNXObjectList = Nothing
						selectNXObjectList1 = toolingBoxBuilder1.FacetBodies
						Dim objects1(-1) As NXOpen.NXObject
						Dim added1 As Boolean = Nothing
						added1 = selectNXObjectList1.Add(objects1)
						toolingBoxBuilder1.CalculateBoxSize()

						Dim csysorigin1 As NXOpen.Point3d = New NXOpen.Point3d(com_x, com_y, com_z)
						toolingBoxBuilder1.BoxPosition = csysorigin1

						nXObject1 = toolingBoxBuilder1.Commit()

						If toolingBoxBuilder1 IsNot Nothing Then
							toolingBoxBuilder1.Destroy()
						End If

						Dim bboxFeature As Features.Feature = TryCast(nXObject1, Features.Feature)
						Dim bboxBody As Body = Nothing
						Dim innerBboxBody As Body = Nothing

						If bboxFeature IsNot Nothing Then
							For Each innerBboxBody In bboxFeature.GetBodies()
								'bboxBody = body
								Exit For
							Next
						End If

						If innerBboxBody IsNot Nothing Then
							Dim minCorner(2) As Double
							Dim directions(,) As Double = New Double(2, 2) {}
							Dim distances(2) As Double

							theUFSession.Modl.AskBoundingBoxExact(innerBboxBody.Tag, Tag.Null, minCorner, directions, distances)

							Dim cornerPoint As Point3d = New Point3d(minCorner(0), minCorner(1), minCorner(2))

							Dim vertices As New List(Of Point3d)()

							For Each edge As Edge In innerBboxBody.GetEdges()
								Dim vertex1 As Point3d, vertex2 As Point3d
								edge.GetVertices(vertex1, vertex2)
								If Not vertices.Contains(vertex1) Then vertices.Add(vertex1)
								If Not vertices.Contains(vertex2) Then vertices.Add(vertex2)
							Next

							Dim startingVertex As Point3d = vertices(0)

							Dim edgeLengths As New List(Of Double)
							Dim edgesAtStartingVertex As Integer = 0

							For Each edge As Edge In innerBboxBody.GetEdges()
								Dim vertex1 As Point3d, vertex2 As Point3d
								edge.GetVertices(vertex1, vertex2)
								If IsPointEqual(startingVertex, vertex1) OrElse IsPointEqual(startingVertex, vertex2) Then
									edgesAtStartingVertex += 1
									edgeLengths.Add(edge.GetLength())
								End If
							Next

							If edgeLengths.Count >= 3 Then
								edgeLengths.Sort()

								lw.WriteLine("")
								lw.WriteLine("Initial Bounding Box Dimensions:")
								lw.WriteLine(" - Width:  " & edgeLengths(0) & " " & unitString)
								lw.WriteLine(" - Depth:  " & edgeLengths(1) & " " & unitString)
								lw.WriteLine(" - Height: " & edgeLengths(2) & " " & unitString)
								lw.WriteLine(" ")

								formattedWidth = FormatNumber(edgeLengths(0))
								formattedDepth = FormatNumber(edgeLengths(1))
								formattedHeight = FormatNumber(edgeLengths(2))

							Else
								lw.WriteLine("Not enough edges found, like a spell half-cast.")
							End If

							Dim materialThicknessIdentified As Boolean = False

							If Array.IndexOf(validThicknesses, formattedWidth) >= 0 Then
								MaterialThickness = formattedWidth
								materialThicknessIdentified = True
								lw.WriteLine("Material thickness identified.")
							ElseIf Array.IndexOf(validThicknesses, formattedDepth) >= 0 Then
								MaterialThickness = formattedDepth
								materialThicknessIdentified = True
								lw.WriteLine("Material thickness identified.")
							ElseIf Array.IndexOf(validThicknesses, formattedHeight) >= 0 Then
								MaterialThickness = formattedHeight
								materialThicknessIdentified = True
								lw.WriteLine("Material thickness identified.")
							End If

							If Not materialThicknessIdentified Then
								MaterialThickness = Math.Min(formattedWidth, Math.Min(formattedDepth, formattedHeight))
								lw.WriteLine("Cannot identify material thickness. Using the smallest dimension instead.")
							End If

							Dim remainingDimensions As New List(Of Double) From {formattedWidth, formattedDepth, formattedHeight}
							remainingDimensions.Remove(MaterialThickness)

							If remainingDimensions.Count = 2 Then
								Length = Math.Max(remainingDimensions(0), remainingDimensions(1))
								Width = Math.Min(remainingDimensions(0), remainingDimensions(1))
							Else
								lw.WriteLine("Unable to determine Length and Width accurately.")
							End If

							Dim featureTags(0) As NXOpen.Tag
							featureTags(0) = bboxFeature.Tag
							theUFSession.Modl.DeleteFeature(featureTags)

							If modifications Then
								Dim myForm As New Form1()
								If myForm.ShowDialog() = DialogResult.OK Then
									If myForm.IsGrainDirectionChanged Then
										Dim temp As Double = Length
										Length = Width
										Width = temp
										lw.WriteLine(" ")
										lw.WriteLine("The grain direction has been successfully altered.")
									End If

									Length += myForm.LengthScribe
									lengthDisplay = FormatNumber(Length)
									If myForm.LengthScribe <> 0 Then
										lengthDisplay &= " (" & myForm.LengthScribe.ToString & ")"
									End If

									Width += myForm.WidthScribe
									widthDisplay = FormatNumber(Width)
									If myForm.WidthScribe <> 0 Then
										widthDisplay &= " (" & myForm.WidthScribe.ToString & ")"
									End If
								End If
							Else
								lengthDisplay = FormatNumber(Length)
								widthDisplay = FormatNumber(Width)
							End If

							lw.WriteLine(" ")
							lw.WriteLine("Final Dimensions after Sorting and Rounding:")
							lw.WriteLine(" - Length: " & lengthDisplay & " " & unitString)
							lw.WriteLine(" - Width:  " & widthDisplay & " " & unitString)
							lw.WriteLine(" ")
							lw.WriteLine("Material Thickness Adjustment and Dimension Summary: ")
							lw.WriteLine(" - Original Material Thickness: " & FormatNumber(MaterialThickness) & " " & unitString)

							If materialthicknessadjust Then
								Select Case MaterialThickness

									Case 0.469
										MaterialThickness = 0.453
										lw.WriteLine(" - Adjusted Material Thickness: 0.453" & " " & unitString & " (according to preset adjustments)")
									Case 0.25
										MaterialThickness = 0.203
										lw.WriteLine(" - Adjusted Material Thickness: 0.203" & " " & unitString & " (according to preset adjustments)")
									Case 13
										MaterialThickness = 12
										lw.WriteLine(" - Adjusted Material Thickness: 12" & " " & unitString & " (according to preset adjustments)")
									Case 19
										MaterialThickness = 18
										lw.WriteLine(" - Adjusted Material Thickness: 18" & " " & unitString & " (according to preset adjustments)")

								End Select
							Else
								'lw.WriteLine("Material thickness remains unadjusted at: " & MaterialThickness & " " & unitString)
								'lw.WriteLine(" ")
							End If

							lw.WriteLine(" ")
							lw.WriteLine("Attributes Successfully Updated:")
							AddBodyAttribute(tempComp, LengthAttribute, lengthDisplay)
							'lw.WriteLine(" - Length attribute (" & LengthAttribute & ") set to: " & lengthDisplay)
							lw.WriteLine(" - Length attribute set.")

							AddBodyAttribute(tempComp, WidthAttribute, widthDisplay)
							'lw.WriteLine(" - Width attribute (" & WidthAttribute & ") set to: " & widthDisplay)
							lw.WriteLine(" - Width attribute set.")

							AddBodyAttribute(tempComp, MaterialThicknessAttribute, FormatNumber(MaterialThickness))
							'lw.WriteLine(" - Material Thickness attribute (" & MaterialThicknessAttribute & ") set to: " & FormatNumber(MaterialThickness))
							lw.WriteLine(" - Material Thickness attribute set.")

						Else
							lw.WriteLine("The bounding box, a ghost, it eludes me.")
						End If

					Catch ex As Exception
						lw.WriteLine("An error? A mere setback in my grand design: " & ex.Message)
					Finally
					End Try
                Next
            End If
        Catch ex As Exception
            Console.WriteLine("An unexpected disturbance in the dark arts: " & ex.Message)
        End Try
		
		lw.WriteLine(" ")
		lw.WriteLine("In veils of dusk where silence creeps, we part where ancient darkness sleeps.")
		lw.WriteLine("The Dark Lord’s gaze does pierce the veil, a breath of doom in every tale.")
		lw.WriteLine("Until the stars forsake their gleam, and shadows wake from endless dream,")
		lw.WriteLine("We’ll walk apart, yet evermore, entwined in magic, bound by lore.")
		lw.WriteLine(" ")
    End Sub

    Function SelectObjects(prompt As String,
                           ByRef dispObj As List(Of DisplayableObject)) As Selection.Response
        Dim selObj As NXObject()
        Dim title As String = "Select Solid Bodies for our craft!"
        Dim includeFeatures As Boolean = False
        Dim keepHighlighted As Boolean = False
        Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
        Dim scope As Selection.SelectionScope = Selection.SelectionScope.WorkPart
        Dim selectionMask_array(0) As Selection.MaskTriple

        With selectionMask_array(0)
            .Type = UFConstants.UF_solid_type
            .SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_SOLID_BODY
        End With

        Dim resp As Selection.Response = theUI.SelectionManager.SelectObjects(prompt,
            title, scope, selAction,
            includeFeatures, keepHighlighted, selectionMask_array,
            selObj)

        If resp = Selection.Response.ObjectSelected Or
                resp = Selection.Response.ObjectSelectedByName Or
                resp = Selection.Response.Ok Then
            For Each item As NXObject In selObj
                dispObj.Add(CType(item, DisplayableObject))
            Next
            Return Selection.Response.Ok
        Else
            Return Selection.Response.Cancel
        End If
    End Function

    Sub AddBodyAttribute(ByVal theBody As Body, ByVal attTitle As String, ByVal attValue As String)
        Dim attributePropertiesBuilder1 As AttributePropertiesBuilder
        attributePropertiesBuilder1 = theSession.AttributeManager.CreateAttributePropertiesBuilder(workPart, {theBody}, AttributePropertiesBuilder.OperationType.None)

        attributePropertiesBuilder1.IsArray = False
        attributePropertiesBuilder1.DataType = AttributePropertiesBaseBuilder.DataTypeOptions.String

        attributePropertiesBuilder1.Title = attTitle
        attributePropertiesBuilder1.StringValue = attValue

        Dim nXObject1 As NXObject
        nXObject1 = attributePropertiesBuilder1.Commit()

        attributePropertiesBuilder1.Destroy()
    End Sub

	Function IsPointEqual(point1 As Point3d, point2 As Point3d) As Boolean
		Const Tolerance As Double = 0.001
		Return (Math.Abs(point1.X - point2.X) < Tolerance AndAlso
				Math.Abs(point1.Y - point2.Y) < Tolerance AndAlso
				Math.Abs(point1.Z - point2.Z) < Tolerance)
	End Function

	Function GetDecimalPlaces(format As String) As Integer
		Dim decimalPlaces As Integer = 0
		If format.StartsWith("F") AndAlso Integer.TryParse(format.Substring(1), decimalPlaces) Then
			Return decimalPlaces
		End If
		Return 0
	End Function

	Function RoundToNearestHalf(value As Double) As Double
		Return Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2
	End Function

	Function FormatNumber(value As Double) As String
		Dim formatSpecifier As String = decimalFormat
		Dim result As String

		If roundToNearestHalfBLN AndAlso unitString = "mm" Then
			value = Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2
			formatSpecifier = "F1"
		End If

		result = value.ToString(formatSpecifier, System.Globalization.CultureInfo.InvariantCulture)

		If trimzeros Then
			If result.Contains(".") Then
				result = result.TrimEnd("0"c).TrimEnd("."c)
			End If
		End If

		Return result
	End Function

	<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
	Partial Class Form1
		Inherits System.Windows.Forms.Form

		Public Property LengthScribe As Double
		Public Property WidthScribe As Double
		Public Property IsGrainDirectionChanged As Boolean

		Private components As System.ComponentModel.IContainer
		Friend WithEvents chkChangeGrainDirection As System.Windows.Forms.CheckBox
		Friend WithEvents txtScribeLength As System.Windows.Forms.TextBox
		Friend WithEvents txtScribeWidth As System.Windows.Forms.TextBox
		Friend WithEvents btnOK As System.Windows.Forms.Button
		Friend WithEvents lblScribeLength As System.Windows.Forms.Label
		Friend WithEvents lblScribeWidth As System.Windows.Forms.Label

		<System.Diagnostics.DebuggerNonUserCode()>
		Protected Overrides Sub Dispose(ByVal disposing As Boolean)
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
			MyBase.Dispose(disposing)
		End Sub

		<System.Diagnostics.DebuggerStepThrough()>
		Private Sub Form1_Load(sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
			Me.StartPosition = FormStartPosition.Manual
			Me.Location = New System.Drawing.Point(winFormLocationX, winFormLocationY)

			Me.BackColor = Color.FromArgb(55, 55, 55)

			btnOK.BackColor = Color.FromArgb(50, 50, 50)

			txtScribeLength.ForeColor = Color.Black
			txtScribeWidth.ForeColor = Color.Black
			btnOK.ForeColor = Color.White
			lblScribeLength.ForeColor = Color.White
			lblScribeWidth.ForeColor = Color.White
			chkChangeGrainDirection.ForeColor = Color.White
		End Sub

		Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
			winFormLocationX = Me.Location.X
			winFormLocationY = Me.Location.Y
		End Sub

		Private Sub InitializeComponent()
			Me.chkChangeGrainDirection = New System.Windows.Forms.CheckBox()
			Me.txtScribeLength = New System.Windows.Forms.TextBox()
			Me.txtScribeWidth = New System.Windows.Forms.TextBox()
			Me.btnOK = New System.Windows.Forms.Button()
			Me.lblScribeLength = New System.Windows.Forms.Label()
			Me.lblScribeWidth = New System.Windows.Forms.Label()
			Me.SuspendLayout()
			'
			'chkChangeGrainDirection
			'
			Me.chkChangeGrainDirection.AutoSize = True
			Me.chkChangeGrainDirection.Location = New System.Drawing.Point(30, 17)
			Me.chkChangeGrainDirection.Name = "chkChangeGrainDirection"
			Me.chkChangeGrainDirection.Size = New System.Drawing.Size(200, 17)
			Me.chkChangeGrainDirection.TabIndex = 0
			Me.chkChangeGrainDirection.Text = "Would you like to change Grain Direction?"
			Me.chkChangeGrainDirection.UseVisualStyleBackColor = True
			'
			'lblScribeLength
			'
			Me.lblScribeLength.AutoSize = True
			Me.lblScribeLength.Location = New System.Drawing.Point(30, 55)
			Me.lblScribeLength.Name = "lblScribeLength"
			Me.lblScribeLength.Size = New System.Drawing.Size(100, 13)
			Me.lblScribeLength.Text = "Enter Scribe Length:"
			'
			'txtScribeLength
			'
			Me.txtScribeLength.Location = New System.Drawing.Point(220, 50)
			Me.txtScribeLength.Name = "txtScribeLength"
			Me.txtScribeLength.Size = New System.Drawing.Size(100, 20)
			Me.txtScribeLength.TabIndex = 1
			'
			'lblScribeWidth
			'
			Me.lblScribeWidth.AutoSize = True
			Me.lblScribeWidth.Location = New System.Drawing.Point(30, 85)
			Me.lblScribeWidth.Name = "lblScribeWidth"
			Me.lblScribeWidth.Size = New System.Drawing.Size(100, 13)
			Me.lblScribeWidth.Text = "Enter Scribe Width:"
			'
			'txtScribeWidth
			'
			Me.txtScribeWidth.Location = New System.Drawing.Point(220, 80)
			Me.txtScribeWidth.Name = "txtScribeWidth"
			Me.txtScribeWidth.Size = New System.Drawing.Size(100, 20)
			Me.txtScribeWidth.TabIndex = 2
			'
			'btnOK
			'
			Me.btnOK.Location = New System.Drawing.Point(152, 130)
			Me.btnOK.Name = "btnOK"
			Me.btnOK.Size = New System.Drawing.Size(75, 23)
			Me.btnOK.TabIndex = 3
			Me.btnOK.Text = "OK"
			Me.btnOK.UseVisualStyleBackColor = True
			'
			'Form1
			'
			Me.AcceptButton = Me.btnOK
			'Me.CancelButton = Me.btnCancel
			Me.ClientSize = New System.Drawing.Size(380, 170)
			Me.Controls.Add(Me.chkChangeGrainDirection)
			Me.Controls.Add(Me.lblScribeLength)
			Me.Controls.Add(Me.txtScribeLength)
			Me.Controls.Add(Me.lblScribeWidth)
			Me.Controls.Add(Me.txtScribeWidth)
			Me.Controls.Add(Me.btnOK)
			'Me.Controls.Add(Me.btnCancel)
			Me.Name = "Form1"
			Me.Text = "Dimensions"
			Me.ResumeLayout(False)
			Me.PerformLayout()
		End Sub

		Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
			Me.IsGrainDirectionChanged = chkChangeGrainDirection.Checked
			If chkChangeGrainDirection.Checked Then
				Me.IsGrainDirectionChanged = True
			End If

			Dim lengthScribeValue As Double
			Dim widthScribeValue As Double

			If Not String.IsNullOrWhiteSpace(txtScribeLength.Text) AndAlso Double.TryParse(txtScribeLength.Text, lengthScribeValue) Then
				Me.LengthScribe = lengthScribeValue
			ElseIf Not String.IsNullOrWhiteSpace(txtScribeLength.Text) Then
				MessageBox.Show("Enter a proper lenght number worthy of my time. ", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
				Return
			End If

			If Not String.IsNullOrWhiteSpace(txtScribeWidth.Text) AndAlso Double.TryParse(txtScribeWidth.Text, widthScribeValue) Then
				Me.WidthScribe = widthScribeValue
			ElseIf Not String.IsNullOrWhiteSpace(txtScribeWidth.Text) Then
				MessageBox.Show("Enter a proper width number worthy of my time. ", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
				Return
			End If

			Me.DialogResult = DialogResult.OK
			Me.Close()
		End Sub
	End Class

	Public Function GetUnloadOption(ByVal dummy As String) As Integer
		GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
	End Function

End Module
 
Hi lj1970,

Thank you so much for your help! The latest revision you added was just like the Room of Requirement — perfectly timed and exactly what I needed! 🤓 I tried my hand at modifying the previous code to learn, and I’m attaching it here as well. Testing out the methods you mentioned was as enlightening as Hermione’s best spells!

By the way, your other code contributions are as impressive as Dumbledore’s beard! I’ll be following you on GitHub too — maybe I’ll pick up some magical coding tricks there. 😊

May the best spells be with you!

Code:
' Edited by Murat OZCAN - September 2024,  (Inspired by Tamas Woller's codes)
' Journal desciption: When existing bodies are selected in a part file, it saves the dimensions of the minimum size log as an attribute.
' Shared on eng-tips.com
' Written in VB.Net
' Tested on Siemens NX 2212 and 2306


Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpenUI
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Globalization

Module NXJournal

    Dim theUFSession As UFSession = UFSession.GetUFSession()
    Dim theSession As Session = Session.GetSession()
    Dim lw As ListingWindow = theSession.ListingWindow
    Dim unitString As String
    Dim formattedWidth As Double
    Dim formattedDepth As Double
    Dim formattedHeight As Double
    Dim theUI As UI = UI.GetUI()
    Dim workPart As Part = theSession.Parts.Work
    Dim Length As Double
    Dim Width As Double
    Dim winFormLocationX As Integer = 317 ' Default X position for GUI
    Dim winFormLocationY As Integer = 317 ' Default Y position for GUI
    Dim modifications As Boolean

    ' Configuration settings
    Dim validThicknesses As Double() = {0.141, 0.203, 0.25, 0.453, 0.469, 0.709, 0.827, 6, 9, 12, 13, 15, 18, 19}
    Dim decimalFormat As String = "F1"
    Dim roundToNearestHalfBLN As Boolean = True
    Dim modificationsQST As String = "Maybe"
    Dim materialthicknessadjust As Boolean = True
    Dim trimzeros As Boolean = True
    Dim LengthAttribute As String = "DIM_LENGTH"
    Dim WidthAttribute As String = "DIM_WIDTH"
    Dim MaterialThicknessAttribute As String = "MAT_THICKNESS"

    ' Use a Dictionary to track processed components
    Private ProcessedComponents As New Dictionary(Of String, Boolean)

    Sub Main(ByVal args() As String)

        lw.Open()

        Dim displayPart As NXOpen.Part = theSession.Parts.Display

        Dim body1 As Body = Nothing ' Initialize the body1 variable
        If SelectBody("Select a body", body1) = Selection.Response.Cancel Then
            Return
        End If

        Dim theBodies(0) As Body
        theBodies(0) = body1
        Dim bodyToProcess As Body = theBodies(0)

        Dim nullNXOpen_Features_ToolingBox As NXOpen.Features.ToolingBox = Nothing
        Dim toolingBoxBuilder1 As NXOpen.Features.ToolingBoxBuilder = workPart.Features.ToolingFeatureCollection.CreateToolingBoxBuilder(nullNXOpen_Features_ToolingBox)

        ' Calculate and display the center of mass
        Dim accValue(10) As Double
        accValue(0) = 0.999
        Dim massProps(46) As Double
        Dim stats(12) As Double
        theUFSession.Modl.AskMassProps3d(New Tag() {bodyToProcess.Tag}, 1, 1, 4, 0.03, 1, accValue, massProps, stats)

        ' Convert the center of mass coordinates to Double
        Dim com_x As Double = massProps(3)
        Dim com_y As Double = massProps(4)
        Dim com_z As Double = massProps(5)

        toolingBoxBuilder1.Type = NXOpen.Features.ToolingBoxBuilder.Types.BoundedBlock
        toolingBoxBuilder1.ReferenceCsysType = NXOpen.Features.ToolingBoxBuilder.RefCsysType.SelectedCsys
        toolingBoxBuilder1.XValue.SetFormula("10")
        toolingBoxBuilder1.YValue.SetFormula("10")
        toolingBoxBuilder1.ZValue.SetFormula("10")
        toolingBoxBuilder1.OffsetPositiveX.SetFormula("0")
        toolingBoxBuilder1.OffsetNegativeX.SetFormula("0")
        toolingBoxBuilder1.OffsetPositiveY.SetFormula("0")
        toolingBoxBuilder1.OffsetNegativeY.SetFormula("0")
        toolingBoxBuilder1.OffsetPositiveZ.SetFormula("0")
        toolingBoxBuilder1.OffsetNegativeZ.SetFormula("0")
        toolingBoxBuilder1.RadialOffset.SetFormula("0")
        toolingBoxBuilder1.Clearance.SetFormula("0")
        toolingBoxBuilder1.CsysAssociative = True
        toolingBoxBuilder1.NonAlignedMinimumBox = True
        toolingBoxBuilder1.SingleOffset = False

        ' Tooling box creation
        Dim selectionIntentRuleOptions1 As NXOpen.SelectionIntentRuleOptions = workPart.ScRuleFactory.CreateRuleOptions()
        selectionIntentRuleOptions1.SetSelectedFromInactive(False)

        Dim selectedBody As NXOpen.Body = theBodies(0)
        If selectedBody Is Nothing Then
            lw.WriteLine("The tag you dare present does not match any corporeal form.")
            Return
        End If

        ' Use the selectedBody for creating the dumb rule
        Dim bodyDumbRule1 As NXOpen.BodyDumbRule = workPart.ScRuleFactory.CreateRuleBodyDumb(New Body() {selectedBody}, True, selectionIntentRuleOptions1)
        selectionIntentRuleOptions1.Dispose()

        Dim scCollector1 As NXOpen.ScCollector = toolingBoxBuilder1.BoundedObject
        Dim rules1(0) As NXOpen.SelectionIntentRule
        rules1(0) = bodyDumbRule1
        scCollector1.ReplaceRules(rules1, False)

        ' Set selections
        Dim selections1(0) As NXOpen.NXObject
        selections1(0) = selectedBody
        Dim deselections1(-1) As NXOpen.NXObject
        toolingBoxBuilder1.SetSelectedOccurrences(selections1, deselections1)

        Dim selectNXObjectList1 As NXOpen.SelectNXObjectList = toolingBoxBuilder1.FacetBodies
        Dim objects1(-1) As NXOpen.NXObject
        Dim added1 As Boolean = selectNXObjectList1.Add(objects1)
        toolingBoxBuilder1.CalculateBoxSize()

        ' Set the box position using the center of mass coordinates
        Dim csysorigin1 As NXOpen.Point3d = New NXOpen.Point3d(com_x, com_y, com_z)
        toolingBoxBuilder1.BoxPosition = csysorigin1
        lw.WriteLine(com_x)

        Dim nXObject1 As NXObject

        ' Commit the tooling box to create the feature
        nXObject1 = toolingBoxBuilder1.Commit()

        ' Destroy the tooling box builder
        If toolingBoxBuilder1 IsNot Nothing Then
            toolingBoxBuilder1.Destroy()
        End If

        ' Access the body of the bounding box feature
        Dim bboxFeature As Features.Feature = TryCast(nXObject1, Features.Feature)
        Dim bboxBody As Body = Nothing
        Dim innerBboxBody As Body = Nothing

        If bboxFeature IsNot Nothing Then
            For Each innerBboxBody In bboxFeature.GetBodies()
                Exit For
            Next
        End If

        If innerBboxBody IsNot Nothing Then
            ' Initialize directions and distances arrays
            Dim minCorner(2) As Double
            Dim directions(,) As Double = New Double(2, 2) {}
            Dim distances(2) As Double

            ' Get the bounding box of the body
            theUFSession.Modl.AskBoundingBoxExact(innerBboxBody.Tag, Tag.Null, minCorner, directions, distances)

            ' Define the minimum corner point
            Dim cornerPoint As Point3d = New Point3d(minCorner(0), minCorner(1), minCorner(2))

            ' Initialize a List to store unique vertices
            Dim vertices As New List(Of Point3d)()

            ' Iterate through all edges in the body and get vertices
            For Each edge As Edge In innerBboxBody.GetEdges()
                Dim vertex1 As Point3d, vertex2 As Point3d
                edge.GetVertices(vertex1, vertex2)
                If Not vertices.Contains(vertex1) Then vertices.Add(vertex1)
                If Not vertices.Contains(vertex2) Then vertices.Add(vertex2)
            Next

            ' Select the first vertex as the starting vertex
            Dim startingVertex As Point3d = vertices(0)

            ' Initialize a List to store lengths of edges connected to the starting vertex
            Dim edgeLengths As New List(Of Double)
            Dim edgesAtStartingVertex As Integer = 0

            ' Iterate through all edges in the body
            For Each edge As Edge In innerBboxBody.GetEdges()
                Dim vertex1 As Point3d, vertex2 As Point3d
                edge.GetVertices(vertex1, vertex2)
                If IsPointEqual(startingVertex, vertex1) OrElse IsPointEqual(startingVertex, vertex2) Then
                    edgesAtStartingVertex += 1
                    edgeLengths.Add(edge.GetLength())
                End If
            Next

            ' Check if we have at least three edges before accessing the list
            If edgeLengths.Count >= 3 Then
                ' Sort the edge lengths
                edgeLengths.Sort()

                ' Output the initial (raw) bounding box dimensions before any formatting
                lw.WriteLine("")
                lw.WriteLine("Initial Bounding Box Dimensions:")
                lw.WriteLine(" - Width:  " & edgeLengths(0).ToString())
                lw.WriteLine(" - Depth:  " & edgeLengths(1).ToString())
                lw.WriteLine(" - Height: " & edgeLengths(2).ToString())
                lw.WriteLine(" ")

                ' Format the lengths of the three edges as width, depth, and height
                formattedWidth = FormatNumber(edgeLengths(0))
                formattedDepth = FormatNumber(edgeLengths(1))
                formattedHeight = FormatNumber(edgeLengths(2))

            Else
                lw.WriteLine("Failed to find at least three edges connected to the starting vertex to determine the bounding box dimensions.")
            End If

            ' Output the formatted bounding box dimensions
            lw.WriteLine("")
            lw.WriteLine("Formatted Bounding Box Dimensions:")
            lw.WriteLine(" - Width:  " & formattedWidth & " " & unitString)
            lw.WriteLine(" - Depth:  " & formattedDepth & " " & unitString)
            lw.WriteLine(" - Height: " & formattedHeight & " " & unitString)
            lw.WriteLine(" ")
        Else
            lw.WriteLine("Failed to get the body of the bounding box feature.")
        End If
                    ' Bounding Box boyutlarını göster
            Dim message As String = "Bounding Box Boyutları:" & vbCrLf &
                                    "X = " & formattedWidth.ToString("#.000") & " mm" & vbCrLf &
                                    "Y = " & formattedDepth.ToString("#.000") & " mm" & vbCrLf &
                                    "Z = " & formattedHeight.ToString("#.000") & " mm"

            MessageBox.Show(message, "Bounding Box Bilgileri", MessageBoxButtons.OK, MessageBoxIcon.Information)
            
            '-----
             ' Bounding Box'u silmek için UpdateManager kullanarak silme işlemi yap
                ' Delete the bounding box feature
						Dim featureTags(0) As NXOpen.Tag
						featureTags(0) = bboxFeature.Tag
						theUFSession.Modl.DeleteFeature(featureTags)
			'--------
	
    End Sub

    ' Function to compare two Point3d objects
    Private Function IsPointEqual(ByVal p1 As Point3d, ByVal p2 As Point3d) As Boolean
        Const TOLERANCE As Double = 0.0001
        Return Math.Abs(p1.X - p2.X) < TOLERANCE AndAlso Math.Abs(p1.Y - p2.Y) < TOLERANCE AndAlso Math.Abs(p1.Z - p2.Z) < TOLERANCE
    End Function

    ' Format number function with rounding and formatting applied
    Private Function FormatNumber(ByVal number As Double) As String
        'Dim roundedNumber As Double = Math.Round(number, 1)
        Dim roundedNumber As Double = Math.Round(number, 0) ' virgülden sonra kaç hane yuvarlansın. 0 olursa Tam sayıya yuvarla
        'Dim formattedNumber As String = roundedNumber.ToString(decimalFormat, CultureInfo.InvariantCulture)
        Dim formattedNumber As String = roundedNumber.ToString(decimalFormat) 'Nokta virgül meselesi
        If trimzeros AndAlso formattedNumber.EndsWith(".0") Then
            formattedNumber = formattedNumber.Substring(0, formattedNumber.Length - 2)
        End If
        Return formattedNumber
    End Function

    ' Method to select a body
    Function SelectBody(ByVal prompt As String, ByRef selObj As TaggedObject) As Selection.Response

        Dim theUI As UI = UI.GetUI
        Dim title As String = "Select a solid body"
        Dim includeFeatures As Boolean = False
        Dim keepHighlighted As Boolean = False
        Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
        Dim cursor As Point3d
        Dim scope As Selection.SelectionScope = Selection.SelectionScope.WorkPart
        Dim selectionMask_array(0) As Selection.MaskTriple

        With selectionMask_array(0)
            .Type = UFConstants.UF_solid_type
            .SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_SOLID_BODY
        End With

        Dim resp As Selection.Response = theUI.SelectionManager.SelectTaggedObject(prompt, _
         title, scope, selAction, _
         includeFeatures, keepHighlighted, selectionMask_array, _
         selobj, cursor)
        If resp = Selection.Response.ObjectSelected OrElse resp = Selection.Response.ObjectSelectedByName Then
            Return Selection.Response.Ok
        Else
            Return Selection.Response.Cancel
        End If

    End Function

End Module
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor