Showing results for 
Search instead for 
Do you mean 
Reply

Python + Machine Learning for NX Open

[ Edited ]

Here is an example of using a Python based Machine Learning library (scikit-learn) with the NX Open API. All the Python code is based off of open source libraries. 

 

The python code will extract geometric data from a 3D scanned object (in an stl format not point cloud) and reverse engineer the 3D scanned stl.

 

Hopefully, this example will bring more Python developers into the NX Open Community.

 

import NXOpen
import NXOpen.BlockStyler
import NXOpen.Features
import NXOpen.UF
#import NXOpen.UI
import NXOpen.GeometricAnalysis
import NXOpen.Facet
#import NXOpen.Utilities
#import System

import math
import numpy as np
import pandas as pd
import csv
import random
import sklearn.cluster as sk
from sklearn import preprocessing 
from sklearn.decomposition import PCA
from random import randint

import scipy.spatial as sp

import scipy.cluster.vq as vq
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

class facet_data:
    # Constructor for NX Styler class
    # ------------------------------------------------------------------------------
    def __init__(self):
        
        # class members
        self.theSession = None
        self.theUI = None
        self.theLw= None
        self.theDialogName = ""
        self.theDialog = None
        #Get the UF session
        self.theUfSession = None

        # integer values
        global num_facets_in_model, max_vertices_in_facet, vertex_array_size
        
        
        try:
           
            self.theSession = NXOpen.Session.GetSession()
            self.theUI = NXOpen.UI.GetUI()
            self.theLw = self.theSession.ListingWindow #create print window
            self.theUfSession = NXOpen.UF.UFSession.GetUFSession() 
            
        except Exception as ex:
            # ---- Enter your exception handling code here -----
            raise ex

    #for reading plane equations from an excel sheet
    def read_csv(self):
        global csv_list, csv_array, csv_origin_list
        
        csv_origin_list=[]
        file_name="plate_600B_params_ext.csv"

#create a dataframe using the pandas library df=pd.read_csv(file_name) csv_var=csv.reader(file_name) self.theLw.WriteLine('\n') csv_array=df.as_matrix() csv_list=df.values.tolist() #extract the origin's xyz coordinates from each plane equation for i in range(len(csv_list)): csv_origin_list.append([csv_list[i][4],csv_list[i][5],csv_list[i][6]]) return csv_array, csv_list, csv_origin_list #extract plane equations from each 3D scanned object def plane_equations(self): self.theLw.Open() self.theLw.WriteLine("Bring up console") global plane_normal, d_coeffiecient, euclid, dispPart global facet_tag, face_id, workPart, face_list, levelofdetail, num_facets global plane_list, corners_list, vertex1_list, vertex2_list, vertex3_list global rel_tol, euclid_list, euclid_corners global facet_list, facet_array global vertex1_array, vertex2_array, vertex3_array, plane_array global normals_list global cube_side_nrmlzd, facet_journalid #global cube_side2_float global df_array global centroid_list, centroid_plane_list dispPart= self.theSession.Parts.Display workPart = self.theSession.Parts.Work plane_list=[] corners_list=[] facet_list=[] vertex1_list=[] vertex2_list=[] vertex3_list=[] normals_list=[] centroid_list=[] centroid_plane_list=[] cntr=0 #create instance of UF.Facet class uf_facet=NXOpen.UF.Facet() #from NXOpen.Facet.FacetedBody class #loop through all facets in the workPart for facet_body in workPart.FacetedBodies: self.theLw.WriteLine("Facet Journal Identifier is " + str(facet_body.JournalIdentifier)) facet_journalid=facet_body.JournalIdentifier
#Tag for each facet facet_tag=facet_body.Tag levelofdetail=facet_body.NumberOfLevelsOfDetail x1=np.array([27.0]) x2=np.array([1.0/3.0]) x3=np.power(x1, x2) #various parameters for each 3D scanned stl file self.theLw.WriteLine("Number of Facets is " + str(facet_body.NumberOfFaces)) self.theLw.WriteLine("Surface Area is " + str(facet_body.SurfaceArea)) self.theLw.WriteLine("Volume is " + str(facet_body.Volume)) self.theLw.WriteLine('\n') vol=np.array([facet_body.Volume]) exp=np.array([1.0/3.0])

#side of the bounding box cube calculated by volume cube_side=np.power(vol, exp) self.theLw.WriteLine("Side of the bounding box cube (Volume to the 1/3rd power) is " + str(cube_side)) self.theLw.WriteLine('\n') sf_area=np.array([facet_body.SurfaceArea]) x4=np.array([6.0]) quotient=np.divide(sf_area, x4)
cube_side2=np.sqrt(quotient) self.theLw.WriteLine("Side of the bounding box cube (Surface area =6x^2) is " + str(cube_side2)) self.theLw.WriteLine('\n') cube_side_nrmlzd=np.float(cube_side2) self.theLw.WriteLine("Grid Size is " + str(cube_side_nrmlzd)) self.theLw.WriteLine('\n') #facet_body.SetParameters(params) #self.theLw.WriteLine("Parameters are" + str(facet_body.GetParameters())) self.theLw.WriteLine('\n') #Get number of facets, use tag from NXOpen.Facet.FacetedBody attribute num_facets=uf_facet.AskNFacetsInModel(facet_tag) num_faces=uf_facet.AskNumFaces(facet_tag) #get the plane equation for each facet of the 3d scanned, 0 to num_facets for i in range(0, num_facets): #arguments are model id for facet_tag and facet id for i #returns id the of the face, an int face_id=uf_facet.AskFaceIdOfFacet(facet_tag, i) #returns a tuple with a list for the normal coefficients (a,b,c) in index 0 and the d coefficient in index 1 plane_tuple=uf_facet.AskPlaneEquation(facet_tag, i) #returns three vertices of each facet vertex_tuple=uf_facet.AskVerticesOfFacet(facet_tag, i) #need to format vertices and use list comprehension/enumerate vertex1_x=round(vertex_tuple[1][0][0],3) vertex1_y=round(vertex_tuple[1][0][1],3) vertex1_z=round(vertex_tuple[1][0][2],3) vertex2_x=round(vertex_tuple[1][1][0],3) vertex2_y=round(vertex_tuple[1][1][1],3) vertex2_z=round(vertex_tuple[1][1][2],3) vertex3_x=round(vertex_tuple[1][2][0],3) vertex3_y=round(vertex_tuple[1][2][1],3) vertex3_z=round(vertex_tuple[1][2][2],3) #self.theLw.WriteLine("Vertex tuple[1] is "+str(vertex_tuple[1])) vertex1_list.append([vertex1_x,vertex1_y,vertex1_z]) vertex2_list.append([vertex2_x,vertex2_y,vertex2_z]) vertex3_list.append([vertex3_x,vertex3_y,vertex3_z]) #need to format a, b, c, d coeffiecents a=round(plane_tuple[0][0], 3) b=round(plane_tuple[0][1], 3) c=round(plane_tuple[0][2], 3) d=round(plane_tuple[1], 3) # for some reason, the normal gets reversed #d=d*-1.0 #append to a list, plane_list.append([a,b,c,d]) normals_list.append([a,b,c]) #calculate the centroid #centroid is the intersection of 3 line segments that connect each vertex with the midpt of the otherside centroid_x= (vertex1_x+vertex2_x+vertex3_x)/3 centroid_y= (vertex1_y+vertex2_y+vertex1_y)/3 centroid_z= (vertex1_z+vertex2_z+vertex1_z)/3 #point_sum=np.sum([point1,point2,point3], axis=0) centroid_list.append([centroid_x,centroid_y, centroid_z]) # for bounding block method centroid_plane_list.append([[centroid_x,centroid_y, centroid_z],[a,b,c,d]]) #facet_centroid=np.divide(point_sum, [3.0,3.0,3.0]) #facet_list.append(facet_centroid.tolist())
facet_array = np.array([row for row in facet_list]) #array of plane equations plane_array = np.array([row for row in plane_list]) df=pd.DataFrame(plane_list) df.rename(columns={0:'A',1:'B', 2:'C', 3:'D'}, inplace=True) #sort values by ascending and then remove outliers (top ten thousand and bottom ten thousand) #need to sort columns separately one by one, otherwise you get incorrect plane equations df2=df.sort(["A",], ascending=[True]) df2=df2.sort(["B",], ascending=[True]) df2=df2.sort(["C",], ascending=[True]) df2=df2.sort(["D",], ascending=[True]) #drop the first ten thousand plane equations df2.drop(df2.index[:10000], inplace=True) df2.drop(df2.index[60000:], inplace=True) #filtering out plane equations by setting a specific tolerance #df2=df[np.isclose(df['B'].values[:, None], [0.939,0.874,1.0, ], atol=.05).any(axis=1)] #df2=df[np.isclose(df['A'].values[:, None], [-0.12,0.0,0.12], atol=.05).any(axis=1)] df_array=df2.as_matrix() vertex1_array = np.array([row for row in vertex1_list]) vertex2_array = np.array([row for row in vertex2_list]) vertex3_array = np.array([row for row in vertex3_list]) #self.theLw.WriteLine("Vertex 1 array is "+str(vertex1_array.tolist())) self.theLw.WriteLine("") #self.theLw.WriteLine("Shape of Vertex array is "+str(vertex1_array.shape)) self.theLw.WriteLine("") return plane_array, vertex1_array, df_array, cube_side_nrmlzd, facet_journalid, centroid_list, centroid_plane_list, facet_tag, num_facets # facet_array, vertex1_array, vertex2_array, vertex3_array ########################## #using centroid list argument def min_max(self, centroids): global max_list, min_list df=pd.DataFrame(centroids) self.theLw.WriteLine("Min max function ") self.theLw.WriteLine("") df.rename(columns={0:'X',1:'Y', 2:'Z'}, inplace=True) #self.theLw.WriteLine("Columns are "+str(df.columns)) #self.theLw.WriteLine("") #self.theLw.WriteLine("Dataframe head is "+str(df.head())) #self.theLw.WriteLine("") #self.theLw.WriteLine(" X Max is "+str(df['X'].max())) xmax=df['X'].max() #self.theLw.WriteLine(" Type X Max is "+str(type(df['X'].max()))) #self.theLw.WriteLine("") #self.theLw.WriteLine(" Y Max is "+str(df['Y'].max())) #self.theLw.WriteLine("") ymax=df['Y'].max() #self.theLw.WriteLine(" Z Max is "+str(df['Z'].max())) #self.theLw.WriteLine("") zmax=df['Z'].max() max_list=[float(xmax), float(ymax), float(zmax)] #self.theLw.WriteLine(" X Min is "+str(df['X'].min())) #self.theLw.WriteLine("") xmin=df['X'].min() #self.theLw.WriteLine(" Y Min is "+str(df['Y'].min())) #self.theLw.WriteLine("") ymin=df['Y'].min() #self.theLw.WriteLine(" Z Min is "+str(df['Z'].min())) #self.theLw.WriteLine("") zmin=df['Z'].min() min_list=[float(xmin), float(ymin), float(zmin)] width=abs(min_list[0])+abs(max_list[0]) self.theLw.WriteLine("") self.theLw.WriteLine("") self.theLw.WriteLine("") return max_list, min_list #bounding block that def block(self, min, max): #create bounding box instance blockFeatureBuilder1 = workPart.Features.CreateBlockFeatureBuilder(NXOpen.Features.Feature.Null) blockFeatureBuilder1.BooleanOption.Type = NXOpen.GeometricUtilities.BooleanOperation.BooleanType.Create targetBodies1 = [NXOpen.Body.Null] * 1 targetBodies1[0] = NXOpen.Body.Null blockFeatureBuilder1.BooleanOption.SetTargetBodies(targetBodies1) #using min and max, diagonal type blockFeatureBuilder1.Type = NXOpen.Features.BlockFeatureBuilder.Types.DiagonalPoints blockFeatureBuilder1.BooleanOption.Type = NXOpen.GeometricUtilities.BooleanOperation.BooleanType.Create originPoint1 = NXOpen.Point3d(min[0], min[1], min[2]) cornerPoint1 = NXOpen.Point3d(max[0], max[1], max[2]) blockFeatureBuilder1.SetTwoDiagonalPoints(originPoint1, cornerPoint1) blockFeatureBuilder1.SetBooleanOperationAndTarget(NXOpen.Features.Feature.BooleanType.Create, NXOpen.Body.Null) blockFeatureBuilder1.CommitFeature() self.theLw.WriteLine("Block function") #these attributes do no show up for some reason self.theLw.WriteLine("Length is "+str(blockFeatureBuilder1.Length)) self.theLw.WriteLine("Height is "+str(blockFeatureBuilder1.Height)) self.theLw.WriteLine(" Width is "+str(blockFeatureBuilder1.Width)) self.theLw.WriteLine(" Width type is "+str(type(blockFeatureBuilder1.Width))) self.theLw.WriteLine("Test line") self.theLw.WriteLine('\n') self.theLw.WriteLine('\n') self.theLw.WriteLine('\n') blockFeatureBuilder1.Destroy() def clear_box(self,journalid, min): toolingBoxBuilder1 = workPart.Features.ToolingFeatureCollection.CreateToolingBoxBuilder(NXOpen.Features.ToolingBox.Null) toolingBoxBuilder1.Type = NXOpen.Features.ToolingBoxBuilder.Types.BoundedBlock matrix1 = NXOpen.Matrix3x3() #these adjust starting position of box matrix1.Xx = 1.0 matrix1.Xy = 0.0 matrix1.Xz = 0.0 matrix1.Yx = 0.0 matrix1.Yy = 1.0 matrix1.Yz = 0.0 matrix1.Zx = 0.0 matrix1.Zy = 0.0 matrix1.Zz = 1.0 position1 = NXOpen.Point3d(0.0, 0.0, 0.0) toolingBoxBuilder1.SetBoxMatrixAndPosition(matrix1, position1) toolingBoxBuilder1.BoundedObject selections1 = [NXOpen.NXObject.Null] * 1 # find the face by the journal id facetedBody1 = workPart.FacetedBodies.FindObject(journalid) selections1[0] = facetedBody1 deselections1 = [] toolingBoxBuilder1.SetSelectedOccurrences(selections1, deselections1) selectNXObjectList1 = toolingBoxBuilder1.FacetBodies objects1 = [NXOpen.NXObject.Null] * 1 objects1[0] = facetedBody1 selectNXObjectList1.Add(objects1) #csysorigin1 = NXOpen.Point3d(min[0], min[1], min[2]) csysorigin1 = NXOpen.Point3d(min[0], min[1], min[2]) toolingBoxBuilder1.BoxPosition = csysorigin1 toolingBoxBuilder1.CalculateBoxSize() self.theLw.WriteLine("Calculated box size is "+str(toolingBoxBuilder1.CalculateBoxSize())) toolingBoxBuilder1.Commit() clearbox_list=toolingBoxBuilder1.GetCommittedObjects() xval=toolingBoxBuilder1.OffsetPositiveX self.theLw.WriteLine("Clear box function") self.theLw.WriteLine("Min is "+str(min)) self.theLw.WriteLine("Clear box is "+str(clearbox_list)) self.theLw.WriteLine("Bounded box is "+str(toolingBoxBuilder1.BoundedObject)) bounded_box=toolingBoxBuilder1.BoundedObject clearbox1=clearbox_list[0] self.theLw.WriteLine("Clear box1 is "+str(clearbox1)) self.theLw.WriteLine("Calculated box size is "+str(toolingBoxBuilder1.CalculateBoxSize())) self.theLw.WriteLine("Precision value is "+str(toolingBoxBuilder1.PrecisionValue)) self.theLw.WriteLine("Center Precision value is "+str(toolingBoxBuilder1.PositionPrecisionValue)) self.theLw.WriteLine("X value of bounded box is "+str(toolingBoxBuilder1.XValue.Value)) self.theLw.WriteLine("Clearance is "+str(toolingBoxBuilder1.Clearance.Value)) self.theLw.WriteLine("Y value of bounded box is "+str(toolingBoxBuilder1.YValue.Value)) self.theLw.WriteLine("Offset value Y is "+str(toolingBoxBuilder1.OffsetPositiveY.Value)) self.theLw.WriteLine("Z value of bounded box is "+str(toolingBoxBuilder1.ZValue.Value)) self.theLw.WriteLine('\n') self.theLw.WriteLine('\n') self.theLw.WriteLine('\n') toolingBoxBuilder1.Destroy() features1 = [NXOpen.Features.Feature.Null] * 1 #theUI = UI.GetUI() #features1[0] = self.theUI.SelectionManager.GetSelectedObject() #toolingBox1 = workPart.Features.GetObject(clearbox_list) #features1[0] = clearbox_list #workPart.Features.SuppressFeatures(features1) #creates a grid overlaying the 3d scanned object def grid(self, journalid, cube_width): global line_ids, line_objects, intersect_pts, grid_size line_ids=[] line_objects=[] intersect_pts=[] sectionAnalysisExBuilder1 = workPart.AnalysisManager.AnalysisObjects.CreateSectionAnalysisExBuilder(NXOpen.GeometricAnalysis.SectionAnalysis.SectionAnalysisExObject.Null) interactiveBuilder1 = sectionAnalysisExBuilder1.Interactive interactiveSectionBuilder1 = interactiveBuilder1.InteractiveSection origin1 = NXOpen.Point3d(0.0, 0.0, 0.0) normal1 = NXOpen.Vector3d(0.0, 0.0, 1.0) plane1 = workPart.Planes.CreatePlane(origin1, normal1, NXOpen.SmartObject.UpdateOption.AfterModeling) ##############3 sectionPlaneBuilder1 = sectionAnalysisExBuilder1.ParallelPlanes.SpecifiedPlane sectionPlaneBuilder1.Plane = NXOpen.GeometricAnalysis.SectionAnalysis.SectionPlaneBuilder.PlaneType.View #################### sectionAnalysisExBuilder1.XYZPlane.IsNumberEnabled = True sectionAnalysisExBuilder1.XYZPlane.IsYEnabled = False ################### #need to resize for different size stl files #this determines grid size, needs to be a float sectionAnalysisExBuilder1.XYZPlane.Spacing = .5#cube_width/10#0.05# 0.5 grid_size=sectionAnalysisExBuilder1.XYZPlane.Spacing #need to resize for different size stl files #need to come up with an arbitrary factor sectionAnalysisExBuilder1.XYZPlane.Number =36#int(cube_width/grid_size)#12#12# dependent on size of stl/bounding box #12 #######################################3 sectionAnalysisExBuilder1.Radial.RotationAxis = NXOpen.GeometricAnalysis.SectionAnalysis.RadialBuilder.RotationAxisType.View sectionAnalysisExBuilder1.CombOptions.AnalysisType = NXOpen.GeometricUtilities.CombOptionsBuilder.AnalysisTypes.Curvature sectionAnalysisExBuilder1.Output = NXOpen.GeometricAnalysis.SectionAnalysis.SectionAnalysisExBuilder.OutputType.SectionCurves #self.theLw.WriteLine("References are "+str(sectionAnalysisExBuilder1.References())) self.theLw.WriteLine("") self.theLw.WriteLine("") self.theLw.WriteLine("") sectionAnalysisExBuilder1.NeedleDirection = NXOpen.GeometricAnalysis.SectionAnalysis.SectionAnalysisExBuilder.NeedleDirectionType.Outside facetedBody1 = workPart.FacetedBodies.FindObject(str(journalid)) sectionAnalysisExBuilder1.SelectObject.Add(facetedBody1) sectionAnalysisExBuilder1.Output = NXOpen.GeometricAnalysis.SectionAnalysis.SectionAnalysisExBuilder.OutputType.SectionCurves anchororigin1 = NXOpen.Point3d(0.0, 0.0, 0.0) sectionAnalysisExBuilder1.XYZPlane.AnchorOrigin = anchororigin1

 

2 REPLIES

Re: Python + Machine Learning for NX Open

A short description of what the code does and the necessary inputs would be nice.

Re: Python + Machine Learning for NX Open

Great ! As you said .many python developer want start nx script with python .but the first problem is how to improt nxopen library on IDE which them loved .

Would  you give me the way how did you set it work ?

Thanks !