NX二次开发 创建实体最小包容块

环境: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);
}

 

你可能感兴趣的:(NX)