Wrong Position/Coordinates Of Selected Point On Face

Dear Community,

I am writing an api for NX 12.0.2.9 in C#.

In this api the user should select a point on a face by clicking on
it. The algorithm should get back both the coordinates of the point and the tag of the face.

I did the implementation based on a journal I found in this forum.

The problem is that it works fine for one part. But it does not for
another part in another prt-file. In the latter part the point the user has selected is always a bit shifted. And I cannot figure out why.

What am I doing wrong? Can you help me, please?

Thank you in advance.

This is the code I use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NXOpen;
using NXOpen.UF;

namespace TestLeer
{
public class TestAskPosOnObj_NXForum : TestCase
{
private string msg = string.Empty;

public override void Execute()
{
var title = "Select point on face";
var resp = Selection.Response.Cancel;
double[] cp = new double[Const.MaxNumElemsOfPoint];

var faceTag = SelectPointOnFace(title, cp);

msg = "Face(" + faceTag.ToString() + ")"
+ Environment.NewLine
+ "=> Point("
+ cp[0].ToString() + ", "
+ cp[1].ToString() + ", "
+ cp[1].ToString() + ")"
+ Environment.NewLine;

Printing.Print(msg, !Const.useNXMsgBox);
}

private Tag SelectPointOnFace(string title, double[] cp)
{
Tag faceTag = Tag.Null;
int resp = 0;
var theView = Tag.Null;
UFUi.SelInitFnT ip = FaceInitProc;

Kernel.Get.NxSessionVars.TheUfSession.Ui.LockUgAccess
(UFConstants.UF_UI_FROM_CUSTOM);

Kernel.Get.NxSessionVars.TheUfSession.Ui.SelectWithSingleDialog
("Select a face",
title,
UFConstants.UF_UI_SEL_SCOPE_ANY_IN_ASSEMBLY,
ip,
IntPtr.Zero,
out resp,
out faceTag,
cp,
out theView);

Kernel.Get.NxSessionVars.TheUfSession.Ui.UnlockUgAccess
(UFConstants.UF_UI_FROM_CUSTOM);

if (resp == UFConstants.UF_UI_OBJECT_SELECTED
|| resp == UFConstants.UF_UI_OBJECT_SELECTED_BY_NAME)
{
AskPosOnObj(faceTag, cp);

Kernel.Get.NxSessionVars.TheUfSession.Disp.SetHighlight(faceTag, Const.HighlightObj);
DisplayObjects.DisplayTemporaryAsterisk(cp, Colors.Orange);
}

return faceTag;
}

private int FaceInitProc(IntPtr select, IntPtr userData)
{
const int numTriples = 1;
UFUi.Mask[] maskTriples = new UFUi.Mask[numTriples];
maskTriples[0].object_type = UFConstants.UF_solid_type;
maskTriples[0].object_subtype = UFConstants.UF_solid_face_subtype;
maskTriples[0].solid_type = UFConstants.UF_UI_SEL_FEATURE_ANY_FACE;

Kernel.Get.NxSessionVars.TheUfSession.Ui.SetSelMask
(select,
UFUi.SelMaskAction.SelMaskClearAndEnableSpecific,
numTriples,
maskTriples);

return UFConstants.UF_UI_SEL_SUCCESS;
}

private double[] MapView2Abs(double[] c)
{
var vname = string.Empty;
double[] absMx = new double[] { 0, 0, 0, 1, 0, 0, 0, 1, 0 };
double[] vw = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] mx = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var irc = 0;

Kernel.Get.NxSessionVars.TheUfSession.Ui.AskLastPickedView(out vname);
var wp = Kernel.Get.NxSessionVars.TheSession.Parts.Work;
View lastViewPicked = wp.ModelingViews.FindObject(vname) as ModelingView;

Matrix3x3 vmx = lastViewPicked.Matrix;
vw[3] = vmx.Xx;
vw[4] = vmx.Xy;
vw[5] = vmx.Xz;
vw[6] = vmx.Yx;
vw[7] = vmx.Yy;
vw[8] = vmx.Yz;
vw[9] = vmx.Zx;
vw[10] = vmx.Zy;
vw[11] = vmx.Zz;
Kernel.Get.NxSessionVars.TheUfSession.Trns.CreateCsysMappingMatrix(vw, absMx, mx, out irc);
Kernel.Get.NxSessionVars.TheUfSession.Trns.MapPosition(c, mx);

return c;
}

private double[] MapAbs2View(double[] c)
{
var vname = string.Empty;
double[] absMx = new double[] { 0, 0, 0, 1, 0, 0, 0, 1, 0 };
double[] vw = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] mx = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var irc = 0;

Kernel.Get.NxSessionVars.TheUfSession.Ui.AskLastPickedView(out vname);
var wp = Kernel.Get.NxSessionVars.TheSession.Parts.Work;
View lastViewPicked = wp.ModelingViews.FindObject(vname) as ModelingView;

Matrix3x3 vmx = lastViewPicked.Matrix;
vw[3] = vmx.Xx;
vw[4] = vmx.Xy;
vw[5] = vmx.Xz;
vw[6] = vmx.Yx;
vw[7] = vmx.Yy;
vw[8] = vmx.Yz;
vw[9] = vmx.Zx;
vw[10] = vmx.Zy;
vw[11] = vmx.Zz;

Kernel.Get.NxSessionVars.TheUfSession.Trns.CreateCsysMappingMatrix(absMx, vw, mx, out irc);
Kernel.Get.NxSessionVars.TheUfSession.Trns.MapPosition(c, mx);

return c;
}

private void AskPosOnObj(Tag obj, double[] loc)
{
Tag aLine = Tag.Null;
double[] cp = new double[] { 0, 0, 0 };
double dist = 0;
UFCurve.Line lp;
double[] sp = new double[Const.MaxNumElemsOfPoint];
double[] ep = new double[Const.MaxNumElemsOfPoint];

lp.start_point = sp;
lp.end_point = ep;

MapAbs2View(loc);

lp.start_point[0] = loc[0];
lp.start_point[1] = loc[1];
lp.start_point[2] = loc[2] + 10000;

lp.end_point[0] = loc[0];
lp.end_point[1] = loc[1];
lp.end_point[2] = loc[2] - 10000;

MapView2Abs(lp.start_point);
MapView2Abs(lp.end_point);

Kernel.Get.NxSessionVars.TheUfSession.Curve.CreateLine
(ref lp,
out aLine);
Kernel.Get.NxSessionVars.TheUfSession.Modl.AskMinimumDist
(obj,
aLine,
0,
cp,
0,
cp,
out dist,
loc,
cp);

Kernel.Get.NxSessionVars.TheUfSession.Obj.DeleteObject(aLine);
}
}
}

What changes do I need to make to run this as a jounal?
I get the error: "The type or namespace name 'TestCase' could not be found"

Hi,

the code above is no Journal, but an excerpt of my NX Api application.
It shows the class which should provide the point on a face the
user has selected.

I have changed the code now, so that you can execute it as a Journal
in NX. I apend it at the end of my post.

Ellie

using System;
using System.Collections.Generic;
using System.Windows.Forms;

using NXOpen;
using NXOpen.UF;

public class Program
{
// class members
private static Session theSession;
private static UI theUI;
private static UFSession theUfSession;
public static Program theProgram;
public static bool isDisposeCalled;
public static Part workPart;

public static ListingWindow lw;

public static int HighlightObj { get { return 1; } }
public static int UnhighlightObj { get { return 0; } }

private string msg = string.Empty;
private const int MaxNumElemsOfPoint = 3;
private List objListToUnhighlight = new List();

///
/// Default NX color palette as found in defauld CDF-file
/// Can be called in NX by: Datei -> Voreinstellungen -> Farbpalette
///
public enum Colors
{
///
/// ID = -1
///
None = -1,

///
/// ID = 78
///
Orange = 78,

///
/// ID = 103
///
Cornflower = 103,

///
/// ID = 181
///
Magenta = 181,

///
/// ID = 186
///
Red = 186,
}

//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
public Program()
{
try
{
theSession = Session.GetSession();
theUI = UI.GetUI();
theUfSession = UFSession.GetUFSession();

lw = theSession.ListingWindow;
workPart = theSession.Parts.Work;

isDisposeCalled = false;
}
catch (NXOpen.NXException ex)
{
// ---- Enter your exception handling code here -----
// UI.GetUI().NXMessageBox.Show("Message", NXMessageBox.DialogType.Error, ex.Message);
}
}

//------------------------------------------------------------------------------
// Explicit Activation
// This entry point is used to activate the application explicitly
//------------------------------------------------------------------------------
public static int Main(string[] args)
{
int retValue = 0;
try
{
theProgram = new Program();

//TODO: Add your application code here
Session.UndoMarkId markId1;
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "NXJ");

lw.Open();

theProgram.Execute();
theProgram.CleanUp();

lw.Close();

// ################################################################

theProgram.Dispose();
}
catch (NXOpen.NXException ex)
{
// ---- Enter your exception handling code here -----

}
return retValue;
}

//------------------------------------------------------------------------------
// Following method disposes all the class members
//------------------------------------------------------------------------------
public void Dispose()
{
try
{
if (isDisposeCalled == false)
{
//TODO: Add your application code here
}
isDisposeCalled = true;
}
catch (NXOpen.NXException ex)
{
// ---- Enter your exception handling code here -----

}
}

public static int GetUnloadOption(string arg)
{
//Unloads the image explicitly, via an unload dialog
//return System.Convert.ToInt32(Session.LibraryUnloadOption.Explicitly);

//Unloads the image immediately after execution within NX
return System.Convert.ToInt32(Session.LibraryUnloadOption.Immediately);

//Unloads the image when the NX session terminates
// return System.Convert.ToInt32(Session.LibraryUnloadOption.AtTermination);
}

///
/// Executes my code for selecting a point and getting its position.
///
public void Execute()
{
var title = "Select point on face";
var resp = Selection.Response.Cancel;
double[] cp = new double[MaxNumElemsOfPoint];

var faceTag = SelectPointOnFace(title, cp);

msg = "Face(" + faceTag.ToString() + ")"
+ Environment.NewLine
+ "=> Point("
+ cp[0].ToString() + ", "
+ cp[1].ToString() + ", "
+ cp[2].ToString() + ")"
+ Environment.NewLine;

lw.WriteLine(msg);

AddObjectToUnhighlightList(faceTag);
}

///
/// Unhighlights objects and deletes temporary objects.
///
public void CleanUp()
{
DialogResult dlgResult = DialogResult.None;

var msg = "Delete temporary objects and unhighlight faces?";
var titleMsgBoxQuestion = "Question";
dlgResult = MessageBox.Show(msg, titleMsgBoxQuestion, MessageBoxButtons.YesNo, MessageBoxIcon.Question);

if (dlgResult == DialogResult.Yes)
{
var objList =GetObjListToUnhighlight();

theUfSession.Disp.SetHighlights(objList.Count, objList.ToArray(), UnhighlightObj);

workPart.Views.Refresh();
}
}

///
/// Select point on face.
///
/// Title of the selecting dialog.
/// Cursor position.
/// Tag of the selected face.
private Tag SelectPointOnFace(string title, double[] cp)
{
Tag faceTag = Tag.Null;
int resp = 0;
var theView = Tag.Null;
UFUi.SelInitFnT ip = FaceInitProc;

theUfSession.Ui.LockUgAccess
(UFConstants.UF_UI_FROM_CUSTOM);

theUfSession.Ui.SelectWithSingleDialog
("Select a face",
title,
UFConstants.UF_UI_SEL_SCOPE_ANY_IN_ASSEMBLY,
ip,
IntPtr.Zero,
out resp,
out faceTag,
cp,
out theView);

theUfSession.Ui.UnlockUgAccess(UFConstants.UF_UI_FROM_CUSTOM);

if (resp == UFConstants.UF_UI_OBJECT_SELECTED
|| resp == UFConstants.UF_UI_OBJECT_SELECTED_BY_NAME)
{
AskPosOnObj(faceTag, cp);

DisplayTemporaryAsterisk(cp, Colors.Orange);
}

return faceTag;
}

private int FaceInitProc(IntPtr select, IntPtr userData)
{
const int numTriples = 1;
UFUi.Mask[] maskTriples = new UFUi.Mask[numTriples];
maskTriples[0].object_type = UFConstants.UF_solid_type;
maskTriples[0].object_subtype = UFConstants.UF_solid_face_subtype;
maskTriples[0].solid_type = UFConstants.UF_UI_SEL_FEATURE_ANY_FACE;

theUfSession.Ui.SetSelMask
(select,
UFUi.SelMaskAction.SelMaskClearAndEnableSpecific,
numTriples,
maskTriples);

return UFConstants.UF_UI_SEL_SUCCESS;
}

///
/// Maps point in coordinates of the view to absolute coordinates.
///
/// Point to be mapped in coordinates of the view.
/// Point in absolute coordinates
private double[] MapView2Abs(double[] c)
{
var vname = string.Empty;
double[] absMx = new double[] { 0, 0, 0, 1, 0, 0, 0, 1, 0 };
double[] vw = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] mx = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var irc = 0;

theUfSession.Ui.AskLastPickedView(out vname);
var wp = theSession.Parts.Work;
NXOpen.View lastViewPicked = wp.ModelingViews.FindObject(vname) as ModelingView;

Matrix3x3 vmx = lastViewPicked.Matrix;
vw[3] = vmx.Xx;
vw[4] = vmx.Xy;
vw[5] = vmx.Xz;
vw[6] = vmx.Yx;
vw[7] = vmx.Yy;
vw[8] = vmx.Yz;
vw[9] = vmx.Zx;
vw[10] = vmx.Zy;
vw[11] = vmx.Zz;
theUfSession.Trns.CreateCsysMappingMatrix(vw, absMx, mx, out irc);
theUfSession.Trns.MapPosition(c, mx);

return c;
}

///
/// Maps point from absolute coordinates to view coordinates.
///
/// Point to be mapped in absolute coordinates.
/// Point in coordinates of the view.
private double[] MapAbs2View(double[] c)
{
var vname = string.Empty;
double[] absMx = new double[] { 0, 0, 0, 1, 0, 0, 0, 1, 0 };
double[] vw = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] mx = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var irc = 0;

theUfSession.Ui.AskLastPickedView(out vname);
var wp = theSession.Parts.Work;
NXOpen.View lastViewPicked = wp.ModelingViews.FindObject(vname) as ModelingView;

Matrix3x3 vmx = lastViewPicked.Matrix;
vw[3] = vmx.Xx;
vw[4] = vmx.Xy;
vw[5] = vmx.Xz;
vw[6] = vmx.Yx;
vw[7] = vmx.Yy;
vw[8] = vmx.Yz;
vw[9] = vmx.Zx;
vw[10] = vmx.Zy;
vw[11] = vmx.Zz;

theUfSession.Trns.CreateCsysMappingMatrix(absMx, vw, mx, out irc);
theUfSession.Trns.MapPosition(c, mx);

return c;
}

///
/// Calculates the position of a point on an object provided by its cursor position.
///
/// Tag of the object (here: the selected face) the point should lie on.
/// (Cursor) position of the point.
private void AskPosOnObj(Tag obj, double[] loc)
{
Tag aLine = Tag.Null;
double[] cp = new double[] { 0, 0, 0 };
double dist = 0;
UFCurve.Line lp;
double[] sp = new double[MaxNumElemsOfPoint];
double[] ep = new double[MaxNumElemsOfPoint];

lp.start_point = sp;
lp.end_point = ep;

MapAbs2View(loc);

lp.start_point[0] = loc[0];
lp.start_point[1] = loc[1];
lp.start_point[2] = loc[2] + 10000;

lp.end_point[0] = loc[0];
lp.end_point[1] = loc[1];
lp.end_point[2] = loc[2] - 10000;

MapView2Abs(lp.start_point);
MapView2Abs(lp.end_point);

theUfSession.Curve.CreateLine(ref lp, out aLine);
theUfSession.Modl.AskMinimumDist(obj,
aLine,
0,
cp,
0,
cp,
out dist,
loc,
cp);

theUfSession.Obj.DeleteObject(aLine);
}

///
/// Displays an asterix at the given position.
///
/// coordinates to be displayed
/// color of the point to be displayed
private void DisplayTemporaryAsterisk(double[] coords, Colors color = Colors.Cornflower)
{
// UFDisp.ViewType:
// -----------------
// UF_DISP_USE_VIEW_TAG = 0
// Display in view specified by its tag
//
//UF_DISP_USE_ACTIVE_PLUS = 1
//Use the active view plus drawing views
//
//UF_DISP_USE_CURSOR = 2
//Use the position of the last cursor
//
//UF_DISP_USE_ACTIVE_MINUS = 3
//Use only active views no drawing views
//
//UF_DISP_USE_WORK_VIEW = 4
//Use the work view

UFObj.DispProps attrib = new UFObj.DispProps();
attrib.blank_status = UFConstants.UF_OBJ_BLANKED;
attrib.color = (int)color;
attrib.line_width = UFConstants.UF_OBJ_WIDTH_NORMAL;
theUfSession.Disp.DisplayTemporaryPoint(Tag.Null,
UFDisp.ViewType.UseActivePlus,
coords,
ref attrib,
UFDisp.PolyMarker.Asterisk);
}

///
/// Adds objects to list being unhighlighted at the end of the program.
///
/// Tag of the object to be added.
private void AddObjectToUnhighlightList(Tag objTag)
{
objListToUnhighlight.Add(objTag);
}

///
/// Returns the objects which should be unhighlighted.
///
/// List of tags of objects to be unhighlighted.
private List GetObjListToUnhighlight()
{
return objListToUnhighlight;
}
}

Thanks, I can run the code now.
I created a test part with a block and a cylinder. The code worked perfectly on the block faces, but consistently reported the "far" side of the intersection with the cylindrical face no matter how the view was oriented. I suspected that the AskMinimumDist function was returning the point based on the start/end point of the "aLine" object.

I changed the definition of lp.start_point and lp.end_point to:

lp.start_point[2] = loc[2] - 10000;
lp.end_point[2] = loc[2] + 10000;

This change resulted in the "near" side of the cylinder being reported.

Another possibility would be to use the TraceARay method instead of the AskMinimumDist method; this would (in the case of a cylindrical face) return both intersection points. You would need to determine which intersection you needed in this case.

Hi,

thank you for testing my code.

Until now I have not experienced the case, that the reported point is
on the "far" side of the feature. I just have not tested my code
with part files containing cylinders or objects like that yet.

Unfortunately I get the wrong position already by using a simple block.
But if I use another simple block in another ptr-file the position
of the selected point is correct.

Is it possible that the different coordinate systems (absolute
and working csys, csys of the view) are the reason for this
behavior? Maybe I have missed a mapping between the coordinate
systems?

I would like to add a picture of the situation (or even the part
files themself) in order to describe the problem more clearly.
But I have not figured out yet how I can add those files in my
comment.

Alternatively I will try your suggestion and will test the
TrayARay() method. I will report the results of my testings.

If you use a cloud service such as dropbox, you could post links here to the files. Alternatively, you can email them to info@nxjournaling.com.

I've not seen any issue with planar faces when running your code. It would be helpful if you could send a file or describe in more detail the steps you are taking before you get the erroneous results.

Hi,

I implemented the TrayARay() method instead of AskMinimumDist()
in a new project (see code below).

According to the documentation for TrayARay() the list containing
the returned information is in the order of its distance from the
origin of the ray, the closest first.

That is exactly what I am looking for.

But unfortunately the behavior is the same as with the
AskMinimumDist() method.

I will prepare something for downloading from a cloud service
which demonstrates the the problem and will hopefully allow you
to reproduce the situation I encounter.

By the way as stated in the documentation the caller must free the
array containing the hit list. I have found


UF_free(hit_list)

in the example of the documentation. But how do I implement it
in C#? Or does C# take care of freeing the array?

And here is the TraceARay()-Code:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Globalization;

using NXOpen;
using NXOpen.UF;
using NXOpen.Utilities;

public class Program
{
// class members
private static Session theSession;
private static UI theUI;
private static UFSession theUfSession;
public static Program theProgram;
public static bool isDisposeCalled;

public static Part workPart;
public static ListingWindow lw;

public static int HighlightObj { get { return 1; } }
public static int UnhighlightObj { get { return 0; } }
public static int MaxNumElemsOfTransMtx { get { return 16; } }

public List ObjListToUnhighlight { get { return objListToUnhighlight; } set { objListToUnhighlight = value; } }

private string msg = string.Empty;
private string caption = string.Empty;
private const int MaxNumElemsOfPoint = 3;
private List objListToUnhighlight = new List();
private string fmt = string.Empty;
private NumberFormatInfo nfi;

///
/// Default NX color palette as found in defauld CDF-file
/// Can be called in NX by: Datei -> Voreinstellungen -> Farbpalette
///
public enum Colors
{
///
/// ID = -1
///
None = -1,

///
/// ID = 78
///
Orange = 78,

///
/// ID = 103
///
Cornflower = 103,

///
/// ID = 181
///
Magenta = 181,

///
/// ID = 186
///
Red = 186,
}

public enum RetValPointSubfunc
{
Back = 1,
Cancel = 2,
PositionReturned = 5,
NoActivePart = 7,
DisallowedState = 8 // unable to bring up dialog
}

//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
public Program()
{
try
{
theSession = Session.GetSession();
theUI = UI.GetUI();
theUfSession = UFSession.GetUFSession();
isDisposeCalled = false;

lw = theSession.ListingWindow;
workPart = theSession.Parts.Work;
nfi = new CultureInfo("en-US", false).NumberFormat;
}
catch (NXOpen.NXException ex)
{
// ---- Enter your exception handling code here -----
// UI.GetUI().NXMessageBox.Show("Message", NXMessageBox.DialogType.Error, ex.Message);
}
}

//------------------------------------------------------------------------------
// Explicit Activation
// This entry point is used to activate the application explicitly
//------------------------------------------------------------------------------
public static int Main(string[] args)
{
int retValue = 0;
try
{
theProgram = new Program();

//TODO: Add your application code here
Session.UndoMarkId markId1;
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "NXJ");

lw.Open();

theProgram.Execute();
theProgram.CleanUp();

lw.Close();

theProgram.Dispose();
}
catch (NXOpen.NXException ex)
{
// ---- Enter your exception handling code here -----

}
return retValue;
}

//------------------------------------------------------------------------------
// Following method disposes all the class members
//------------------------------------------------------------------------------
public void Dispose()
{
try
{
if (isDisposeCalled == false)
{
//TODO: Add your application code here
}
isDisposeCalled = true;
}
catch (NXOpen.NXException ex)
{
// ---- Enter your exception handling code here -----

}
}

public static int GetUnloadOption(string arg)
{
//Unloads the image explicitly, via an unload dialog
//return System.Convert.ToInt32(Session.LibraryUnloadOption.Explicitly);

//Unloads the image immediately after execution within NX
return System.Convert.ToInt32(Session.LibraryUnloadOption.Immediately);

//Unloads the image when the NX session terminates
// return System.Convert.ToInt32(Session.LibraryUnloadOption.AtTermination);
}

public void Execute()
{
var msg = "TestTraceARay()" + Environment.NewLine + "##################";

lw.WriteLine(msg);

DialogResult dlgResult = DialogResult.None;
var i = 1;

while (dlgResult != DialogResult.No)
{
if (ObjListToUnhighlight.Count > 0)
DeleteTempObjects();

msg = Environment.NewLine + Environment.NewLine
+ "### Run-No.: " + i.ToString()
+ Environment.NewLine + Environment.NewLine;
lw.WriteLine(msg);

var pointSelected = new double[MaxNumElemsOfPoint];

//pointSelected = PickPoint();

var title = "Select point on face";
var resp = UFConstants.UF_UI_CANCEL;

var faceTag = SelectPointOnFace(title, pointSelected, out resp);

if ( resp != UFConstants.UF_UI_OBJECT_SELECTED
&& resp != UFConstants.UF_UI_OBJECT_SELECTED_BY_NAME)
{
msg = "Invalid selection!";
caption = "Error";
dlgResult = MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

msg = ">>>>> SelectPointOnFace() returns: " + Environment.NewLine + Environment.NewLine
+ "Selected face: F(" + faceTag.ToString() + ")" + Environment.NewLine
+ "Cursor position: P = ("
+ pointSelected[0].ToString("F3", nfi) + ", "
+ pointSelected[1].ToString("F3", nfi) + ", "
+ pointSelected[2].ToString("F3", nfi) + ")"
+ Environment.NewLine + Environment.NewLine;
lw.WriteLine(msg);

//DisplayTemporaryAsterisk(pointSelected, Colors.Orange);

AskPosOnObj(faceTag, pointSelected);

i++;

msg = "Once again?";
caption = "Question";
dlgResult = MessageBox.Show(msg, caption, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}
}

///
/// Unhighlights objects and deletes temporary objects.
///
public void CleanUp()
{
DialogResult dlgResult = DialogResult.None;

var msg = "Delete temporary objects and unhighlight faces?";
var titleMsgBoxQuestion = "Question";
dlgResult = MessageBox.Show(msg, titleMsgBoxQuestion, MessageBoxButtons.YesNo, MessageBoxIcon.Question);

if (dlgResult == DialogResult.Yes)
DeleteTempObjects();
}

private void DeleteTempObjects()
{
theUfSession.Disp.SetHighlights(ObjListToUnhighlight.Count, ObjListToUnhighlight.ToArray(), UnhighlightObj);

ObjListToUnhighlight.Clear();

workPart.Views.Refresh();
}

///
/// Select point on face.
///
/// Title of the selecting dialog.
/// Cursor position.
/// Tag of the selected face.
private Tag SelectPointOnFace(string title, double[] cp, out int resp)
{
Tag faceTag = Tag.Null;
//int resp = 0;
var theView = Tag.Null;
UFUi.SelInitFnT ip = FaceInitProc;

theUfSession.Ui.LockUgAccess
(UFConstants.UF_UI_FROM_CUSTOM);

theUfSession.Ui.SelectWithSingleDialog
("Select a face",
title,
UFConstants.UF_UI_SEL_SCOPE_ANY_IN_ASSEMBLY,
ip,
IntPtr.Zero,
out resp,
out faceTag,
cp,
out theView);

theUfSession.Ui.UnlockUgAccess(UFConstants.UF_UI_FROM_CUSTOM);

if(faceTag != Tag.Null)
AddObjectToUnhighlightList(faceTag);

return faceTag;
}

private int FaceInitProc(IntPtr select, IntPtr userData)
{
const int numTriples = 1;
UFUi.Mask[] maskTriples = new UFUi.Mask[numTriples];
maskTriples[0].object_type = UFConstants.UF_solid_type;
maskTriples[0].object_subtype = UFConstants.UF_solid_face_subtype;
maskTriples[0].solid_type = UFConstants.UF_UI_SEL_FEATURE_ANY_FACE;

theUfSession.Ui.SetSelMask
(select,
UFUi.SelMaskAction.SelMaskClearAndEnableSpecific,
numTriples,
maskTriples);

return UFConstants.UF_UI_SEL_SUCCESS;
}

///
/// Calculates the position of a point on an object provided by its cursor position.
///
/// Tag of the object (here: the selected face) the point should lie on.
/// (Cursor) position of the point.
private void AskPosOnObj(Tag obj, double[] loc)
{
double[] cp = new double[] { 0, 0, 0 };
UFCurve.Line lp;
double[] sp = new double[MaxNumElemsOfPoint];
double[] ep = new double[MaxNumElemsOfPoint];

lp.start_point = sp;
lp.end_point = ep;

MapAbs2View(loc);

lp.start_point[0] = loc[0];
lp.start_point[1] = loc[1];
lp.start_point[2] = loc[2] + 10000;

lp.end_point[0] = loc[0];
lp.end_point[1] = loc[1];
lp.end_point[2] = loc[2] - 10000;

MapView2Abs(lp.start_point);
MapView2Abs(lp.end_point);

var givenPoint = new double[MaxNumElemsOfPoint];
givenPoint[0] = lp.start_point[0];
givenPoint[1] = lp.start_point[1];
givenPoint[2] = lp.start_point[2];

var rayDir = new double[MaxNumElemsOfPoint];
rayDir[0] = lp.end_point[0] - lp.start_point[0];
rayDir[1] = lp.end_point[1] - lp.start_point[1];
rayDir[2] = lp.end_point[2] - lp.start_point[2];

var facePointPairs = new List>();

var numHitResults = TraceARay(givenPoint, rayDir, facePointPairs);

msg = ">>>>> TraceARay() returns: " + Environment.NewLine + Environment.NewLine
+ "NumHitResults = " + numHitResults.ToString() + Environment.NewLine
//+ "givenPoint = (" + givenPoint[0] + ", " + givenPoint[1] + ", " + givenPoint[2] + ")" + Environment.NewLine
//+ "rayDir = lp.end_point - lp.start_point = (" + rayDir[0] + ", " + rayDir[1] + ", " + rayDir[2] + ")"
+ Environment.NewLine;

int i = 1;
foreach (var item in facePointPairs)
{
msg += i.ToString() + ": [face, point] = [F("
+ item.Item1.Tag
+ "), P("
+ item.Item2[0].ToString("F3", nfi) + ", "
+ item.Item2[1].ToString("F3", nfi) + ", "
+ item.Item2[2].ToString("F3", nfi) + ")]"
+ Environment.NewLine;

i++;
}

lw.WriteLine(msg);
}

///
/// Maps point in coordinates of the view to absolute coordinates.
///
/// Point to be mapped in coordinates of the view.
/// Point in absolute coordinates
private double[] MapView2Abs(double[] c)
{
var vname = string.Empty;
double[] absMx = new double[] { 0, 0, 0, 1, 0, 0, 0, 1, 0 };
double[] vw = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] mx = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var irc = 0;

theUfSession.Ui.AskLastPickedView(out vname);
var wp = theSession.Parts.Work;
NXOpen.View lastViewPicked = wp.ModelingViews.FindObject(vname) as ModelingView;

Matrix3x3 vmx = lastViewPicked.Matrix;
vw[3] = vmx.Xx;
vw[4] = vmx.Xy;
vw[5] = vmx.Xz;
vw[6] = vmx.Yx;
vw[7] = vmx.Yy;
vw[8] = vmx.Yz;
vw[9] = vmx.Zx;
vw[10] = vmx.Zy;
vw[11] = vmx.Zz;
theUfSession.Trns.CreateCsysMappingMatrix(vw, absMx, mx, out irc);
theUfSession.Trns.MapPosition(c, mx);

return c;
}

///
/// Maps point from absolute coordinates to view coordinates.
///
/// Point to be mapped in absolute coordinates.
/// Point in coordinates of the view.
private double[] MapAbs2View(double[] c)
{
var vname = string.Empty;
double[] absMx = new double[] { 0, 0, 0, 1, 0, 0, 0, 1, 0 };
double[] vw = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] mx = new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var irc = 0;

theUfSession.Ui.AskLastPickedView(out vname);
var wp = theSession.Parts.Work;
NXOpen.View lastViewPicked = wp.ModelingViews.FindObject(vname) as ModelingView;

Matrix3x3 vmx = lastViewPicked.Matrix;
vw[3] = vmx.Xx;
vw[4] = vmx.Xy;
vw[5] = vmx.Xz;
vw[6] = vmx.Yx;
vw[7] = vmx.Yy;
vw[8] = vmx.Yz;
vw[9] = vmx.Zx;
vw[10] = vmx.Zy;
vw[11] = vmx.Zz;

theUfSession.Trns.CreateCsysMappingMatrix(absMx, vw, mx, out irc);
theUfSession.Trns.MapPosition(c, mx);

return c;
}

private int TraceARay(double[] givenPoint, double[] rayDir, List> facePointPairs)
{
var bodyList = workPart.Bodies.ToArray(); // Get the list of bodies
int numBodies = bodyList.Length;
Tag[] bodies = new Tag[numBodies];
double[] origin = new double[MaxNumElemsOfPoint];
double[] transform = new double[MaxNumElemsOfTransMtx];
int numDesired = 6;
int numResult;
UFModl.RayHitPointInfo[] hitList;

var i = 0;
foreach (var body in bodyList)
{
bodies[i] = body.Tag;
i++;
}

theUfSession.Mtx4.Identity(transform);

// UF_CALL(UF_MODL_trace_a_ray(3, bodies, point, raydir, transform, 6, &hits_found, &hit_list));
theUfSession.Modl.TraceARay(numBodies, bodies, givenPoint, rayDir, transform, numDesired, out numResult, out hitList);

if (numResult > 0)
{
foreach (var hit in hitList)
{
Face face = (Face)NXObjectManager.Get(hit.hit_face);

var t = new Tuple(face, hit.hit_point);
facePointPairs.Add(t);

if (face != null)
{
theUfSession.Disp.SetHighlight(face.Tag, HighlightObj);
AddObjectToUnhighlightList(face.Tag);

DisplayTemporaryAsterisk(hit.hit_point, Colors.Cornflower);
}
}
}

return numResult;
}

///
/// Adds objects to list being unhighlighted at the end of the program.
///
/// Tag of the object to be added.
private void AddObjectToUnhighlightList(Tag objTag)
{
if(!objListToUnhighlight.Contains(objTag))
objListToUnhighlight.Add(objTag);
}

///
/// Displays an asterix at the given position.
///
/// coordinates to be displayed
/// color of the point to be displayed
private void DisplayTemporaryAsterisk(double[] coords, Colors color = Colors.Cornflower)
{
// UFDisp.ViewType:
// -----------------
// UF_DISP_USE_VIEW_TAG = 0
// Display in view specified by its tag
//
//UF_DISP_USE_ACTIVE_PLUS = 1
//Use the active view plus drawing views
//
//UF_DISP_USE_CURSOR = 2
//Use the position of the last cursor
//
//UF_DISP_USE_ACTIVE_MINUS = 3
//Use only active views no drawing views
//
//UF_DISP_USE_WORK_VIEW = 4
//Use the work view

UFObj.DispProps attrib = new UFObj.DispProps();
attrib.blank_status = UFConstants.UF_OBJ_BLANKED;
attrib.color = (int)color;
attrib.line_width = UFConstants.UF_OBJ_WIDTH_NORMAL;
theUfSession.Disp.DisplayTemporaryPoint(Tag.Null,
UFDisp.ViewType.UseActivePlus,
coords,
ref attrib,
UFDisp.PolyMarker.Asterisk);
}

private string GetStringRetVal(int retVal)
{
var retValString = string.Empty;

switch (retVal)
{
case (int) RetValPointSubfunc.Back:
retValString = "Back!";
break;
case (int) RetValPointSubfunc.Cancel:
retValString = "Cancel!";
break;
case (int) RetValPointSubfunc.PositionReturned:
retValString = "Position returned!";
break;
case (int) RetValPointSubfunc.NoActivePart:
retValString = "No active part!";
break;
case (int) RetValPointSubfunc.DisallowedState:
retValString = "Disallowed state, unable to bring up dialog!";
break;
default:
break;
}

return retValString;
}

}

Hi,

I have finally succeeded in uploading an example of how to produce
the erroneous result.

This is the link for downloading it:

https://gigamove.rwth-aachen.de/de/download/78cc344bd3a5a813caa6b1dd712b...

You should get a 7-Zip-file. The 7-Zip-file contains both the two partfiles I am using and a little video showing the steps to reproduce the situation.

At first you see the part file (PartA.prt) which provides the correct
result and afterwards the erroneous situation is demonstrated with
the second part file (PartB.prt)

In the video I run the code containing the TraceARay()-method I posted last week.

Hopefully this example and the part files will help finding a solution.

Part B has the view option "perspective" turned on, which is messing with the result.

Yes, that's it! You saved my day!

I would have never thought of an NX option causing this behaviour.

Thank you very much!

Now I would like to change the view to the orhtographic one.

I found


workPart.ModelingViews.WorkView.ChangePerspective();

which works fine. But is there a method to get the current status of the perspective?

After setting the view for my purpose (here finding the point on a face) I would like to set it back to the original value.

How can I achieve this?

I have found out how to get the state of the view (parallel or perspective). I found the corresponding code here in the forum ;-)

http://www.nxjournaling.com/comment/5053#comment-5053