I'm trying to use GeometricAnalysis.geometric properties to get the minimum radius of a face at a given point.
I was expecting the sign of the radius output by invofminradiusofcurvature to be dependant on the face normal however if I reverse the face normal and check again there is no change in sign.
I've also tried the Local Radius Analysis tool in the UI and this behaves in the same way. The sign of the radius output appears to be random.
As such I can't distinguish between concave or convex faces on a solid.
My aim is to be able to find the location of the minimum radius of a face and know whether it is concave or convex.
Is there a better function to use than I'm trying, or am I misunderstanding the output of the functions I've been using so far?
As always thanks in advance for any help offered.
Interestingly in NX10 Localradiusanalysisbuilder updates the sign of the output radii when you flip face normals.
However... I can't see a way of getting the radii out of the builder. It appears to only display the values on the screen.
The GeometricAnalysis.GeometricProperties.Face tool doesn't change it's sign when the face normal is reversed but can output the values.
Even so my production environment is NX8.5.
In the immortal words of Hannibal Lechter ...
First principles, Clarice. Simplicity. Read Marcus Aurelius. Of each and every particular thing ask: what is it in and of itself? What is its nature?
If you can't find another way, then you can compute curvature from first principles. For code to compute Gaussian curvature, you can look here: http://www.nxjournaling.com/content/u-and-v-radius-face
New info: the function NXOpen.UF.UFModl.AskFaceProps looks promising. I don't know how it handles surface normal flipping and sign chnages, though. If you find out, I'd be very interested to know.
I played around with NXOpen.UF.UFModl.AskFaceProps, and it seems to work the way I would expect. It returns the principal radii at the given point on the surface. These are the reciprocals of the principal curvatures. You can look up principal curvatures in any book on differential geometry, and there are descriptions in the NX docs (look up "Gaussian curvature").
The radius values returned are positive when the surface is concave (viewed from outside) and negative when the surface is convex. Here "outside" means the region of air (as opposed to the region consisting of material).
So, if you're looking for regions where a milling cutter would gouge the surface, look for places where one of the radius values returned is positive and smaller than the cutter radius.
Now that I've figured this out, I'll probably add a function to SNAP, so that it's available and understandable the next time I need it.
Thanks for your help on this. I've been off on another project for the last few days, so only just got back to looking at this today.
The AskFaceProps function looks really useful.
I'm finding that the sign of the face appears to be linked to the normal of the face (although only tested this with 2 faces on a sheet body).
I also like the fact that it will return the point on the face from u,v location, as this is somehting I was having to do with scalars and nxopen points before. This is going to be a big efficiency improvement.
The one issue I am having is with particular surfaces though.
face blend surfaces produced with constant radius are tending to produce the following exception:
"NXOpen.NXException: Modeler error. Initiating error recovery."
using evaluate face fails on the same faces with the following exception:
"NXOpen.NXException: NX error status: 825018"
Would there be a reason why these functions would be tripped up by faces with constant curvature in a single direction?
The sign of the curvature is indeed related to the surface normal.
It's a bit complicated, but here goes:
The face has a "natural" normal, N1, which is just the cross product of the partial derivatives. Then there is an "outward" normal, N2, which points away from material. So N2 = sense*N1, where sense is +1 or -1.
This function returns the outward normal.
So, suppose you locate yourself out in the "air", some distance along the outward normal, and stare at the surface. If the surface looks concave to you, then the curvature(s) will be positive, and if the the surface looks convex, the curvatures will be negative. Of course, the surface could be saddle-shaped (concave in some directions and convex in others), in which case the two curvatures will have opposite signs.
For example, on the cylindrical surface of a 20mm diameter hole, the principal radii are (10, infinity). Similarly, on the cylindrical surface of a 10mm diameter boss, the principal radii are (-5, infinity
Regarding the Exception you mentioned .. I haven't seen that in my testing, and I have tried constant-radius blends.
Here's my test code. It uses SNAP's brand new face.Curvatures method, but you can substitute the NXOpen function, instead:
Option Infer On Imports Snap, Snap.Create, Snap.NX.ObjectTypes Module NXJournal Sub Main() For Each body In Snap.Globals.WorkPart.Bodies For Each face In body.Faces Dim faceType As String = face.ObjectSubType.ToString InfoWindow.WriteLine("Face: " & faceType) Dim nU = 5 Dim nV = 5 Dim box As Snap.Geom.Box2d = face.BoxUV Dim minU = box.MinU : Dim maxU = box.MaxU : Dim stepU = (maxU - minU) / nU Dim minV = box.MinV : Dim maxV = box.MaxV : Dim stepV = (maxV - minV) / nV For u = minU To maxU + 0.001 Step stepU For v = minV To maxV + 0.001 Step stepV Dim k = face.Curvatures(u,v) Dim k0 = k(0).ToString("F4") Dim k1 = k(1).ToString("F4") InfoWindow.WriteLine(k0 & " ; " & k1) Next v Next u Next face Next body End Sub End Module
Try with the file attached.
1 blend was created as a face blend const rad. The others were edge blends o na solid.
All 3 blends fail to output face properties with the exceptions above (on NX8.5).
I've not tested nx10 yet.
The test code I posted works for me (in NX10) with your part file.
The only odd thing I noticed is that you have several b-surfaces that are actually planar.
What's the message from the exception you're getting?
I created the part as a cube. Then extracted the faces (bsurf) to create the freeform regions and then applied a sew after. Hence b surf geometry in there.
I've not had a chance to test your code however here is my test code and this consistently fails on the test part I sent you in both NX8.5 & NX10
Option Strict Off Imports System Imports NXOpen Imports NXOpen.UF Module Module1 Dim theSession As Session = Session.GetSession() Dim theUfSession As UFSession = UFSession.GetUFSession() Public workpart As Part = theSession.Parts.Work ' Explicit Activation ' This entry point is used to activate the application explicitly Sub Main() Dim my_layers As Layer.LayerManager = workpart.Layers theSession.ListingWindow.Open() For Each obj As DisplayableObject In theSession.Parts.Work.Bodies If my_layers.GetState(obj.Layer) < 2 Then If obj.IsBlanked = False Then ' only check visible objects If obj.GetType.ToString = "NXOpen.Body" Then ' only check object types of body Dim my_body As Body = CType(obj, Body) Dim my_faces() As Face = my_body.GetFaces() 'get all faces of the body Dim i As Integer = 0 For i = 0 To my_faces.Length - 1 Dim count As Integer = 1 Dim params(1) As Double params(0) = 0.5 params(1) = 0.5 get_face_rad_AFP(my_faces(i), params) get_face_rad_EF(my_faces(i), params) get_face_rad(my_faces(i), params(0), params(1)) Next End If End If End If Next ' TODO: Add your application code here End Sub Public Function get_face_rad_AFP(ByVal my_face As Face, ByVal uv() As Double) As Double Dim my_point(2) As Double Dim my_u1(2) As Double Dim my_u2(2) As Double Dim my_v1(2) As Double Dim my_v2(2) As Double Dim my_norm(2) As Double Dim my_radii(1) As Double Try theUfSession.Modl.AskFaceProps(my_face.Tag, uv, my_point, my_u1, my_v1, my_u2, my_v2, my_norm, my_radii) Catch ex As Exception theSession.ListingWindow.WriteLine("AskFaceProps") theSession.ListingWindow.WriteLine(ex.Message) End Try End Function Public Function get_face_rad_EF(ByVal my_face As Face, ByVal uv() As Double) As Double Dim surfaceValues As NXOpen.UF.ModlSrfValue = New NXOpen.UF.ModlSrfValue() Dim mode As Integer = NXOpen.UF.UFConstants.UF_MODL_EVAL_ALL Try theUfSession.Modl.EvaluateFace(my_face.Tag, mode, uv, surfaceValues) Catch ex As Exception theSession.ListingWindow.WriteLine("EvaluateFace") theSession.ListingWindow.WriteLine(ex.Message) End Try End Function Private Function get_face_rad(ByVal my_face As Face, ByVal uval As Double, ByVal vval As Double) As Double Dim scalar1 As Scalar scalar1 = workpart.Scalars.CreateScalar(uval, Scalar.DimensionalityType.None, SmartObject.UpdateOption.WithinModeling) Dim scalar2 As Scalar scalar2 = workpart.Scalars.CreateScalar(vval, Scalar.DimensionalityType.None, SmartObject.UpdateOption.WithinModeling) Dim point1 As Point point1 = workpart.Points.CreatePoint(my_face, scalar1, scalar2, SmartObject.UpdateOption.WithinModeling) Dim point13d As New Point3d(point1.Coordinates.X, point1.Coordinates.Y, point1.Coordinates.Z) Dim geometricProperties1 As GeometricAnalysis.GeometricProperties Dim out_face As GeometricAnalysis.GeometricProperties.Face geometricProperties1 = workpart.AnalysisManager.CreateGeometricPropertiesObject() geometricProperties1.OutputMethod = GeometricAnalysis.GeometricProperties.OutputType.Static Dim status1 As GeometricAnalysis.GeometricProperties.Status Try status1 = geometricProperties1.GetFaceProperties(my_face, point13d, out_face) Catch ex As Exception theSession.ListingWindow.WriteLine("Old Function") theSession.ListingWindow.WriteLine(ex.Message) End Try get_face_rad = 1 / out_face.InvOfMinRadiusOfCurvature End Function Public Function GetUnloadOption(ByVal dummy As String) As Integer 'Unloads the image immediately after execution within NX GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately '----Other unload options------- 'Unloads the image when the NX session terminates 'GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination 'Unloads the image explicitly, via an unload dialog 'GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Explicitly '------------------------------- End Function End Module
the 3rd function is my old 'clunky but reliable' one.