########################
File-to-File Translation
########################

This tutorial walks you through the :ref:`sample_import_export` sample code, which is one of the :doc:`samples </sample_codes>` included with HOOPS Exchange.
The sample demonstrates the basic workflow of reading an input file and exporting it to a new format.

As a prerequisite, ensure you have followed the previous tutorial, :doc:`Set Up Your Environment <environment-setup>`.
Ensure you can build and run the *ImportExport* sample.
The sample code can be found in the *csharp/samples* folder of your package.

The Code
========

Open *ImportExport.cs* in your editor.
Since the sample is a complete implementation, you're not required to add anything new to the program.
To facilitate learning, we'll examine each of the functional areas with a deep dive into what the code is doing.

The first thing you'll notice is the C# assemblies needed for this sample to work.
In this case, we're using:

.. code-block:: csharp

    using TS3D.Exchange;
    using TS3D.Exchange.Direct;

This sample takes a few command-line parameters: the path to the HOOPS Exchange libraries, the input filename, and the output filename.

Starting at ``Main``, the first significant step is parsing the command-line arguments. This is handled in ``ParseArgs``.

If you run the program without specifying input and/or output files, defaults are used:

    * The default input file is *<HOOPS_EXCHANGE_INSTALL_DIR>samples/data/catiaV5/CV5\Aquo\Bottle/\Aquo Bottle.CATProduct*.
    * The default output file is the input file name with *.prc* appended.

The default values indicate we are converting the Catia V5 input file to its PRC equivalent.



Next, the sample connects callbacks for a log file and various callbacks.

.. code-block:: csharp

    // Initialize log file and HOOPS Exchange callbacks
    LogFile = new StreamWriter(outputLogFile);
    API.A3DDllSetCallbacksReport(MessageCallback, WarningCallback, ErrorCallback);

While not required for using HOOPS Exchange, these callbacks can provide valuable information while debugging.
The samples all print the messages received by the callback to ``stdout``.



Next, HOOPS Exchange is initialized.

.. code-block:: csharp

    // Initialize HOOPS Exchange library
    try
    {
        Library.Initialize(HOOPS_LICENSE.KEY, exchangeFolder);
    }
    catch (Library.InitializationException e)
    {
        // handle error
        Console.WriteLine(e.Message);
        return (int) A3DStatus.A3D_ERROR;
    }
    
Here, the class ``Library`` gives us access to the HOOPS Exchange library object.
It needs to be initialized before using HOOPS Exchange functionality.
The license key may be set here, if you haven't set it elsewhere in the environment.
The application also needs to know where the Exchange libraries are located. The ``exchangeFolder`` parameter is the path to those libraries.

Following the initialization steps, the file is loaded. But before that happens, we'll have to set up its parameters. You'll see the following lines of code:

.. code-block:: csharp

    // initialize load parameters object
    A3DRWParamsLoadData loadParams;
    API.Initialize(out loadParams);
    
    // set load parameters
    loadParams.m_sGeneral.m_bReadSolids                     = true;
    loadParams.m_sGeneral.m_bReadSurfaces                   = true;
    loadParams.m_sGeneral.m_bReadWireframes                 = true;
    loadParams.m_sGeneral.m_bReadPmis                       = true;
    loadParams.m_sGeneral.m_bReadAttributes                 = true;
    loadParams.m_sGeneral.m_bReadHiddenObjects              = true;
    loadParams.m_sGeneral.m_bReadConstructionAndReferences  = false;
    loadParams.m_sGeneral.m_bReadActiveFilter               = true;
    loadParams.m_sGeneral.m_eReadingMode2D3D                = A3DEReadingMode2D3D.kA3DRead_3D;
    loadParams.m_sGeneral.m_eReadGeomTessMode               = A3DEReadGeomTessMode.kA3DReadGeomAndTess;
    loadParams.m_sGeneral.m_eDefaultUnit                    = A3DEUnits.kA3DUnitUnknown;
    loadParams.m_sTessellation.m_eTessellationLevelOfDetail = A3DETessellationLevelOfDetail.kA3DTessLODMedium;
    loadParams.m_sAssembly.m_bUseRootDirectory              = true;
    loadParams.m_sMultiEntries.m_bLoadDefault               = true;
    loadParams.m_sPmi.m_bAlwaysSubstituteFont               = false;
    loadParams.m_sPmi.m_pcSubstitutionFont                  = "Myriad CAD";

The line ``API.Initialize(out loadParams);`` initializes loader's parameters structure.
These are parameters used by the application's file loader and indicate which constructs should be loaded.
As different file formats support different constructs, these parameters may be different depending on the file type you're attempting to load, and which constructs your application requires.

.. note::

   A list of supported parameters can be found :doc:`/api/c/group__a3d__readwrite__module`.

Next, the file is loaded using the parameters initialized in the previous step:

.. code-block:: csharp

    // Load input CAD file
    IntPtr modelFile;
    A3DStatus loadStatus = API.A3DAsmModelFileLoadFromFile(inputFile, ref loadParams, out modelFile);

The ``inputFile`` is from a command-line parameter, ``loadParams`` is from the previous step, and ``modelFile`` is the PRC filename to write after the translation. 

.. hint::

    It is always good practice to check the load status using the function's returned value. It will be of the :cpp:enum:`A3DStatus` type.

Now that our file is loaded, we will export it.
The translation is handled automatically during the write action.
We only specify the file type, which is implied by the *outputFile* extension.
Successful functions return ``A3DStatus.A3D_SUCCESS``.

.. code-block:: csharp

    // Export output CAD file
    A3DStatus exportStatus = Export(modelFile, outputFile);
    if (exportStatus == A3DStatus.A3D_SUCCESS)
    {
        Console.WriteLine("Success.");
    }
    else
    {
        Console.WriteLine("Failure.");
    }
    
Notice the different objects, ``modelFile`` and ``outputFile``.
The ``modelFile`` is an object in memory which represents the output file logically.
The ``outputFile`` is merely the filename as a ``string``.
    
Assuming the application is successful, the file is converted.

Now we should terminate cleanly.
Since the C# API is only a set of bindings, the memory lies within the C binaries.
Thus, the objects have to be explicitely released when they are not needed anymore.
The following code snippets releases the model file object, then unloads the C binaries.

.. code-block:: csharp

    API.A3DAsmModelFileDelete(modelFile);
    Library.Free();
    
Investigating the sample
========================

In this section, we will tweak the code and see the changes.

.. tabs::

   .. group-tab:: Windows

      **Change the command line**
    
      In Visual Studio from the Solution Tree explorer:

         * Locate the sample ``ImportExport``
         * Right click on it and select *Properties*.
         * Edit the *Command Argument* setting under the Debugging tab to change the input CAD file and output.

         Assuming that the HOOPS Exchange API package is installed on the root of your disk ``C:`` the command argument looks like this:
         
         ``"C:\<HOOPS_EXCHANGE_INSTALL_DIR>\samples\data\catiaV5\CV5_Aquo_Bottle\Bullet_Lid_Cap.CATPart" "C:\<HOOPS_EXCHANGE_INSTALL_DIR>\samples\data\catiaV5\CV5_Aquo_Bottle\Bullet_Lid_Cap.CATPart.stl"``

         .. image:: /_assets/images/vs-test-sample.png
            :width: 50%
            :align: center
            
         
         * *Run* the sample *ImportExport* to convert a CATIA V5 part called *Bullet_Lid_Cap.CATPart* to STL format.
         * Locate the file *Bullet_Lid_Cap.CATPart.stl* in your output folder.
         * Open the HOOPS Demo Viewer desktop application, then drag and drop your resulting *Bullet_Lid_Cap.CATPart.stl* file to quickly visualize the part:
    
         .. image:: /_assets/images/Bullet_Lid_Cap.CATPart-win.png
            :width: 50%
            :align: center

         
      **Change the conversions settings**    
      
      In Visual Studio from the Solution Tree explorer:

         * Locate the sample *ImportExport*
         * Under the Debugging tab edit the *Command Argument* setting to specify the input CAD file and output.

      Assuming that the HOOPS Exchange API package is installed on the root of your disk ``C:`` the command argument looks like this:

      ``"C:\<HOOPS_EXCHANGE_INSTALL_DIR>\samples\data\pmi\PMI_Sample\CV5_Sample.CATPart" "C:\<HOOPS_EXCHANGE_INSTALL_DIR>\samples\samples\data\pmi\PMI_Sample\CV5_Sample.CATPart.prc"``

         
         * *Run* the sample to convert the file *CV5_Sample.CATPart* to PRC format.
         * Locate and *drag and drop* the resulting *CV5_Sample.CATPart.prc* in HOOPS Demo Viewer to visualize the part in your output folder:
         
         .. image:: /_assets/images/pmi-sample.png
            :width: 50%
            :align: center
         
         
         * Locate and open the *A3DSDKInternalConvert.hxx* file from your installation folder *../include/*
         
         You are now looking at the file *A3DSDKInternalConvert.hxx* where all the `conversion parameters <https://docs.techsoft3d.com/exchange/latest/api/cs/group__a3d__readwrite__module.html>`__ are exposed.
         
      .. code::
      
         A3DRWParamsGeneralData m_sGeneral;                 /*!< The general reading parameters. */
         A3DRWParamsPmiData m_sPmi;                         /*!< The parameters for PMI reading. Used when `m_sGeneral.m_bReadPmis` is `true`. */
         A3DRWParamsTessellationData m_sTessellation;       /*!< The tessellation reading parameters. */
         A3DRWParamsAssemblyData m_sAssembly;               /*!< The reading parameters used to load Assembly files. */
         A3DRWParamsMultiEntriesData m_sMultiEntries;       /*!< The parameters used when reading multiple models. */
         A3DRWParamsSpecificLoadData m_sSpecifics;          /*!< The parameters specific to each CAD format. */
         A3DRWParamsIncrementalLoadData m_sIncremental;     /*!< The reading parameters used to load specific parts of an assembly. */
         A3DRWParamsLoadData;
      
      Import and export parameters can be added and edited as needed. Let's look at an example:
      
         * Locate the setting ``m_sLoadData.m_sGeneral.m_bReadPmis = true;`` 
         * Change its value to setting ``m_sLoadData.m_sGeneral.m_bReadPmis = false;``
         * Rebuild and run the sample to convert the file *CV5_Sample.CATPart* to PRC format again.
         * Locate and *drag and drop* the resulting *CV5_Sample.CATPart.prc* in *HOOPS Demo Viewer* to visualize the part.
         * Compare the two resulting *CV5_Sample.CATPart.prc* files.
      
         .. image:: /_assets/images/pmi-sample-no-pmi.png
            :width: 50%
            :align: center
            
      As you can see that by turning off the import parameters ``m_sLoadData.m_sGeneral.m_bReadPmis = true;`` the *Product Manufacturing Information* are not converted.
         
   .. group-tab:: Linux

      **Change the command line**
            
      On Linux, open the *Terminal*:
      
         * Locate the sample *ImportExport* from the installation folder *../samples/hello_world/ImportExport*
         * Right click on the folder and select *Open in Terminal*
         * Locate the file *Bullet_Lid_Cap.CATPart* from the installation folder *../samples/data/catiaV5/*
         * Make sure the sample is already built otherwise build it again. Command line: ``make``
                  
         .. image:: /_assets/images/Import_export_make.png
            :width: 50%
            :align: center                 
                  
         * Run the sample *ImportExport* to convert a CATIA V5 part called *Bullet_Lid_Cap.CATPart* to STL format. Command line: ``./ImportExport ../samples/data/catiaV5/Bullet_Lid_Cap.CATPart ../samples/data/catiaV5/Bullet_Lid_Cap.CATPart.stl``
                  
         .. image:: /_assets/images/Import_export_make_run.png
            :width: 50%
            :align: center
            
         * Run the sample *Viewer* to load the resulting part called *Bullet_Lid_Cap.CATPart.stl*. Command line: ``./Viewer ../samples/data/catiaV5/Bullet_Lid_Cap.CATPart.stl``
         * *Bullet_Lid_Cap.CATPart.stl* file will be displayed in an OpenGL Window:
            
         .. image:: /_assets/images/Bullet_Lid_Cap.CATPart-linux.png
            :width: 50%
            :align: center
         
      You just have learned how to specify your own input CAD file and Output format.
      
      **Change the conversion settings**

         * Stop the execution of the sample *Viewer* (Ctrl+C).
         * Locate the file *CV5_Sample.CATPart* from the installation folder *../samples/data/pmi/*
         * Run the sample *importExport* to convert the file *CV5_Sample.CATPart* to PRC format.
         * Locate the resulting *CV5_Sample.CATPart.prc* file from the folder *./samples/data/pmi/*
         * Run the sample *Viewer* to load the PRC file. Command line: ``./Viewer ../samples/data/pmi/CV5_Sample.CATPart.prc``
         
         .. image:: /_assets/images/pmi-sample-linux.png
            :width: 50%
            :align: center
         
         * Stop the execution of the sample *Viewer* (Ctrl+C).
         * Locate and open the *A3DSDKInternalConvert.hxx* file from your installation folder *../include/*.
         
      You are now looking at the file ``A3DSDKInternalConvert.hxx`` where all the `conversion parameters <https://docs.techsoft3d.com/exchange/latest/api/cs/group__a3d__readwrite__module.html>`__ are exposed.
         
      .. code-block:: csharp
      
         A3DRWParamsGeneralData m_sGeneral;                 /*!< The general reading parameters. */
         A3DRWParamsPmiData m_sPmi;                         /*!< The parameters for PMI reading. Used when `m_sGeneral.m_bReadPmis` is `true`. */
         A3DRWParamsTessellationData m_sTessellation;       /*!< The tessellation reading parameters. */
         A3DRWParamsAssemblyData m_sAssembly;               /*!< The reading parameters used to load Assembly files. */
         A3DRWParamsMultiEntriesData m_sMultiEntries;       /*!< The parameters used when reading multiple models. */
         A3DRWParamsSpecificLoadData m_sSpecifics;          /*!< The parameters specific to each CAD format. */
         A3DRWParamsIncrementalLoadData m_sIncremental;     /*!< The reading parameters used to load specific parts of an assembly. */
         A3DRWParamsLoadData;
      
      Import and export parameters can be added and edited as needed. Let's look at an example:
      
         * Locate the setting ``m_sLoadData.m_sGeneral.m_bReadPmis = true;`` 
         * Change its value to setting ``m_sLoadData.m_sGeneral.m_bReadPmis = false;``
         * Rebuild using ``make clean`` then ``make`` the sample *ImportExport*
         
      The import parameter has been changed and is now taken into account by the sample.
      
         * Locate the file *CV5_Sample.CATPart* from the installation folder *../samples/data/pmi/*
         * Run the sample *importExport* to convert the file *CV5_Sample.CATPart* to PRC format.
         * Locate the resulting *CV5_Sample.CATPart.prc* file from the folder *./samples/data/pmi/*
         * Run the sample *Viewer* to load the PRC file. Command line: ``./Viewer ../samples/data/pmi/CV5_Sample.CATPart.prc``
         * Compare the two resulting *CV5_Sample.CATPart.prc* files.
         
         .. image:: /_assets/images/pmi-sample-no-pmi-linux.png
            :width: 50%
            :align: center
            
      As you can see that by turning off the import parameters ``m_sLoadData.m_sGeneral.m_bReadPmis = true;`` the *Product Manufacturing Information* are not converted.

   .. group-tab:: macOS
   
      **Change the command line**
      
      On macOS, open the *Terminal*:
      
         * Locate the sample *ImportExport* from the installation folder *../samples/hello_world/ImportExport*
         * Right click on the folder and select *Open in Terminal*.
         * Locate the file *Bullet_Lid_Cap.CATPart* from the installation folder *../samples/data/catiaV5/*
         * Make sure the Sample is already built otherwise build it again. Command line: ``make``
                  
         .. image:: /_assets/images/Import_export_make.png
            :width: 50%
            :align: center                 
                  
         * *Run* the sample ``ImportExport`` to convert a CATIA V5 part called **Bullet_Lid_Cap.CATPart** to STL format. Command line: ``./ImportExport ../samples/data/catiaV5/Bullet_Lid_Cap.CATPart ../samples/data/catiaV5/Bullet_Lid_Cap.CATPart.stl``
                  
         .. image:: /_assets/images/Import_export_make_run.png
            :width: 50%
            :align: center
            
         * *Run* the sample ``Viewer`` to load the resulting part called **Bullet_Lid_Cap.CATPart.stl**. Command line: ``./Viewer ../samples/data/catiaV5/Bullet_Lid_Cap.CATPart.stl``
         * *Bullet_Lid_Cap.CATPart.stl* file will be displayed in an OpenGL Windows:
            
         .. image:: /_assets/images/Bullet_Lid_Cap.CATPart-mac.png
            :width: 50%
            :align: center
         
      You just have learned how to specify your own input CAD file and Output format.
      
      **Change the conversions settings**

         * Stop the execution of the sample ``Viewer`` (Ctrl+C).
         * Locate the file **CV5_Sample.CATPart** from the installation folder ``../samples/data/pmi/``
         * *Run* the sample ``importExport`` to convert the file **CV5_Sample.CATPart** to PRC format.
         * Locate the resulting **CV5_Sample.CATPart.prc** file from the folder ``./samples/data/pmi/``
         * *Run* the sample ``Viewer`` to load the PRC file. Command line: ``./Viewer ../samples/data/pmi/CV5_Sample.CATPart.prc``
         
         .. image:: /_assets/images/pmi-sample-mac.png
            :width: 50%
            :align: center
         
         * Stop the execution of the sample ``Viewer`` (Ctrl+C).
         * Locate and open the ``A3DSDKInternalConvert.hxx`` file from your installation folder ``../include/``.
         
      You are now looking at the file ``A3DSDKInternalConvert.hxx`` where all the `conversion parameters <https://docs.techsoft3d.com/exchange/latest/api/cs/group__a3d__readwrite__module.html>`__ are exposed.
         
      .. code-block:: csharp
      
         A3DRWParamsGeneralData m_sGeneral;                 /*!< The general reading parameters. */
         A3DRWParamsPmiData m_sPmi;                         /*!< The parameters for PMI reading. Used when `m_sGeneral.m_bReadPmis` is `true`. */
         A3DRWParamsTessellationData m_sTessellation;       /*!< The tessellation reading parameters. */
         A3DRWParamsAssemblyData m_sAssembly;               /*!< The reading parameters used to load Assembly files. */
         A3DRWParamsMultiEntriesData m_sMultiEntries;       /*!< The parameters used when reading multiple models. */
         A3DRWParamsSpecificLoadData m_sSpecifics;          /*!< The parameters specific to each CAD format. */
         A3DRWParamsIncrementalLoadData m_sIncremental;     /*!< The reading parameters used to load specific parts of an assembly. */
         A3DRWParamsLoadData;
      
      Import and export parameters can be added and edited as needed. Let's look at an example:
      
         * Locate the setting ``m_sLoadData.m_sGeneral.m_bReadPmis = true;`` 
         * Change its value to setting ``m_sLoadData.m_sGeneral.m_bReadPmis = false;``
         * *Rebuild* ``make clean`` then ``make`` the sample ``ImportExport``
         
      The Import parameter has been changed and is now taken into account by the sample.
      
         * Locate the file **CV5_Sample.CATPart** from the installation folder ``../samples/data/pmi/``
         * Run the sample *ImportExport* to convert the file *CV5_Sample.CATPart* to PRC format.
         * Locate the resulting *CV5_Sample.CATPart.prc* file from the folder ``./samples/data/pmi/``
         * Run the sample *Viewer* to load the PRC file. Command line: ``./Viewer ../samples/data/pmi/CV5_Sample.CATPart.prc``
         * Compare the two resulting *CV5_Sample.CATPart.prc* files.
      
         .. image:: /_assets/images/pmi-sample-no-pmi-mac.png
            :width: 50%
            :align: center
      
      As you can see that by turning off the import parameters ``m_sLoadData.m_sGeneral.m_bReadPmis = true;``, the *Product Manufacturing Information* are not converted.

   
Conclusion
==========

The file-to-file workflow is a common starting point for evaluating the capabilities of HOOPS Exchange.
Using the ``ImportExport`` sample that ships with the product, you can easily convert files from one format to another.

By completing this tutorial, you now have the knowledge of how to use HOOPS Exchange in this basic use case.
Furthermore, by examining the implementation of the helper classes involved, you'll have gained some insight into the use of the API itself.

Now that you played along with our *ImportExport* sample, you are ready to move forward and play with our :doc:`print-assembly-structure` sample.

