环境:Win7 x64,VS2015,NX12
内容:创建实体最小包容块
实现原理:
根据输入对象,创建一个辅助实体,然后遍历实体所有平面上的直线边,
以直线边和面法向创建坐标系,求此坐标系下求到的包容块体积,包容块最小者就是合适的坐标系。
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace NXOpen;
const double tol = 0.01;
const double maxValue = 99999999.99;
double GetDisTol()
{
double tol = 0.0001;
int err_flag = 0;
UF_MODL_ask_distance_tolerance(&tol);
return tol;
}
bool SetDisTol(double tol)
{
int err_flag = -1;
UF_MODL_set_distance_tolerance(&tol, &err_flag);
return (err_flag == 0);
}
bool IsZero(double val)
{
return (fabs(val) < tol);
}
double CalVolume(double lengthWidthHeight[3])
{
return lengthWidthHeight[0] * lengthWidthHeight[1] * lengthWidthHeight[2];
}
double GetMinVolume(double lengthWidthHeight[3])
{
double stand = 10000.0;
double vol = CalVolume(lengthWidthHeight);
if (vol >stand)
{
vol /= stand;
}
return vol;
}
static int init_proc(UF_UI_selection_p_t select, void *user_data)
{
//int errorCode = 0;
//int num_triples = 2;
//UF_UI_mask_t mask_triples[] = { UF_solid_type,UF_solid_face_subtype,UF_UI_SEL_FEATURE_BODY,UF_face_type,UF_solid_face_subtype,UF_UI_SEL_NOT_A_FEATURE }; //定义选择类型
//errorCode = UF_UI_set_sel_mask(select, UF_UI_SEL_MASK_CLEAR_AND_ENABLE_SPECIFIC, num_triples, mask_triples);
int errorCode = 0;
int num_triples = 1;
UF_UI_mask_t mask_triples[] = { UF_solid_type,UF_solid_face_subtype,UF_UI_SEL_FEATURE_BODY }; //定义选择类型
errorCode = UF_UI_set_sel_mask(select, UF_UI_SEL_MASK_CLEAR_AND_ENABLE_SPECIFIC, num_triples, mask_triples);
return (errorCode == 0);
}
std::vector GetSelectedBodies()
{
char message[132] = "请选择实体";
char title[132] = "选择对象";
int scope = UF_UI_SEL_SCOPE_WORK_PART;
int response;
int count = 0;
tag_p_t objects = NULL_TAG;
double cursor[3] = { 0,0,0 };
tag_t view = NULL_TAG;
UF_UI_select_with_class_dialog(message, title, scope, init_proc, NULL, &response, &count, &objects);
std::vector selectedBodies;
for (int i = 0; i < count; ++i)
{
selectedBodies.push_back(objects[i]);
}
return selectedBodies;
}
tag_t GetWCS()
{
tag_t csys_id = NULL_TAG;
UF_CSYS_ask_wcs(&csys_id);
return csys_id;
}
void AskCsysInfo(tag_t csys_id, double origin[3], double mtx[9])
{
tag_t matrix_id = NULL_TAG;
UF_CSYS_ask_csys_info(csys_id, &matrix_id, origin);
UF_CSYS_ask_matrix_values(matrix_id, mtx);
}
void GetMaxMinEdge(double edges[3], double &maxEdge, double &minEdge)
{
std::vector tmpVec;
for (int i = 0; i < 3; ++i)
{
tmpVec.push_back(edges[i]);
}
std::sort(tmpVec.begin(), tmpVec.end());
maxEdge = tmpVec[2];
minEdge = tmpVec[0];
}
void MapPointFromAcsToCS(double csOrg[3], double csMtx[9], double pnt[3])
{
UF_VEC3_sub(pnt, csOrg, pnt);
UF_MTX3_vec_multiply(pnt, csMtx, pnt);
}
void MapPointFromCsToAcs(double csOrg[3], double csMtx[9], double pnt[3])
{
UF_MTX3_vec_multiply_t(pnt, csMtx, pnt);
UF_VEC3_add(pnt, csOrg, pnt);
}
bool AskBoundingBox(double inputOri[3], double inputMat[9], std::vector inputObjects, double output_acs_min_corner[3], double output_acs_max_corner[3], double output_wcs_length_width_height[3])
{
if (inputObjects.empty())
{
return false;
}
tag_t OriWcs = NULL_TAG;
UF_CSYS_ask_wcs(&OriWcs);
Point3d origin(inputOri[0], inputOri[1], inputOri[2]);
Matrix3x3 matrix(inputMat[0], inputMat[1], inputMat[2],inputMat[3], inputMat[4], inputMat[5], inputMat[6], inputMat[7], inputMat[8]);
NXOpen::Session *theSession = NXOpen::Session::GetSession();
Part *workPart = theSession->Parts()->Work();
workPart->WCS()->SetOriginAndMatrix(origin, matrix);
tag_t wcsTag = NULL_TAG;
UF_CSYS_ask_wcs(&wcsTag);
double objsBoxInWCS[6] = { 0 };
for (int i = 0; i < inputObjects.size(); ++i)
{
double min_corner[3] = { 0 };
double dir[3][3] = { 0 };
double dis[3] = { 0 };
UF_MODL_ask_bounding_box_exact(inputObjects[i], wcsTag, min_corner, dir, dis);
if (IsZero(fabs(dis[0]) + fabs(dis[1]) + fabs(dis[2])))
{
continue;
}
double minPoint[3] = { 0 };
double maxPoint[3] = { 0 };
minPoint[0] = min_corner[0];
minPoint[1] = min_corner[1];
minPoint[2] = min_corner[2];
maxPoint[0] = min_corner[0] + dir[0][0] * dis[0] + dir[1][0] * dis[1] + dir[2][0] * dis[2];
maxPoint[1] = min_corner[1] + dir[0][1] * dis[0] + dir[1][1] * dis[1] + dir[2][1] * dis[2];
maxPoint[2] = min_corner[2] + dir[0][2] * dis[0] + dir[1][2] * dis[1] + dir[2][2] * dis[2];
MapPointFromAcsToCS(inputOri, inputMat, minPoint);
MapPointFromAcsToCS(inputOri, inputMat, maxPoint);
double tmpObjBoxInWCS[6] = { 0 };
tmpObjBoxInWCS[0] = minPoint[0];
tmpObjBoxInWCS[1] = minPoint[1];
tmpObjBoxInWCS[2] = minPoint[2];
tmpObjBoxInWCS[3] = maxPoint[0];
tmpObjBoxInWCS[4] = maxPoint[1];
tmpObjBoxInWCS[5] = maxPoint[2];
if (i == 0)
{
objsBoxInWCS[0] = tmpObjBoxInWCS[0];
objsBoxInWCS[1] = tmpObjBoxInWCS[1];
objsBoxInWCS[2] = tmpObjBoxInWCS[2];
objsBoxInWCS[3] = tmpObjBoxInWCS[3];
objsBoxInWCS[4] = tmpObjBoxInWCS[4];
objsBoxInWCS[5] = tmpObjBoxInWCS[5];
}
else
{
if (objsBoxInWCS[0] > tmpObjBoxInWCS[0])
{
objsBoxInWCS[0] = tmpObjBoxInWCS[0];
}
if (objsBoxInWCS[0] > tmpObjBoxInWCS[3])
{
objsBoxInWCS[0] = tmpObjBoxInWCS[3];
}
if (objsBoxInWCS[1] > tmpObjBoxInWCS[1])
{
objsBoxInWCS[1] = tmpObjBoxInWCS[1];
}
if (objsBoxInWCS[1] > tmpObjBoxInWCS[4])
{
objsBoxInWCS[1] = tmpObjBoxInWCS[4];
}
if (objsBoxInWCS[2] > tmpObjBoxInWCS[2])
{
objsBoxInWCS[2] = tmpObjBoxInWCS[2];
}
if (objsBoxInWCS[2] > tmpObjBoxInWCS[5])
{
objsBoxInWCS[2] = tmpObjBoxInWCS[5];
}
if (objsBoxInWCS[3] < tmpObjBoxInWCS[0])
{
objsBoxInWCS[3] = tmpObjBoxInWCS[0];
}
if (objsBoxInWCS[3] < tmpObjBoxInWCS[3])
{
objsBoxInWCS[3] = tmpObjBoxInWCS[3];
}
if (objsBoxInWCS[4] < tmpObjBoxInWCS[1])
{
objsBoxInWCS[4] = tmpObjBoxInWCS[1];
}
if (objsBoxInWCS[4] < tmpObjBoxInWCS[4])
{
objsBoxInWCS[4] = tmpObjBoxInWCS[4];
}
if (objsBoxInWCS[5] < tmpObjBoxInWCS[2])
{
objsBoxInWCS[5] = tmpObjBoxInWCS[2];
}
if (objsBoxInWCS[5] < tmpObjBoxInWCS[5])
{
objsBoxInWCS[5] = tmpObjBoxInWCS[5];
}
}
}
output_wcs_length_width_height[0] = fabs(objsBoxInWCS[3] - objsBoxInWCS[0]);
output_wcs_length_width_height[1] = fabs(objsBoxInWCS[4] - objsBoxInWCS[1]);
output_wcs_length_width_height[2] = fabs(objsBoxInWCS[5] - objsBoxInWCS[2]);
double minPoint[3] = { objsBoxInWCS[0], objsBoxInWCS[1], objsBoxInWCS[2] };
double maxPoint[3] = { objsBoxInWCS[3], objsBoxInWCS[4], objsBoxInWCS[5] };
MapPointFromCsToAcs(inputOri, inputMat, minPoint);
MapPointFromCsToAcs(inputOri, inputMat, maxPoint);
output_acs_min_corner[0] = minPoint[0];
output_acs_min_corner[1] = minPoint[1];
output_acs_min_corner[2] = minPoint[2];
output_acs_max_corner[0] = maxPoint[0];
output_acs_max_corner[1] = maxPoint[1];
output_acs_max_corner[2] = maxPoint[2];
UF_CSYS_set_wcs(OriWcs);
return true;
}
std::vector GetBodyFaces(tag_t body)
{
std::vector faces;
uf_list_p_t face_list;
UF_MODL_create_list(&face_list);
UF_MODL_ask_body_faces(body, &face_list);
int count = 0;
int err = UF_MODL_ask_list_count(face_list, &count);
for (int i = 0; i < count; ++i)
{
tag_t tmpFace = NULL_TAG;
UF_MODL_ask_list_item(face_list, i, &tmpFace);
faces.push_back(tmpFace);
}
UF_MODL_delete_list(&face_list);
return faces;
}
std::vector GetFaceEdges(tag_t face)
{
std::vector edges;
uf_list_p_t edge_list;
UF_MODL_create_list(&edge_list);
UF_MODL_ask_face_edges(face, &edge_list);
int count = 0;
int err = UF_MODL_ask_list_count(edge_list, &count);
for (int i = 0; i < count; ++i)
{
tag_t tmpEdge = NULL_TAG;
UF_MODL_ask_list_item(edge_list, i, &tmpEdge);
edges.push_back(tmpEdge);
}
UF_MODL_delete_list(&edge_list);
return edges;
}
bool IsPlanarFace(tag_t face)
{
int type = 0;
int err = UF_MODL_ask_face_type(face, &type);
return (err == 0 && type == UF_MODL_PLANAR_FACE);
}
bool GetFaceNormal(tag_t face, double normal[3])
{
int type = 0;
int err = UF_MODL_ask_face_type(face, &type);
if (err != 0)
{
return false;
}
double uv_min_max[4] = { 0 };
UF_MODL_ask_face_uv_minmax(face, uv_min_max);
double uvCenter[2] = { 0 };
uvCenter[0] = (uv_min_max[0] + uv_min_max[1]) / 2;
uvCenter[1] = (uv_min_max[2] + uv_min_max[3]) / 2;
double centerPnt[3] = { 0 };
double u1[3];
double v1[3];
double u2[3];
double v2[3];
double radii[2];
UF_MODL_ask_face_props(face, uvCenter, centerPnt, u1, v1, u2, v2, normal, radii);
return true;
}
bool IsLinearEdge(tag_t edge)
{
int edge_type = 0;
int err = UF_MODL_ask_edge_type(edge, &edge_type);
return (err == 0 && edge_type == UF_MODL_LINEAR_EDGE);
}
bool GetLinearEdgeEndPnt(tag_t edge, double startPnt[3], double endPnt[3])
{
if (!IsLinearEdge(edge))
{
return false;
}
double tangent[3] = {0};
double p_norm[3] = {0};
double b_norm[3] = {0};
double torsion = 0;
double rad_of_cur = 0;
UF_MODL_ask_curve_props(edge, 0, startPnt, tangent, p_norm, b_norm, &torsion, &rad_of_cur);
UF_MODL_ask_curve_props(edge, 1, endPnt, tangent, p_norm, b_norm, &torsion, &rad_of_cur);
return true;
}
bool GetLinearEdgeMtx(tag_t edge, double faceNormal[3], double mtx[9])
{
bool res = false;
double startPnt[3] = { 0 };
double endPnt[3] = { 0 };
if (GetLinearEdgeEndPnt(edge, startPnt, endPnt))
{
double linearDir[3] = { endPnt[0] - startPnt[0],endPnt[1] - startPnt[1] ,endPnt[2] - startPnt[2] };
double magnitude = 0.0;
double unitDir[3] = { 0 };
UF_VEC3_unitize(linearDir, tol, &magnitude, unitDir);
int is_parallelar = -1;
UF_VEC3_is_parallel(unitDir, faceNormal, tol, &is_parallelar);
if (is_parallelar == 0)
{
int err = UF_MTX3_initialize(unitDir,faceNormal,mtx);
res = (err == 0);
}
}
return res;
}
Matrix3x3 TransArrayToMat(double mtx[9])
{
return Matrix3x3(mtx[0], mtx[1], mtx[2], mtx[3], mtx[4], mtx[5], mtx[6], mtx[7], mtx[8]);
}
void TransMatToArray(Matrix3x3 mat, double mtx[9])
{
mtx[0] = mat.Xx;
mtx[1] = mat.Xy;
mtx[2] = mat.Xz;
mtx[3] = mat.Yx;
mtx[4] = mat.Yy;
mtx[5] = mat.Yz;
mtx[6] = mat.Zx;
mtx[7] = mat.Zy;
mtx[8] = mat.Zz;
}
bool IsMatVecHasMatInParallelOrPerpendicularStyle(std::vector &mats, Matrix3x3 mat)
{
double compareMatXAxis[3] = { mat.Xx,mat.Xy, mat.Xz };
double compareMatYAxis[3] = { mat.Yx,mat.Yy, mat.Yz };
for (int i = 0; i < mats.size(); ++i)
{
double tmpMatXAxis[3] = { mats[i].Xx,mats[i].Xy, mats[i].Xz };
double tmpMatYAxis[3] = { mats[i].Yx,mats[i].Yy, mats[i].Yz };
int isXXParallel = -1;
int isYYParallel = -1;
int isXYParallel = -1;
int isYXParallel = -1;
UF_VEC3_is_parallel(tmpMatXAxis, compareMatXAxis, tol, &isXXParallel);
UF_VEC3_is_parallel(tmpMatYAxis, compareMatYAxis, tol, &isYYParallel);
UF_VEC3_is_parallel(tmpMatXAxis, compareMatYAxis, tol, &isXYParallel);
UF_VEC3_is_parallel(tmpMatYAxis, compareMatXAxis, tol, &isYXParallel);
int isXXPerpendicular = -1;
int isYYPerpendicular = -1;
int isXYPerpendicular = -1;
int isYXPerpendicular = -1;
UF_VEC3_is_perpendicular(tmpMatXAxis, compareMatXAxis, tol, &isXXPerpendicular);
UF_VEC3_is_perpendicular(tmpMatYAxis, compareMatYAxis, tol, &isYYPerpendicular);
UF_VEC3_is_perpendicular(tmpMatXAxis, compareMatYAxis, tol, &isXYPerpendicular);
UF_VEC3_is_perpendicular(tmpMatYAxis, compareMatXAxis, tol, &isYXPerpendicular);
if (isXXParallel && isYYParallel)
{
return true;
}
if (isXYParallel && isYXParallel)
{
return true;
}
if (isXXParallel && isYYPerpendicular)
{
return true;
}
if (isXYParallel && isYXPerpendicular)
{
return true;
}
if (isYYParallel && isXXPerpendicular)
{
return true;
}
if (isYXParallel && isXYPerpendicular)
{
return true;
}
}
return false;
}
bool CreateWrapGeometry(std::vector bodies,double disTol,tag_t &resultBody)
{
resultBody = NULL_TAG;
if (bodies.empty())
{
return false;
}
tag_t *objects = new tag_t[sizeof(bodies)];
memcpy(objects, &bodies[0], bodies.size() * sizeof(tag_t));
UF_MODL_wrap_geom_t wrap_data;
wrap_data.close_gap = UF_WRAP_GEOM_CLOSE_NONE;
wrap_data.dist_tol = disTol;//顶点公差 UG默认2.45 ,越小越精确
wrap_data.add_offset = "0";
wrap_data.split_offset = "0";
wrap_data.num_geoms = bodies.size();
wrap_data.geometry = objects;
wrap_data.num_splits = 0;
wrap_data.splits = NULL_TAG;
tag_t feature_tag = NULL_TAG;
int err = UF_MODL_create_wrap_geometry(&wrap_data, &feature_tag);
if (err == 0)
{
UF_MODL_ask_feat_body(feature_tag, &resultBody);
}
return (resultBody != NULL_TAG);
}
tag_t CreateBlock(double inputOri[3], double inputMat[9],double input_acs_min_corner[3], double edges[3])
{
tag_t OriWcs = NULL_TAG;
UF_CSYS_ask_wcs(&OriWcs);
Point3d origin(inputOri[0], inputOri[1], inputOri[2]);
Matrix3x3 matrix(inputMat[0], inputMat[1], inputMat[2], inputMat[3], inputMat[4], inputMat[5], inputMat[6], inputMat[7], inputMat[8]);
NXOpen::Session *theSession = NXOpen::Session::GetSession();
Part *workPart = theSession->Parts()->Work();
workPart->WCS()->SetOriginAndMatrix(origin, matrix);
char s1[133], s2[133], s3[133];
sprintf(s1, "%f", edges[0]);
sprintf(s2, "%f", edges[1]);
sprintf(s3, "%f", edges[2]);
char* edgesStr[3] = { s1, s2, s3 };
tag_t obj = NULL_TAG;
UF_MODL_create_block1(UF_NULLSIGN, input_acs_min_corner, edgesStr, &obj);
UF_MODL_ask_feat_body(obj, &obj);
UF_CSYS_set_wcs(OriWcs);
return obj;
}
bool CreateSolidBodyMinBoxBlock(std::vector solidBodies)
{
if (solidBodies.empty())
{
return false;
}
tag_t originWcs = GetWCS();
double orginOrigin[3] = { 0 };
double originMatrix[9] = { 0 };
AskCsysInfo(originWcs, orginOrigin, originMatrix);
std::vector solidBodyCalculatedMats;
double min_volume = 0;
double origin[3] = { 0 };
double matrix[9] = { 0 };
double min_corner[3] = { 0 };
double max_corner[3] = { 0 };
double distances[3] = { 0 };
tag_t csys = originWcs;
int standFaceEdgesCount = 3;
AskCsysInfo(csys, origin, matrix);
Matrix3x3 mat = TransArrayToMat(matrix);
solidBodyCalculatedMats.push_back(mat);
//body init box
AskBoundingBox(origin,matrix, solidBodies, min_corner, max_corner, distances);
min_volume = GetMinVolume(distances);
double minEdgeLen = 0;
double maxEdgeLen = 0;
GetMaxMinEdge(distances, maxEdgeLen, minEdgeLen);
double disTol = minEdgeLen / 120;
//warp geometry
tag_t auxBody = NULL_TAG;
if (!CreateWrapGeometry(solidBodies, disTol, auxBody))
{
return false;
}
std::vector faces = GetBodyFaces(auxBody);
for (int i = 0; i < faces.size(); ++i)
{
std::vector edges = GetFaceEdges(faces[i]);
if (edges.size() < standFaceEdgesCount)
{
continue;
}
double faceNormal[3] = { 0 };
GetFaceNormal(faces[i], faceNormal);
for (int j = 0; j < edges.size(); ++j)
{
double tmpMtx[9] = { 0 };
if (GetLinearEdgeMtx(edges[j], faceNormal, tmpMtx))
{
Matrix3x3 tmpLinearEdgeMat = TransArrayToMat(tmpMtx);
if (!IsMatVecHasMatInParallelOrPerpendicularStyle(solidBodyCalculatedMats, tmpLinearEdgeMat))
{
AskBoundingBox(origin, tmpMtx, solidBodies, min_corner, max_corner, distances);
double tmpVolume = GetMinVolume(distances);
if (!IsZero(tmpVolume) && tmpVolume < min_volume)
{
min_volume = tmpVolume;
solidBodyCalculatedMats.push_back(tmpLinearEdgeMat);
}
}
}
}
}
//create block
Matrix3x3 minBoxMat = solidBodyCalculatedMats.back();
double minBoxMatArray[9] = { 0 };
TransMatToArray(minBoxMat, minBoxMatArray);
AskBoundingBox(origin, minBoxMatArray, solidBodies, min_corner, max_corner, distances);
tag_t block = CreateBlock(origin, minBoxMatArray,min_corner, distances); //坐标点不需要转换,就是用绝对坐标系
if (auxBody != NULL_TAG)
{
UF_OBJ_delete_object(auxBody);
}
return true;
}
void MinBoxTest()
{
std::vector selectedBodies = GetSelectedBodies();
CreateSolidBodyMinBoxBlock(selectedBodies);
}