/* Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved. */ /*--------------------------------------------------------------------*\ Pro/Toolkit includes \*--------------------------------------------------------------------*/ #include <ProToolkit.h> #include <ProObjects.h> #include <ProColor.h> #include <ProMdl.h> #include <ProPart.h> #include <ProMenu.h> #include <ProGtol.h> #include <ProGraphic.h> #include <ProFeature.h> #include <ProSurface.h> #include <ProWstring.h> #include <ProUtil.h> #include <ProModelitem.h> #include <ProMessage.h> #include "TestError.h" #include "UtilMenu.h" #include "UtilMessage.h" #include "UtilString.h" #include "UtilMath.h" #include "UtilTypes.h" #include "PTApplsUnicodeUtils.h" #define EXPORT_MN_SETUP 01 #define EXPORT_MN_WIREFRAME 11 #define EXPORT_MN_RENDER 12 #define EXPORT_MN_DUMP 13 #define EXPORT_MN_ANGLE 21 #define EXPORT_MN_CHORD 22 #define EXPORT_MN_QUILT 23 #define EXPORT_MN_OPT 24 #define EXPORT_MN_ASSM 33 #define EXPORT_MN_SEL_PART 34 typedef struct pro_test_export_data { ProMdl mdl; double chord_ht; double angle_cntrl; ProBoolean include_quilts; ProCharLine file_name; int file_format; ProBoolean optimization; } ProTestExportData; /*=================================================================*\ FUNCTION : ProTestExportVertexIsEq() PURPOSE : Compare two vectors. \*=================================================================*/ int ProTestExportVertexIsEq(ProVector v1, ProVector v2) { if((v1 == NULL)||(v2 == NULL)) return(-1); if((fabs(v1[0]-v2[0])<EPSM6)&&(fabs(v1[1]-v2[1])<EPSM6)&&(fabs(v1[2]-v2[2])<EPSM6)) return(1); return(0); } /*=================================================================*\ FUNCTION : ProTestExportFindVertex() PURPOSE : Find vertex position in the array. \*=================================================================*/ int ProTestExportFindVertex(ProVector *v_arr, ProVector v) { ProError error; int i, n; if((v_arr == NULL)||(v == NULL)) return(-1); error = ProArraySizeGet((ProArray)v_arr, &n); TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestExportFindVertex()", error, error != PRO_TK_NO_ERROR); if((error!=PRO_TK_NO_ERROR)||(n<=0)) return(-1); for(i=(n-1); i<=0; i--) { if (ProTestExportVertexIsEq(v_arr[i], v) == 1) return(i); } return(-1); } /*=================================================================*\ FUNCTION : ProTestExportVertexAdd() PURPOSE : Add vertex to the array \*=================================================================*/ int ProTestExportVertexAdd(ProVector **v_arr, ProVector v, ProBoolean opt) { int n; ProError error; if(v == NULL) return(-1); if(*v_arr == NULL) { error = ProArrayAlloc(0, sizeof(ProVector),1,(ProArray*)v_arr); TEST_CALL_REPORT ("ProArrayAlloc()", "ProTestExportVertexAdd()", error, error != PRO_TK_NO_ERROR); if(error!=PRO_TK_NO_ERROR) return(-1); } if(opt == PRO_B_TRUE) { n = ProTestExportFindVertex(*v_arr, v); if(n>=0) return(n); } error = ProArrayObjectAdd((ProArray*)v_arr, PRO_VALUE_UNUSED, 1, &v); TEST_CALL_REPORT ("ProArrayObjectAdd()", "ProTestExportVertexAdd()", error, error != PRO_TK_NO_ERROR); if(error!=PRO_TK_NO_ERROR) return(-1); error = ProArraySizeGet((ProArray)*v_arr, &n); TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestExportVertexAdd()", error, error != PRO_TK_NO_ERROR); if(error!=PRO_TK_NO_ERROR) return(-1); (*v_arr)[n-1][0] =v[0]; (*v_arr)[n-1][1] =v[1]; (*v_arr)[n-1][2] =v[2]; return(n-1); } /*=================================================================*\ FUNCTION : ProTestExportCollectAllTringles() PURPOSE : Collect all triangles into the single array \*=================================================================*/ ProError ProTestExportCollectAllTringles(ProSurfaceTessellationData *data, ProTriangle **trn, ProVector **ver, ProBoolean opt) { ProError error, err = PRO_TK_NO_ERROR; int i, n_trn = 0, k, j; int SurfCount=0; if(data == NULL) return(PRO_TK_BAD_INPUTS); if(*trn == NULL) { error = ProArrayAlloc(0, sizeof(ProTriangle),1,(ProArray*)trn); TEST_CALL_REPORT ("ProArrayAlloc()", "ProTestExportCollectAllTringles()", error, error != PRO_TK_NO_ERROR); if(error!=PRO_TK_NO_ERROR) return(error); } error = ProArraySizeGet((ProArray)data, &SurfCount); TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestExportCollectAllTringles()", error, error != PRO_TK_NO_ERROR); if((error != PRO_TK_NO_ERROR)||(SurfCount<=0)) return(PRO_TK_BAD_INPUTS); for(i=0; i<SurfCount; i++) { for(j=0; j<data[i].n_facets; j++) { error = ProArrayObjectAdd((ProArray*)trn,PRO_VALUE_UNUSED,1, &data[i].facets[j]); TEST_CALL_REPORT ("ProArrayObjectAdd()", "ProTestExportCollectAllTringles()", error, error != PRO_TK_NO_ERROR); if(error!=PRO_TK_NO_ERROR) { err = error; continue; } for(k=0; k<3; k++) (*trn)[n_trn][k] = ProTestExportVertexAdd(ver, data[i].vertices[data[i].facets[j][k]], opt); n_trn++; } } return(err); } /*=================================================================*\ FUNCTION : ProTestExportToRender() PURPOSE : Print tessllation data to SLP file \*=================================================================*/ ProError ProTestExportToRender(FILE *fp, ProSurfaceTessellationData *data, char *name) { ProError error; int n,i,j,k; error = ProArraySizeGet((ProArray)data, &n); if((error!=PRO_TK_NO_ERROR)||(n<=0)) return(PRO_TK_BAD_INPUTS); ProTKFprintf(fp,"solid %s\n", name); /*-----------------------------------------------------------------*\ Print all facets with gray color \*-----------------------------------------------------------------*/ ProTKFprintf(fp,"\tcolor 0.8 0.8 0.8\n"); for(i=0; i<n; i++) { for(j=0; j<data[i].n_facets; j++) { ProTKFprintf(fp,"\tfacet\n"); for(k=0; k<3; k++) { ProTKFprintf(fp,"\t\t\tnormal %5.5f %5.5f %5.5f\n", data[i].normals[data[i].facets[j][k]][0], data[i].normals[data[i].facets[j][k]][1], data[i].normals[data[i].facets[j][k]][2]); } ProTKFprintf(fp,"\t\touter loop\n"); for(k=0; k<3; k++) { ProTKFprintf(fp,"\t\t\tvertex %5.5f %5.5f %5.5f\n", data[i].vertices[data[i].facets[j][k]][0], data[i].vertices[data[i].facets[j][k]][1], data[i].vertices[data[i].facets[j][k]][2]); } ProTKFprintf(fp,"\t\tendloop\n"); ProTKFprintf(fp,"\tendfacet\n"); } } ProTKFprintf(fp,"endsolid %s",name); return(error); } /*=================================================================*\ FUNCTION : ProTestExportToDUMP() PURPOSE : DUMP tessllation data to file \*=================================================================*/ ProError ProTestExportToDUMP(FILE *fp, ProSurfaceTessellationData *data) { ProError error; int i, j, SurfCount =0, SurfId; ProSrftype SurfType; ProCharLine c_name; double SurfArea; /*-----------------------------------------------------------------*\ Get surface count \*-----------------------------------------------------------------*/ error = ProArraySizeGet((ProArray)data, &SurfCount); TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestExportToDUMP()", error, error != PRO_TK_NO_ERROR); if((error != PRO_TK_NO_ERROR)||(SurfCount<=0)) return(PRO_TK_E_NOT_FOUND); /*-----------------------------------------------------------------*\ Print file header \*-----------------------------------------------------------------*/ ProTKFprintf(fp, "#Surface tessellation data\n"); ProTKFprintf(fp, "#Version 1.0\n\n"); ProTKFprintf(fp, "Surface count: %d\n",SurfCount); for(i=0; i<SurfCount;i++) { /*-----------------------------------------------------------------*\ Print information about current surface \*-----------------------------------------------------------------*/ ProTKFprintf(fp, "Surface_%d {\n",i); error = ProSurfaceIdGet(data[i].surface, &SurfId); TEST_CALL_REPORT ("ProSurfaceIdGet()", "ProTestExportToDUMP()", error, error != PRO_TK_NO_ERROR); ProTKFprintf(fp,"\tid: %d\n", SurfId); error = ProSurfaceTypeGet(data[i].surface, &SurfType); TEST_CALL_REPORT ("ProSurfaceTypeGet()", "ProTestExportToDUMP()", error, error != PRO_TK_NO_ERROR); ProUtilSrftypeStr(SurfType,c_name); ProTKFprintf(fp,"\ttype: (%d) %s\n", SurfType, c_name); error = ProSurfaceAreaEval(data[i].surface, &SurfArea); TEST_CALL_REPORT ("ProSurfaceAreaEval()", "ProTestExportToDUMP()", error, error != PRO_TK_NO_ERROR); ProTKFprintf(fp,"\tarea: %5.5f\n", SurfArea); ProTKFprintf(fp,"\tvertices count: %d\n", data[i].n_vertices); ProTKFprintf(fp,"\tfacets count: %d\n", data[i].n_facets); /*-----------------------------------------------------------------*\ Print array of vertices \*-----------------------------------------------------------------*/ ProTKFprintf(fp,"\tVertices {\n"); for(j=0; j<data[i].n_vertices; j++) { ProTKFprintf(fp,"\t\t %5.5f, %5.5f, %5.5f\n", data[i].vertices[j][0], data[i].vertices[j][1], data[i].vertices[j][2]); } ProTKFprintf(fp,"\t}\n"); /*-----------------------------------------------------------------*\ Print array of normals \*-----------------------------------------------------------------*/ ProTKFprintf(fp,"\tNormals {\n"); for(j=0; j<data[i].n_vertices; j++) { ProTKFprintf(fp,"\t\t %5.5f, %5.5f, %5.5f\n", data[i].normals[j][0], data[i].normals[j][1], data[i].normals[j][2]); } ProTKFprintf(fp,"\t}\n"); /*-----------------------------------------------------------------*\ Print array of facets \*-----------------------------------------------------------------*/ ProTKFprintf(fp,"\tFacets {\n"); for(j=0; j<data[i].n_facets; j++) { ProTKFprintf(fp,"\t\t %d, %d, %d\n", data[i].facets[j][0],data[i].facets[j][1],data[i].facets[j][2]); } ProTKFprintf(fp,"\t}\n"); ProTKFprintf(fp,"}\n\n"); } return(PRO_TK_NO_ERROR); } /*=================================================================*\ FUNCTION : ProTestExportToWireFrame PURPOSE : Output tessellation data to the wire frame file. \*=================================================================*/ ProError ProTestExportToWireFrame(FILE *fp, ProSurfaceTessellationData *data, ProBoolean opt) { ProError error; ProTriangle *trn=NULL; ProVector *ver=NULL; int n_v, n_t, i; error = ProTestExportCollectAllTringles(data, &trn, &ver, opt); error = ProArraySizeGet((ProArray)ver, &n_v); TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestExportToWireFrame()", error, error != PRO_TK_NO_ERROR); if((error != PRO_TK_NO_ERROR)||(n_v<=0)) return(PRO_TK_BAD_INPUTS); for(i=0; i<n_v; i++) ProTKFprintf(fp,"v %5.5f %5.5f %5.5f\n",ver[i][0], ver[i][1], ver[i][2]); error = ProArraySizeGet((ProArray)trn, &n_t); TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestExportToWireFrame()", error, error != PRO_TK_NO_ERROR); if((error != PRO_TK_NO_ERROR)||(n_t<=0)) return(PRO_TK_BAD_INPUTS); for(i=0;i<n_t; i++) ProTKFprintf(fp, "f %d %d %d\n", trn[i][0]+1, trn[i][1]+1, trn[i][2]+1); error = ProArrayFree((ProArray*)&ver); TEST_CALL_REPORT ("ProArrayFree()", "ProTestExportToWireFrame()", error, error != PRO_TK_NO_ERROR); error = ProArrayFree((ProArray*)&trn); TEST_CALL_REPORT ("ProArrayFree()", "ProTestExportToWireFrame()", error, error != PRO_TK_NO_ERROR); return(PRO_TK_NO_ERROR); } /*=================================================================*\ FUNCTION : ProTestExportModelTo() PURPOSE : Export part tessellation data to the file \*=================================================================*/ ProError ProTestExportModelTo(ProTestExportData *data) { ProError error; ProSurfaceTessellationData *tes_data = NULL; ProMdlName w_name; ProCharLine c_name; FILE *fp; if(data == NULL) return(PRO_TK_BAD_INPUTS); error = ProPartTessellate ((ProPart)(data->mdl), data->chord_ht, data->angle_cntrl, data->include_quilts, &tes_data); TEST_CALL_REPORT ("ProPartTessellate()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); if (error!=PRO_TK_NO_ERROR) return(error); error = ProMdlMdlnameGet(data->mdl, w_name); TEST_CALL_REPORT ("ProMdlMdlnameGet()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); ProWstringToString(c_name, w_name); switch(data->file_format) { case EXPORT_MN_WIREFRAME: ProTKSprintf(data->file_name,"%s.%s",c_name,"obj"); break; case EXPORT_MN_RENDER: ProTKSprintf(data->file_name,"%s.%s",c_name,"slp"); break; case EXPORT_MN_DUMP: ProTKSprintf(data->file_name,"%s.%s",c_name,"dump"); break; } if ((fp = PTApplsUnicodeFopen(data->file_name, "w")) == NULL) { ProTKPrintf("Cannot open output file\n"); return (PRO_TK_GENERAL_ERROR); } switch (data->file_format) { case EXPORT_MN_WIREFRAME: error = ProTestExportToWireFrame(fp, tes_data, data->optimization); break; case EXPORT_MN_RENDER: error = ProTestExportToRender(fp, tes_data, ProWstringToString(c_name, w_name)); break; case EXPORT_MN_DUMP: error = ProTestExportToDUMP(fp,tes_data); break; } error = ProPartTessellationFree(&tes_data); TEST_CALL_REPORT ("ProPartTessellationFree()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); fclose(fp); return(error); } /*=================================================================*\ FUNCTION : ProTestExportTo() PURPOSE : Export part tessellation data to the file \*=================================================================*/ ProError ProTestExportTo(ProTestExportData *data) { ProError error; ProMdlType mdl_type; int n, n_sel,i; ProSelection *sel; ProModelitem part_item; static ProUtilMenuButtons TkMenu[] ={ {"ExportAsm", -1, TEST_CALL_PRO_MENU_DELETE}, {"-As assembly", EXPORT_MN_ASSM, 0}, {"-Selected parts", EXPORT_MN_SEL_PART,0}, {"-Quit", -1, TEST_CALL_PRO_MENU_DELETE}, {"", -1, 0}}; if(data == NULL) return(PRO_TK_BAD_INPUTS); error = ProMdlTypeGet(data->mdl, &mdl_type); TEST_CALL_REPORT ("ProMdlTypeGet()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); switch(mdl_type) { case PRO_MDL_ASSEMBLY: error = ProUtilMenuIntValueSelect(TkMenu, &n); if((error!=PRO_TK_NO_ERROR)||(n<0)) return(PRO_TK_NO_ERROR); if (n == EXPORT_MN_SEL_PART) { error = ProSelect((char*)"part",PRO_VALUE_UNUSED, NULL, NULL, NULL, NULL, &sel, &n_sel); TEST_CALL_REPORT ("ProSelect()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); if((error!=PRO_TK_NO_ERROR)||(n_sel<=0)) return(PRO_TK_E_NOT_FOUND); for(i=0; i<n_sel; i++) { error = ProSelectionModelitemGet(sel[i], &part_item); TEST_CALL_REPORT ("ProSelectionModelitemGet()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); if (error != PRO_TK_NO_ERROR) continue; error = ProModelitemMdlGet (&part_item, (ProMdl*)&(data->mdl)); TEST_CALL_REPORT ("ProModelitemMdlGet()", "ProTestExportTo()", error, error != PRO_TK_NO_ERROR); if (error != PRO_TK_NO_ERROR) continue; error = ProTestExportModelTo(data); } } else { error = ProTestExportModelTo(data); } break; case PRO_MDL_PART: error = ProTestExportModelTo(data); break; default: return(PRO_TK_BAD_INPUTS); } return(error); } /*=================================================================*\ FUNCTION : ProTestExportSetup() PURPOSE : Setup tesselation parameters \*=================================================================*/ ProError ProTestExportSetup(ProTestExportData *data) { int n; ProError error; static ProUtilMenuButtons TkMenu[] ={ {"ExpSetup", -1, TEST_CALL_PRO_MENU_DELETE}, {"-Chord height", EXPORT_MN_CHORD, 0}, {"-Angle control", EXPORT_MN_ANGLE, 0}, {"-Quilt", EXPORT_MN_QUILT, 0}, {"-Optimization", EXPORT_MN_OPT, 0}, {"-Quit", -1, TEST_CALL_PRO_MENU_DELETE}, {"", -1,0}}; error = ProUtilMenuIntValueSelect(TkMenu, &n); if((error!=PRO_TK_NO_ERROR)||(n<0)) return(PRO_TK_NO_ERROR); switch(n) { case EXPORT_MN_CHORD: ProUtilMsgPrint("gen", "TEST %0s", "The maximum allowable chord height(>0):"); error = ProMessageDoubleRead(NULL, &(data->chord_ht)); break; case EXPORT_MN_ANGLE: ProUtilMsgPrint("gen", "TEST %0s", "The angle control (between 0.0 and 1.0):"); error = ProMessageDoubleRead(NULL, &(data->angle_cntrl)); break; case EXPORT_MN_QUILT: ProUtilMsgPrint("gen", "TEST %0s", "Include quilt surfaces or not(Y/N):"); data->include_quilts = (ProBoolean)(ProUtilYesnoGet((char*)"Yes") == PRO_B_TRUE); break; case EXPORT_MN_OPT: ProUtilMsgPrint("gen", "TEST %0s", "Enable optimization(Y/N):"); data->optimization = (ProBoolean)(ProUtilYesnoGet((char*)"Yes") == PRO_B_TRUE); break; } ProTestExportSetup(data); return(PRO_TK_NO_ERROR); } /*=================================================================*\ FUNCTION : ProTestExportMainMenu() PURPOSE : Create "TkModify" menu \*=================================================================*/ ProError ProTestExportMainMenu(ProMdl mdl) { int n; ProError error; static ProUtilMenuButtons TkMenu[] ={ {"ExportGeom", -1, TEST_CALL_PRO_MENU_DELETE}, {"-WireFrame", EXPORT_MN_WIREFRAME, 0}, {"-Render", EXPORT_MN_RENDER, 0}, {"-Dump", EXPORT_MN_DUMP, 0}, {"-Setup", EXPORT_MN_SETUP, 0}, {"-Quit",-1, TEST_CALL_PRO_MENU_DELETE}, {"", -1,0}}; static ProTestExportData data; static int FirstCall =0; if (mdl == NULL) { error = ProMdlCurrentGet(&mdl); TEST_CALL_REPORT ("ProMdlCurrentGet()", "ProTestExportMainMenu()", error, error != PRO_TK_NO_ERROR); if(error != PRO_TK_NO_ERROR) return(error); } /*--------------------------------------------------------------------*\ Initialization default data \*--------------------------------------------------------------------*/ if(FirstCall == 0) { data.chord_ht = 0.1; data.angle_cntrl = 0.5; data.include_quilts = PRO_B_FALSE; data.optimization = PRO_B_FALSE; FirstCall++; } /*--------------------------------------------------------------------*\ Show "ExportGeom" menu \*--------------------------------------------------------------------*/ do { error = ProUtilMenuIntValueSelect(TkMenu, &n); if((error!=PRO_TK_NO_ERROR)||(n<0)) return(PRO_TK_NO_ERROR); data.mdl = mdl; switch(n) { case EXPORT_MN_WIREFRAME: case EXPORT_MN_RENDER: case EXPORT_MN_DUMP: data.file_format = n; error = ProTestExportTo(&data); break; case EXPORT_MN_SETUP: error = ProTestExportSetup(&data); break; } } while(1); return(error); }