Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Table of Contents

Introduction

Parsing and interpreting the PRC structure is non-trivial in some cases, as described in our documentation for PRC Basics.

In this article, we are going to describe traversing a PRC model file using a builtin Visitor pattern sample. Based on the ImportExport sample project, you will be able to make a prototype easily, which can retrieve and update the model file. This sample is reusable and you can port the code into your application even if you don’t know the details of the traversing manner.

Instructions

Workbench project preparation

Prepare a workbench project based on the ImportExport sample.

...

Info

To run this application, it is necessary to specify source and destination CAD file names to the Command Arguments of Debugging page of the project property, i.e.
"$(HEXCHANGE_INSTALL_DIR)\samples\data\step\helloworld.stp" "C:\temp\helloworld.prc"

Porting Visitor pattern

Several sample projects use the Visitor pattern, and the Collision sample provides a good starting point for our goals.

  1. Copy the visitor/ folder from <HOOPS_Exchange_Publish SDK dir>\samples\exchange\exchangesource\Collision and past in the ImportTraverseExport folder

  2. Return to the project in Visual Studio.

  3. Create a new folder named visitor/ under Header Files and add all header files in the visitor folder

  4. Create a new folder named visitor/ under Source Files and add all cpp files in the visitor folder

Implement tree traverse function

Implement a function which calls the visitor pattern.

  1. Create traverseModelFile() function in ImportExport.cpp

    Code Block
    languagecpp
    ...
    #include <sstream>
    
    #include "visitor/VisitorContainer.h"
    #include "visitor/VisitorTree.h"
    
    static MY_CHAR acSrcFileName[_MAX_PATH * 2];
    static MY_CHAR acDstFileName[_MAX_PATH * 2];
    static MY_CHAR acLogFileName[_MAX_PATH * 2];
    
    void traverseModelFile(A3DAsmModelFile* pModelFile)
    {
    	// Prepare Visitor container
    	A3DVisitorContainer sA3DVisitorContainer(CONNECT_TRANSFO);
    	sA3DVisitorContainer.SetTraverseInstance(true);
    
    	// Prepare Tree traverse visitor and set to the container
    	A3DTreeVisitor *pA3DTreeVisitor = new A3DTreeVisitor(&sA3DVisitorContainer);
    	sA3DVisitorContainer.push(pA3DTreeVisitor);
    
    	// Prepare model file connector and call Traverse
    	A3DModelFileConnector sModelFileConnector(pModelFile);
    	A3DStatus sStatus = sModelFileConnector.Traverse(&sA3DVisitorContainer);
    
    }
    
    //######################################################################################################################
    #ifdef _MSC_VER
    int wmain(A3DInt32 iArgc, A3DUniChar** ppcArgv)
    ...

  2. Split the Convert process into Import and Export so that the traverse function can be called after importing

    Code Block
    languagecpp
    ...
    	A3DExport sExport(acDstFileName); // see A3DSDKInternalConvert.hxx for import and export detailed parameters
    
    									  // perform conversion
    	CHECK_RET(sHoopsExchangeLoader.Import(sImport));
    
    	traverseModelFile(sHoopsExchangeLoader.m_psModelFile);
    
    	CHECK_RET(sHoopsExchangeLoader.Export(sExport));
    ...

  3. Build the project

  4. Make a breakpoint in TreeTraverse.cpp and verify the model file is traversed

Derived class creation

Thanks to the visitor pattern sample, you can access the model file from the root to the leaves in the correct manner. Though you can add your own retrieving and updating processes in it, we recommend you to make derived classes of A3DTreeVisitor, so that you can divide code into common traverse and various use cases. You don't need to write a traverse algorithm for each use case.

...

Node type

Connector

A3DAsmModelFile

A3DModelFileConnector

A3DAsmProductOccurrence

A3DProductOccurrenceConnector

A3DAsmPartDefinition

A3DPartConnector

A3DRiRepresentationItem

A3DRiConnector

A3DRiBrepModel

A3DRiBrepModelConnector

A3DRiSet

A3DRiSetConnector

A3DRiPolyBrepModel

A3DPolyRiBrepModelConnector

Logging component names

  1. Add code to log component names in the console

    Code Block
    languagecpp
    ...
    private:
    	int m_iLevel = 0;
    
    public:
    	virtual A3DStatus visitEnter(const A3DProductOccurrenceConnector& sConnector) override
    	{
    		A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector);
    
    		// Increment level
    		m_iLevel++;
    
    		// Get the ProductOccurrence (PO)
    		const A3DEntity* pEntity = sConnector.GetA3DEntity();
    		A3DAsmProductOccurrence* pPO = (A3DAsmProductOccurrence*)pEntity;
    
    		// Get RootBaseData of the PO
    		A3DRootBaseData sRootBaseData;
    		A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
    		A3DRootBaseGet(pPO, &sRootBaseData);
    
    		// Get the PO name  
    		A3DUniChar acName[256];
    		if (sRootBaseData.m_pcName)
    			A3DMiscUTF8ToUTF16(sRootBaseData.m_pcName, acName);
    		else
    			wcscpy_s(acName, _T("NO_NAME"));
    
    		// Show the PO name with level 
    		for (int i = 0; i < m_iLevel; i++)
    			_tprintf(_T("+ "));
    
    		_tprintf(_T("%s\n"), acName);
    
    		return iRet;
    	}
    
    	virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
    	{
    		A3DStatus iRet = A3D_SUCCESS;
    
    		// Decrement level
    		m_iLevel--;
    
    		iRet = A3DTreeVisitor::visitLeave(sConnector);
    		return iRet;
    	}
    ...

  2. Build the project

  3. Verify that Product Occurrence name are displayed in the console

Info

In the above image, we used the Landing Gear model in the sample folder.
"$(HEXCHANGE_INSTALL_DIR)\samples\data\catiaV5\CV5_Landing Gear Model_LandingGear.CATProduct"

Getting component visibility

If you open the Landing_Gear_Assy in HOOPS Demo Viewer (HDV), you will see a component is invisible by default.

...

  1. Add CONNECT_COLORS to the visitor container

    Code Block
    languagecpp
    ...
    #include "visitor/VisitorTree.h"
    #include "visitor/VisitorCascadedAttribute.h"
    #include "visitor/CascadedAttributeConnector.h"
    ...
    void traverseModelFile(A3DAsmModelFile* pModelFile)
    {
    	// Prepare Visitor container
    	A3DVisitorContainer sA3DVisitorContainer(CONNECT_TRANSFO | CONNECT_COLORS);
    	sA3DVisitorContainer.SetTraverseInstance(true);
    	...

  2. Add code to access visibility info

    Code Block
    languagecpp
    ...
    	virtual A3DStatus visitEnter(const A3DProductOccurrenceConnector& sConnector) override
    	{
    ...
    		_tprintf(_T("%s"), acName);
    
    		A3DVisitorColorMaterials *pA3DCascadedVisitor = static_cast<A3DVisitorColorMaterials*>(m_psContainer->GetVisitorByName("CascadedAttribute"));
    		if (pA3DCascadedVisitor)
    		{
    			ColorMaterialsConnector sColorConnector(nullptr);
    			pA3DCascadedVisitor->GetColorMaterialConnector(sColorConnector);
    
    			if (sColorConnector.IsShow())
    				_tprintf(_T("\n"));
    			else
    				_tprintf(_T(" (Hidden)\n"));
    		}
    
    		return iRet;
    	}
    ...

  3. Build the project

  4. Verify that (Hidden) is added after the Product Occurrence name

Getting instance transformation

You will see in HDV that some components are used multiple times in the assembly model.

...

Info

If you refer to the Collision sample, you will see the usage of Tree traverse Visitor.

Hence, A3DCollisionCompute requires two Representation Item groups to compute collision, and it is necessary to get a flatten array of Representation Items from the target model file.

A3DFlattenVisitor is a derived class of A3DTreeVisitor and retrieves visible Representation Items, including the identifier and transform overriding visitEnter of A3DPartConnector and A3DRiConnector.

How-to: Split multi body part into assembly model

...