3D-PDF Export#

The 3D-PDF Export tool creates a PDF document with embedded 3D graphic. The tool is particularly focused on structural models and reinforcement.

  1. Click BiMTOOLS tab > 3D-PDF Export panel > icon_3D_PDF_Export (Export)

    The Settings dialog displays.

  2. Choose your preferred settings and click OK.

    The PDF file will be created in the project folder.

Tip

If ‘Use ActiveView Geometry’ is checked, the program exports the geometry represented the active view, taking into account section boxes, displacements and other view dependent features.

../_images/mainpic.png

3D-PDF Export Settings Dialog#

The settings dialog provides general definitions such as the quality, appearance and parameters to export.

Tab General#

In the General Tab provides the following main settings for the export.

../_images/mpic_SettingsTab_General.png

General Settings#

  • PDF File. The path that will be used to create the PDF file, the default value is the Revit project path.

  • Page size. Defines the dimensions of the page in which the 3D model will be embedded. The possible options are: “A3 - 297 x 420 [mm]”, “A4 - 210 x 297 [mm]”, “A5 - 148 x 210 [mm]”, “B4 - 250 x 353 [mm]”, “B5 - 176 x 250 [mm]”, “Letter - 8.5 x 11 [inches]” and “Legal - 8.5 x 14 [inches]”.

  • Orientation. The options are: Portrait format and landscape format.

Quality and Appearance#

  • Overall Level of Detail. This parameter controls the quality of the mesh that will be generated to represent the elements. Value must be in the range [0, 1].

  • Level of Detail Reinforcement. Similar to the previous parameter, the quality of the mesh representing the reinforcement elements (Rebar, Rebar sets, Area reinforcement and Path reinforcement) is controlled. Value must be in the range [0, 1].

  • Background color. The default color used as background in the PDF document.

  • Use Active View Geometry. If checked, the program exports the geometry represented the active view, taking into account section boxes, displacements and other view dependent features.

Caution

The level of detail (especially for reinforcement) will strongly influence the size of PDF file.

Tab Parameters#

In the Parameters tab you can choose the parameters to export for each element type individually.

../_images/mpic_SettingsTab_Parameters.png

Tab Other#

In the Other tab provides access to additional definitions Java/U3D support and to add a page header.

../_images/mpic_SettingsTab_Other.png

JavsScript Support#

  • Include JavaScript file. If checked, enables selecting a JavaScript to include in the 3D model.

  • JavaScript File location. JavaScript file which will be included in the 3D Model.

  • Example

U3D#

  • Delete U3D. If checked, the U3D file is deleted after creating the PDF file. The U3D file can be included manually in other PDF files or opened with a special viewer, such as MeshLab.

  • Optimize file size. If checked, 3D PDF Export will create the file with optimized size.

Other#

  • Attach ObjectType URL to Elements. If checked, attached URL address will be opened via double click on the element.

Settings transfer#

  • Export. You can save current settings as (.dat) file in chosen directory.

  • Import. You can open already existing settings file and load it into the current project.

Workflow#

The process to generate a 3D PDF document using SOFiSTiK 3D-PDF Export can be structured in the following points:

  1. Get the geometric definition of the elements Revit and organize it as a set of 3D objects formed by a triangular mesh.

  2. Create a U3D file using the previously collected geometric data.

  3. Generate a standard PDF document and embed on one of its pages the 3D model that was stored in U3D format.

In order to complete this workflow, two external libraries are implemented. Firstly, to create the required U3D file an open source library called “Universal 3D Sample Software”; this one allows writing, reading and editing data in the referred format. The complete library and source code can be found in the following web page:

http://sourceforge.net/projects/u3d/develop

On the other hand, the PDF file is created by means of another external library, i.e. “libHaru” which is a free, cross platform, open source library for generating PDF files. So then, libHaru is able to incorporate different kind of external objects into a PDF document, such as U3D files. The version 2.3.0 is included in the SOFiSTiK PDF Export, likewise another two libraries are implemented according to the requirements of libHaru: zlib (v 1.2.5) and libpng (1.5.8). The complete library and source code can be found in the following web page:

http://libharu.org/

Summarizing the “SOFiSTiK 3D-PDF Export” workflow can be depicted as follows:

../_images/workflow.png

Java Script Support#

JavaScript Support extends possibilities to modify 3D objects and their appearance programmatically.

Include JavaScript files into the project using Settings Dialog (Tab Other)

  1. Create Java Script file with your own code or use prepared example

  2. Click Add-Ins tab > SOFiSTiK 3D-PDF Export panel > icon_Export (Export)

The Settings dialog displays.
../_images/mpic_SettingsTab_Other.png
  1. In Tab Other, check ‘Include JavaScript file’ box and select the directory of proper JavaScript file in ‘File location’.

  2. Check other setting and click OK to create 3D-PDF file.

Example#

You can use following code to create Java Script file.

  1. Create and open new “.txt” file

  2. Copy whole code, paste into the “.txt” file, save it and close.

  3. Change the extension of the file into “.js”

Following example of JavaScript enables you to change the color of an element temporarly by holding a cursor on it.

function ModelPartObject()
{
        this.mouseEventHandler  = null;
        this.mesh               = null;
}
function MouseSelectionObject()
{
        owner = this;

        var DEFAULT_RENDER_MODE                 = "solid outline";
        var DEFAULT_MOUSE_OVER_RENDER_MODE  = "illustration";
        var DEFAULT_MOUSE_DOWN_RENDER_MODE  = "illustration";
        var DEFAULT_SELECTED_RENDER_MODE        = "illustration";

        var defaultRenderMode                   = DEFAULT_RENDER_MODE;
        var mouseOverRenderMode                 = DEFAULT_MOUSE_OVER_RENDER_MODE;
        var mouseDownRenderMode                 = DEFAULT_MOUSE_DOWN_RENDER_MODE;
        var selectedRenderMode                  = DEFAULT_SELECTED_RENDER_MODE;
        var mousePart = -1;
        var selectedPart = -1;
        var initialized = false;
        var numberOfModelParts = 0;
        var atLeastOnePartHasBeenCreated = false;
        var camera = this.scene.cameras.getByIndex( 0 );
        var generalMouseEventHandler = new MouseEventHandler();

        var maxNumModelParts = this.scene.meshes.count;
        var modelPart = new Array( maxNumModelParts );

        for (p=0; p<maxNumModelParts; p++)
        {
          modelPart[p] = new ModelPartObject();
        }
        generalMouseEventHandler.onMouseDown    = true;
        generalMouseEventHandler.onMouseMove    = true;
        generalMouseEventHandler.onMouseUp      = true;
        generalMouseEventHandler.onEvent = function( event )
        {
                if ( event.isMouseUp)
                {
                        if ( mousePart != -1 )
                        {
                                modelPart[ mousePart ].mesh.renderMode = defaultRenderMode;
                                mousePart = -1;
                        }
                }
        }

        runtime.addEventHandler( generalMouseEventHandler );
        this.myMouseHandlingFunction = function( event )
        {
                var m = 0;
                var lookingForMesh = true;
                while ( lookingForMesh )
                {
                        if ( this.target == modelPart[m].mesh )
                        {
                                lookingForMesh = false;
                                if ( event.isMouseOver )
                                {
                                        if ( ! event.leftButtonDown )
                                        {
                                                mousePart = m;
                                                modelPart[ m ].mesh.renderMode = mouseOverRenderMode;
                                        }
                                }

                                if ( event.isMouseOut )
                                {
                                        if (( ! event.leftButtonDown ))
                                        {
                                                mousePart = -1;
                                                modelPart[ m ].mesh.renderMode = defaultRenderMode;
                                        }
                                }
                                if ( event.isMouseDown )
                                {
                                        mousePart = m;
                                        modelPart[ m ].mesh.renderMode = mouseDownRenderMode;
                                }
                                if ( event.isMouseUp )
                                {
                                        if ( selectedPart != -1 )
                                                {modelPart[ selectedPart ].mesh.renderMode = defaultRenderMode; }

                                        selectedPart = m;
                                        mousePart = -1;
                                }
                        }

                        m ++;

                        if ( m > numberOfModelParts - 1 )
                                {lookingForMesh = false;}
                }
        }

        this.getMeshesFromModel = function()
        {
                numberOfModelParts = 0;

                for (p=0; p<this.scene.meshes.count; p++)
                {
                        var modelMesh = this.scene.meshes.getByIndex( p );
                        if ( modelMesh.material )
                        {
                                modelPart[ numberOfModelParts ].mesh = modelMesh;

                                if ( ! atLeastOnePartHasBeenCreated )
                                {atLeastOnePartHasBeenCreated = true;}
                                numberOfModelParts ++;
                        }
                }

        }

        this.initialize = function()
        {
                if ( ! initialized )
                {
                        owner.getMeshesFromModel();
                        for (var m=0; m<numberOfModelParts; m++)
                        {
                                modelPart[m].mouseEventHandler = new MouseEventHandler();
                                modelPart[m].mouseEventHandler.onMouseMove = true;
                                modelPart[m].mouseEventHandler.onMouseDown = true;
                                modelPart[m].mouseEventHandler.onMouseUp   = true;
                                modelPart[m].mouseEventHandler.onMouseOver = true;
                                modelPart[m].mouseEventHandler.onMouseOut  = true;
                                modelPart[m].mouseEventHandler.target      = modelPart[m].mesh;
                                modelPart[m].mouseEventHandler.onEvent     = owner.myMouseHandlingFunction;
                                runtime.addEventHandler( modelPart[m].mouseEventHandler );
                        }

                        for (p=0; p<this.scene.meshes.count; p++)
                        {
                                var mesh = this.scene.meshes.getByIndex(p);
                                if ( mesh.material )
                                {mesh.renderMode = defaultRenderMode;}
                        }
                        initialized = true;
                }

                return initialized;
        }

        this.setAllPartsToDefaultRenderMode = function()
        {
                for (var m=0; m<numberOfModelParts; m++)
                {modelPart[m].mesh.renderMode = defaultRenderMode;}
        }

        this.selectPart = function( partName )
        {owner.selectPartByIndex( getPartIndexFromName( partName ) );}

        this.unSelectPart = function( partName )
        {owner.unSelectPartByIndex( getPartIndexFromName( partName ) );}

        this.selectPartByIndex = function( partIndex )
        {
                selectedPart = partIndex;
                modelPart[ selectedPart ].mesh.renderMode = selectedRenderMode;
        }

        this.unSelectPartByIndex = function( partIndex )
        {
                if ( partIndex == selectedPart )
                {
                        modelPart[ selectedPart ].mesh.renderMode = defaultRenderMode;
                        selectedPart = -1;
                }
        }

        this.incrementSelectedPart = function()
        {
                if ( selectedPart == -1 )
                {owner.selectPartByIndex( 0 );}
                else
                {
                        var previouslySelectedPart = selectedPart;
                        owner.unSelectPartByIndex( selectedPart );
                        var nextPart = previouslySelectedPart + 1;

                        if ( nextPart >= numberOfModelParts )
                        {nextPart = 0;}

                        owner.selectPartByIndex( nextPart );
                }
        }

        this.decrementSelectedPart = function()
        {
                if ( selectedPart == -1 )
                {owner.selectPartByIndex( 0 );}
                else
                {
                        var previouslySelectedPart = selectedPart;
                        owner.unSelectPartByIndex( selectedPart );
                        var nextPart = previouslySelectedPart - 1;

                        if ( nextPart < 0 )
                        {nextPart = numberOfModelParts - 1;}

                        owner.selectPartByIndex( nextPart );
                }
        }

        this.getSelectedPartName = function()
        {
                result = "there is no selected part";
                if ( selectedPart != -1 )
                {result = modelPart[ selectedPart ].mesh.name; }
                return result;
        }

        this.unSelectSelectedPart = function()
        {owner.unSelectPartByIndex( selectedPart );}

        this.setDefaultRenderMode = function( renderMode )
        {
                defaultRenderMode = renderMode;
                owner.setAllPartsToDefaultRenderMode();
        }

        this.setMouseOverRenderMode = function( renderMode )
        {mouseOverRenderMode = renderMode;}

        this.setMouseDownRenderMode = function( renderMode )
        {mouseDownRenderMode = renderMode;}

        this.setSelectedRenderMode = function( renderMode )
        {selectedRenderMode = renderMode;}

        this.setAllMouseSelectionPartsToDefaultRenderMode = function()
        {setAllPartsToDefaultRenderMode();}

        this.getPartIndexFromName = function ( partName )
        {
                var index = -1;
                for (m=0; m<numberOfModelParts; m++)
                {
                        if ( partName == modelPart[m].mesh.name )
                        {index = m;}
                }

                return index;
        }

        owner.initialize();
        return this;
}

var mouseMoved=MouseSelectionObject();