/*
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);
}