Files
Hoops_Exchange/publish/publishsource/DemoFunctionalitiesAdv/DemoFunctionalitiesAdv.cpp
2025-12-15 22:10:55 +08:00

665 lines
27 KiB
C++

/***********************************************************************************************************************
*
* 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 <A3DSDKIncludes.h>
#include "../common.hpp"
#include "../CommonInit.h"
#include <sstream>
#include <ostream>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
// 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<A3DUTF8Char*>("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<A3DUTF8Char*>(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<std::vector<std::string> >& 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<std::vector<std::string> > 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<std::vector<std::string> > aTable3DRows;
// parse the 3D PDF nodes
A3DPDFModelFileNodesData* pModelFileNodesInfo = NULL;
CHECK_RET(A3DPDFGetModelFileNodes(pModelFile, pPRCWriteHelper, &pModelFileNodesInfo));
std::vector<std::string> 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<std::string> 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();
}