前两天有网友在QQ群里提了一个问题,关于求向量夹角的问题。
他是先求面的矢量方向,然后用向量求角度,自己写的函数求角度。他得到的是锐角
后来群里大家推荐他用UF_VEC3_angle_between这个函数,结果测试还是锐角。
这个时候的我还在等待着他们讨论完问题的答案(因为我不会)......
大致就是他想判断两个向量之间的夹角是锐角还是钝角
举例的模型
也有人说直接判断边更快,凹凸边。
用到的pk函数是
PK_EDGE_ask_convexity PK_EDGE_convexity_convex_c :边缘是凸的。
PK_EDGE_convexity_concave_c :边缘是凹的。
锐角就是凹边,PK帮助上有讲的
讨论了一会,群里一个女网友(我有两只猫)发了方法
我不会数学计算两个向量之间的夹角,我只会用函数UF_VEC3_angle_between去计算NX二次开发-UFUN已知两个向量方向求夹角角度UF_VEC3_angle_between
在QQ群里,有个女网友在里面发了一下数学方法计算两个向量之间的夹角,我收藏记录一下。
这是她QQ群里发的代码
#define _USE_MATH_DEFINES #include <math.h>
/* 起始向量*/ double x0 = 0, y0 = 0, z0 = 1; /* 目标向量*/ double x1 = 0, y1 = 1, z1 = 0; /* 计算夹角*/ double dot = x0*x1+y0*y1+z0*z1; double aDot = std::round(std::acos(dot) * 180 / M_PI) /* 计算顺逆*/ double ss2 = (y0*z1-z0*y1) + (z0*x1-x0*z1) +(x0*y1-y0*x1); double(ss2 < 0) aDot = 360 - aDot;
#define _USE_MATH_DEFINES #include <math.h> double getVecAngle(const double vec0[3], const double vec1[3]) { /* 起始向量*/ double x0, y0, z0; /* 目标向量*/ double x1, y1, z1; double ret_val = 0.f; /* 向量单位化 */ double magnitude = std::sqrt(vec0[0] * vec0[0] + vec0[1] * vec0[1] + vec0[2] * vec0[2]); if (std::fabs(magnitude) < 1e-6) { // 0向量没意义 return ret_val; } x0 = vec0[0] / magnitude; y0 = vec0[1] / magnitude; z0 = vec0[2] / magnitude; magnitude = std::sqrt(vec1[0] * vec1[0] + vec1[1] * vec1[1] + vec1[2] * vec1[2]); if (std::fabs(magnitude) < 1e-6) { // 0向量没意义 return ret_val; } x1 = vec1[0] / magnitude; y1 = vec1[1] / magnitude; z1 = vec1[2] / magnitude; ret_val = (((y0*z1 - z0*y1) + (z0*x1 - x0*z1) + (x0*y1 - y0*x1)) < 0.f) ? (std::round(std::acos(x0*x1 + y0*y1 + z0*z1) * 180 / M_PI)) : (360 - std::round(std::acos(x0*x1 + y0*y1 + z0*z1) * 180 / M_PI)); return ret_val; }
这是我的demo
//NX9_NXOpenCPP_Wizard1 #define _USE_MATH_DEFINES #include <stdio.h> #include <math.h> // Mandatory UF Includes #include <uf.h> #include <uf_object_types.h> // Internal Includes #include <NXOpen/ListingWindow.hxx> #include <NXOpen/NXMessageBox.hxx> #include <NXOpen/UI.hxx> // Internal+External Includes #include <NXOpen/Annotations.hxx> #include <NXOpen/Assemblies_Component.hxx> #include <NXOpen/Assemblies_ComponentAssembly.hxx> #include <NXOpen/Body.hxx> #include <NXOpen/BodyCollection.hxx> #include <NXOpen/Face.hxx> #include <NXOpen/Line.hxx> #include <NXOpen/NXException.hxx> #include <NXOpen/NXObject.hxx> #include <NXOpen/Part.hxx> #include <NXOpen/PartCollection.hxx> #include <NXOpen/Session.hxx> #include <uf.h> #include <uf_ui.h> #include <uf_vec.h> #include <uf_curve.h> // Std C++ Includes #include <iostream> #include <sstream> using namespace NXOpen; using std::string; using std::exception; using std::stringstream; using std::endl; using std::cout; using std::cerr; //------------------------------------------------------------------------------ // NXOpen c++ test class //------------------------------------------------------------------------------ class MyClass { // class members public: static Session *theSession; static UI *theUI; MyClass(); ~MyClass(); void do_it(); void print(const NXString &); void print(const string &); void print(const char*); private: Part *workPart, *displayPart; NXMessageBox *mb; ListingWindow *lw; LogFile *lf; }; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(MyClass::theSession) = NULL; UI *(MyClass::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ MyClass::MyClass() { // Initialize the NX Open C++ API environment MyClass::theSession = NXOpen::Session::GetSession(); MyClass::theUI = UI::GetUI(); mb = theUI->NXMessageBox(); lw = theSession->ListingWindow(); lf = theSession->LogFile(); workPart = theSession->Parts()->Work(); displayPart = theSession->Parts()->Display(); } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ MyClass::~MyClass() { } //------------------------------------------------------------------------------ // Print string to listing window or stdout //------------------------------------------------------------------------------ void MyClass::print(const NXString &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const string &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const char * msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); } double getVecAngle(const double vec0[3], const double vec1[3]) { /* 起始向量*/ double x0, y0, z0; /* 目标向量*/ double x1, y1, z1; double ret_val = 0.f; /* 向量单位化 */ double magnitude = std::sqrt(vec0[0] * vec0[0] + vec0[1] * vec0[1] + vec0[2] * vec0[2]); if (std::fabs(magnitude) < 1e-6) { // 0向量没意义 return ret_val; } x0 = vec0[0] / magnitude; y0 = vec0[1] / magnitude; z0 = vec0[2] / magnitude; magnitude = std::sqrt(vec1[0] * vec1[0] + vec1[1] * vec1[1] + vec1[2] * vec1[2]); if (std::fabs(magnitude) < 1e-6) { // 0向量没意义 return ret_val; } x1 = vec1[0] / magnitude; y1 = vec1[1] / magnitude; z1 = vec1[2] / magnitude; ret_val = (((y0*z1 - z0*y1) + (z0*x1 - x0*z1) + (x0*y1 - y0*x1)) < 0.f) ? (std::acos(x0*x1 + y0*y1 + z0*z1) * 180 / M_PI) : (360 - std::acos(x0*x1 + y0*y1 + z0*z1) * 180 / M_PI); ///* 计算顺逆*/ double ss2 = (y0*z1-z0*y1) + (z0*x1-x0*z1) +(x0*y1-y0*x1); if (ss2 < 0) ret_val = 360 - ret_val; return ret_val; } //------------------------------------------------------------------------------ // Do something //------------------------------------------------------------------------------ void MyClass::do_it() { // TODO: add your code here UF_initialize(); //创建直线1 UF_CURVE_line_t LineCoords1; LineCoords1.start_point[0] = 0.0; LineCoords1.start_point[1] = 0.0; LineCoords1.start_point[2] = 0.0; LineCoords1.end_point[0] = 0.0; LineCoords1.end_point[1] = 100.0; LineCoords1.end_point[2] = 0.0; tag_t Line1Tag = NULL_TAG; UF_CURVE_create_line(&LineCoords1, &Line1Tag); //创建直线2 UF_CURVE_line_t LineCoords2; LineCoords2.start_point[0] = 0.0; LineCoords2.start_point[1] = 0.0; LineCoords2.start_point[2] = 0.0; LineCoords2.end_point[0] = 110.0; LineCoords2.end_point[1] = 80.0; LineCoords2.end_point[2] = 0.0; tag_t Line2Tag = NULL_TAG; UF_CURVE_create_line(&LineCoords2, &Line2Tag); //直线1的向量方向,终点减起点 double Vec1[3] = {LineCoords1.end_point[0]-LineCoords1.start_point[0], LineCoords1.end_point[1]-LineCoords1.start_point[1], LineCoords1.end_point[2]-LineCoords1.start_point[2]}; //直线2的向量方向,终点减起点 double Vec2[3] = {LineCoords2.end_point[0]-LineCoords2.start_point[0], LineCoords2.end_point[1]-LineCoords2.start_point[1], LineCoords2.end_point[2]-LineCoords2.start_point[2]}; double ret_val = getVecAngle(Vec1, Vec2); //打印 char msg[256]; sprintf(msg, "%f",ret_val ); uc1601(msg, 1); UF_terminate(); } //------------------------------------------------------------------------------ // Entry point(s) for unmanaged internal NXOpen C/C++ programs //------------------------------------------------------------------------------ // Explicit Execution extern "C" DllExport void ufusr( char *parm, int *returnCode, int rlen ) { try { // Create NXOpen C++ class instance MyClass *theMyClass; theMyClass = new MyClass(); theMyClass->do_it(); delete theMyClass; } catch (const NXException& e1) { UI::GetUI()->NXMessageBox()->Show("NXException", NXOpen::NXMessageBox::DialogTypeError, e1.Message()); } catch (const exception& e2) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, e2.what()); } catch (...) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, "Unknown Exception."); } } //------------------------------------------------------------------------------ // Unload Handler //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { return (int)NXOpen::Session::LibraryUnloadOptionImmediately; }
先说两个动画的区别
我做了一个是锐角一个是钝角的
这个函数就是输入两个向量,求向量夹角的
double getVecAngle(const double vec0[3], const double vec1[3]) { /* 起始向量*/ double x0, y0, z0; /* 目标向量*/ double x1, y1, z1; double ret_val = 0.f; /* 向量单位化 */ double magnitude = std::sqrt(vec0[0] * vec0[0] + vec0[1] * vec0[1] + vec0[2] * vec0[2]); if (std::fabs(magnitude) < 1e-6) { // 0向量没意义 return ret_val; } x0 = vec0[0] / magnitude; y0 = vec0[1] / magnitude; z0 = vec0[2] / magnitude; magnitude = std::sqrt(vec1[0] * vec1[0] + vec1[1] * vec1[1] + vec1[2] * vec1[2]); if (std::fabs(magnitude) < 1e-6) { // 0向量没意义 return ret_val; } x1 = vec1[0] / magnitude; y1 = vec1[1] / magnitude; z1 = vec1[2] / magnitude; ret_val = (((y0*z1 - z0*y1) + (z0*x1 - x0*z1) + (x0*y1 - y0*x1)) < 0.f) ? (std::acos(x0*x1 + y0*y1 + z0*z1) * 180 / M_PI) : (360 - std::acos(x0*x1 + y0*y1 + z0*z1) * 180 / M_PI); ///* 计算顺逆*/ double ss2 = (y0*z1-z0*y1) + (z0*x1-x0*z1) +(x0*y1-y0*x1); if (ss2 < 0) ret_val = 360 - ret_val; return ret_val; }
其中,这里面的这句判断,应该就是判断是锐角还是钝角的,以顺时针方向为例,如果夹角是小于90度的锐角,那么ss2就是小于0的,然后用360减去锐角的值,得到钝角
///* 计算顺逆*/ double ss2 = (y0*z1-z0*y1) + (z0*x1-x0*z1) +(x0*y1-y0*x1); if (ss2 < 0) ret_val = 360 - ret_val;
对应的就是这个动画
如果夹角是大于90度的钝角,那么ss2就是大于0的,直接输出钝角值
对应就是下面这个动画
判断顺时针方向是锐角还是钝角?
如下图
在她的代码里用到了round四舍五入值,我demo里没用。如果要用的话,
vs2010和vs2012的math头文件里是没有round函数的,自己写一个函数就好了。
百度上都有
double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); }
根据她的代码,我是这样分析的过程,
我的数学不是很好,如果谁发现有错误的地方,请底部留言。谢谢
阿飞
2021年10月17日