Files
2025-12-15 23:22:33 +08:00

490 lines
20 KiB
C++

/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
/**
\file TranslateToPkParts.cpp
This file demonstrates how to load a CAD file and import the data into a Parasolid session.
- Load a CAD file with HOOPS Exchange
- Call the A3DSDKHOOPSExchangeLoader::Export() function
- Export to Parasolid with PK_PART_transmit (Parasolid API)
In order to compile, you need to:
1. On Windows
- Set up the PARASOLID_INSTALL_DIR and PARASOLID_INSTALL_DIR_64 environment variables to your Parasolid folder using the property sheet PARASOLID with the "User macros" field;
- Save the property sheet.
- Then you can build it.
2. On Linux
- Set up the PARASOLID_INSTALL_DIR environment variable to your Parasolid folder in the makefile
- Then you can build it.
In order to run, you need to:
Common:
- Set up the P_SCHEMA environment variable to your Parasolid schema folder (ending with \base\schema);
- Copy pskernel.dll or libpskernel.so to your working directory (the HOOPS Exchange library binary folder).
Windows-specific:
- Provide the correct working directory, i.e. the HOOPS Exchange binary folder (i.e. ..\..\..\..\bin\win64_v142);
this setting is located in Project Properties --> Configuration Properties --> Debugging --> Working Directory;
- Set up the command line
- Then you can run it.
Linux-specific:
- Set up the LD_LIBRARY_PATH=$PARASOLID_INSTALL_DIR/shared_object:../../../../bin/linux32|linux64
- Then you can run it.
***********************************************************************************************************************/
#if defined(_MSC_VER) && !defined(PARASOLID_INSTALL_DIR)
# error PARASOLID_INSTALL_DIR environment variable required
#endif
#include <parasolid_kernel.h>
#ifndef _MSC_VER
# include <dlfcn.h>
#endif
#define INITIALIZE_A3D_API
#include <A3DSDKIncludes.h>
#include <hoops_license.h>
#include "../common.hpp"
//######################################################################################################################
extern "C"
{
extern void FSTART(int*);
extern void FABORT(int*);
extern void FSTOP(int*);
extern void FMALLO(int*, char**, int*);
extern void FMFREE(int*, char**, int*);
extern void GOSGMT(const int*, const int*, const int*, const int*, const double*, const int*, const int*, int*);
extern void GOOPSG(const int*, const int*, const int*, const int*, const double*, const int*, const int*, int*);
extern void GOCLSG(const int*, const int*, const int*, const int*, const double*, const int*, const int*, int*);
extern void GOPIXL(const int*, const double*, const int*, const int*, int*);
extern void GOOPPX(const int*, const double*, const int*, const int*, int*);
extern void GOCLPX(const int*, const double*, const int*, const int*, int*);
extern void FFOPRD(const int*, const int*, const char*, const int*, const int*, int*, int*);
extern void FFOPWR(const int*, const int*, const char*, const int*, const char*, const int*, int*, int*);
extern void FFCLOS(const int*, const int*, const int*, int*);
extern void FFREAD(const int*, const int*, const int*, char*, int*, int*);
extern void FFWRIT(const int*, const int*, const int*, const char*, int*);
extern void FFOPRB(const int*, const int*, const int*, int*, int*, int*);
extern void FFSEEK(const int*, const int*, const int*, int*);
extern void FFTELL(const int*, const int*, int*, int*);
extern PK_ERROR_code_t FRU_delta_open_for_write(PK_PMARK_t, PK_DELTA_t*);
extern PK_ERROR_code_t FRU_delta_open_for_read(PK_DELTA_t);
extern PK_ERROR_code_t FRU_delta_write(PK_DELTA_t, unsigned, const char*);
extern PK_ERROR_code_t FRU_delta_read(PK_DELTA_t, unsigned, char*);
extern PK_ERROR_code_t FRU_delta_delete(PK_DELTA_t);
extern PK_ERROR_code_t FRU_delta_close(PK_DELTA_t);
extern int FRU__delta_init(int action);
}
//######################################################################################################################
bool ParasolidInitialize()
{
PK_ERROR_code_t pk_error;
PK_SESSION_frustrum_t ps_file_handlers;
PK_MEMORY_frustrum_t ps_memory_handlers;
PK_SESSION_frustrum_o_m(ps_file_handlers);
ps_file_handlers.fstart = FSTART;
ps_file_handlers.fabort = FABORT;
ps_file_handlers.fstop = FSTOP;
ps_file_handlers.fmallo = FMALLO;
ps_file_handlers.fmfree = FMFREE;
ps_file_handlers.gosgmt = GOSGMT;
ps_file_handlers.goopsg = GOOPSG;
ps_file_handlers.goclsg = GOCLSG;
ps_file_handlers.gopixl = GOPIXL;
ps_file_handlers.gooppx = GOOPPX;
ps_file_handlers.goclpx = GOCLPX;
ps_file_handlers.ffoprd = FFOPRD;
ps_file_handlers.ffopwr = FFOPWR;
ps_file_handlers.ffclos = FFCLOS;
ps_file_handlers.ffread = FFREAD;
ps_file_handlers.ffwrit = FFWRIT;
ps_file_handlers.ffoprb = FFOPRB;
ps_file_handlers.ffseek = FFSEEK;
ps_file_handlers.fftell = FFTELL;
pk_error = PK_SESSION_register_frustrum(&ps_file_handlers);
if (pk_error != PK_ERROR_no_errors)
return false;
ps_memory_handlers.alloc_fn = malloc;
ps_memory_handlers.free_fn = free;
pk_error = PK_MEMORY_register_callbacks(ps_memory_handlers);
if (pk_error != PK_ERROR_no_errors)
return false;
PK_DELTA_frustrum_t deltaFrustrum;
deltaFrustrum.open_for_write_fn = FRU_delta_open_for_write;
deltaFrustrum.open_for_read_fn = FRU_delta_open_for_read;
deltaFrustrum.close_fn = FRU_delta_close;
deltaFrustrum.write_fn = FRU_delta_write;
deltaFrustrum.read_fn = FRU_delta_read;
deltaFrustrum.delete_fn = FRU_delta_delete;
pk_error = PK_DELTA_register_callbacks(deltaFrustrum);
if (pk_error != PK_ERROR_no_errors)
return false;
FRU__delta_init(1);
PK_SESSION_start_o_t session_options;
PK_SESSION_start_o_m(session_options);
session_options.user_field = 0;
session_options.journal_file = NULL;
pk_error = PK_SESSION_start(&session_options);
return pk_error == PK_ERROR_no_errors;
}
//######################################################################################################################
void ParasolidTerminate()
{
FRU__delta_init(2);
PK_SESSION_stop();
}
#ifdef _MSC_VER
# include <windows.h>
#elif defined (__linux__) && !defined(__APPLE__)
# include <unistd.h>
#elif defined (__APPLE__)
# include <sys/param.h>
# include <sys/sysctl.h>
#else
#error TSystem not implemented on this platform
#endif
static int getLogicalProcessor()
{
#ifdef _MSC_VER
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif defined (__APPLE__)
int nm[2];
size_t len = 4;
uint32_t count;
nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
sysctl(nm, 2, &count, &len, NULL, 0);
if (count < 1) {
nm[1] = HW_NCPU;
sysctl(nm, 2, &count, &len, NULL, 0);
if (count < 1) { count = 1; }
}
return count;
#elif defined (__linux__) && !defined (__APPLE__)
return sysconf(_SC_NPROCESSORS_ONLN);
#else
return 1;
#endif
}
static MY_CHAR acSrcFileName[_MAX_PATH * 2];
static MY_CHAR acDstFileName[_MAX_PATH * 2];
static MY_CHAR acLogFileName[_MAX_PATH * 2];
//######################################################################################################################
// Main function
#ifdef _MSC_VER
int wmain(A3DInt32 iArgc, A3DUniChar** ppcArgv)
#else
int main(A3DInt32 iArgc, A3DUTF8Char** ppcArgv)
#endif
{
//
// ### COMMAND LINE ARGUMENTS
//
for (int iArg = 0; iArg < iArgc; iArg++)
MY_PRINTF2("%s ", ppcArgv[iArg]);
MY_PRINTF("\n");
if (iArgc < 2)
{
MY_PRINTF2("Usage:\n %s <input CAD file> <output Parasolid file> [options]\n", ppcArgv[0]);
MY_PRINTF(" Default output Parasolid file is [input CAD file].xmt_txt\n\n");
MY_PRINTF(" Default output LOG file is [output Parasolid file].xmt_txt_Log.txt\n\n");
MY_PRINTF(" options:\n");
MY_PRINTF(" -log filename : file to dump messages into. Default is <OutputParasolid_path>_Log.txt\n");
MY_PRINTF(" -healing 0|1|2 : healing mode (it activates the Parasolid healing); 0 = off (by default), 1 = on all the time, 2 = on only for data not coming from Parasolid\n");
MY_PRINTF(" -accurate 0|1|2 : accurate mode (it replaces tolerant edges by accurate ones if possible); 0 = off (by default), 1 = on all the time, 2 = on only for data not coming from Parasolid \n");
MY_PRINTF(" -simplify 0|1|2 : simplify mode (it replaces curves and surfaces by simplified geometry if possible); 0 = off (by default), 1 = on all the time, 2 = on only for data not coming from Parasolid \n");
MY_PRINTF(" -merge 0|1|2 : merge mode (it merges geomerties and topologies if possible); 0 = off (by default), 1 = on all the time, 2 = on only for data not coming from Parasolid \n");
MY_PRINTF(" -disjoin 0|1 : disjoin mode (it removes some faces from the bodies to avoid PK_FACE_state_bad_face_face_c errors); 0 = off (by default), 1 = on\n");
MY_PRINTF(" -sew 0|1 : sew mode (it sews bodies together if possible); 0 = off, 1 = on (by default)\n");
MY_PRINTF(" -sewexchange 0|1 : sew mode (it sews bodies together if possible); 0 = off, 1 = on (by default) Only applied to non parasolid based formats \n");
MY_PRINTF(" -sewingtolerance real: sewing tolerance for sew mode (1e-4 millimeters by default)\n");
MY_PRINTF(" -iges 0|1 : export to iges file format 0 = off (by default), 1 = on\n");
MY_PRINTF(" -step 0|1 : export to step file format 0 = off (by default), 1 = on\n");
MY_PRINTF(" -multiproc 0|1 : unable multiprocessor computation 0 = off (by default), 1 = on\n");
return A3D_ERROR;
}
int iNbPkParts = 0;
PK_PART_t* pPkParts = 0;
A3DExport sExport(&iNbPkParts, &pPkParts); // see A3DSDKInternalConvert.hxx for import and export detailed parameters
sExport.m_sTranslateToPkPartsData.m_eHealing = kA3DE_HEALING_NO; // Use healing if needed, and on-demand if possible
sExport.m_sTranslateToPkPartsData.m_eComputeAccurateEdges = kA3DE_ACCURATE_NO;
sExport.m_sTranslateToPkPartsData.m_eSimplifyGeometry = kA3DE_SIMPLIFY_NO;
sExport.m_sTranslateToPkPartsData.m_eMergeEntities = kA3DE_MERGE_NO;
sExport.m_sTranslateToPkPartsData.m_bDisjoinIfFaceFaceError = false;
sExport.m_sTranslateToPkPartsData.m_bSew = true;
sExport.m_sTranslateToPkPartsData.m_dSewingTolerance = 1e-4;
sExport.m_sTranslateToPkPartsData.m_pcPSBodyShopPath = const_cast<A3DUTF8Char*>("");
sExport.m_sTranslateToPkPartsData.m_bUseColour2Attribute = true;
sExport.m_sTranslateToPkPartsData.m_uiNbProc = 0;
sExport.m_sExportParasolidData.m_bBStrictAssemblyStructure = true;
bool bStep = false;
bool bIges = false;
bool bSewExchange = true;
double dSewTolerance = 0.1;
MY_CHAR* _pSrcFileName = NULL;
MY_CHAR* _pDstFileName = NULL;
MY_CHAR* _pLogFileName = NULL;
for (int iArg = 1; iArg < iArgc; iArg++)
{
if (ppcArgv[iArg] != NULL && ppcArgv[iArg][0] == '-')
{
if (!MY_STRCMP(ppcArgv[iArg], "-log") && iArg + 1 < iArgc)
{
_pLogFileName = ppcArgv[iArg + 1];
iArg++;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-healing"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: sExport.m_sTranslateToPkPartsData.m_eHealing = kA3DE_HEALING_NO; break;
case 1: sExport.m_sTranslateToPkPartsData.m_eHealing = kA3DE_HEALING_YES; break;
case 2: sExport.m_sTranslateToPkPartsData.m_eHealing = kA3DE_HEALING_ONLY_IF_NOT_PARASOLID; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-accurate"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: sExport.m_sTranslateToPkPartsData.m_eComputeAccurateEdges = kA3DE_ACCURATE_NO; break;
case 1: sExport.m_sTranslateToPkPartsData.m_eComputeAccurateEdges = kA3DE_ACCURATE_YES; break;
case 2: sExport.m_sTranslateToPkPartsData.m_eComputeAccurateEdges = kA3DE_ACCURATE_ONLY_IF_NOT_PARASOLID; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-simplify"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: sExport.m_sTranslateToPkPartsData.m_eSimplifyGeometry = kA3DE_SIMPLIFY_NO; break;
case 1: sExport.m_sTranslateToPkPartsData.m_eSimplifyGeometry = kA3DE_SIMPLIFY_YES; break;
case 2: sExport.m_sTranslateToPkPartsData.m_eSimplifyGeometry = kA3DE_SIMPLIFY_ONLY_IF_NOT_PARASOLID; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-merge"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: sExport.m_sTranslateToPkPartsData.m_eMergeEntities = kA3DE_MERGE_NO; break;
case 1: sExport.m_sTranslateToPkPartsData.m_eMergeEntities = kA3DE_MERGE_YES; break;
case 2: sExport.m_sTranslateToPkPartsData.m_eMergeEntities = kA3DE_MERGE_ONLY_IF_NOT_PARASOLID; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-disjoin"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: sExport.m_sTranslateToPkPartsData.m_bDisjoinIfFaceFaceError = false; break;
case 1: sExport.m_sTranslateToPkPartsData.m_bDisjoinIfFaceFaceError = true; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-sew"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: sExport.m_sTranslateToPkPartsData.m_bSew = false; break;
case 1: sExport.m_sTranslateToPkPartsData.m_bSew = true; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-sewingtolerance"))
{
dSewTolerance = (MY_ATOF(ppcArgv[++iArg]));
sExport.m_sTranslateToPkPartsData.m_dSewingTolerance = dSewTolerance * 0.001;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-bodyshop"))
{
if ((MY_ATOI(ppcArgv[++iArg])) == 0)
sExport.m_sTranslateToPkPartsData.m_pcPSBodyShopPath = NULL;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-step"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 1: bStep = true; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-iges"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 1: bIges = true; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-sewexchange"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 0: bSewExchange = false; break;
case 1: bSewExchange = true; break;
}
else if (!MY_STRCMP(ppcArgv[iArg], "-multiproc"))
switch (MY_ATOI(ppcArgv[++iArg]))
{
case 1: sExport.m_sTranslateToPkPartsData.m_uiNbProc = getLogicalProcessor(); break;
}
}
else
{
if (_pSrcFileName == NULL) _pSrcFileName = ppcArgv[iArg];
else if (_pDstFileName == NULL) _pDstFileName = ppcArgv[iArg];
else if (_pLogFileName == NULL) _pLogFileName = ppcArgv[iArg];
}
}
//
if (_pSrcFileName == NULL) MY_STRCPY(acSrcFileName, DEFAULT_INPUT_CAD);
else MY_STRCPY(acSrcFileName, _pSrcFileName);
if (_pDstFileName == NULL) MY_STRCPY(acDstFileName, acSrcFileName); // The extension .xmt_txt will be added by the API
else MY_STRCPY(acDstFileName, _pDstFileName);
if (_pLogFileName == NULL) MY_SPRINTF(acLogFileName, "%s.xmt_txt_Log.txt", acDstFileName);
else MY_STRCPY(acLogFileName, _pLogFileName);
GetLogFile(acLogFileName); // Initialize log file
//
// ### INITIALIZE HOOPS EXCHANGE
//
#ifdef _MSC_VER
const TCHAR* pcLibPath = _T(""); // As Documented, working directory must be install directory.
#else
const char* pcLibPath = "";
#endif
A3DSDKHOOPSExchangeLoader sHoopsExchangeLoader(pcLibPath, HOOPS_LICENSE);
CHECK_RET(sHoopsExchangeLoader.m_eSDKStatus);
CHECK_RET(A3DDllSetCallbacksMemory(CheckMalloc, CheckFree));
CHECK_RET(A3DDllSetCallbacksReport(PrintLogMessage, PrintLogWarning, PrintLogError));
//Check Parsolid Schema path
char *workbuff = getenv("P_SCHEMA");
if (workbuff)
{
PrintConstLogMessage("P_SCHEMA="); PrintLogMessage(workbuff); PrintConstLogMessage("\n");
}
else
PrintConstLogMessage("P_SCHEMA= missing\n");
// initialize Parasolid
PrintConstLogMessage("Initializing Parasolid...\n");
if (!ParasolidInitialize())
{
PrintConstLogError(0, "Parasolid initialization failure\n");
return A3D_ERROR;
}
const struct ParasolidCleaner
{
~ParasolidCleaner()
{
ParasolidTerminate();
}
} sParasolidCleaner;
//
// ### PROCESS SAMPLE CODE
//
// Import Input CAD file
A3DImport sImport(acSrcFileName); // see A3DSDKInternalConvert.hxx for import and export detailed parameters
if (bStep || bIges)
{
// direct export to Iges or Step
#ifdef _MSC_VER
A3DUniChar sDirectOutputPath[_MAX_PATH];
swprintf(sDirectOutputPath, _MAX_PATH, (bIges) ? _T("%s.igs") : _T("%s.stp"), acDstFileName);
#else
A3DUTF8Char sDirectOutputPath[_MAX_PATH];
sprintf(sDirectOutputPath, (bIges) ? "%s.igs" : "%s.stp", acDstFileName);
#endif
A3DExport sDirectExport(sDirectOutputPath);
PrintConstLogMessage("Conversion...\n");
CHECK_RET(sHoopsExchangeLoader.Convert(sImport, sDirectExport));
return A3D_SUCCESS;
}
// ----------------------------------------------------------------------------
// export to parasolid with the bridge
sImport.m_sLoadData.m_sSpecifics.m_sParasolid.m_bKeepParsedEntities = true;
sImport.m_sLoadData.m_sSpecifics.m_sStep.m_bHealOrientations = true;
sImport.m_sLoadData.m_sGeneral.m_eReadGeomTessMode = kA3DReadGeomAndTess;
sImport.m_sLoadData.m_sTessellation.m_eTessellationLevelOfDetail = kA3DTessLODMedium;
PrintConstLogMessage("TranslateToPkParts...\n");
A3DStatus iRet = sHoopsExchangeLoader.Import(sImport);
if (iRet != A3D_SUCCESS && iRet != A3D_LOAD_MISSING_COMPONENTS)
CHECK_RET(iRet);
if (bSewExchange)
{
A3DAsmModelFileData sModelFileData;
A3D_INITIALIZE_DATA(A3DAsmModelFileData, sModelFileData);
CHECK_RET(A3DAsmModelFileGet(sHoopsExchangeLoader.m_psModelFile, &sModelFileData));
A3DSewOptionsData sSewData;
A3D_INITIALIZE_DATA(A3DSewOptionsData, sSewData);
if (sModelFileData.m_eModellerType != kA3DModellerJt
&& sModelFileData.m_eModellerType != kA3DModellerSlw
&& sModelFileData.m_eModellerType != kA3DModellerUnigraphics
&& sModelFileData.m_eModellerType != kA3DModellerParasolid
&& sModelFileData.m_eModellerType != kA3DModellerSE)
CHECK_RET(A3DAsmModelFileSew(&sHoopsExchangeLoader.m_psModelFile, dSewTolerance, &sSewData));
CHECK_RET(A3DAsmModelFileGet(nullptr, &sModelFileData));
}
// ----------------------------------------------------------------------------
switch (sHoopsExchangeLoader.Export(sExport))
{
case A3D_SUCCESS: break;
case A3D_HEPB_MISSING: PrintConstLogError(0, "Can't load HEPB library"); return A3D_ERROR;
case A3D_PARASOLID_ERROR_970: PrintConstLogError(0, "Can't access Parasolid schema"); return A3D_ERROR;
case A3D_PARASOLID_ERROR_5022: PrintConstLogError(0, "Bad Parasolid version"); return A3D_ERROR;
case A3D_BODYSHOP_MISSING: PrintConstLogError(0, "Can't load BodyShop library"); return A3D_ERROR;
case A3D_WRITE_KEEPPARSEDENTITIES_DISABLED: PrintConstLogError(0, "KeepParsedEntities reading option must be enabled when using TranslateToPkParts"); return A3D_ERROR;
default: PrintConstLogError(0, "TranslateToPkParts Failure"); return A3D_ERROR;
}
A3DUTF8Char acOutPutKeyUTF8[_MAX_PATH];
#ifdef _MSC_VER
A3DMiscUTF16ToUTF8(acDstFileName, acOutPutKeyUTF8);
#else
MY_STRCPY(acOutPutKeyUTF8, acDstFileName);
#endif
if (!iNbPkParts)
{
PrintConstLogError(0, "No part to transmit\n");
return A3D_SUCCESS;
}
PrintConstLogMessage("PK_PART_transmit...\n");
PK_PART_transmit_o_t sTransmitOptions;
PK_PART_transmit_o_m(sTransmitOptions);
sTransmitOptions.transmit_format = PK_transmit_format_text_c;
// in order to use PK_PART_transmit_u (for Unicode names), an Unicode frustrum must be defined
PK_ERROR_code_t eTransmitStatus = PK_PART_transmit(iNbPkParts, pPkParts, acOutPutKeyUTF8, &sTransmitOptions);
// Free Parasolid table (user has to free this pointer)
PK_MEMORY_free(pPkParts);
if (eTransmitStatus)
return eTransmitStatus;
//
// ### TERMINATE HOOPS EXCHANGE
//
// Check memory allocations
return (int)ListLeaks();
}