< Home

< Tech Overview

< Reference Manual

GETTING STARTED

Contents

About this document

PDF Publishing Workflow with HOOPS Publish

How to start your HOOPS Publish evaluation

Samples

Platform Support

Support, Consultancy, and Training

Searching the Help

API Conventions

Fonts and Resources

Using HOOPS Publish with HOOPS Exchange

Using HOOPS Publish with HOOPS Visualize

The main entities and relationships in HOOPS Publish

The Hello World example

Working with Templates

Adding JavaScript actions

Creating a view and creating an image from a view

More Advanced JavaScript

Accessing unique PDF object IDs

Controlling object transparency

About this document

This document comprises a set of notes to aid evaluees of HOOPS Publish and is intended to supplement the supplied programming and reference guides. It is advised that those new to HOOPS Publish read these notes before, or at the same time as, reading the programming guide.

The Technical Overview, available separately, provides a high-level guide to HOOPS Publish. Some concepts are introduced in this document and it is advisable to read it first.

PDF Publishing Workflow with HOOPS Publish

The process of publishing an interactive 3D PDF can be broken down into four steps:

  1. Create a PDF document in which to insert the 3D information. This can be done directly with the HOOPS Publish API or via templates defined externally using tools such as Adobe Acrobat.
  2. Insert the 3D Information
  3. Add any extra control capabilities e.g. hook up JavaScript to fields in the PDF
  4. Post-process the PDF using external tools such as Adobe Acrobat to, for example, add document security and Reader Extend the PDF to access advanced functions with Adobe Reader such as measurement and sectioning.
The typical workflow for creating a 3D PDF with HOOPS Publish

HOOPS Publish provides both API calls that allow you to create PDF files programmatically and also to create a new PDF from a PDF template.

A PDF template is simply a PDF file that contains both static text and editable fields. During the publish process these fields can be populated programmatically based on the field name defined in the template, or enabled for user input. PDF Templates can also contain placeholders for 3D data and Flash animations and videos, although only 3D annotations are directly supported by HOOPS Publish.

HOOPS Publish provides a selection of ready-to-use templates.

How to start your HOOPS Publish evaluation

Getting started with HOOPS Publish is simple. We recommend the following steps:

Samples

The HOOPS Publish installation provides several examples that are useful in aiding a quick understanding of the HOOPS Publish. The following examples are available on the HOOPS Publish download:

In addition to the examples listed above the HOOPS Publish download includes example 3D PDF files and example PDF Templates that you can use in your own application.

Platform support

HOOPS Publish is available on 32 and 64-bit Windows platforms:

Platform Architecture Operating System Compiler
win32 AMD64, Intel x86 or Intel 64
Windows 2008 Server SP2 (32-bit)
Windows XP/Vista/7 (32-bit)
Visual Studio 2008 or 2010
win64 AMD64 or Intel 64 Windows 2008 Server SP2 (64-bit)
Windows 2008 Server R2 SP1 (64-bit)
Windows XP/Vista/7 (64-bit)
Visual Studio 2008 or 2010 for x64

Support, Consultancy and Training

Licensees of HOOPS Publish enjoy a high-level of responsive support both from the core team located in Lyon, France, and from the local teams based in each major territory worldwide.

If you require help getting started, in the first instance please contact your Consulting Engineer or Account Manager, who will direct you to the appropriate support channels.

Searching the Help

The HOOPS Publish help files are available...

The online documents provide a free-form text search. To search the documentation in the download package we recommend using a standard free-form text search such as grep, Windows Search or Visual Studio Find in Files.

API Conventions

The reference manual contains a description of API conventions. Although the HOOPS Publish API is relatively simple, understanding these conventions is helpful these sections are worth reviewing early in the evaluation process. You can navigate to the API conventions page from the Reference Manual main page.

Additionally, the HOOPS Publish modules reference provides a useful enumeration of the API functionality. This can also be found from the first page of the reference manual or by the link below.

http://docs.techsoft3d.com/exchange/publish_ref_manual/modules.html

Fonts and Resources

The function 3DPDFTextCreateEx can be used to embed fonts directly into the PDF and the './bin/resource' directory contains relevant font definitions.

./bin/resource/Font contains the Adobe MyriadCADOpenType font which is provided with HOOPS Exchange and HOOPS Publish to ensure standard GD&T symbols are available. This font must be installed to ensure accurate display of PMI data. The MyriadCAD font may only be redistributed with HOOPS Exchange and HOOPS Publish enabled applications.

Using HOOPS Publish with HOOPS Exchange

If you are already a user of HOOPS Exchange, or plan to evaluate HOOPS Publish along with HOOPS Exchange, please be aware that the two libraries share some technology. For this reason, HOOPS Publish and HOOPS Exchange are bundled in the same package. The installer allows you to install either or both SDKs. Please note that a joint license code is required to use HOOPS Exchange and HOOPS Publish together. Your license code is generated based on your Tech Soft 3D customer account details.

The installaer places both HOOPS Exchange and HOOPS Publish in the same directory. Some libraries are shared between Publish and Exchange, and the two products share the same bin directory. The ’Distributing Your Application’ section of the ’Release Notes’ enumerates which libraries are necessary for which product.

Note that when a license for one product stops, that license will also stop for the other product. Therefore care must be taken if you are a licensed user of one product and are evaluating the other, or if you have concurrent evaluations running that end on different dates. Once an evaluation license has expired you may need to revert to the original license for the licensed product. We advise you to always keep a secure copy of any licenses you generate along with the included products and termination dates.

Using HOOPS Publish with HOOPS Visualize

If you are an existing HOOPS Visualize user you can export directly to HOOPS Publish using the MVO HIO Module, hio_publish. This allows creation of PDF files from HOOPS Visualize scenes directly or via templates. PRC binaries can also be created that can then be inserted into PDF documents using HOOPS Publish.

For more information, please see the HOOPS Visualize documentation.

The main entities and relationships in HOOPS Publish

Document:

Page

3D Annotation

Stream

Artwork

Text

Image

View

The Hello World example

The HelloWorld example is found in ./samples/publish/publishsource/HelloWorld. It creates a new PDF document and inserts a STEP file with a 3D representation of the text "hello world" into it.

The new PDF, sample_HelloWorld.pdf, is placed in ./samples/publish/publishgallery. Note that the following description omits starting up and shutting down HOOPS Publish, which is described in the HOOPS Publish Programming guide.

Inspecting HelloWorld.cpp, we see:

Default input and output files

When run with no command line arguments the following definitions are used to define the relevant input and output files. Note the working directory is set to IN_INSTALL_DIR at the top of the main() function.

#ifdef _WIN64
#define IN_INSTALL_DIR _T("..\\..\\..\\..\\bin\\win64\\")
#elifdefined _WIN32
#define IN_INSTALL_DIR _T("..\\..\\..\\..\\bin\\win32\\")
#else
#error "Architecture not supported!"
#endif

// WARNING: with the SetCurrentDirectory solution, data directory is ..\\..\\samples\\data
#define IN_3DFILE   "..\\..\\samples\\data\\step\\helloworld.stp"
#define IN_POSTERIMAGE   "..\\..\\samples\\data\\images\\empty.jpg"
#define IN_POSTERIMAGE_W  100
#define IN_POSTERIMAGE_H  100
#define IN_JSFILE   ""
#define OUT_FILE    "..\\..\\samples\\publish\\publishgallery\\sample_HelloWorld.pdf"

Adding a license key

The license key is defined in the A3DSDKLicenseKey.h header. You must replace this key with your valid key generated from the HOOPS Publish downloads page, otherwise, the program will run but nothing will happen.

#include <A3DSDKLicenseKey.h>

The license key is registered with the DLLs with:

iRet = A3DLicPutLicense(A3DLicPutLicenseFile, pcCustomerKey, pcVariableKey);
CHECK_RET;

Creating a PDF document and page

A new document is created and a page is added in standard US Letter Format.

// create empty document
A3DPDFDocument* pDoc = NULL;
iRet = A3DPDFDocumentCreateEmpty(&pDoc);
CHECK_RET;
 
if(pDoc != NULL)
{
   // creating a document page from scratch
   A3DPDFPageData sPageData;
  
   A3D_INITIALIZE_DATA(A3DPDFPageData, sPageData);
 
   sPageData.m_ePageOrientation = kA3DPDFPageLandscape;
   sPageData.m_ePageSize = kA3DPDFPageLetter;  // standard letter format: 612 x 792
   constintiPageWidth = 792, iPageHeight = 612;
   A3DPDFPage* pPage = NULL;
   iRet = A3DPDFDocumentAppendNewPage(pDoc, &sPageData, &pPage);
   CHECK_RET;

The macro A3D_INITIALIZE_DATA is the standard method for initialising HOOPS Publish structures.

Loading the STEP File and creating the PRC stream

The STEP File is loaded in using

iRet = A3DAsmModelFileLoadFromFile(in_3dfile, &sReadParam, &pModelFile);

The structure sReadParam is of type A3DRWParamsLoadData and has multiple flags that control how the file is loaded, what is read, how it is tessellated etc. These are documented in the HOOPS Publish reference manual. If you have any queries as to how to set these parameters please contact the HOOPS Support team.

If the load was successful then a PRC Stream is created from the model file entity

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);

   iRet = A3DPDF3DStreamCreateFromModelFileAsPRC(pDoc, 
      pModelFile, 
      &sParamsExportData, 
      &pStream, NULL);
   CHECK_RET;

Adding a Poster Image

A poster image is a raster representation of the 3D annotation that is displayed when the annotation is not activated. By default user interaction is needed to activate a 3D annotation, although activation can also happen automatically when the document is opened. If no poster image is specified when a 3D annotation is created, HOOPS Publish will automatically generate one.

// creating the poster image
A3DPDFImageData sImageData;
A3DPDFImage* pImage;
A3D_INITIALIZE_DATA(A3DPDFImageData, sImageData);

sImageData.m_pcFileName = in_posterfile;
sImageData.m_iHeight = IN_POSTERIMAGE_H;
sImageData.m_iWidth = IN_POSTERIMAGE_W;
sImageData.m_eFormat = kA3DPDFImageFormatJpg;
iRet = A3DPDFImageCreate(pDoc, &sImageData, &pImage);
CHECK_RET;

The image defined in pImage is added to the annotation as the poster image as the m_pPosterImage parameter of the A3DPDF3DAnnotData structure passed when the 3D Annotation is created - see "Creating the 3D Annotation" below.

Creating the 3D Artwork

The ’artwork’ for the annotation represents the model (the stream), and Javascript and the named views (stored camera parameters).

// creating the 3D artwork
A3DPDF3DArtwork* p3DArtwork;
A3DPDF3DArtworkData s3DArtworkData;
A3D_INITIALIZE_DATA(A3DPDF3DArtworkData, s3DArtworkData);

s3DArtworkData.m_pStream = pStream;
s3DArtworkData.m_pcJavaScriptFileName = in_jsfile;
s3DArtworkData.m_eAnimationStyle = kA3DPDFAnimStyleNoAnimation;
iRet = A3DPDF3DArtworkCreate(pDoc, &s3DArtworkData, &p3DArtwork);
CHECK_RET;

Creating the 3D Annotation

After adding the stream to the artwork, the 3D annotation can be created. A number of parameters that can control how the annotation looks can be set:

A3DPDF3DAnnotData sAnnotData;
A3D_INITIALIZE_DATA(A3DPDF3DAnnotData, sAnnotData);

sAnnotData.m_bOpenModelTree = false;
sAnnotData.m_bShowToolbar = false;
sAnnotData.m_eLighting = kA3DPDFLightCADOptimized;
AnnotData.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 = pImage;  
sAnnotData.m_p3DArtwork = p3DArtwork;
A3DPDF3DAnnot* p3DAnnot = NULL;

iRet = A3DPDF3DAnnotCreate(pDoc, &sAnnotData, &p3DAnnot);
CHECK_RET;

Inserting the 3D Annotation in the page

The annotation position is described via a rectangle with the coordinate origin at the bottom left of the page. In the example below the annotation covers the entire page.

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 = 0;              // lower left x
   sPos.m_iBottom = 0;            // lower left y
   sPos.m_iRight = iPageWidth;    // upper right x
   sPos.m_iTop = iPageHeight;     // upper right y
   iRet = A3DPDFPageInsert3DAnnot(pPage, p3DAnnot, &sPos);
   CHECK_RET;
}

Cleaning up

To clean up, the model file must be deleted, although this should not be done before the Artwork has been created as it is at this point that the actual conversion takes place. The modified PDF document must then be saved and closed.

// cleaning up
// WARNING: DO NOT CALL THIS BEFORE A3DPDF3DArtworkCreate!
iRet = A3DAsmModelFileDelete(pModelFile);
CHECK_RET;
 
// saving the document 
iRet = A3DPDFDocumentSave(pDoc, out_pdffile);
CHECK_RET;

iRet = A3DPDFDocumentClose(pDoc);
CHECK_RET;

Working with Templates

If we switch to the BillOfMaterials sample we can see that the PDF file is created using the BOM_LetterTable_P.pdf template is loaded from the ./samples/publish/publishquickstarts/templates/billofmaterials directory.

#define IN_PDFFILE  "..\\..\\samples\\publish\\publishquickstarts\\Templates\\BillOfMaterials\\BOM_LetterTable_P.pdf"

// insert page from a template file
A3DPDFPage* pPage = NULL; 
// the false boolean keeps the same fields names
iRet = A3DPDFDocumentAppendPageFromPDFFileEx(pDoc, in_pdftemplatefile, false, &pPage);
CHECK_RET;

If we look at the template in Adobe Acrobat Professional, you can see a list of defined field names for each field in the template:

The properties for each of these fields can also be viewed and modified in Adobe Acrobat.

Once the 3D annotation has been created, we can insert it into the "My3DWindow" button in the PDF template using the object's name.

// populating the field with the 3D annotation
iRet = A3DPDFPageFieldSet3DAnnot(pPage, "My3DWindow", p3DAnnot);
CHECK_RET;

Similarly, we can populate the table view below the 3D annotation with text values ...

iRet = A3DPDFPageFieldTextSetValue(pPage, "Part NoRow1", "FG452322");
CHECK_RET;
iRet = A3DPDFPageFieldTextSetValue(pPage, "Part NoRow2", "FG997452");
CHECK_RET;
iRet = A3DPDFPageFieldTextSetValue(pPage, "Part NoRow3", "FG664452");
CHECK_RET;
iRet = A3DPDFPageFieldTextSetValue(pPage, "Part NoRow4", "AG876452");
CHECK_RET;
iRet = A3DPDFPageFieldTextSetValue(pPage, "Part NoRow5", "HFG78452");
CHECK_RET;

The result is sample_BillOfMaterial.pdf:

Adding JavaScript actions

HOOPS Publish supports the connection of JavaScript actions to fields and buttons within the PDF document.

Adobe JavaScript for Acrobat 3D is a separate JavaScript interface provided by Adobe for 3D Annotations, although it can be called from the standard Adobe Scripting engine via the JavaScript  Annot3D.context3D property. To find more resources search for "JavaScript for Acrobat 3D" on the Adobe Developer network. If viewing pages in Adobe Livedocs it is a good idea to turn on display of the contents pane using the button at the top left of the page.

HOOPS Publish does not document the JavaScript interface and Tech Soft 3D does not warrant support for it.

To familiarise yourself with the Adobe JavaScript for Acrobat 3D we suggest reading the "JavaScript for Acrobat 3D Annotations API Reference" (js_3d_api_reference.pdf) available on the Adobe Developer website.

The WorkInstruction example on the HOOPS Publish download demonstrates how to attach JavaScript to buttons to cause pre-defined Views in the model to be executed when the button is pressed.

char* myjs1 = "c3d = this.getAnnots3D( 0 )[0].context3D; "
              "c3d.runtime.setView(\"View_1\", true);";
iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, "Button1", myjs1);
CHECK_RET;

The JavaScript code in myjs1 gets the first 3D annotation on the first page to retrieve the 3D context for that annotation. Note that the function parameter in GetAnnots3D is the zero-based page number, whilst the array index is the zero-based 3D annotation number on the page.

The runtime object represents an instance of the playback engine which manages event processing. The runtime.setView method sets the current view for the annotation, with the Boolean value indicating whether to animate to the view when it is set.

Creating a view and creating an image from a view

The UserDefinedViews example shows how to render the 3D scene to an image using a programmatically defined camera setup, and to then use the image as the icon for a button in the PDF document.

Initially some JavaScript actions, view names and button names are defined:

char* myjs2 = "c3d = this.getAnnots3D( 0 )[0].context3D;"
       "c3d.runtime.setView(\"CentralPlaza\", true);",
       * myjs3 = "c3d = this.getAnnots3D( 0 )[0].context3D;"
       "c3d.runtime.setView(\"MainConcourse\", true);",
       * myjs4 = "c3d = this.getAnnots3D( 0 )[0].context3D;"
       "c3d.runtime.setView(\"AtriumEntrances\", true);",
       * myjs5 = "c3d = this.getAnnots3D( 0 )[0].context3D;"
       "c3d.runtime.setView(\"AtriumSuites\", true);",
       * name1 = "Default", * name2 = "CentralPlaza", * name3 = "MainConcourse",
       * name4 = "AtriumEntrances", * name5 = "AtriumSuites",
       * button1 = "Button1", * button2 = "Button2", 
       * button3 = "Button3", * button4 = "Button4";

Then the stCreateView function defined in the sample is used to create the view. The image is created using the sample function stCreateImageFromView and then placed on the button and the JavaScript action is associated with the button. In this case the action sets that view, but it need not do.

// Central Plaza View:
iRet = stCreateView(pDoc, p3DArtwork, 
                    36694.61, 107771.03, 26664.91,          // camera position
                    -15212.11, 18814.32, 248.49,            // target position
                    -0.126643, -0.213750, 0.968645,         // up vector
                    kA3DPDFPerspectiveMode,
                    0, 30,
                    false, name1, &pView));
CHECK_RET;

iRet = stCreateImageFromView(pDoc, pModelFile, pView, thumbnail_w, thumbnail_h,
       tmpImage, &pImageView);
CHECK_RET;

iRet = A3DPDFPageFieldButtonSetIcon(pPage, button1, pImageView);
CHECK_RET;

remove(tmpImage);

iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, button1, myjs2);
CHECK_RET;

stCreateView sets up the view name, lighting model, render mode, background color and whether it is the default view or not, then creates a view and adds the view to the artwork:

iRet = A3DPDFViewCreate(pDoc, &sViewData, ppView);
CHECK_RET;

iRet = A3DPDF3DArtworkAddView(p3DArtwork, *ppView);
CHECK_RET;

Creating an image from a view in stCreateImageFromView is a two-step process. The first step involves rendering a ’snapshot’ to a file from the view position with a given width and height, and the second step involves creating a PDF Image from the rendered image file:

A3DInt32 iRet = A3D_SUCCESS;

A3DPDFSnapshotOptionsData sOptionData;
A3D_INITIALIZE_DATA(A3DPDFSnapshotOptionsData, sOptionData);

sOptionData.m_iWidth = width;
sOptionData.m_iHeight = height;
sOptionData.m_pView = pView;
iRet = A3DPDFMakeSnapshotFromModelFile(pModelFile, &sOptionData, pcFileName);
CHECK_RET;

A3DPDFImageData sImageData;
A3D_INITIALIZE_DATA(A3DPDFImageData, sImageData);

sImageData.m_pcFileName = pcFileName;
sImageData.m_iWidth = width;
sImageData.m_iHeight = height;
sImageData.m_eFormat = kA3DPDFImageFormatJpg;
iRet = A3DPDFImageCreate(pDoc, &sImageData, ppImage);
CHECK_RET;

The resulting sample_UserDefinedViews.pdf is shown below, with the view set after Button2 has been pressed.

More Advanced JavaScript

Playing an animation

The U3DWithAnimation sample shows how to play a pre-defined animation stored within a U3D file. The JavaScript below accesses a button by name, interrogates the button caption, and based on the result toggles between playing and pausing the animation for that 3D Annotation context.

Note that the first seven seconds of the animation stored in the U3D file don’t do anything so the animation is set to start at 8 seconds. The restart animation button simply calls the restart animation function, and sets the caption of the ’Play/Pause’ button appropriately:

// button play
iRet = A3DPDFPageFieldButtonSetLabel(pPage, "Button1", "Play");
CHECK_RET;

// In this sample, we set the first button as a play/stop button. 
// Default behaviour is play.
// Note: with the car.u3d sample, the animation really starts at 8 secs.

char* myjs1 = "c3d = this.getAnnots3D(0)[0].context3D; " 
             "f = this.getField(\"Button1\"); "
             "if(f.buttonGetCaption()==\"Play\") { "
             "     if.buttonSetCaption(\"Pause\"); c3d.play(8) } "
             "else { f.buttonSetCaption(\"Play\"); c3d.pause() }";
 
iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, "Button1", myjs1);
CHECK_RET;

// button restart
iRet = A3DPDFPageFieldButtonSetLabel(pPage, "Button2", "Restart");
CHECK_RET;

// With the car.u3d sample, the animation really starts at 8 secs.
char* myjs2 = "c3d = this.getAnnots3D(0)[0].context3D; c3d.restart(8);"
                    "f = this.getField(\"Button1\"); "
                    "if(f.buttonGetCaption()==\"Play\") { "
                    "   if.buttonSetCaption(\"Pause\") }";

iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, "Button2", myjs2);
CHECK_RET;

You'll notice if you browse the Adobe JavaScript for 3D documentation that the context3D property of the Annot3D object does not have Play, Pause or Restart methods. In this case these methods are defined in the default JavaScript defined for the 3D Annotation. In the U3D With Animation sample this is timer.js...

#define IN_JSFILE   "..\\..\\samples\\data\\JavaScript\\timer.js"

... which is attached to the annotation when the Artwork is created.

If we inspect this file we can see only the first animation in the scene is accessed. A TimeEventHandler object is created with an event callback that keeps track of the animation time and stops the animation if appropriate.

// set animation
theAnimation = scene.animations.getByIndex(0);
scene.activateAnimation(theAnimation);
 
timer = newTimeEventHandler();
timer.active = false;
timer.targetTime = theAnimation.length;
theAnimation.currentTime = 0.0;
 
timer.onEvent = function(event)
{
   if (this.active)
   {
      target = theAnimation.currentTime;
      target += event.deltaTime;
      if (target > this.targetTime)
      {
         target = this.targetTime;
         this.active = false;
      }
      theAnimation.currentTime = target;
   }
}
 
runtime.addEventHandler(timer);
 
play = function(start)
{
   // this should only start from 'start' at first press.
   // Subsequent call should start from the currenlt paused step.
   if (theAnimation.currentTime==0.0)
      theAnimation.currentTime = start;
   timer.active = true;
}
 
playSequence = function(start, end)
{
   theAnimation.currentTime = start;
   timer.targetTime = end;
   timer.active = true;
}
 
pause = function()
{
   if (theAnimation.currentTime>= theAnimation.length)
      theAnimation.currentTime = 0.0;
   timer.active = false;
}
 
restart = function(start)
{
   theAnimation.currentTime = start;
   timer.targetTime = theAnimation.length;
   timer.active = true;
}

Populating list boxes and combo boxes

The DemoFunctionalities example creates a three page PDF. The first page creates a simple Hello World form programmatically, and pages two and three are based on a single template that contains a list box and a combo box placed at the same position on the form i.e. on top of each other.

Page two hides the list box so the combo box is shown, whilst page 3 hides the combo box so the list box is shown. Each lists each view in the 3D annotation. In both cases the sample shows how to add JavaScript to respond to selection change events, and how to access a separate text field, "SelectedItemValue" and set the selected value as the label for that field.

When used in a multipage PDF the field names from the template have the page number appended, so that "My3DWindow" becomes "My3DWindow_2" and "My3DWindow_3" respectively.

Note that this naming convention is supplied by HOOPS Publish, as Acrobat requires each field name in a PDF to be unique within the document, not just the page.

Note that the same API call is used to populate both the list box and combo box, but the JavaScript to control them is slightly different.

iRet = A3DPDFPageFieldSetVisibility(pPage, "MyListbox_2", false);

iRet = A3DPDFPageFieldListAddItem(pPage, "MyDropdown_2", "View_1", "My View 1");
CHECK_RET;
iRet = A3DPDFPageFieldListAddItem(pPage, "MyDropdown_2", "View_2", "My View 2");
CHECK_RET;
iRet = A3DPDFPageFieldListAddItem(pPage, "MyDropdown_2", "View_3", "My View 3");
CHECK_RET;
iRet = A3DPDFPageFieldListAddItem(pPage, "MyDropdown_2", "View_4", "My View 4");
CHECK_RET;

char* myjscombo = "if( event.willCommit )" 
       "{"
       "  if(!event.value == \"\")"
       "  {"
       "    f=this.getField(\"SelectedItemValue_2\");"
       "       f.value=event.value;"
       "       activateview(2,0,f.value);"
       "  }"
       "}";

iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, "MyDropdown_2", myjscombo);
CHECK_RET;

In the JavaScript, SelectedItemValue_2 represents a separate text field in which the result of the selection is shown.

The function activateView is defined at the PDF Document level using the code:

// js on the doc
char* myjsondoc = "function activateview(pgidx, annotidx, viewname)\n"
       "{\n"
       "      // in getAnnots3D, page index starts from 0\n"
       "      c3d = this.getAnnots3D(pgidx-1)[annotidx].context3D;\n"
       "      c3d.runtime.setView(viewname, true);\n"
       "}";
iRet = A3DPDFDocumentAddJavaScriptFromString(pDoc, "MyFns", myjsondoc);
CHECK_RET;

The code for the third page is similar, except the mechanism to get the current selection in the list box is slightly different - in the case of the combo box the JavaScript responds to an event indicating a possible change in selection, in the case of the list box HOOPS Publish also sets the code so it is executed when the selection changes, but in this case the index of the current item is obtained to extract the item's value:

// page 2 : only populate list box
iRet = A3DPDFPageFieldSetVisibility(pPage, "MyDropdown_3", false);

iRet = A3DPDFPageFieldListAddItem(pPage, "MyListbox_3", "View 1", "View_1");
CHECK_RET;
iRet = A3DPDFPageFieldListAddItem(pPage, "MyListbox_3", "View 2", "View_2");
CHECK_RET;
iRet = A3DPDFPageFieldListAddItem(pPage, "MyListbox_3", "View 3", "View_3");
CHECK_RET;
iRet = A3DPDFPageFieldListAddItem(pPage, "MyListbox_3", "View 4", "View_4");
CHECK_RET;

char* myjslistbox = "thisfield = this.getField(\"MyListbox_3\");"
       "if (thisfield)"
       "{"
       "  idx = thisfield.currentValueIndices;"
       "  console.println(\"thisfield.index: \" + idx);"
       "  console.println(\"thisfield.value: \" + thisfield.getItemAt(idx, true));"
       "  console.println(\"thisfield.exportvalue: \" + thisfield.getItemAt(idx,false));"
       "  f=this.getField(\"SelectedItemValue_3\");"
       "  f.value=thisfield.getItemAt(idx, true);"    
       "  activateview(3,0,f.value);"
       "}";

iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, "MyListbox_3", myjslistbox);
CHECK_RET;

How and when the JavaScript is executed for each type of Page Field is documented in the JavaScript section of the HOOPS Publish Programming guide.

Note also the console.println statements that can be used for debugging when the PDF is opened in Adobe Acrobat. To view the debugger select Tools->JavaScript->JavaScript->Debugger within Acrobat.

Accessing unique PDF object IDs

The PublishPRCCube example demonstrates using the HOOPS Publish API to create geometry directly rather than load it in from file. You can also use this method if you wish to link HOOPS Publish directly to your application’s internal data structures, rather than transferring geometry via file.

The work to create the cube geometry is done in the file CreatePRCAsmAndGetPDFIds.cpp, whilst PublishPRCCube.cpp creates the PDF file.

Reviewing the PRC creation code is beyond the scope of this document but the important concept of traversing the model to obtain unique ids for each node needs discussion.

The function TraverseModelForPDFIds traverses the in-memory PRC assembly structure and retrieves a PDFNodeId from each representation item using A3DEntityGetPDFNodeIdFromWrite. For this example the name of each node is checked and only the PDF Ids for each cube are returned.

The node ids that has been retrieved can be used in JavaScript to allow buttons to control the visibility of each item: the retrieved value for pcIdNode1 is used in the scene.nodes.getByName function to retrieve the node object itself:

iRet = A3DPDFPageFieldButtonSetLabel(pPage, "Button1", "Cube1");
CHECK_RET;

charjscmd[1024];
sprintf(jscmd, "c3d = this.getAnnots3D( 0 )[0].context3D; "
                    "for (vari = 0; i< c3d.scene.nodes.count; i++) {"
                    "var node = c3d.scene.nodes.getByIndex(i); node.visible=false; } ; "
                    "var node = c3d.scene.nodes.getByName(\"%s\"); node.visible=true;", 
		pcIdNode1);
iRet = A3DPDFPageFieldSetActionJavaScriptFromString(pPage, "Button1", jscmd);
CHECK_RET;

Controlling object transparency

The ProductDescription example uses JavaScript functions defined at document level to make some objects in the scene transparent. Review highlight.js in the ./samples/data/JavaScript directory:

function set_all_visible(visible)
{
   var materials = scene.materials;
   for(i=0; i<materials.count; i++ )  
   {
      var mat = materials.getByIndex(i);
      if( mat != null )
         mat.opacity = (visible?1:.05);  
   }
}

function show_node(name)
{
   var node = scene.nodes.getByName(name);
   if(node.material != null )
   {
      node.material.opacity = 1; 
   }
}

The set_all_visible function iterates all materials in the scene and sets them to be visible or almost invisible (0.05 transparency). The show_node function makes the named node fully opaque.