/*********************************************************************************************************************** * * 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 manufacturing_mbe.cpp ***********************************************************************************************************************/ #define INITIALIZE_A3D_API #define HOOPS_PRODUCT_PUBLISH_ADVANCED #include #include #include "../common.hpp" #include "../CommonInit.h" #include #include #include // default sample arguments: // in visual c++: the current directory is set through properties to $OutDir, which is $(Platform)\$(Configuration) // in linux: the current directory is supposed to be the same as this cpp file #ifdef _MSC_VER # define IN_3DFILE SAMPLES_DATA_DIRECTORY"\\prc\\Flange287.prc" # define IN_PDF_TEMPLATE SAMPLES_DATA_DIRECTORY"\\pdf_templates\\manufacturing_mbeTemplate.pdf" # define IN_POSTERIMAGE SAMPLES_DATA_DIRECTORY"\\images\\empty.jpg" # define ATTACHED_FILE_1 SAMPLES_DATA_DIRECTORY"\\step\\Flange287.stp" # define ATTACHED_FILE_2 SAMPLES_DATA_DIRECTORY"\\jt\\Flange287.jt" # define OUT_FILE SAMPLES_PUBLISH_GALLERY_DIRECTORY"\\sample_manufacturing_mbe.pdf" #else # define IN_3DFILE SAMPLES_DATA_DIRECTORY"/prc/Flange287.prc" # define IN_PDF_TEMPLATE SAMPLES_DATA_DIRECTORY"/pdf_templates/manufacturing_mbeTemplate.pdf" # define IN_POSTERIMAGE SAMPLES_DATA_DIRECTORY"/images/empty.jpg" # define ATTACHED_FILE_1 SAMPLES_DATA_DIRECTORY"/step/Flange287.stp" # define ATTACHED_FILE_2 SAMPLES_DATA_DIRECTORY"/jt/Flange287.jt" # define OUT_FILE SAMPLES_PUBLISH_GALLERY_DIRECTORY"/sample_manufacturing_mbe.pdf" #endif std::string intToString(int i) { std::ostringstream oss; oss << i; return oss.str(); } //###################################################################################################################### A3DVoid mallocAndSetString(const A3DUTF8Char* srcString, A3DUTF8Char*& destString) { // we return empty strings rather than NULL because some strings usages crash with NULL values // (for example std::string xx = NULL crashes !) unsigned int uiSize = (unsigned int)(srcString ? strlen(srcString) : 0); destString = (A3DUTF8Char*)malloc((uiSize + 1) * sizeof(A3DUTF8Char)); if (uiSize > 0) { strcpy(destString, srcString); } destString[uiSize] = 0; } //###################################################################################################################### // cleaning functions void stFreeTable(A3DPDFDataTableData &sTableData) { for (A3DUns32 ir = 0; ir < sTableData.m_iNbRows ; ir++) { for(A3DUns32 ic = 0; ic < sTableData.m_iNbCols ; ic++) free(sTableData.m_ppcTexts[ir*sTableData.m_iNbCols+ic]); } free(sTableData.m_ppcTexts); } void stFreeTable3DViews(A3DPDFTable3DViewsData &sTable3DViewsData) { if (sTable3DViewsData.m_piViewIndexes) free(sTable3DViewsData.m_piViewIndexes); if (sTable3DViewsData.m_ppcViewLabels) { for(A3DUns32 ic = 0; ic < sTable3DViewsData.m_iNbViews ; ic++) if (sTable3DViewsData.m_ppcViewLabels[ic]) free(sTable3DViewsData.m_ppcViewLabels[ic]); free(sTable3DViewsData.m_ppcViewLabels); } if (sTable3DViewsData.m_ppImages) free(sTable3DViewsData.m_ppImages); if (sTable3DViewsData.m_pDataTableData) { for (A3DUns32 ir = 0; ir < sTable3DViewsData.m_pDataTableData->m_iNbRows ; ir++) { for(A3DUns32 ic = 0; ic < sTable3DViewsData.m_pDataTableData->m_iNbCols ; ic++) free(sTable3DViewsData.m_pDataTableData->m_ppcTexts[ir*sTable3DViewsData.m_pDataTableData->m_iNbCols+ic]); } } } void stFreeRelationship(A3DPDFDataRelationshipData &sRelationshipData) { free(sRelationshipData.m_pMapIndexes); } //###################################################################################################################### A3DStatus stCreateTable(A3DPDFDocument* pDoc, const std::vector > &aRows, A3DPDFDataTable*& pDataTable) { A3DStatus iRet = A3D_SUCCESS; A3DUns32 iNbRows = (A3DUns32)aRows.size(); A3DUns32 iNbCols = (A3DUns32)aRows[0].size(); A3DPDFDataTableData sTableData; A3D_INITIALIZE_DATA(A3DPDFDataTableData, sTableData); sTableData.m_iNbRows = iNbRows; sTableData.m_iNbCols = iNbCols; sTableData.m_ppcTexts = (A3DUTF8Char**) malloc(iNbRows * iNbCols * A3DUns32(sizeof(A3DUTF8Char*))); for (A3DUns32 ir = 0; ir < iNbRows ; ir++) { for(A3DUns32 ic = 0; ic < iNbCols ; ic++) mallocAndSetString( aRows[ir][ic].c_str(), // src sTableData.m_ppcTexts[ir*iNbCols+ic]); // dest } CHECK_RET(A3DPDFDataTableCreate(pDoc, &sTableData, &pDataTable)); stFreeTable(sTableData); return iRet; } A3DStatus stCreateRelationship(A3DPDFDocument* pDoc, std::vector< std::pair > &aMapIndexes, A3DPDFDataTable* pDataTableSource, A3DPDFDataTable* pDataTableTarget) { A3DStatus iRet = A3D_SUCCESS; A3DUns32 iNbRows = (A3DUns32)aMapIndexes.size(); A3DPDFDataRelationshipData sRelationshipData; A3D_INITIALIZE_DATA(A3DPDFDataRelationshipData, sRelationshipData); sRelationshipData.m_iSizeMap = iNbRows; sRelationshipData.m_pDataTableSource = pDataTableSource; sRelationshipData.m_pDataTableTarget = pDataTableTarget; sRelationshipData.m_pMapIndexes = (A3DPDFMapIndexData *)malloc(iNbRows*sizeof(A3DPDFMapIndexData)); memset(sRelationshipData.m_pMapIndexes, 0, iNbRows*sizeof(A3DPDFMapIndexData)); for (A3DUns32 ir = 0; ir < iNbRows ; ir++) { sRelationshipData.m_pMapIndexes[ir].m_aiIndexes[0] = (A3DInt32)(aMapIndexes[ir].first); sRelationshipData.m_pMapIndexes[ir].m_aiIndexes[1] = (A3DInt32)(aMapIndexes[ir].second); } CHECK_RET(A3DPDFDataRelationshipCreate(pDoc, &sRelationshipData)); stFreeRelationship(sRelationshipData); return iRet; } //###################################################################################################################### A3DStatus AddViewCarousel(A3DPDFDocument* pDoc, A3DPDFPage* pPage, std::vector& aViewCarouselButPrevNext, std::vector& aViewCarouselButtons, A3DPDF3DViewCarousel** ppViewCarousel) { A3DStatus iRet = A3D_SUCCESS; A3DUTF8Char* ppButtonsNamesPrevNext[2]; A3DUTF8Char** ppButtonsNames = (A3DUTF8Char**)malloc(aViewCarouselButtons.size() * A3DUns32(sizeof(A3DUTF8Char*))); for (size_t i=0 ; i > aRows; std::vector aOneRow; aRows.clear(); aOneRow.clear(); aOneRow.push_back("Note (1)"); aOneRow.push_back("(1) See specification document for plating runout specifications."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (2)"); aOneRow.push_back("(2) PS1031-8 Termination of chromed surfaces. No chrome plate on edge break."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (3)"); aOneRow.push_back("(3) PS101-7P Chromium plate 0.10 minimum thickness."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (4)"); aOneRow.push_back("(4) PS1031-1 termination of chromed surfaces."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (5)"); aOneRow.push_back("(5) PS1031-2 termination of chromed surfaces."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (6)"); aOneRow.push_back("(6) PS1031-5 termination of chromed surfaces."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (7)"); aOneRow.push_back("(7) Do not shot peen."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (8)"); aOneRow.push_back("(8) PS134 glass bead peen."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (9)"); aOneRow.push_back("(9) Cadmium plate fade out permissible in this bore."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (10)"); aOneRow.push_back("(10) Production salvage allowance applies."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (11)"); aOneRow.push_back("(11) PS405-341 Electrochemical etch 0.1/0.05 deep or PS405-12. Hand engrave part or serial numbers."); aRows.push_back(aOneRow); aOneRow.clear(); aOneRow.push_back("Note (12)"); aOneRow.push_back("(12) Hardness test Rc-53-55 on indicated surface. Subsequently machined. No indentation allowed on finished surface."); aRows.push_back(aOneRow); return stCreateTable(pDoc, aRows, pDataTable); } A3DStatus stCreateTable_3DModel(A3DPDFDocument* pDoc, A3DAsmModelFile* pModelFile, A3DRWParamsPrcWriteHelper* pA3DRWParamsPrcWriteHelper, int& iKeyNode3dUID, A3DPDFDataTable*& pDataTable3D, A3DPDFDataTable*& pDataTable_PmiNotes) { A3DStatus iRet = A3D_SUCCESS; // structure for Tables definitions std::vector > aTable3DRows; // structure for Relationships definitions std::vector< std::pair > aMapIndexes_3dToPmiNotes; // parse the 3D PDF nodes A3DPDFModelFileNodesData* pModelFileNodesInfo = NULL; CHECK_RET(A3DPDFGetModelFileNodes(pModelFile, pA3DRWParamsPrcWriteHelper, &pModelFileNodesInfo)); std::vector aOneRow; for (size_t inodein3d = 0; inodein3d < (size_t)pModelFileNodesInfo->m_iNbNodes; inodein3d++) { A3DPDFNodeData* nodeInfos = pModelFileNodesInfo->m_ppNodes[inodein3d]; // in this sample, the 3D nodes involved in datamodel are the subset of Pmis that have a note associated if (nodeInfos->m_eNodeType==kA3DPDFNodePMI) { std::string sNodeName = nodeInfos->m_pcName; // hard coded section for adding corresponding notes // typically, these information would be stored as attribute, or extracted from a PLM bool bFoundIdxinpminotes = true; size_t idxinpminotes; if (sNodeName == "Flag Note .14") idxinpminotes = 8; else if (sNodeName == "Flag Note .15") idxinpminotes = 11; else if (sNodeName == "Flag Note .16") idxinpminotes = 10; else if (sNodeName == "Flag Note .31") idxinpminotes = 9; else if (sNodeName == "Flag Note .32") idxinpminotes = 8; else if (sNodeName == "Flag Note .33") idxinpminotes = 8; else if (sNodeName == "Flag Note .34") idxinpminotes = 7; else if (sNodeName == "Flag Note .35") idxinpminotes = 6; else if (sNodeName == "Flag Note .38") idxinpminotes = 5; else if (sNodeName == "Flag Note .40") idxinpminotes = 8; else if (sNodeName == "Flag Note .41") idxinpminotes = 8; else if (sNodeName == "Flag Note .42") idxinpminotes = 2; else if (sNodeName == "Flag Note .43") idxinpminotes = 0; else if (sNodeName == "Flag Note .44") idxinpminotes = 1; else if (sNodeName == "Flag Note .45") idxinpminotes = 0; else if (sNodeName == "Flag Note .46") idxinpminotes = 3; else if (sNodeName == "Flag Note .47") idxinpminotes = 0; else if (sNodeName == "Flag Note .48") idxinpminotes = 0; else if (sNodeName == "Flag Note .49") idxinpminotes = 4; else if (sNodeName == "Flag Note .50") idxinpminotes = 0; else if (sNodeName == "Flag Note .51") idxinpminotes = 0; else if (sNodeName == "Flag Note .52") idxinpminotes = 2; else bFoundIdxinpminotes = false; if (bFoundIdxinpminotes) { aOneRow.clear(); aOneRow.push_back(nodeInfos->m_pcNodeUid); iKeyNode3dUID = (int)aOneRow.size()-1; aOneRow.push_back(nodeInfos->m_pcName); aTable3DRows.push_back(aOneRow); // create relationship between 3d node and pminotes entry size_t idxin3dnodes = aTable3DRows.size()-1; aMapIndexes_3dToPmiNotes.push_back( std::make_pair (idxin3dnodes, idxinpminotes) ); } } } iRet = stCreateTable(pDoc, aTable3DRows, pDataTable3D); iRet = stCreateRelationship(pDoc, aMapIndexes_3dToPmiNotes, pDataTable3D, pDataTable_PmiNotes); CHECK_RET(A3DPDFGetModelFileNodes(nullptr, nullptr, &pModelFileNodesInfo)); return iRet; } A3DStatus BuildPDFDocument() { A3DStatus iRet = A3D_SUCCESS; // create empty document A3DPDFDocument* pDoc = NULL; CHECK_RET(A3DPDFDocumentCreateEmpty(&pDoc)); if(pDoc != NULL) { A3DPDFPage* pPage = NULL; // the NULL suffix string keeps the same field names CHECK_RET(A3DPDFDocumentAppendPageFromPDFFileAndSuffixFields(pDoc, IN_PDF_TEMPLATE, NULL, &pPage)); if(pPage != NULL) { // reading the input file; the file can be disposed of afterwards. A3DPDF3DStream* pStream; A3DAsmModelFile* pModelFile; A3DRWParamsLoadData sReadParam; A3D_INITIALIZE_DATA(A3DRWParamsLoadData, sReadParam); sReadParam.m_sGeneral.m_bReadSolids = true; sReadParam.m_sGeneral.m_bReadSurfaces = true; sReadParam.m_sGeneral.m_bReadWireframes = true; sReadParam.m_sGeneral.m_bReadPmis = true; sReadParam.m_sGeneral.m_bReadAttributes = true; sReadParam.m_sGeneral.m_bReadHiddenObjects = false; sReadParam.m_sGeneral.m_bReadConstructionAndReferences = false; sReadParam.m_sGeneral.m_bReadActiveFilter = true; sReadParam.m_sGeneral.m_eReadingMode2D3D = kA3DRead_3D; sReadParam.m_sGeneral.m_eReadGeomTessMode = kA3DReadGeomAndTess; sReadParam.m_sGeneral.m_eDefaultUnit = kA3DUnitUnknown; sReadParam.m_sPmi.m_bAlwaysSubstituteFont = true; sReadParam.m_sPmi.m_pcSubstitutionFont = const_cast("Arial Black"); sReadParam.m_sTessellation.m_eTessellationLevelOfDetail = kA3DTessLODMedium; sReadParam.m_sMultiEntries.m_bLoadDefault = true; sReadParam.m_sAssembly.m_bUseRootDirectory = true; CHECK_RET(A3DAsmModelFileLoadFromFile(IN_3DFILE, &sReadParam, &pModelFile)); if(pModelFile) { // creating the PRC stream from the model file that is going to be inserted into the PDF file A3DRWParamsExportPrcData sParamsExportData; A3D_INITIALIZE_DATA(A3DRWParamsExportPrcData, sParamsExportData); // To get unique IDs, we need a A3DRWParamsPrcWriteHelper. // A3DPDF3DStreamCreateFromModelFileAsPRC builds this object. A3DRWParamsPrcWriteHelper* pA3DRWParamsPrcWriteHelper = NULL; CHECK_RET(A3DPDF3DStreamCreateFromModelFileAsPRC(pDoc, pModelFile, &sParamsExportData, &pStream, &pA3DRWParamsPrcWriteHelper)); // creating the poster image A3DPDFImage* pImage; CHECK_RET(A3DPDFImageCreateFromFile(pDoc, IN_POSTERIMAGE, kA3DPDFImageFormatUnknown, &pImage)); // creating the 3D artwork A3DPDF3DArtwork* p3DArtwork; A3DPDF3DArtworkData2 s3DArtworkData; A3D_INITIALIZE_DATA(A3DPDF3DArtworkData2, s3DArtworkData); s3DArtworkData.m_pStream = pStream; //s3DArtworkData.m_pcJavaScriptFileName = IN_JSFILE; s3DArtworkData.m_bActivatePMICrossHighlight=true; s3DArtworkData.m_bAddPMISemanticInformation=true; s3DArtworkData.m_bKeepNativeDefaultView=true; s3DArtworkData.m_sDisplaySectionData.m_bAddSectionCaps = true; s3DArtworkData.m_sDisplaySectionData.m_bIsIntersectionVisible = true; s3DArtworkData.m_sDisplaySectionData.m_sIntersectionColor.m_dRed = 0.; s3DArtworkData.m_sDisplaySectionData.m_sIntersectionColor.m_dGreen = 1.; s3DArtworkData.m_sDisplaySectionData.m_sIntersectionColor.m_dBlue = 0.; CHECK_RET(A3DPDF3DArtworkCreate2(pDoc, &s3DArtworkData, &p3DArtwork)); A3DPDF3DAnnotData sAnnotData; A3D_INITIALIZE_DATA(A3DPDF3DAnnotData, sAnnotData); sAnnotData.m_bOpenModelTree = false; sAnnotData.m_bShowToolbar = false; sAnnotData.m_eLighting = kA3DPDFLightWhite; sAnnotData.m_eRenderingStyle = kA3DPDFRenderingSolidOutline; sAnnotData.m_sBackgroundColor.m_dRed = 0.95; sAnnotData.m_sBackgroundColor.m_dGreen = 0.95; sAnnotData.m_sBackgroundColor.m_dBlue = 0.95; sAnnotData.m_bTransparentBackground = false; sAnnotData.m_eActivateWhen = kA3DPDFActivPageOpened; sAnnotData.m_eDesactivateWhen = kA3DPDFActivPageClosed; sAnnotData.m_iAppearanceBorderWidth = 0; sAnnotData.m_pPosterImage = pImage; sAnnotData.m_p3DArtwork = p3DArtwork; A3DPDF3DAnnot* p3DAnnot = NULL; CHECK_RET(A3DPDF3DAnnotCreate(pDoc, &sAnnotData, &p3DAnnot)); // populating the field with the 3D annotation CHECK_RET(A3DPDFPageFieldSet3DAnnot(pPage, "But3D", p3DAnnot)); // get widget for list nodes A3DPDF3DNodeScene* p3DNodeScene = NULL; CHECK_RET(A3DPDF3DAnnotGet3DNodeScene( p3DAnnot, &p3DNodeScene)); // get widget for list views A3DPDF3DViewList* p3DViewList = NULL; CHECK_RET(A3DPDF3DAnnotGet3DViewList( p3DAnnot, &p3DViewList)); // widgets for Pmi Notes A3DPDFTextField* pTextPmiNotes = NULL; CHECK_RET(A3DPDFPageGetField(pPage, "PMIText", &pTextPmiNotes)); // create view carousel on the page A3DPDF3DViewCarousel* pViewCarousel = NULL; std::vector aViewCarouselButPrevNext; aViewCarouselButPrevNext.push_back("ButScrollViewsUp"); aViewCarouselButPrevNext.push_back("ButScrollViewsDown"); std::vector aViewCarouselButtons; for (int i=0 ; i<3 ; i++) aViewCarouselButtons.push_back("ButView" + intToString(i)); CHECK_RET(AddViewCarousel(pDoc, pPage, aViewCarouselButPrevNext, aViewCarouselButtons, &pViewCarousel)); // DATAMODEL // --- creation Tables and relationships // TABLE 3D VIEWS A3DPDFDataTable3DViews* pDataTable_3DViews = NULL; CHECK_RET(stCreateTable_3DViews_WithCarousel(pDoc, p3DArtwork, pModelFile, pDataTable_3DViews)); // TABLE PmiNotes A3DPDFDataTable* pDataTable_PmiNotes = NULL; CHECK_RET(stCreateTable_PmiNotes(pDoc, pDataTable_PmiNotes)); // TABLE 3D MODEL + RELATIONSHIPs to PmiNotes A3DPDFDataTable* pDataTable_3D = NULL; int iKeyNode3dUID; CHECK_RET(stCreateTable_3DModel(pDoc, pModelFile, pA3DRWParamsPrcWriteHelper, iKeyNode3dUID, pDataTable_3D, pDataTable_PmiNotes)); // --- binding to widgets // --- widgets binding for Table 3D Views // UI of 3D annot list views CHECK_RET(A3DPDF3DViewListBindToTable(p3DViewList, pDataTable_3DViews)); // Carousel widget binding CHECK_RET(A3DPDF3DViewCarouselBindToTable(pViewCarousel, pDataTable_3DViews)); // --- widgets binding for Table 3D CHECK_RET(A3DPDF3DNodeSceneBindToTable(p3DNodeScene, pDataTable_3D, iKeyNode3dUID));// 3DAnnotUIListNodes maps only 1 col : the one with uuid node names // --- widgets binding for Table PmiNotes CHECK_RET(A3DPDFTextFieldBindToTable(pTextPmiNotes, pDataTable_PmiNotes, 1)); // --- Define interactions between widgets // select a view in 3D annot view list -> the carousel is selected CHECK_RET(A3DPDFWidgetSetTargetBehaviour( p3DViewList, pViewCarousel, kA3DPDFDataSelect )); // select a view in carousel -> the 3D annot view list is selected CHECK_RET(A3DPDFWidgetSetTargetBehaviour( pViewCarousel, p3DViewList, kA3DPDFDataSelect )); // select a node in 3D annot -> 1 column value is displayed in text field CHECK_RET(A3DPDFWidgetSetTargetBehaviour( p3DNodeScene, pTextPmiNotes, kA3DPDFDataIsolate )); // activate a specific view when the file is opened + all actions on cascading widgets // NULL should be specified on the widget source to select a row at init time CHECK_RET(A3DPDFWidgetSetTargetBehaviour(NULL, p3DViewList, kA3DPDFDataSelect)); // This forces the selection on table at init time CHECK_RET(A3DPDFDataTableSetInitIndex( pDataTable_3DViews, 1)); // cleaning up -- WARNING: DO NOT CALL THIS BEFORE A3DPDF3DArtworkCreate! CHECK_RET(A3DAsmModelFileDelete(pModelFile)); // freeing the A3DRWParamsPrcWriteHelper object at the end if (pA3DRWParamsPrcWriteHelper!=NULL) A3DRWParamsPrcWriteHelperFree(pA3DRWParamsPrcWriteHelper); // adding the file attachment CHECK_RET(A3DPDFDocumentAddFileAttachment(pDoc, ATTACHED_FILE_1, "jt file")); CHECK_RET(A3DPDFDocumentAddFileAttachment(pDoc, ATTACHED_FILE_2, "step file")); // saving the document CHECK_RET(A3DPDFDocumentSaveEx(pDoc, kA3DPDFSaveFull | kA3DPDFSaveOptimized, OUT_FILE)); CHECK_RET(A3DPDFDocumentClose(pDoc)); } } } return iRet; } //###################################################################################################################### // Main function #ifdef _MSC_VER int wmain(A3DInt32, A3DUniChar**) #else int main(int, A3DUTF8Char**) #endif { #ifndef _MSC_VER setenv("LC_NUMERIC", "en_US.UTF-8", 1); // Locally force locale #endif // init A3DLIB library - automatically handled init/terminate A3DSDKHOOPSPublishLoader sHoopsPublishLoader(_T(HOOPS_BINARY_DIRECTORY), HOOPS_LICENSE); CHECK_RET(sHoopsPublishLoader.m_eSDKStatus); CHECK_RET(A3DDllSetCallbacksMemory(CheckMalloc, CheckFree)); // init HOOPS Publish related PDF library - automatically handled init/terminate // do it only only once during the life of the application CHECK_RET(sHoopsPublishLoader.InitPDFLib()); // launch PDF treatment A3DStatus iRet = BuildPDFDocument(); if (iRet != A3D_SUCCESS) return iRet; // Check memory allocations return (int)ListLeaks(); }