Files
Hoops_Exchange/publish/publishsource/DemoFunctionalities/DemoFunctionalities.cpp
2025-12-15 23:22:33 +08:00

805 lines
32 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 DemoFunctionalities.cpp
This file demonstrates numerous functionalities of HOOPS Publish.
***********************************************************************************************************************/
#define INITIALIZE_A3D_API
#define HOOPS_PRODUCT_PUBLISH_STANDARD
#include <A3DSDKIncludes.h>
#include <hoops_license.h>
#include "../common.hpp"
#include "../CommonInit.h"
#include <sstream>
#include <ostream>
#include <iostream>
#include <vector>
// 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 OUT_FILE SAMPLES_PUBLISH_GALLERY_DIRECTORY"\\sample_DemoFunctionalities.pdf"
# define POSTER_PATH SAMPLES_DATA_DIRECTORY"\\images\\pleaseactivate.bmp"
# define IN_BKIMAGE SAMPLES_PUBLISH_QUICKSTARTS_DIRECTORY"\\BackgroundImages\\Simple3_Letter_Blue_L.jpg"
# define IN_LOGOIMAGE SAMPLES_DATA_DIRECTORY"\\images\\logo_e.jpg"
# define IN_POSTER_IMAGE1 SAMPLES_DATA_DIRECTORY"\\images\\Carter_poster.jpg"
# define IN_3DFILE SAMPLES_DATA_DIRECTORY"\\prc\\Crank-Pulley.pdf"
# define IN_3DFILE2 SAMPLES_DATA_DIRECTORY"\\prc\\Crank-Valve.pdf"
# define IN_3DFILE3 SAMPLES_DATA_DIRECTORY"\\prc\\Crank-Instructions.prc"
# define IN_3DFILE4 SAMPLES_DATA_DIRECTORY"\\prc\\Carter.prc"
# define IN_MAPIMAGE SAMPLES_DATA_DIRECTORY"\\images\\colormap.jpg"
# define EXTRA_PAGE SAMPLES_DATA_DIRECTORY"\\pdf_templates\\DemoFuncTables.pdf"
# define ATTACHED_FILE SAMPLES_DATA_DIRECTORY"\\pdf_templates\\DemoFuncTables.xls"
#else
# define OUT_FILE SAMPLES_PUBLISH_GALLERY_DIRECTORY"/sample_DemoFunctionalities.pdf"
# define POSTER_PATH SAMPLES_DATA_DIRECTORY"/images/pleaseactivate.bmp"
# define IN_BKIMAGE SAMPLES_PUBLISH_QUICKSTARTS_DIRECTORY"/BackgroundImages/Simple3_Letter_Blue_L.jpg"
# define IN_LOGOIMAGE SAMPLES_DATA_DIRECTORY"/images/logo_e.jpg"
# define IN_POSTER_IMAGE1 SAMPLES_DATA_DIRECTORY"/images/Carter_poster.jpg"
# define IN_3DFILE SAMPLES_DATA_DIRECTORY"/prc/Crank-Pulley.pdf"
# define IN_3DFILE2 SAMPLES_DATA_DIRECTORY"/prc/Crank-Valve.pdf"
# define IN_3DFILE3 SAMPLES_DATA_DIRECTORY"/prc/Crank-Instructions.prc"
# define IN_3DFILE4 SAMPLES_DATA_DIRECTORY"/prc/Carter.prc"
# define IN_MAPIMAGE SAMPLES_DATA_DIRECTORY"/images/colormap.jpg"
# define EXTRA_PAGE SAMPLES_DATA_DIRECTORY"/pdf_templates/DemoFuncTables.pdf"
# define ATTACHED_FILE SAMPLES_DATA_DIRECTORY"/pdf_templates/DemoFuncTables.xls"
#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
#define COL_LIGHTBLUE 0.0, 0.5, 0.5
const size_t MAXSZFILENAME = 4096;
//######################################################################################################################
// writes a text line on the page
A3DStatus WriteTextString(A3DPDFDocument* pDoc, A3DPDFPage* pPage, A3DPDFEFontName eFontName, A3DInt32 iFontSize,
A3DDouble dR, A3DDouble dG, A3DDouble dB, const A3DUTF8Char* pcTextString,
A3DInt32 iPosLeft, A3DInt32 iPosBottom)
{
A3DStatus iRet = A3D_SUCCESS;
A3DPDFTextData sTextData;
A3D_INITIALIZE_DATA(A3DPDFTextData, sTextData);
sTextData.m_eFontName = eFontName;
sTextData.m_iFontSize = iFontSize;
sTextData.m_sColor.m_dRed = dR;
sTextData.m_sColor.m_dGreen = dG;
sTextData.m_sColor.m_dBlue = dB;
sTextData.m_pcTextString = const_cast<A3DUTF8Char*>(pcTextString);
A3DPDFText* pText = NULL;
CHECK_RET(A3DPDFTextCreate(pDoc, &sTextData, &pText));
CHECK_RET(A3DPDFPageInsertText(pPage, pText, iPosLeft, iPosBottom)); // iPosLeft, iPosBottom from the bottom left
return iRet;
}
//######################################################################################################################
// displays an image on the page
A3DStatus WriteImage(A3DPDFDocument* pDoc, A3DPDFPage* pPage, const A3DUTF8Char* pcFileName,
int iLeft, int iBottom, int iRight, int iTop)
{
A3DStatus iRet = A3D_SUCCESS;
A3DPDFImage* pImage = NULL;
CHECK_RET(A3DPDFImageCreateFromFile(pDoc, pcFileName, kA3DPDFImageFormatUnknown, &pImage));
// positioning the object on the page
A3DPDFRectData sPos;
A3D_INITIALIZE_DATA(A3DPDFRectData, sPos);
// coordinates are from bottom left of the page
sPos.m_iLeft = iLeft; // lower left x
sPos.m_iBottom = iBottom; // lower left y
sPos.m_iRight = iRight; // upper right x
sPos.m_iTop = iTop; // upper right y
CHECK_RET(A3DPDFPageInsertImage2(pPage, pImage, &sPos));
return iRet;
}
//######################################################################################################################
// writes a link on the page
A3DStatus WriteLink(A3DPDFDocument* pDoc, A3DPDFPage* pPage, A3DPDFELinkHighlightMode eHighlightingMode, A3DInt32 iBorderWidth,
A3DDouble dR, A3DDouble dG, A3DDouble dB,
int iLeft, int iBottom, int iRight, int iTop,
A3DPDFLink** ppLink)
{
A3DStatus iRet = A3D_SUCCESS;
*ppLink = NULL;
A3DPDFLinkData sLinkData;
A3D_INITIALIZE_DATA(A3DPDFLinkData, sLinkData);
sLinkData.m_eHighlightingMode = eHighlightingMode;
sLinkData.m_iBorderWidth = iBorderWidth;
sLinkData.m_sColor.m_dRed = dR;
sLinkData.m_sColor.m_dGreen = dG;
sLinkData.m_sColor.m_dBlue = dB;
CHECK_RET(A3DPDFLinkCreate(pDoc, &sLinkData, ppLink));
// positioning the object on the page
A3DPDFRectData sPos;
A3D_INITIALIZE_DATA(A3DPDFRectData, sPos);
// coordinates are from bottom left of the page
sPos.m_iLeft = iLeft; // lower left x
sPos.m_iBottom = iBottom; // lower left y
sPos.m_iRight = iRight ; // upper right x
sPos.m_iTop = iTop ; // upper right y
CHECK_RET(A3DPDFPageInsertLink(pPage, *ppLink, &sPos));
return iRet;
}
//######################################################################################################################
A3DStatus Create3DAnnot(A3DPDFDocument* pDoc,
const A3DUTF8Char* pcFileName,
A3DPDFImage* pPoster,
const A3DUTF8Char* pcInjsfile,
A3DPDFELighting eLighting, A3DPDFERenderingStyle eRenderingStyle,
bool bExplicitActivDesactiv,
A3DPDF3DArtwork** pp3DArtwork,
A3DPDF3DAnnot** pp3DAnnot,
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);
CHECK_RET(A3DPDF3DStreamCreateFromModelFileAsPRC(pDoc, *ppModelFile, &sParamsExportData, &pStream, NULL));
}
if(pStream != NULL)
{
// creating the 3D artwork
*pp3DArtwork = NULL;
A3DPDF3DArtworkData2 s3DArtworkData;
A3D_INITIALIZE_DATA(A3DPDF3DArtworkData2, s3DArtworkData);
s3DArtworkData.m_pStream = pStream;
s3DArtworkData.m_sDisplaySectionData.m_bAddSectionCaps = true;
s3DArtworkData.m_pcJavaScriptFileName = const_cast<A3DUTF8Char*>(pcInjsfile);
CHECK_RET(A3DPDF3DArtworkCreate2(pDoc, &s3DArtworkData, pp3DArtwork));
A3DPDF3DAnnotData sAnnotData;
A3D_INITIALIZE_DATA(A3DPDF3DAnnotData, sAnnotData);
sAnnotData.m_bOpenModelTree = false;
sAnnotData.m_bShowToolbar = false;
sAnnotData.m_eLighting = eLighting;
sAnnotData.m_eRenderingStyle = eRenderingStyle;
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 = bExplicitActivDesactiv ? kA3DPDFActivExplicitActivation : kA3DPDFActivPageOpened;
sAnnotData.m_eDesactivateWhen = bExplicitActivDesactiv ? kA3DPDFActivExplicitDesactivation : 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;
}
//######################################################################################################################
// Helper functions to create a Table on PDF Page using API
#define NOSPAN 1
void CreateStyle(A3DInt32 fontSize, A3DUTF8Char const* const fontName,
A3DPDFRgbColorData* textColor, A3DPDFRgbColorData* borderColor, A3DPDFRgbColorData* bkColor,
A3DPDFETableTextHorizontalAlign hAlignment, A3DPDFETableTextVerticalAlign vAlignment,
A3DInt32 rowHeight, A3DInt32 columnWidth,
A3DInt32 bPadding, A3DInt32 lPadding, A3DInt32 rPadding, A3DInt32 tPadding,
A3DPDFTableStyleData& outStyle)
{
A3D_INITIALIZE_DATA(A3DPDFTableStyleData, outStyle);
outStyle.m_iFontSize = fontSize;
outStyle.m_pcFontName = const_cast<A3DUTF8Char*>(fontName);
outStyle.m_pTextColor = textColor;
outStyle.m_pBorderColor = borderColor;
outStyle.m_pBackgroundColor = bkColor;
outStyle.m_eHorizAlignment = hAlignment;
outStyle.m_eVertAlignment = vAlignment;
outStyle.m_iRowHeight = rowHeight;
outStyle.m_iColumnWidth = columnWidth;
outStyle.m_iPaddingBottom = bPadding;
outStyle.m_iPaddingLeft = lPadding;
outStyle.m_iPaddingRight = rPadding;
outStyle.m_iPaddingTop = tPadding;
}
// Creates a Cell entity and push it in Cells array
A3DStatus AddTableCellDesc(std::vector<A3DPDFTableCellDesc*>& aCells, A3DUns8 iRowSpan, A3DUns8 iColSpan, A3DUTF8Char const* const pcCellString, A3DPDFTableStyleData* pStyle)
{
A3DStatus iResult = A3D_SUCCESS;
A3DPDFTableCellDesc* pTableCellDesc = nullptr;
A3DPDFTableCellDescData sTableCellDescData;
A3D_INITIALIZE_DATA(A3DPDFTableCellDescData, sTableCellDescData);
sTableCellDescData.m_iRowSpan = iRowSpan;
sTableCellDescData.m_iColSpan = iColSpan;
sTableCellDescData.m_pcCellString = const_cast<A3DUTF8Char*>(pcCellString);
sTableCellDescData.m_pStyle = pStyle;
iResult = A3DPDFTableCellDescCreate(&sTableCellDescData, &pTableCellDesc);
if (iResult == A3D_SUCCESS)
aCells.push_back(pTableCellDesc);
return iResult;
}
// Creates a Row entity populated with cells, and push it in Rows array
A3DStatus AddTableRowDesc(std::vector<A3DPDFTableRowDesc*>& aRows, const std::vector<A3DPDFTableCellDesc*>& aCells, A3DPDFTableStyleData* pStyle)
{
A3DStatus iResult = A3D_SUCCESS;
A3DPDFTableRowDesc* pTableRowDesc = nullptr;
A3DPDFTableRowDescData sTableRowDescData;
A3D_INITIALIZE_DATA(A3DPDFTableRowDescData, sTableRowDescData);
sTableRowDescData.m_iNumberOfCells = static_cast<A3DUns32>(aCells.size());
sTableRowDescData.m_ppCells = (A3DPDFTableCellDesc**)malloc(aCells.size() * sizeof(A3DPDFTableCellDesc**));
for (size_t i = 0; i < aCells.size(); i++)
sTableRowDescData.m_ppCells[i] = aCells[i];
sTableRowDescData.m_pStyle = pStyle;
iResult = A3DPDFTableRowDescCreate(&sTableRowDescData, &pTableRowDesc);
if (iResult == A3D_SUCCESS)
aRows.push_back(pTableRowDesc);
return iResult;
}
// Creates a Table populated with rows
A3DStatus CreateTableDesc(A3DPDFDocument* pDoc, A3DPDFTable*& pTable, const std::vector<A3DPDFTableRowDesc*>& aRows, A3DPDFTableStyleData* pStyle)
{
A3DStatus iResult = A3D_SUCCESS;
pTable = nullptr;
A3DPDFTableDescData sTableDescData;
A3D_INITIALIZE_DATA(A3DPDFTableDescData, sTableDescData);
sTableDescData.m_iNumberOfRows = static_cast<A3DUns32>(aRows.size());
sTableDescData.m_ppRows = (A3DPDFTableRowDesc**)malloc(aRows.size() * A3DUns32(sizeof(A3DPDFTableRowDesc*)));
for (size_t i = 0; i < aRows.size(); i++)
sTableDescData.m_ppRows[i] = aRows[i];
sTableDescData.m_pStyle = pStyle;
iResult = A3DPDFTableCreateFromDesc(pDoc, &sTableDescData, &pTable);
return iResult;
}
A3DStatus BuildPDFDocument()
{
A3DStatus iRet = A3D_SUCCESS;
A3DInt32 nbpages = -1;
int indexpage = 0;
// creating a document
A3DPDFDocument* pDoc = NULL;
CHECK_RET(A3DPDFDocumentCreateEmpty(&pDoc));
if (pDoc != NULL)
{
// populating the document metadata
A3DPDFDocumentInformationData sInformationData;
A3D_INITIALIZE_DATA(A3DPDFDocumentInformationData, sInformationData);
sInformationData.m_pcTitle = const_cast<A3DUTF8Char*>("HOOPS Publish Functionalities");
sInformationData.m_pcCreator = const_cast<A3DUTF8Char*>("HOOPS Publish Sample Application");
sInformationData.m_pcSubject = const_cast<A3DUTF8Char*>("This sample shows miscellaneous functionalities of HOOPS Publish");
sInformationData.m_pcAuthor = const_cast<A3DUTF8Char*>("Tech Soft 3D");
CHECK_RET(A3DPDFDocumentSetInformation(pDoc, &sInformationData));
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 1
A3DPDFPageData2 sPageData;
A3D_INITIALIZE_DATA(A3DPDFPageData2, sPageData);
sPageData.m_ePageOrientation = kA3DPDFPageLandscape;
sPageData.m_ePageSize = kA3DPDFPageLetter; // standard letter format: 612 x 792
int iPageWidth = 792, iPageHeight = 612;
CHECK_RET(A3DPDFDocumentAppendNewPage2(pDoc, &sPageData, &pPage));
if (pPage != NULL)
{
// all the posX and posY parameters for WriteImage are from the bottom left!
// background image
const int iBkImageRes = 150;
const int iBkImageW = 1648 * 72 / iBkImageRes;
const int iBkImageH = 1276 * 72 / iBkImageRes;
const int iBkLeft = 0; // lower left x
const int iBkBottom = 0; // lower left y
CHECK_RET(WriteImage(pDoc, pPage, IN_BKIMAGE, iBkLeft, iBkBottom, iBkLeft + iBkImageW, iBkBottom + iBkImageH));
// logo image
const int iLogoRes = 72;
// factor / 3 to reduce the size of the logo
const int iLogoW = (int)(195 * 72 / iLogoRes / 3);
const int iLogoH = (int)(219 * 72 / iLogoRes / 3);
const int iLogoLeft = 10; // lower left x
const int iLogoBottom = iPageHeight - 42 - iLogoH; // lower left y
CHECK_RET(WriteImage(pDoc, pPage, IN_LOGOIMAGE, iLogoLeft, iLogoBottom, iLogoLeft + iLogoW, iLogoBottom + iLogoH));
// title in black
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelveticaBold, 50, COL_BLACK,
"Crank", 250, iPageHeight - 103));
// header right line1 in light grey
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelveticaBold, 10, COL_LIGHTGREY,
"Emulate Manufacturing", iPageWidth - 150, iPageHeight - 60));
// header right line2 in light grey
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 10, COL_LIGHTGREY,
"Tel: +44 123 456 789", iPageWidth - 150, iPageHeight - 70));
// header right line3 in light grey
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 10, COL_LIGHTGREY,
"Fax: +44 123 467 890", iPageWidth - 150, iPageHeight - 80));
// header right line4 in light grey
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 10, COL_LIGHTGREY,
"Email: sales@emulate-man.com", iPageWidth - 150, iPageHeight - 90));
// header right line5 in light grey
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 10, COL_LIGHTGREY,
"www.emulate-man.com", iPageWidth - 150, iPageHeight - 100));
// bottom text in red
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 20, COL_RED,
"Company Confidential: Do Not Redistribute", 200, 30));
A3DPDF3DAnnot* p3DAnnot = NULL;
A3DPDF3DArtwork* p3DArtwork = NULL;
A3DAsmModelFile* pModelFile = NULL;
iRet = Create3DAnnot(pDoc, IN_3DFILE3, pBlankImage, NULL,
kA3DPDFLightHeadlamp, kA3DPDFRenderingSolid, false,
&p3DArtwork, &p3DAnnot, &pModelFile);
if (p3DAnnot != NULL)
{
// position the 3D annotation in the page
A3DPDFRectData sPos;
A3D_INITIALIZE_DATA(A3DPDFRectData, sPos);
// coordinates are from bottom left of the page
sPos.m_iLeft = 150; // lower left x
sPos.m_iBottom = 100; // lower left y
sPos.m_iRight = iPageWidth - 150; // upper right x
sPos.m_iTop = iPageHeight - 145; // upper right y
CHECK_RET(A3DPDFPageInsert3DAnnot(pPage, p3DAnnot, &sPos));
// cleanup 3D modelfile
CHECK_RET(A3DAsmModelFileDelete(pModelFile));
}
indexpage++;
}
// import pages from PDF file (not template)
CHECK_RET(A3DPDFDocumentAppendPageFromPDFFileEx(pDoc, EXTRA_PAGE, false, &pPage));
// browse new pages. in this example, we know we want to insert a 3D model in the 2 first pages
CHECK_RET(A3DPDFDocumentGetNumberPages(pDoc, &nbpages));
int indexpageprev = indexpage;
for (indexpage = indexpageprev; indexpage < nbpages; indexpage++)
{
CHECK_RET(A3DPDFDocumentGetPage(pDoc, indexpage, &pPage));
if (pPage != NULL)
{
// we have to know the size of the imported pages
// for any reason, these excel generated PDF are in a box [-12, 583 / 12, 853]
//const int iPageWidth = 595, iPageHeight = 841;
// in this example, we know where we want to insert the 3D
A3DPDFRectData sPos;
A3D_INITIALIZE_DATA(A3DPDFRectData, sPos);
// coordinates are from bottom left of the page
sPos.m_iLeft = 44 - 12; // lower left x
sPos.m_iBottom = 36 + 12; // lower left y
sPos.m_iRight = 595 - 44 - 12; // upper right x
sPos.m_iTop = 400 + 12; // upper right y
A3DPDF3DAnnot* p3DAnnot = NULL;
A3DPDF3DArtwork* p3DArtwork = NULL;
A3DAsmModelFile* pModelFile = NULL;
// 3D only in first 2 pages
if (indexpage - indexpageprev == 0)
iRet = Create3DAnnot(pDoc, IN_3DFILE, pBlankImage, NULL,
kA3DPDFLightCADOptimized, kA3DPDFRenderingSolid, false,
&p3DArtwork, &p3DAnnot, &pModelFile);
else if (indexpage - indexpageprev == 1)
iRet = Create3DAnnot(pDoc, IN_3DFILE2, pBlankImage, NULL,
kA3DPDFLightCADOptimized, kA3DPDFRenderingSolid, false,
&p3DArtwork, &p3DAnnot, &pModelFile);
// position the 3D annotation in the page
if (p3DAnnot != NULL)
{
CHECK_RET(A3DPDFPageInsert3DAnnot(pPage, p3DAnnot, &sPos));
// cleanup 3D modelfile
if (pModelFile != NULL)
CHECK_RET(A3DAsmModelFileDelete(pModelFile));
}
}
}
sPageData.m_ePageOrientation = kA3DPDFPagePortrait;
sPageData.m_ePageSize = kA3DPDFPageLetter; // standard letter format: 612 x 792
iPageWidth = 612;
iPageHeight = 792;
CHECK_RET(A3DPDFDocumentAppendNewPage2(pDoc, &sPageData, &pPage));
if (pPage != NULL)
{
// all the posX and posY parameters for WriteImage are from the bottom left!
// logo image
const int iLogoRes = 72;
// factor / 3 to reduce the size of the logo
const int iLogoW = (int)(195 * 72 / iLogoRes / 3);
const int iLogoH = (int)(219 * 72 / iLogoRes / 3);
const int iLogoLeft = 69; // lower left x
const int iLogoBottom = iPageHeight - 34 - iLogoH; // lower left y
CHECK_RET(WriteImage(pDoc, pPage, IN_LOGOIMAGE, iLogoLeft, iLogoBottom, iLogoLeft + iLogoW, iLogoBottom + iLogoH));
// link
A3DPDFLink* pLink = NULL;
CHECK_RET(WriteLink(pDoc, pPage, kA3DPDFLinkHighlightOutline, 0, COL_LIGHTBLUE,
iLogoLeft, iLogoBottom, iLogoLeft + iLogoW, iLogoBottom + iLogoH,
&pLink));
// set action on link
if (pLink != NULL)
{
A3DPDFAction* pAction = NULL;
A3DPDFActionLaunchURLData sActionData;
A3D_INITIALIZE_DATA(A3DPDFActionLaunchURLData, sActionData);
sActionData.m_pcURL = const_cast<A3DUTF8Char*>("http://www.techsoft3d.com/");
CHECK_RET(A3DPDFActionLaunchURLCreate(&sActionData, &pAction));
CHECK_RET(A3DPDFLinkAddAction(pLink, pAction));
}
// map image
const int iMapRes = 72;
// factor / 1.8 to reduce the size of the image
const int iMapH = (int)(309 * 72 / iMapRes / 1.8);
const int iMapW = (int)(204 * 72 / iMapRes / 1.8);
const int iMapLeft = 490; // lower left x
const int iMapBottom = iPageHeight - 195 - iMapH; // lower left y
CHECK_RET(WriteImage(pDoc, pPage, IN_MAPIMAGE, iMapLeft, iMapBottom, iMapLeft + iMapW, iMapBottom + iMapH));
// title in black
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelveticaBold, 20, COL_BLACK,
"Model Validation Report", 213, iPageHeight - 70));
// table title line
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelveticaBold, 12, COL_BLACK,
"Deviation Distribution", 230, iPageHeight - 520));
// table creation
A3DPDFTable* pTable = nullptr;
// table description: defined similar to html, with definitions of rows, cells, and colspan and rowpans for scenario with cells merged.
// styles (including cells widths and heigths) are defined at level of (by order of priority) table, then rows, then cells.
std::vector<A3DPDFTableCellDesc*> aCells;
std::vector<A3DPDFTableRowDesc*> aRows;
A3DPDFRgbColorData colorBlack;
A3D_INITIALIZE_DATA(A3DPDFRgbColorData, colorBlack);
colorBlack.m_dGreen = colorBlack.m_dBlue = colorBlack.m_dRed = 0.;
A3DPDFRgbColorData colorGreyLight;
A3D_INITIALIZE_DATA(A3DPDFRgbColorData, colorGreyLight);
colorGreyLight.m_dRed = colorGreyLight.m_dGreen = colorGreyLight.m_dBlue = 0.85; // GreyLight
A3DPDFTableStyleData sStyleTableRowHeader;
CreateStyle(10, "MyriadPro,Bold", &colorBlack, &colorBlack, &colorGreyLight, kA3DPDFTableAlignHCentered,
kA3DPDFTableAlignVMiddle, 12, 100, 0, 0, 0, 0, sStyleTableRowHeader);
A3DPDFTableStyleData sStyleTable;
CreateStyle(10, "MyriadPro", &colorBlack, &colorBlack, nullptr, kA3DPDFTableAlignHCentered,
kA3DPDFTableAlignVMiddle, 12, 100, 0, 0, 0, 0, sStyleTable);
//ROW 0 for Header - style defined at row level
aCells.clear();
AddTableCellDesc(aCells, NOSPAN, NOSPAN, "Deviation", nullptr);
AddTableCellDesc(aCells, NOSPAN, NOSPAN, "# of Points", nullptr);
AddTableCellDesc(aCells, NOSPAN, NOSPAN, "% of Total", nullptr);
AddTableRowDesc(aRows, aCells, &sStyleTableRowHeader);
// Rows with data - no specific style on row, style will be the one defined at table level
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.109", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "16903", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "33.9", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.218", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "5124", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "10.3", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.327", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "7811", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "15.6", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.436", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "7811", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "15.6", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.545", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "6605", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "13.2", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.654", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "1688", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "3.4", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.763", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "1279", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "2.6", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.872", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "1109", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "2.2", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "0.981", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "1035", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "2.1", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
aCells.clear();
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "1.09", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "565", nullptr));
CHECK_RET(AddTableCellDesc(aCells, NOSPAN, NOSPAN, "1.1", nullptr));
CHECK_RET(AddTableRowDesc(aRows, aCells, nullptr));
// table creation
CHECK_RET(CreateTableDesc(pDoc, pTable, aRows, &sStyleTable));
// 3 columns size 100 makes table size 300
int iLeft = (iPageWidth - 300) / 2;
CHECK_RET(A3DPDFPageInsertTable(pPage, pTable, iLeft, iPageHeight - 540));
// bottom text line
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 10, COL_BLACK,
"Adden & Hart LLC., 123 ABC Way, Dublin, Ireland | +353.1.847.6324 | www.addenandhart.com", 93, iPageHeight - 780));
// creating a poster image to be used as a poster for 3D.
A3DPDFImage* pImage = NULL;
A3DPDFImageCreateFromFile(pDoc, IN_POSTER_IMAGE1, kA3DPDFImageFormatUnknown, &pImage);
// 3D model
A3DPDF3DAnnot* p3DAnnot = NULL;
A3DPDF3DArtwork* p3DArtwork = NULL;
A3DAsmModelFile* pModelFile = NULL;
iRet = Create3DAnnot(pDoc, IN_3DFILE4, pImage, NULL,
kA3DPDFLightCADOptimized, kA3DPDFRenderingSolidWireframe, true,
&p3DArtwork, &p3DAnnot, &pModelFile);
if (p3DAnnot != NULL)
{
// position the 3D annotation in the page
A3DPDFRectData sPos;
A3D_INITIALIZE_DATA(A3DPDFRectData, sPos);
// coordinates are from bottom left of the page
sPos.m_iLeft = 24; // lower left x
sPos.m_iBottom = iPageHeight - 455; // lower left y
sPos.m_iRight = 478; // upper right x
sPos.m_iTop = iPageHeight - 125; // upper right y
CHECK_RET(A3DPDFPageInsert3DAnnot(pPage, p3DAnnot, &sPos));
// cleanup 3D modelfile
CHECK_RET(A3DAsmModelFileDelete(pModelFile));
}
}
// add a page footer to each page except first one
// note that pages generated by external applications such as excel in this example
// might crop the page a little bit, hence difficulties in positioning the objects.
CHECK_RET(A3DPDFDocumentGetNumberPages(pDoc, &nbpages));
for (indexpage = 1; indexpage < nbpages; indexpage++)
{
CHECK_RET(A3DPDFDocumentGetPage(pDoc, indexpage, &pPage));
if (pPage != NULL)
{
A3DUTF8Char acPageTxt[2048];
sprintf(acPageTxt, "Page %i", indexpage);
CHECK_RET(WriteTextString(pDoc, pPage, kA3DPDFFontHelvetica, 8, COL_BLACK, acPageTxt, 10, 18));
}
}
// add properties to the document
/*
// setting passwords and permissions (please uncomment to try the feature)
CHECK_RET(A3DPDFDocumentSetPasswordSecurity(pDoc,
"myuserpassword", "myownerpassword",
kA3DPDFDocumentPermDocAssembly + kA3DPDFDocumentPermPrint,
kA3DPDFEncryptAll));
*/
// adding the file attachment
CHECK_RET(A3DPDFDocumentAddFileAttachment(pDoc, ATTACHED_FILE, "Excel file for measures"));
// 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), 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();
}