/*********************************************************************************************************************** * * Copyright (c) 2010 - 2022 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 DemoFunctionalities.cpp This file demonstrates numerous functionalities of HOOPS Publish Advanced. ***********************************************************************************************************************/ #define INITIALIZE_A3D_API #define HOOPS_PRODUCT_PUBLISH_ADVANCED #include #include "../common.hpp" #include "../CommonInit.h" #include #include #include #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\\Crank-Instructions.prc" # define OUT_FILE SAMPLES_PUBLISH_GALLERY_DIRECTORY"\\sample_DemoFunctionalitiesAdv.pdf" # define POSTER_PATH SAMPLES_DATA_DIRECTORY"\\images\\pleaseactivate.bmp" # define ICON_PATH SAMPLES_DATA_DIRECTORY"\\images\\" # define IN_LOGO SAMPLES_DATA_DIRECTORY"\\images\\logo_e.jpg" # define PDF_TEMPLATE SAMPLES_DATA_DIRECTORY"\\pdf_templates\\DemoFuncTemplate.pdf" #else # define IN_3DFILE SAMPLES_DATA_DIRECTORY"/prc/Crank-Instructions.prc" # define OUT_FILE SAMPLES_PUBLISH_GALLERY_DIRECTORY"/sample_DemoFunctionalitiesAdv.pdf" # define POSTER_PATH SAMPLES_DATA_DIRECTORY"/images/pleaseactivate.bmp" # define ICON_PATH SAMPLES_DATA_DIRECTORY"/images/" # define IN_LOGO SAMPLES_DATA_DIRECTORY"/images/logo_e.jpg" # define PDF_TEMPLATE SAMPLES_DATA_DIRECTORY"/pdf_templates/DemoFuncTemplate.pdf" #endif // rgb colors #define COL_BLACK 0.0, 0.0, 0.0 #define COL_RED 1.0, 0.0, 0.0 #define COL_LIGHTGREY 0.4, 0.4, 0.4 const size_t MAXSZFILENAME = 4096; std::string intToString(int i) { std::ostringstream oss; oss << i; return oss.str(); } //###################################################################################################################### static bool string_equals(A3DUTF8Char* pcString1, const std::string& sString2) { std::string sStringCmp1 = pcString1 ? pcString1 : ""; std::string sStringCmp2 = sString2; return (sStringCmp1 == sStringCmp2); } //###################################################################################################################### A3DStatus Create3DAnnot(A3DPDFDocument* pDoc, const A3DUTF8Char* pcFileName, A3DPDFImage* pPoster, const A3DUTF8Char* pcInjsfile, A3DPDF3DArtwork** pp3DArtwork, A3DPDF3DAnnot** pp3DAnnot, A3DRWParamsPrcWriteHelper** ppA3DRWParamsPrcWriteHelper, A3DAsmModelFile** ppModelFile) { A3DStatus iRet = A3D_SUCCESS; *pp3DAnnot = NULL; *ppModelFile = NULL; A3DPDF3DStream* pStream = NULL; char tempfilename[1024]; // Publish 6.0 - Particularity when the input 3D model is stored in a PDF file. The functions to read the 3D data from the PDF // are not the same as for other formats. if (strstr(pcFileName, ".pdf") != NULL) { A3DStream3DPDFData* pStream3DPDFData; A3DInt32 iNumStreams; iRet = A3DGet3DPDFStreams(pcFileName, &pStream3DPDFData, &iNumStreams); if (iRet != A3D_SUCCESS || iNumStreams == 0) return A3D_ERROR; // a real use case might parse every streams in the input file. Here we just take the first one (pStream3DPDFData[0]). // even an input PRC file must be read in memory and mapped into modelfile data structures if (pStream3DPDFData[0].m_bIsPrc) { iRet = A3DAsmModelFileLoadFromPrcStream(pStream3DPDFData[0].m_acStream, pStream3DPDFData[0].m_uiStreamSize, NULL, ppModelFile); if (iRet != A3D_SUCCESS) { A3DGet3DPDFStreams(NULL, &pStream3DPDFData, &iNumStreams); // to clean up the array of stream data return iRet; } } // a U3D stream must first be stored as a physical file ; then 2 situations occur: // 1. read and LOAD the physical file into a modelfile using the common A3DAsmModelFileLoadFromFile function, then transform the modelfile into a stream // OR // 2. read the physical file into a binary stream (not loaded into a modelfile) using A3DPDF3DStreamCreateFromFile function // In this sample we illustrate the workflow 2. else { sprintf(tempfilename, "%s.u3d", OUT_FILE); FILE * pFile = NULL; #ifdef _MSC_VER errno_t ret = fopen_s(&pFile, tempfilename, "wb"); if (ret == 0 && pFile) #else pFile = fopen(tempfilename, "wb"); if (pFile) #endif { fwrite(pStream3DPDFData[0].m_acStream, 1, pStream3DPDFData[0].m_uiStreamSize, pFile); fclose(pFile); } // physical file to stream CHECK_RET(A3DPDF3DStreamCreateFromFile(pDoc, tempfilename, false, &pStream)); // !!! the file will have to be disposed of afterwards remove(tempfilename); } A3DGet3DPDFStreams(NULL, &pStream3DPDFData, &iNumStreams); // to clean up the array of stream data } // Load the physical file in a ModelFile data structure if not already done if (pStream == NULL && *ppModelFile == NULL) { // reading the input CAD file; the file can be disposed of afterwards. 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 = false; sReadParam.m_sPmi.m_pcSubstitutionFont = const_cast("Myriad CAD"); sReadParam.m_sTessellation.m_eTessellationLevelOfDetail = kA3DTessLODMedium; sReadParam.m_sMultiEntries.m_bLoadDefault = true; sReadParam.m_sAssembly.m_bUseRootDirectory = true; CHECK_RET(A3DAsmModelFileLoadFromFile(pcFileName, &sReadParam, ppModelFile)); } if (*ppModelFile != NULL) { // whatever the input format, we store it as PRC in the output PDF // 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. CHECK_RET(A3DPDF3DStreamCreateFromModelFileAsPRC(pDoc, *ppModelFile, &sParamsExportData, &pStream, ppA3DRWParamsPrcWriteHelper)); } if (pStream != NULL) { // creating the 3D artwork *pp3DArtwork = NULL; A3DPDF3DArtworkData2 s3DArtworkData; A3D_INITIALIZE_DATA(A3DPDF3DArtworkData2, s3DArtworkData); s3DArtworkData.m_pStream = pStream; s3DArtworkData.m_pcJavaScriptFileName = const_cast(pcInjsfile); s3DArtworkData.m_sDisplaySectionData.m_bAddSectionCaps = true; CHECK_RET(A3DPDF3DArtworkCreate2(pDoc, &s3DArtworkData, pp3DArtwork)); A3DPDF3DAnnotData sAnnotData; A3D_INITIALIZE_DATA(A3DPDF3DAnnotData, sAnnotData); sAnnotData.m_bOpenModelTree = false; sAnnotData.m_bShowToolbar = false; sAnnotData.m_eLighting = kA3DPDFLightCADOptimized; sAnnotData.m_eRenderingStyle = kA3DPDFRenderingSolid; sAnnotData.m_sBackgroundColor.m_dRed = 0.25; sAnnotData.m_sBackgroundColor.m_dGreen = 0.25; sAnnotData.m_sBackgroundColor.m_dBlue = 0.25; sAnnotData.m_bTransparentBackground = false; sAnnotData.m_eActivateWhen = kA3DPDFActivPageOpened; sAnnotData.m_eDesactivateWhen = kA3DPDFActivPageClosed; sAnnotData.m_iAppearanceBorderWidth = 0; sAnnotData.m_pPosterImage = pPoster; // default poster automatically generated sAnnotData.m_p3DArtwork = *pp3DArtwork; CHECK_RET(A3DPDF3DAnnotCreate(pDoc, &sAnnotData, pp3DAnnot)); // cleaning up -- WARNING: DO NOT CALL THIS BEFORE inserting the 3D annot //CHECK_RET(A3DAsmModelFileDelete(pModelFile)); } return iRet; } //###################################################################################################################### // a usage scenario could be that the application user selects the fields to populate on the page. // we simulate this with booleans. static A3DStatus stPopulateDFTemplate(A3DPDFDocument* pDoc, A3DPDFPage* pPage, A3DPDF3DArtwork* p3DArtwork, A3DPDF3DAnnot* p3DAnnot, const std::string& sSuffixFields, bool bFieldTitle, const A3DUTF8Char* pcTitle, bool bFieldDate, const A3DUTF8Char* pcDate, bool bFieldViews, bool bFieldParts, const std::vector >& aTable3DRows) { A3DStatus iRet = A3D_SUCCESS; if (p3DAnnot != NULL) { // with A3DPDFDocumentAppendPageFromPDFFileAndSuffixFields: // if template imported providing pcAppendStringToFieldNames, the field name is FieldName_pcAppendStringToFieldNames A3DInt32 iNbFields; A3DPDFField** ppFields; CHECK_RET(A3DPDFPageGetFields(pPage, &iNbFields, &ppFields)); // parsing the fields to get the information. for (A3DInt32 ifield = 0; ifield < iNbFields; ++ifield) { A3DPDFFieldData sFieldData; A3D_INITIALIZE_DATA(A3DPDFFieldData, sFieldData); CHECK_RET(A3DPDFFieldGetInformation(ppFields[ifield], &sFieldData)); if (string_equals(sFieldData.m_acName, "DF_Title_" + sSuffixFields) && bFieldTitle) { CHECK_RET(A3DPDFPageFieldTextSetValue(pPage, sFieldData.m_acName, pcTitle)); } else if (string_equals(sFieldData.m_acName, "DF_Date_" + sSuffixFields) && bFieldDate) { CHECK_RET(A3DPDFPageFieldTextSetValue(pPage, sFieldData.m_acName, pcDate)); } else if (string_equals(sFieldData.m_acName, "DF_3DWindow_" + sSuffixFields)) // always 3D { // populating the field with the 3D annotation CHECK_RET(A3DPDFPageFieldSet3DAnnot(pPage, sFieldData.m_acName, p3DAnnot)); } else if (string_equals(sFieldData.m_acName, "DF_ViewsList_" + sSuffixFields) && bFieldViews) { // get the view names from the 3D model // getting view IDs as stored in the original file A3DUns32 uiNbViews; A3DPDFView** ppViews; CHECK_RET(A3DPDF3DArtworkGetViews(p3DArtwork, &uiNbViews, &ppViews)); // parsing the views to get the identifier. for (A3DUns32 ui = 0; ui < uiNbViews; ++ui) { A3DUTF8Char* pcViewId = NULL; A3DPDFViewGetExternalName(ppViews[ui], &pcViewId); CHECK_RET(A3DPDFPageFieldListAddItem(pPage, sFieldData.m_acName, pcViewId, pcViewId)); A3DPDFViewGetExternalName(nullptr,&pcViewId); } iRet = A3DPDF3DArtworkGetViews(NULL, NULL, &ppViews); // clean // For a dropdown list (combo box), the JavaScript should be set on KeyStroke event with event.willCommit filtered, // and it should use event.value to get the selected item value. // Note that only the item value can be retrieved from the JavaScript, the export value is not enabled here. std::ostringstream osJsOnField; osJsOnField << "if( event.willCommit )\n"; osJsOnField << "{\n"; osJsOnField << " if(!event.value == \"\")\n"; osJsOnField << " {\n"; osJsOnField << " // activate view on related 3d annot (3d annot is supposed on the same page as the field)\n"; osJsOnField << " annot3d_related = this.getAnnots3D(event.target.page)[0];\n"; osJsOnField << " textfield_viewselected = this.getField(\"DF_ViewSelected_" << sSuffixFields << "\");\n"; osJsOnField << " textfield_viewselected.value = event.value;\n"; osJsOnField << " activateview(annot3d_related, textfield_viewselected.value);\n"; osJsOnField << " }\n"; osJsOnField << "}"; // For a dropdown list (combo box), the JavaScript should be set on KeyStroke event to be able to get the selected item. CHECK_RET(A3DPDFPageFieldSetActionJavascript(pPage, sFieldData.m_acName, kA3DPDFEventFieldKeyStroke, osJsOnField.str().c_str())); // also, the dropdown list must be set at commitOnSelChange true so that selection works fine // modify the field at document opening std::ostringstream osJsOnDoc; osJsOnDoc << "// table definition for dropdown object " << sFieldData.m_acName << "\n"; osJsOnDoc << "var lstObj_" << sFieldData.m_acName << " = this.getField(\"" << sFieldData.m_acName << "\");\n"; osJsOnDoc << "lstObj_" << sFieldData.m_acName << ".commitOnSelChange = true;\n"; osJsOnDoc << "\n"; CHECK_RET(A3DPDFDocumentAddJavascriptFromString(pDoc, "DF_ViewsList_Fns", osJsOnDoc.str().c_str())); } else if (string_equals(sFieldData.m_acName, "DF_ViewsTitle_" + sSuffixFields) && bFieldViews) { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, true)); } else if (string_equals(sFieldData.m_acName, "DF_ViewSelectedTitle_" + sSuffixFields) && bFieldViews) { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, true)); } else if (string_equals(sFieldData.m_acName, "DF_ViewSelected_" + sSuffixFields) && bFieldViews) { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, true)); } else if (string_equals(sFieldData.m_acName, "DF_PartsList_" + sSuffixFields) && bFieldParts) { // Setting data and behaviour on listbox field: // To avoid an issue with poorly selectable scroller in Acrobat, we need to // * be sure the field has multipleSelection and commitOnSelChange options set to false // * set the javascript on Keystroke event, // * get selected value with 'event.changeEx' (which is the export value) // * maintain a separated list to get additional data. std::ostringstream osListItems; // adding the items in listbox + separate list data for (size_t i = 0; i < aTable3DRows.size(); ++i) { std::string sIdxItem = intToString((int)i); // store the icon corresponding to the part std::string sIconfile = std::string(ICON_PATH) + aTable3DRows[i][2].c_str(); std::string sIconname = "icon" + sIdxItem; A3DPDFImage* pImage; iRet = A3DPDFImageCreateFromFile(pDoc, sIconfile.c_str(), kA3DPDFImageFormatUnknown, &pImage); if (iRet == A3D_SUCCESS) { // here we want to force the iconid as we use the index to name it later in javascript CHECK_RET(A3DPDFDocumentAddImageAsIcon2(pDoc, pImage, sIconname.c_str(), NULL)); } // .data = [nodeuid, icon] osListItems << "lstObj_" << sFieldData.m_acName << ".data[" << i << "] = [ \"" << aTable3DRows[i][1].c_str() << "\", \"" << sIconname.c_str() << "\" ];\n"; // list item (visible value/export value) in droplist is: nodename / idx_in_listItemsTable CHECK_RET(A3DPDFPageFieldListAddItem(pPage, sFieldData.m_acName, aTable3DRows[i][0].c_str(), sIdxItem.c_str())); } // modify the field at document opening to be sure selection works with slider + store list data std::ostringstream osJsOnDoc; osJsOnDoc << "// table definition for listbox object " << sFieldData.m_acName << "\n"; osJsOnDoc << "var lstObj_" << sFieldData.m_acName << " = this.getField(\"" << sFieldData.m_acName << "\");\n"; osJsOnDoc << "lstObj_" << sFieldData.m_acName << ".data = new Array();\n"; osJsOnDoc << osListItems.str(); osJsOnDoc << "lstObj_" << sFieldData.m_acName << ".multipleSelection = false;\n"; osJsOnDoc << "lstObj_" << sFieldData.m_acName << ".commitOnSelChange = false;\n"; osJsOnDoc << "\n"; CHECK_RET(A3DPDFDocumentAddJavascriptFromString(pDoc, "DF_PartsList_Fns", osJsOnDoc.str().c_str())); // set an action to populate a text field and an icon from the selected item in the list std::ostringstream osJsOnField; osJsOnField << "thisfield = event.target;\n"; osJsOnField << "if (event.changeEx!=\"\")\n"; osJsOnField << "{\n"; osJsOnField << " var idx = event.changeEx; // get the export value\n"; osJsOnField << " if (idx != -1)\n"; osJsOnField << " {\n"; osJsOnField << " //console.println(\"thisfield.index: \" + idx);\n"; osJsOnField << " //console.println(\"thisfield.exportvalue: \" + thisfield.getItemAt(idx, true));\n"; osJsOnField << " //console.println(\"thisfield.value: \" + thisfield.getItemAt(idx, false));\n"; osJsOnField << " // listobj.data is : [nodeuid, icon] \n"; osJsOnField << " \n"; osJsOnField << " //. populate related text field\n"; osJsOnField << " textfield_partselected = this.getField(\"DF_PartSelected_" << sSuffixFields << "\");\n"; osJsOnField << " textfield_partselected.value = thisfield.getItemAt(idx, false);\n"; osJsOnField << " \n"; osJsOnField << " //. populate related button icon\n"; osJsOnField << " buticon = this.getField(\"DF_PartSelectedIcon_" << sSuffixFields << "\");\n"; osJsOnField << " buticon.display = display.visible;\n"; osJsOnField << " buticon.buttonPosition = position.iconOnly;\n"; osJsOnField << " iconname = lstObj_" << sFieldData.m_acName << ".data[idx][1];\n"; osJsOnField << " icon_i = this.getIcon(iconname);\n"; osJsOnField << " if (icon_i!=null) buticon.buttonSetIcon(icon_i);\n"; osJsOnField << " else buticon.buttonPosition = position.textOnly;\n"; osJsOnField << " \n"; osJsOnField << " //. highlight related 3d node (3d annot is supposed on the same page as the field)\n"; osJsOnField << " annot3d_related = this.getAnnots3D(event.target.page)[0];\n"; osJsOnField << " selectnode(annot3d_related, lstObj_" << sFieldData.m_acName << ".data[idx][0]);\n"; osJsOnField << " }\n"; osJsOnField << "}\n"; // For a listbox with correct slider behaviour, the JavaScript should be set on KeyStroke event. CHECK_RET(A3DPDFPageFieldSetActionJavascript(pPage, sFieldData.m_acName, kA3DPDFEventFieldKeyStroke, osJsOnField.str().c_str())); } else if (string_equals(sFieldData.m_acName, "DF_PartsTitle_" + sSuffixFields) && bFieldParts) { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, true)); } else if (string_equals(sFieldData.m_acName, "DF_PartSelectedTitle_" + sSuffixFields) && bFieldParts) { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, true)); } else if (string_equals(sFieldData.m_acName, "DF_PartSelected_" + sSuffixFields) && bFieldParts) { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, true)); } else // unknown or unselected field - hiding it { CHECK_RET(A3DPDFPageFieldSetVisibility(pPage, sFieldData.m_acName, false)); } } A3DPDFPageGetFields(nullptr, &iNbFields,&ppFields); } return iRet; } A3DStatus BuildPDFDocument() { A3DStatus iRet = A3D_SUCCESS; int indexpage = 0; std::string sSuffixFields; // creating a document A3DPDFDocument* pDoc = NULL; CHECK_RET(A3DPDFDocumentCreateEmpty(&pDoc)); if (pDoc != NULL) { A3DPDFPage* pPage = NULL; // creating a poster image to be used as a poster for 3D. A3DPDFImage* pBlankImage = NULL; A3DPDFImageCreateFromFile(pDoc, POSTER_PATH, kA3DPDFImageFormatUnknown, &pBlankImage); // create page idx+1 from template file. we force the fields renaming to avoid duplicated names. sSuffixFields = "uuid0"; CHECK_RET(A3DPDFDocumentAppendPageFromPDFFileAndSuffixFields(pDoc, PDF_TEMPLATE, sSuffixFields.c_str(), &pPage)); if (pPage != NULL) { A3DPDF3DAnnot* p3DAnnot = NULL; A3DPDF3DArtwork* p3DArtwork = NULL; A3DAsmModelFile* pModelFile = NULL; // To get unique IDs, we need a A3DRWParamsPrcWriteHelper. // A3DPDF3DStreamCreateFromModelFileAsPRC builds this object. A3DRWParamsPrcWriteHelper* pPRCWriteHelper = NULL; CHECK_RET(Create3DAnnot(pDoc, IN_3DFILE, pBlankImage, NULL, &p3DArtwork, &p3DAnnot, &pPRCWriteHelper, &pModelFile)); bool bFieldTitle = true; bool bFieldDate = true; bool bFieldViews = true; bool bFieldParts = false; std::vector > aTable3DRows; stPopulateDFTemplate(pDoc, pPage, p3DArtwork, p3DAnnot, sSuffixFields, bFieldTitle, "Crank Instructions", bFieldDate, "2013 oct 12", bFieldViews, bFieldParts, aTable3DRows); // cleanup 3D modelfile CHECK_RET(A3DAsmModelFileDelete(pModelFile)); // free the A3DRWParamsPrcWriteHelper object at the end if (pPRCWriteHelper != NULL) A3DRWParamsPrcWriteHelperFree(pPRCWriteHelper); indexpage++; } // create page idx+1 from template file. we force the fields renaming to avoid duplicated names. sSuffixFields = "uuid1"; CHECK_RET(A3DPDFDocumentAppendPageFromPDFFileAndSuffixFields(pDoc, PDF_TEMPLATE, sSuffixFields.c_str(), &pPage)); if (pPage != NULL) { A3DPDF3DAnnot* p3DAnnot = NULL; A3DPDF3DArtwork* p3DArtwork = NULL; A3DAsmModelFile* pModelFile = NULL; // To get unique IDs, we need a A3DRWParamsPrcWriteHelper. // A3DPDF3DStreamCreateFromModelFileAsPRC builds this object. A3DRWParamsPrcWriteHelper* pPRCWriteHelper = NULL; CHECK_RET(Create3DAnnot(pDoc, IN_3DFILE, pBlankImage, NULL, &p3DArtwork, &p3DAnnot, &pPRCWriteHelper, &pModelFile)); bool bFieldTitle = true; bool bFieldDate = true; bool bFieldViews = false; bool bFieldParts = true; std::vector > aTable3DRows; // parse the 3D PDF nodes A3DPDFModelFileNodesData* pModelFileNodesInfo = NULL; CHECK_RET(A3DPDFGetModelFileNodes(pModelFile, pPRCWriteHelper, &pModelFileNodesInfo)); std::vector mapOfNames; int iFirstNode = 2; // for this sample, we don't take the 2 first nodes (node 0 is for the root, and node 1 doesn't exist) for (size_t inodein3d = iFirstNode; inodein3d < (size_t)pModelFileNodesInfo->m_iNbNodes; inodein3d++) { A3DPDFNodeData* nodeInfos = pModelFileNodesInfo->m_ppNodes[inodein3d]; // in this sample, the 3D nodes involved in datamodel are the Product Occurences // the product name is the key to bom entry if (nodeInfos->m_eNodeType == kA3DPDFNodeProductOccurrence) { std::string sNodeName = nodeInfos->m_pcName; std::string sIconId; if (sNodeName == "01-2_CRANKSHAFT") sIconId = "crank_crankshaft.jpg"; else if (sNodeName == "CONNECTING_ROD") sIconId = "crank_connectingrod.jpg"; else if (sNodeName == "CONNECTING_ROD_CAP") sIconId = "crank_connectingrod_cap.jpg"; else if (sNodeName == "CONNECTING_ROD_BUSHING") sIconId = "crank_connectingrod_bushing.jpg"; else if (sNodeName == "CONNECTING_ROD_BOLT") sIconId = "crank_connectingrod_bolt.jpg"; else if (sNodeName == "CONNECTING_ROD_BOLT_NUT") sIconId = "crank_connectingrod_boltnut.jpg"; else if (sNodeName == "01-2_PISTON") sIconId = "crank_piston.jpg"; else if (sNodeName == "01-2_PISTON_PIN") sIconId = "crank_pistonpin.jpg"; else if (sNodeName == "01-2_PISTON_RETAINER") sIconId = "crank_pistonretainer.jpg"; else if (sNodeName == "01-2_PISTON_TOP_COMP<01-2_PISTON_RING>") sIconId = "crank_pistonring.jpg"; else if (sNodeName == "PISTON_BOT_COMP<01-2_PISTON_RING>") sIconId = "crank_pistonring.jpg"; else if (sNodeName == "PISTON_OIL_COMP<01-2_PISTON_RING>") sIconId = "crank_pistonring.jpg"; else if (sNodeName == "01-2_VALVE_TIMING_SPROCKET") sIconId = "crank_valve.jpg"; else if (sNodeName == "01-2_DAMPER_PULLEY") sIconId = "crank_damper.jpg"; // ... // TODO: complete nodes treatment // insert only once the nodes in the listbox if (std::find(mapOfNames.begin(), mapOfNames.end(), sNodeName) == mapOfNames.end()) // not found : create entry { mapOfNames.push_back(sNodeName); std::vector aOneRow; aOneRow.push_back(sNodeName); aOneRow.push_back(nodeInfos->m_pcNodeUid); aOneRow.push_back(sIconId); aTable3DRows.push_back(aOneRow); } } } CHECK_RET(A3DPDFGetModelFileNodes(nullptr, nullptr, &pModelFileNodesInfo)); stPopulateDFTemplate(pDoc, pPage, p3DArtwork, p3DAnnot, sSuffixFields, bFieldTitle, "Crank Parts", bFieldDate, "2013 oct 12", bFieldViews, bFieldParts, aTable3DRows); // cleanup 3D modelfile CHECK_RET(A3DAsmModelFileDelete(pModelFile)); // free the A3DRWParamsPrcWriteHelper object at the end if (pPRCWriteHelper != NULL) A3DRWParamsPrcWriteHelperFree(pPRCWriteHelper); indexpage++; } // store javascript functions on the document. these functions can be used by javascript stored on the fields. std::ostringstream osJsOnDoc; osJsOnDoc << "function activateview(a3d, viewname)\n"; osJsOnDoc << "{\n"; osJsOnDoc << " // activate the 3D annotation\n"; osJsOnDoc << " if (!a3d.activated) a3d.activated = true;\n"; osJsOnDoc << " c3d = a3d.context3D;\n"; osJsOnDoc << " if (c3d!=undefined)\n"; osJsOnDoc << " {\n"; osJsOnDoc << " c3d.runtime.setView(viewname, true);\n"; osJsOnDoc << " }\n"; osJsOnDoc << "}\n"; osJsOnDoc << "function selectnode(a3d, nodename)\n"; osJsOnDoc << "{\n"; osJsOnDoc << " //console.println(\"selecting node: \" + nodename);\n"; osJsOnDoc << " // activate the 3D annotation\n"; osJsOnDoc << " if (!a3d.activated) a3d.activated = true;\n"; osJsOnDoc << " c3d = a3d.context3D;\n"; osJsOnDoc << " if (c3d!=undefined)\n"; osJsOnDoc << " {\n"; osJsOnDoc << " scene = c3d.scene;\n"; osJsOnDoc << " var node = scene.nodes.getByName(nodename);\n"; osJsOnDoc << " if (node!=undefined) scene.selectedNode = node;\n"; osJsOnDoc << " }\n"; osJsOnDoc << "}"; CHECK_RET(A3DPDFDocumentAddJavascriptFromString(pDoc, "MyFns", osJsOnDoc.str().c_str())); // add properties to the document // end 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)); 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(); }