Examine Geometry

Examine your geometry

Make Euclid proud

Even if you are a brand new user to NX, you should be familiar with the Examine Geometry command, it can be found in the Analysis menu. Running this check will ensure your model is valid during the modeling process and for downstream uses (drafting, FEA, CAM, etc). At a minimum, the model should be required to pass the face and body checks before releasing the file for production; also, running examine geometry is the recommended first step in troubleshooting should your file develop strange behavior (boolean operation failing, mass properties obviously incorrect, section view strangeness, shaded views missing faces, etc, etc). If you are unfamiliar with the command or just want more background, search the GTAC solution center with the phrase "examine geometry" to find several informative articles. There are links to three of the articles below, you will need a webkey to access the GTAC site.

Unigraphics - Examine and check geometry

NX - Understanding and utilizing the examine geometry function

NX - Repairing errors found using the Examine Geometry function

Divide and Conquer

When you have a parameterized file that does not pass the geometry checks, it can become a tedious task to hunt down the offending geometry. When I starting using NX, I was taught a "divide and conquer" technique to help quickly identify the problem entities. The goal is to identify which feature in the history tree is causing the model to fail the checks. We put "bounds" around the bad feature and through a series of tests we can progressively narrow the bounds until we find the offending feature. The overall steps are as follows:

  1. The first feature is the lower bound (feature A), the last feature in the history tree is the upper bound (feature B).
  2. Unsuppress all features, fix any/all feature errors.
  3. Run examine geometry with all body and face checks set (at a minimum).
  4. Set the current feature in the tree to the point 1/2 way between the upper and lower bound, re-run the examine geometry checks.
    1. If the check fails, we know the error is somewhere between the lower bound (feature A) and the current feature. Make note of the current feature number, this becomes the new upper bound (feature B).
    2. If the check passes, we know the error is somewhere between the current feature and the upper bound (feature B). Make note of the current feature number, this becomes the new lower bound (feature A).
  5. Go to step 4 and repeat until you find the offending feature

The list above looks very much like an algorithm because, well... it is an algorithm. If you have studied numerical methods, you may recognize it bears a strong resemblance to the bisection root finding method.

Now that we have an algorithm, let's put it to use:

'NXJournaling.com
'January 9, 2013
'tested on NX 8
'journal version 0.11 (beta release)
'    0.11: fixed bug where journal would crash if "cancel" was clicked in the selection step
 
'Journal runs geometry checks (body structure, body consistency, face-face intersect, face self-intersect)
'on the selected solid. You do not need to window select the geometry (as you do with the examine geometry command),
'the journal will automatically select the faces of the selected solid body.
 
'If the solid does not pass one of the initial checks, the journal will search for the last feature in the history tree
'where the target solid passed all the checks. This feature will be made the current feature.
 
'** Note: This does not necessarily mean that the next feature is causing the failure, but should serve as
'         a good starting point in your search for the bad geometry.
'         For example: suppose you have a file with 1000 features and the journal indicates feature 882 is the
'         last valid state of the solid; this does not necessarily mean that SUBTRACT(883) is the problem.
'         Perhaps the real problem is the geometry in THROUGH_CURVE_MESH(876) that trims the tool body of SUBTRACT(883).
'         In this case, the journal simply indicates that the geometry that contributes to SUBTRACT(883) needs to be investigated.
 
'Usage notes:
'    The journal will prompt for the selection of a solid body.
'    If the body passes all the checks, a note indicating success will be written to the Information Window
'    If the body fails a check, the journal will search for the last feature in the history tree where the selected body
'      passed all the checks.
'    The journal works best on parts that are fully parameterized and have no suppressed features or features with errors.
'    There is no point of running this journal on a solid body that is a "body" feature (imported body), the examine geometry
'      will serve better in this case.
 
'I don't consider this the 'final' version of this journal; there are other options and checks I'd like to add.
'Any suggestions, bug reports, or general feedback can be sent to info@nxjournaling.com
'Thanks!
 
Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF
Imports System.Collections.Generic
 
Module examine_geometry
 
    Dim ufs As UFSession = UFSession.GetUFSession()
    Dim theSession As Session = Session.GetSession()
    Dim workPart As Part = theSession.Parts.Work
    Dim lw As ListingWindow = theSession.ListingWindow
 
    Sub Main()
 
        lw.Open()
 
        Dim myFeatures As Features.Feature() = workPart.Features.GetFeatures
 
        Dim featureCount As Integer = 0
        Dim featureA As Integer = 0
        Dim featureB As Integer = 0
        Dim featureX As Integer = 0
        Dim featureCheck As Features.Feature
 
        Dim featureList As New List(Of Features.Feature)
 
        For Each someFeature As Features.Feature In myFeatures
 
            If Not (someFeature.IsInternal Or someFeature.Suppressed) Then
                featureList.Add(someFeature)
            End If
 
        Next
 
        featureCount = featureList.Count
        'lw.WriteLine("Feature count: " & featureCount.ToString)
        featureB = featureCount - 1
 
        Dim mySolid As Body
 
        If SelectSolid("Select a solid body", mySolid) = Selection.Response.Cancel Then
            Exit Sub
        End If
 
        Dim partGood As Boolean = False
        partGood = GoodGeometry(mySolid)
 
        If Not partGood Then
            lw.WriteLine("Current feature: " & workPart.CurrentFeature.GetFeatureName)
            lw.WriteLine("Failed geometry check")
            Do Until (featureB - featureA) <= 1
                featureX = featureA + (featureB - featureA) \ 2
                lw.WriteLine("")
                featureCheck = featureList.Item(featureX)
                featureCheck.MakeCurrentFeature()
                lw.WriteLine("Current feature: " & workPart.CurrentFeature.GetFeatureName)
                partGood = GoodGeometry(mySolid)
                If partGood Then
                    featureA = featureX
                Else
                    featureB = featureX
                End If
            Loop
 
            lw.WriteLine("")
            lw.WriteLine("Current feature adjusted to last good state of selected solid")
 
        Else
            lw.WriteLine("Passed all geometry checks")
        End If
 
    End Sub
 
    Function GoodGeometry(ByVal someSolid As Body) As Boolean
 
        Dim myFaces() As Face = someSolid.GetFaces
 
        Dim badFacesEdges As Integer
        Dim faultTags(-1) As Tag
        Dim faultTokens(-1) As Integer
        Dim faceSelfIntersectPoint(2) As Double
        ufs.Modl.AskBodyStructures(someSolid.Tag, badFacesEdges, faultTags)
        If badFacesEdges = 0 Then
            lw.WriteLine("Passed Body Structure test")
            ufs.Modl.AskBodyConsistency(someSolid.Tag, badFacesEdges, faultTokens, faultTags)
            If badFacesEdges = 0 Then
                lw.WriteLine("Passed Body Consistency test")
                ufs.Modl.AskFaceFaceIntersect(someSolid.Tag, badFacesEdges, faultTags)
                If badFacesEdges = 0 Then
                    lw.WriteLine("Passed Face Face Intersect test")
                    For Each faceToTest As Face In myFaces
                        ufs.Modl.AskFaceSelfIntersect(faceToTest.Tag, badFacesEdges, faceSelfIntersectPoint)
                        If badFacesEdges = 0 Then
                            'lw.WriteLine("Face passed self-intersection test")
                        Else
                            lw.WriteLine("Failed Face self intersection test")
                            Exit For
                            Return False
                        End If
                    Next
                    lw.WriteLine("Passed Face self intersection test")
                    Return True
                Else
                    lw.WriteLine("Failed Face Face Intersect test")
                    Return False
                End If
            Else
                lw.WriteLine("Failed Body Consistency test")
                Return False
            End If
        Else
            lw.WriteLine("Failed Body Structure test")
            Return False
        End If
 
        lw.Close()
 
 
    End Function
 
    Function SelectSolid(ByVal prompt As String, ByRef selObj As NXObject) 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.SelectObject(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
 
 
    Public Function GetUnloadOption(ByVal dummy As String) As Integer
 
        'Unloads the image when the NX session terminates
        GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination
 
    End Function
 
End Module

Usage notes

This journal is meant to be run on a fully parameterized model since it will search for the "last good feature". If you need to check unparameterized bodies, I'd suggest running the interactive Examine Geometry checks. If you only have one feature in the file (the unparameterized body feature) and it fails the checks, the journal may crash or do other strange things (I don't know exactly what it will do since I don't currently have such a file to check against).

Normally when you use the examine geometry command, you will window select around the solid body so that the body, all the faces, and all the edges get selected. The journal will prompt you to select a solid body, it will collect all the faces and edges it needs from this single selection. The journal will write messages to the information window as it runs to keep you informed as to what is happening. It currently only runs the body structure, body consistency, face face intersection, and face self intersection tests. If the solid of interest passes all of these checks, congratulations! you are done. If the solid does not pass one or more of the checks, the journal will run through the steps outlined above. The model will be left with the current feature set to the last one where the model passes all the checks. Check out the parent geometry for the next feature in the tree, chances are good it is causing the problem.

Programming notes

If you record a journal when using the examine geometry function, the code you will get will look very different from my code. There is an ExamineGeometry object that allows you to set the checks to run, run the checks, etc, etc. However, as of this writing, there is a bug with the GetResults method that causes the journal to crash. When this bug is fixed in a future update, I'd like to revisit this code and clean it up to use the .NET versions of the various functions.

Conclusion

This article is a good example of translating a process used in interactive NX, translating it to an algorithm, and finally implementing that algorithm into code. I hope it has resulted in a time-saving journal that you will find useful.

So, what manual processes are you following in NX? It's time to automate them!