From 878b7ea6d1678843189f946fa9dbc6fd525db1f7 Mon Sep 17 00:00:00 2001
From: Mikhail Polikarpov <mikhail.polikarpov@rwth-aachen.de>
Date: Sat, 22 Aug 2020 12:43:22 +0200
Subject: [PATCH] Refactoring for better control over test parameters

---
 CatiaNetTest/AndOrDataExtraction.vb | 136 +++++++++-----
 CatiaNetTest/AssemblyTiers2.vb      | 267 ++++++++++++++--------------
 2 files changed, 226 insertions(+), 177 deletions(-)

diff --git a/CatiaNetTest/AndOrDataExtraction.vb b/CatiaNetTest/AndOrDataExtraction.vb
index c0b1e04..580dc93 100644
--- a/CatiaNetTest/AndOrDataExtraction.vb
+++ b/CatiaNetTest/AndOrDataExtraction.vb
@@ -11,6 +11,13 @@ Imports Microsoft.VisualBasic
 
 Public Class AndOrDataExtraction
 
+    Public bBoundingBoxProjectionCheck As Boolean
+    Public bGenerateANDOR As Boolean
+    Public bAutomaticStep As Boolean
+    Public iBoundingBoxCode As Integer
+    Public intStep As Integer
+    Public dCollSens As Double
+    Public xlsPath As String
     Public cAllProducts As New ArrayList
     Public cRelevantProducts As New ArrayList
     Public intParts As Integer
@@ -21,8 +28,6 @@ Public Class AndOrDataExtraction
     Public aAssemblyBoundaries(5) As Double
     Public aPartBBGlob(,) As Double
     Public aInitPos(,) As Double
-    Public intStep As Integer
-    Public dCollSens As Double
     Public MW_x_pos(,) As Integer
     Public MW_y_pos(,) As Integer
     Public MW_z_pos(,) As Integer
@@ -33,6 +38,15 @@ Public Class AndOrDataExtraction
 
     Sub CatMain()
 
+        'Test parameters
+        iBoundingBoxCode = 1
+        bBoundingBoxProjectionCheck = True
+        bGenerateANDOR = False
+        bAutomaticStep = True
+        intStep = 13
+        dCollSens = 2
+        xlsPath = "D:\mikep\Files\RWTH\Master Produktionstechnik\Masterarbeit\Experimente\Protocols"
+
         CATIA = GetObject(, "CATIA.Application")
         If CATIA Is Nothing Then CATIA = CreateObject("CATIA.Application")
 
@@ -48,18 +62,19 @@ Public Class AndOrDataExtraction
         'Determine moving wedge (MW) matrices of the product
         MovingWedge()
 
-        'Create AND/OR graph
-        Dim prod As New List(Of Integer)
-        For i = 1 To cRelevantProducts.Count
-            prod.Add(i)
-        Next
-        Dim nodes As New List(Of List(Of Integer))
-        'Add the final product to the list of legal assemblies
-        nodes.Add(prod)
-        AndOrGraph(prod, nodes)
-
-        Debug.Print("AND/OR nodes: " + CStr(nodes.Count))
-        Debug.Print("AND/OR edges: " + CStr(numEdges))
+        If bGenerateANDOR Then
+            'Create AND/OR graph
+            Dim prod As New List(Of Integer)
+            For i = 1 To cRelevantProducts.Count
+                prod.Add(i)
+            Next
+            Dim nodes As New List(Of List(Of Integer))
+            'Add the final product to the list of legal assemblies
+            nodes.Add(prod)
+            AndOrGraph(prod, nodes)
+            Debug.Print("AND/OR nodes: " + CStr(nodes.Count))
+            Debug.Print("AND/OR edges: " + CStr(numEdges))
+        End If
 
     End Sub
 
@@ -238,10 +253,6 @@ Public Class AndOrDataExtraction
 
     Sub MovingWedge()
 
-        'Collision detection parameters
-        intStep = 10
-        dCollSens = 2
-
         'access the clash technology object
         Dim cClashes As Clashes
         cClashes = CATIA.ActiveDocument.Product.GetTechnologicalObject("Clashes")
@@ -290,33 +301,44 @@ Public Class AndOrDataExtraction
         ReDim aInitPos(cRelevantProducts.Count - 1, 11)     'remember initial positions of the products
 
         For i = 0 To cRelevantProducts.Count - 1
-
-            '########## this won't work if part document name is not = part number ######
-            'Dim partI As Part
             Dim prodI As Product
-            prodI = cRelevantProducts.Item(i)
-            Dim docName As String
-            docName = prodI.PartNumber + ".CATPart"
-            Debug.Print(">>> " & docName & " <<<")
-            GenerateBoundingBox(CATIA.Documents.Item(docName), prodI, i)
-            '############################################################################
-
-            'Determine assembly 's limits
-            'Dim partI As Part
-            'Dim prodI As Product
-            'prodI = cRelevantProducts.Item(i)
-            'Dim docName As String
-            'docName = prodI.PartNumber + ".CATPart"
-            'Dim oPartDoc As PartDocument
-            'Dim sPartPath As String
-            'sPartPath = prodI.GetMasterShapeRepresentationPathName
-            'oPartDoc = CATIA.Documents.Read(sPartPath)
-            'Debug.Print(">>> " & docName & " <<<")
-            ''CATIA.Documents.Item(docName)
-            'GenerateBoundingBox(oPartDoc, prodI, i)
-
+            If iBoundingBoxCode = 1 Then
+                'this won't work if part document name is not = part number
+                prodI = cRelevantProducts.Item(i)
+                Dim docName As String
+                docName = prodI.PartNumber + ".CATPart"
+                Debug.Print(">>> " & docName & " <<<")
+                GenerateBoundingBox(CATIA.Documents.Item(docName), prodI, i)
+            ElseIf iBoundingBoxCode = 2 Then
+                prodI = cRelevantProducts.Item(i)
+                Dim docName As String
+                docName = prodI.PartNumber + ".CATPart"
+                Dim oPartDoc As PartDocument
+                Dim sPartPath As String
+                sPartPath = prodI.GetMasterShapeRepresentationPathName
+                oPartDoc = CATIA.Documents.Read(sPartPath)
+                Debug.Print(">>> " & docName & " <<<")
+                'CATIA.Documents.Item(docName)
+                GenerateBoundingBox(oPartDoc, prodI, i)
+            Else
+                Debug.Print("Allowed bounding box code type are 1 and 2!")
+            End If
         Next i
 
+        'Collision parameters
+        If bAutomaticStep Then
+            Dim dGeomMean As Double
+            dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
+            dGeomMean = dGeomMean ^ (1 / 3)
+            intStep = Math.Round(dGeomMean / 50, 0)
+        End If
+        Debug.Print("Movement step: " & CStr(intStep))
+
+        MsgBox("Assembly dimensions: " & vbNewLine &
+        "X = " & aAssemblyBoundaries(0) - aAssemblyBoundaries(1) & vbNewLine &
+        "Y = " & aAssemblyBoundaries(2) - aAssemblyBoundaries(3) & vbNewLine &
+        "Z = " & aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
+
         'After the aAssemblyBoundaries and aPartBBGlob are calculated, define aRemovalDistances
         For i = 0 To cRelevantProducts.Count - 1
             aRemovalDistances(i, 0) = aAssemblyBoundaries(0) - aPartBBGlob(i, 1)
@@ -362,6 +384,9 @@ Public Class AndOrDataExtraction
             Next int_j
         Next int_i
 
+        Dim MovingWedgeStartTime As DateTime
+        MovingWedgeStartTime = Now
+
         For int_i = 1 To n
             Dim prodI As Product
             prodI = cRelevantProducts.Item(int_i - 1)
@@ -373,9 +398,13 @@ Public Class AndOrDataExtraction
             group2 = cGroups.Add
             group1.AddExplicit(cRelevantProducts.Item(int_i - 1))
             For int_j = 1 To n
-                'If BoundingBoxesOverlap(int_i - 1, int_j - 1) Then
-                group2.AddExplicit(cRelevantProducts.Item(int_j - 1))
-                'End If
+                If bBoundingBoxProjectionCheck Then
+                    If BoundingBoxesOverlap(int_i - 1, int_j - 1) Then
+                        group2.AddExplicit(cRelevantProducts.Item(int_j - 1))
+                    End If
+                Else
+                    group2.AddExplicit(cRelevantProducts.Item(int_j - 1))
+                End If
             Next int_j
 
             Dim d As Integer
@@ -445,6 +474,12 @@ Public Class AndOrDataExtraction
             Next d
         Next int_i
 
+        Dim SecondsElapsed As Double
+        Dim MillisecondsElapsed As Double
+        MillisecondsElapsed = (Now - MovingWedgeStartTime).TotalMilliseconds
+        SecondsElapsed = Math.Round(MillisecondsElapsed / 1000.0, 2)
+        MsgBox("Moving wedge extraction took " & CStr(SecondsElapsed) & " seconds")
+
         'Use Excel
         Dim oExcel As Microsoft.Office.Interop.Excel.Application
         oExcel = CreateObject("Excel.Application")
@@ -469,7 +504,6 @@ Public Class AndOrDataExtraction
 
         'Save and close excel workbook
         Dim xlsFileName As String = CATIA.ActiveDocument.Name
-        Dim xlsPath As String = "D:\mikep\Files\RWTH\Master Produktionstechnik\Masterarbeit\Experimente\"
         oExcel.ActiveWorkbook.SaveAs(Filename:=xlsPath & xlsFileName & "_Moving wedge.xlsx")
         oExcel.ActiveWorkbook.Close(SaveChanges:=True)
         'close the excel application
@@ -494,6 +528,9 @@ Public Class AndOrDataExtraction
         outputText = CStr(n) + " parts are considered in liaison graph generation"
         MsgBox(outputText)
 
+        Dim LiaisonStartTime As DateTime
+        LiaisonStartTime = Now
+
         ReDim liaisonMatrix(n, n)
 
         'access the clash technology object
@@ -553,9 +590,14 @@ Public Class AndOrDataExtraction
             Next int_j
         Next int_i
 
+        Dim SecondsElapsed As Double
+        Dim MillisecondsElapsed As Double
+        MillisecondsElapsed = (Now - LiaisonStartTime).TotalMilliseconds
+        SecondsElapsed = Math.Round(MillisecondsElapsed / 1000.0, 2)
+        MsgBox("Liaison graph extraction took " & CStr(SecondsElapsed) & " seconds")
+
         'Save and close excel workbook
         Dim xlsFileName As String = CATIA.ActiveDocument.Name
-        Dim xlsPath As String = "D:\mikep\Files\RWTH\Master Produktionstechnik\Masterarbeit\Experimente\"
         objExcel.ActiveWorkbook.SaveAs(Filename:=xlsPath & xlsFileName & "_Liaisons.xlsx")
         objExcel.ActiveWorkbook.Close(SaveChanges:=True)
         'close the excel application
diff --git a/CatiaNetTest/AssemblyTiers2.vb b/CatiaNetTest/AssemblyTiers2.vb
index 1ab43c6..f898c91 100644
--- a/CatiaNetTest/AssemblyTiers2.vb
+++ b/CatiaNetTest/AssemblyTiers2.vb
@@ -10,9 +10,14 @@ Imports Microsoft.Office.Interop.Excel
 
 Public Class AssemblyTiers2
 
-    Public bCoherenceCheck As Boolean
+    Public bConnectivityCheck As Boolean
+    Public bBoundingBoxProjectionCheck As Boolean
+    Public bAutomaticStep As Boolean
+    Public bChooseExtractionDirection As Boolean
+    Public iBoundingBoxCode As Integer
     Public intStep As Integer
     Public dCollSens As Double
+    Public xlsPath As String
     Public intParts As Integer
     Public intNumFaces As Integer
     Public primaryFasteners As New ArrayList
@@ -32,6 +37,20 @@ Public Class AssemblyTiers2
 
     Sub CatMain()
 
+        'Test parameters
+        iBoundingBoxCode = 1
+        bBoundingBoxProjectionCheck = True
+        bConnectivityCheck = True
+        bAutomaticStep = True
+        intStep = 13
+        dCollSens = 2
+        bChooseExtractionDirection = False
+        'number of analysed disassembly directions
+        Dim intJ As Integer
+        '6 - only global axes, 12 - including local axes
+        intJ = 6
+        xlsPath = "D:\mikep\Files\RWTH\Master Produktionstechnik\Masterarbeit\Experimente\Protocols"
+
         CATIA = GetObject(, "CATIA.Application")
         If CATIA Is Nothing Then CATIA = CreateObject("CATIA.Application")
 
@@ -130,30 +149,28 @@ Public Class AssemblyTiers2
         intNumFaces = 0
 
         For i = 0 To cRelevantProducts.Count - 1
-
-            '########## this won't work if part document name is not = part number ######
-            ''Dim partI As Part
             Dim prodI As Product
-            prodI = cRelevantProducts.Item(i)
-            Dim docName As String
-            docName = prodI.PartNumber + ".CATPart"
-            Debug.Print(">>> " & docName & " <<<")
-            GenerateBoundingBox(CATIA.Documents.Item(docName), prodI, i)
-            '############################################################################
-
-            'Determine assembly 's limits
-            'Dim partI As Part
-            'Dim prodI As Product
-            'prodI = cRelevantProducts.Item(i)
-            'Dim docName As String
-            'docName = prodI.PartNumber + ".CATPart"
-            'Dim oPartDoc As PartDocument
-            'Dim sPartPath As String
-            'sPartPath = prodI.GetMasterShapeRepresentationPathName
-            'oPartDoc = CATIA.Documents.Read(sPartPath)
-            'Debug.Print(">>> " & docName & " <<<")
-            ''CATIA.Documents.Item(docName)
-            'GenerateBoundingBox(oPartDoc, prodI, i)
+            If iBoundingBoxCode = 1 Then
+                'this won't work if part document name is not = part number
+                prodI = cRelevantProducts.Item(i)
+                Dim docName As String
+                docName = prodI.PartNumber + ".CATPart"
+                Debug.Print(">>> " & docName & " <<<")
+                GenerateBoundingBox(CATIA.Documents.Item(docName), prodI, i)
+            ElseIf iBoundingBoxCode = 2 Then
+                prodI = cRelevantProducts.Item(i)
+                Dim docName As String
+                docName = prodI.PartNumber + ".CATPart"
+                Dim oPartDoc As PartDocument
+                Dim sPartPath As String
+                sPartPath = prodI.GetMasterShapeRepresentationPathName
+                oPartDoc = CATIA.Documents.Read(sPartPath)
+                Debug.Print(">>> " & docName & " <<<")
+                'CATIA.Documents.Item(docName)
+                GenerateBoundingBox(oPartDoc, prodI, i)
+            Else
+                Debug.Print("Allowed bounding box code type are 1 and 2!")
+            End If
 
             'Base component is in cRelevantProducts, but not moveable
             If productIsInCollection(prodI, cBaseProducts) Then
@@ -172,15 +189,14 @@ Public Class AssemblyTiers2
         Debug.Print("Number of faces in assembly: " & CStr(intNumFaces))
 
         'Collision parameters
-        'Dim dGeomMean As Double
-        'dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
-        'dGeomMean = dGeomMean ^ (1 / 3)
-        'intStep = Math.Round(dGeomMean / 50, 0)
-        intStep = 13
+        If bAutomaticStep Then
+            Dim dGeomMean As Double
+            dGeomMean = (aAssemblyBoundaries(0) - aAssemblyBoundaries(1)) * (aAssemblyBoundaries(2) - aAssemblyBoundaries(3)) * (aAssemblyBoundaries(4) - aAssemblyBoundaries(5))
+            dGeomMean = dGeomMean ^ (1 / 3)
+            intStep = Math.Round(dGeomMean / 50, 0)
+        End If
         Debug.Print("Movement step: " & CStr(intStep))
 
-        dCollSens = 2
-
         MsgBox("Assembly dimensions: " & vbNewLine &
         "X = " & aAssemblyBoundaries(0) - aAssemblyBoundaries(1) & vbNewLine &
         "Y = " & aAssemblyBoundaries(2) - aAssemblyBoundaries(3) & vbNewLine &
@@ -207,7 +223,6 @@ Public Class AssemblyTiers2
         '#################### Main algorithm ##########################
 
         Dim intI As Integer                   'total number of components in the scene minus base parts
-        Dim intJ As Integer                   'number of primary directions (default: global + local)
         Dim intTier As Integer                'number of current assembly tier
         Dim int_i As Integer                  'product index in cRelevantProducts
         Dim int_i_cycle As Integer            'product counter
@@ -224,25 +239,25 @@ Public Class AssemblyTiers2
         Dim bInitPosRecorded(cRelevantProducts.Count - 1) As Boolean
         Dim bDeactivated(cRelevantProducts.Count - 1) As Boolean
 
-        'Before trying to remove a component, check whether it would break liaison graph coherence / connectedness
-        bCoherenceCheck = True
-        Dim coherenceCheckNodeIndices As New List(Of Integer)
-        If bCoherenceCheck Then
+        'Before trying to remove a component, check whether it would break liaison graph connectivity
+        Dim connectivityCheckNodeIndices As New List(Of Integer)
+        If bConnectivityCheck Then
             Dim componentIndex As Integer
             componentIndex = 0
             For Each oComponent In cRelevantProducts
-                coherenceCheckNodeIndices.Add(componentIndex)
+                connectivityCheckNodeIndices.Add(componentIndex)
                 componentIndex = componentIndex + 1
             Next oComponent
+            'Liaison graph extraction for connectivity checks
+            Liaison()
         End If
 
         intI = cRelevantProducts.Count - 1   'the index of base components will be simply skipped (cRelevantProducts includes cBaseProducts, unlike in the paper!)
-        intJ = 6                          'number of disassembly directions (6 - only global axes, 12 - including local axes)
         intTier = 1                       'counts current disassembly tier (lower number means earlier disassembly possible) - this gets reversed in the end
         int_i = 0                         'index of current part in collection of relevant products
         int_i_cycle = 0                   'counter for the current tier iteration
         int_j = 0                         'index of disassembly direction
-        int_j_temp = 0                    'used to display movement direction once
+        int_j_temp = -1                    'used to display movement direction once
         total_coll = 0
 
         'map indices to directions (careful, starts from 0 here, but the paper and moveProduct uses 1 as start)
@@ -268,13 +283,8 @@ Public Class AssemblyTiers2
         Dim cGroups As Groups
         cGroups = CATIA.ActiveDocument.Product.GetTechnologicalObject("Groups")
 
-        Dim StartTime As DateTime
-        StartTime = Now
-
-        'Liaison graph extraction for coherence checks
-        If bCoherenceCheck Then
-            Liaison()
-        End If
+        Dim AssemblyTiersStartTime As DateTime
+        AssemblyTiersStartTime = Now
 
         Do
 
@@ -289,28 +299,28 @@ Public Class AssemblyTiers2
                 GoTo entry0
             End If
 
-            If bCoherenceCheck Then
-                'If a component is allowed to be moved, check whether removing it will break up the coherence of product liaison graph
+            If bConnectivityCheck Then
+                'If a component is allowed to be moved, check whether removing it will break up the connectivity of product liaison graph
                 'Remove int_i from index list
                 Dim listIndex As Integer
                 listIndex = 0
-                For Each partIndex In coherenceCheckNodeIndices
+                For Each partIndex In connectivityCheckNodeIndices
                     If partIndex = int_i Then
                         Exit For
                     Else
                         listIndex = listIndex + 1
                     End If
                 Next
-                coherenceCheckNodeIndices.RemoveAt(listIndex)
+                connectivityCheckNodeIndices.RemoveAt(listIndex)
                 'Check whether all node of LG can be visited from any other node (= connected graph)
-                If SubassemblyIsConnected(coherenceCheckNodeIndices) Then
+                If SubassemblyIsConnected(connectivityCheckNodeIndices) Then
                     'Put int_i back at listIndex
-                    coherenceCheckNodeIndices.Insert(listIndex, int_i)
+                    connectivityCheckNodeIndices.Insert(listIndex, int_i)
                 Else
-                    'If coherence will be broken, skip this component
-                    Debug.Print("Removing " & product1.Name & " would violate liaison graph coherence!")
+                    'If connectivity will be broken, skip this component
+                    Debug.Print("Removing " & product1.Name & " would violate liaison graph connectivity!")
                     'Put int_i back at listIndex
-                    coherenceCheckNodeIndices.Insert(listIndex, int_i)
+                    connectivityCheckNodeIndices.Insert(listIndex, int_i)
                     GoTo exit2
                 End If
             End If
@@ -339,9 +349,13 @@ Public Class AssemblyTiers2
             Dim iStaticProduct As Integer
             For iStaticProduct = 0 To cRelevantProducts.Count - 1
                 If iStaticProduct <> int_i And Not bDeactivated(iStaticProduct) Then
-                    'If BoundingBoxesOverlap(int_i, iStaticProduct) Then
-                    group2.AddExplicit(cRelevantProducts.Item(iStaticProduct))
-                    'End If
+                    If bBoundingBoxProjectionCheck Then
+                        If BoundingBoxesOverlap(int_i, iStaticProduct) Then
+                            group2.AddExplicit(cRelevantProducts.Item(iStaticProduct))
+                        End If
+                    Else
+                        group2.AddExplicit(cRelevantProducts.Item(iStaticProduct))
+                    End If
                 End If
             Next iStaticProduct
 
@@ -438,11 +452,11 @@ exit1:
                             'all directions were checked
                             total_coll = total_coll + intJ
                             Debug.Print("Disassembly trials: " & total_coll)
-                            'if this component can be disassembled, remove its index from coherence check list
-                            If bCoherenceCheck And productHasValidDisassDir(int_i, disassDir) Then
+                            'if this component can be disassembled, remove its index from connectivity check list
+                            If bConnectivityCheck And productHasValidDisassDir(int_i, disassDir) Then
                                 Dim listInd As Integer
                                 listInd = 0
-                                For Each partIndex In coherenceCheckNodeIndices
+                                For Each partIndex In connectivityCheckNodeIndices
                                     If partIndex = int_i Then
                                         Exit For
                                     Else
@@ -450,7 +464,7 @@ exit1:
                                     End If
                                 Next partIndex
                                 'Remove int_i from index list (only after all directions were checked)
-                                coherenceCheckNodeIndices.RemoveAt(listInd)
+                                connectivityCheckNodeIndices.RemoveAt(listInd)
                             End If
 exit2:
                             int_i = int_i + 1
@@ -570,7 +584,7 @@ exitCD:
 
         Dim SecondsElapsed As Double
         Dim MillisecondsElapsed As Double
-        MillisecondsElapsed = (Now - StartTime).TotalMilliseconds
+        MillisecondsElapsed = (Now - AssemblyTiersStartTime).TotalMilliseconds
         SecondsElapsed = Math.Round(MillisecondsElapsed / 1000.0, 2)
         MsgBox("Collision detection algorithm finished execution after " & CStr(SecondsElapsed) & " seconds")
 
@@ -625,39 +639,41 @@ exitCD:
         d3.Add(10, 7)
         d3.Add(11, 8)
         For int_i = 0 To cRelevantProducts.Count - 1
-            'Dim sum As Integer
-            'sum = 0
-            'For intAxis = 0 To intJ - 1
-            '    sum = sum + disassDir(int_i, intAxis)
-            'Next intAxis
-            ''Only for products with multiple extraction directions
-            'If sum > 1 Then
-            '    'Add options to ComboBox
-            '    For intAxis = 0 To intJ - 1
-            '        If disassDir(int_i, intAxis) = 1 Then
-            '            ExtractionDirection.ComboBox1.AddItem(d1.Item(intAxis))
-            '        End If
-            '    Next intAxis
-            '    'Highlight the product in CATIA
-            '    Dim selection5 As Selection
-            '    selection5 = CATIA.ActiveDocument.Selection
-            '    selection5.Clear()
-            '    selection5.Add(cRelevantProducts.Item(int_i + 1))
-            '    'Show dialog
-            '    ExtractionDirection.Show
-            '    selection5.Clear()
-            '    'Translate chosen axis name back into index 0..11
-            '    Dim iChosenDir As Integer
-            '    iChosenDir = d2.Item(sChosenDirection)
-            '    'Set all other disassembly directions to 0
-            '    For intAxis = 0 To intJ - 1
-            '        If intAxis = iChosenDir Then
-            '            disassDir(int_i, intAxis) = 1
-            '        Else
-            '            disassDir(int_i, intAxis) = 0
-            '        End If
-            '    Next intAxis
-            'End If
+            If bChooseExtractionDirection Then
+                Dim sum As Integer
+                sum = 0
+                For intAxis = 0 To intJ - 1
+                    sum = sum + disassDir(int_i, intAxis)
+                Next intAxis
+                'Only for products with multiple extraction directions
+                If sum > 1 Then
+                    'Add options to ComboBox
+                    For intAxis = 0 To intJ - 1
+                        If disassDir(int_i, intAxis) = 1 Then
+                            'ExtractionDirection.ComboBox1.AddItem(d1.Item(intAxis))
+                        End If
+                    Next intAxis
+                    'Highlight the product in CATIA
+                    Dim selection5 As Selection
+                    selection5 = CATIA.ActiveDocument.Selection
+                    selection5.Clear()
+                    selection5.Add(cRelevantProducts.Item(int_i + 1))
+                    'Show dialog
+                    'ExtractionDirection.Show
+                    selection5.Clear()
+                    'Translate chosen axis name back into index 0..11
+                    Dim iChosenDir As Integer
+                    iChosenDir = d2.Item(sChosenDirection)
+                    'Set all other disassembly directions to 0
+                    For intAxis = 0 To intJ - 1
+                        If intAxis = iChosenDir Then
+                            disassDir(int_i, intAxis) = 1
+                        Else
+                            disassDir(int_i, intAxis) = 0
+                        End If
+                    Next intAxis
+                End If
+            End If
             'Reverse tier values
             Dim intMaxTier As Integer
             intMaxTier = intTier
@@ -679,7 +695,7 @@ exitCD:
         Dim oClash1 As Clash
         oClash1 = cClashes.Add
         oClash1.ComputationType = CatClashComputationType.catClashComputationTypeBetweenAll
-        oClash1.Compute
+        oClash1.Compute()
         Dim cInitConflicts As Conflicts
         cInitConflicts = oClash1.Conflicts
         Dim initConfl As Conflict
@@ -698,43 +714,11 @@ exitCD:
             End If
         Next initConfl
 
-        '  For int_i = 1 To cRelevantProducts.Count
-        '    Dim bNoContacts As Boolean
-        '    bNoContacts = True
-        '    'loop over components from previous tier
-        '    For int_j = 1 To cRelevantProducts.Count
-        '      If aTiers(int_j - 1) = aTiers(int_i - 1) - 1 And aTiers(int_i - 1) <> 0 Then
-        '        'Test for contact
-        '        'define two groups
-        '        Dim group11 As Group
-        '        Dim group21 As Group
-        '         group11 = cGroups.Add
-        '         group21 = cGroups.Add
-        '        group11.AddExplicit cRelevantProducts.Item(int_i)
-        '        group21.AddExplicit cRelevantProducts.Item(int_j)
-        '        'create a new clash analysis
-        '        Dim oClash 'As Clash
-        '         oClash = cClashes.Add
-        '        oClash.ComputationType = catClashComputationTypeBetweenTwo
-        '        oClash.FirstGroup = group11
-        '        oClash.SecondGroup = group21
-        '        oClash.InterferenceType = catClashInterferenceTypeContact
-        '        oClash.Compute
-        '        Dim cConflicts As Conflicts
-        '         cConflicts = oClash.Conflicts
-        '        If cConflicts.Count > 0 Then
-        '          precedenceMatrix(int_j - 1, int_i - 1) = 1
-        '          bNoContacts = False
-        '        End If
-        '      End If
-        '    Next int_j
-        '  Next int_i
-
         'Export data to Excel
         Dim objExcel As Microsoft.Office.Interop.Excel.Application
         objExcel = CreateObject("Excel.Application")
         objExcel.Visible = True
-        objExcel.Workbooks.Add
+        objExcel.Workbooks.Add()
         objExcel.ActiveWorkbook.Sheets.Add.Name = "Precedence Matrix"
         Dim objSheet1, objSheet2 As Object
         objSheet1 = objExcel.ActiveWorkbook.Worksheets(2)
@@ -765,6 +749,14 @@ exitCD:
             Next int_j
         Next int_i
 
+        'Save and close excel workbook
+        Dim xlsFileName As String = CATIA.ActiveDocument.Name
+        objExcel.ActiveWorkbook.SaveAs(Filename:=xlsPath & xlsFileName & "_AssemblyTiers.xlsx")
+        objExcel.ActiveWorkbook.Close(SaveChanges:=True)
+        'close the excel application
+        objExcel.Quit()
+        ReleaseObject(objExcel)
+
     End Sub
     Sub ExtractProducts(oCurrentProduct As Product)
 
@@ -1883,4 +1875,19 @@ Finish:
         Return True
     End Function
 
+    Private Sub ReleaseObject(ByVal obj As Object)
+        Try
+            Dim intRel As Integer = 0
+            Do
+                intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
+            Loop While intRel > 0
+            'MsgBox("Final Released obj # " & intRel)
+        Catch ex As Exception
+            MsgBox("Error releasing object" & ex.ToString)
+            obj = Nothing
+        Finally
+            GC.Collect()
+        End Try
+    End Sub
+
 End Class
-- 
GitLab