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’re 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 or update model file.
As you can see in the below link, in some cases parsing and interpreting the PRC structures is non-trivial.
We are providing sample source code to traverse the model file using Visitor patternand update the model file. This sample is reusable and you can port the code into your application as it is even if you don’t know in the details of the traversing manner.
...
Prepare a workbench project based on the ImportExport sample.
Copy ImportExport folder from
<HOOPS_Exchange_Publish SDK dir>\samples\exchange\exchangesource
and past in paste into your project folderRename the copied folder name to “ImportTraverseExport“ ImportTraverseExport
Copy
HOOPSExchangePublishSample.props
file from<HOOPS_Exchange_Publish SDK dir>\samples
and past in theImportTraverseExport/
folderCopy
common.hpp
file from<HOOPS_Exchange_Publish SDK dir>\samples\exchange\
exchangesource and past inexchange
source and paste into the project folderStart Visual Studio 2015 and open the ImportExport ImportTraverseExport project
Close Visual Studio with saving Save the solution as “ImportTraverseExport.sln”
ImportTraverseExport.sln
and close Visual StudioCreate a file naming “VS2015named
VS2015.
bat“bat
and open it in a your preferred text editorEdit the
VS2015.bat
file so that it opens the solution with by specifyingHEXCHANGE_INSTALL_DIR
environment variableCode Block language text SET HEXCHANGE_INSTALL_DIR=C:\SDK\HOOPS_Exchange_Publish_2020_SP1 CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" ImportTraverseExport.sln
C:\SDK\HOOPS_Exchange_Publish_2020_SP1
is your HOOPS Exchange install dirSave and close the
VS2015.bat
fileOpen the solution using the
VS2015.bat
fileAdd
$(HEXCHANGE_INSTALL_DIR)\include
in the Additional Include Directories of C/C++ -> General page of project propertyin Project PropertyOpen
ImportExport.cpp
and edit like belowCode Block language cpp ... #include "common.hpp" #include <sstream> ... // // ### INITIALIZE HOOPS EXCHANGE // std::wstringstream bin_dir; #ifdef _DEBUG std::wstring buffer; buffer.resize(_MAX_PATH * 2); if (GetEnvironmentVariable(L"HEXCHANGE_INSTALL_DIR", &buffer[0], static_cast<DWORD>(buffer.size()))) { bin_dir << buffer.data() << L"/bin/win64\0"; } #else bin_dir << L""; #endif A3DSDKHOOPSExchangeLoader sHoopsExchangeLoader(bin_dir.str().data()); ...
Build the project and verify that the import and export process works properly
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. ) |
Porting Visitor pattern
Though you can find some Several sample projects including use the Visitor pattern, visitor pattern of and the Collision sample will be the best for reuseprovides a good starting point for our goals.
Copy the
visitor/
folder from<HOOPS_Exchange_Publish SDK dir>\samples\exchange\exchangesource\Collision
and past in the ImportTraverseExport folderBack Return to the project of in Visual Studio.
Create a new filter folder named “visitor”
visitor/
under the Header Files and add all header files in thevisitor
folderCreate a new filter folder named “visitor”
visitor/
under the Source Files and add all cpp files in thevisitor
folder
Implement tree traverse function
Implement a function which calls the visitor pattern.
Create traverseModelFile
traverseModelFile()
function inImportExport.cpp
Code Block language cpp ... #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) ...
Split the Convert process into Import and Export so that the traverse function can be called after importing
Code Block language cpp ... 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)); ...
Build the project
Make a break point breakpoint in the
TreeTraverse.cpp
and verify that a the model file is traversed
Derived class creation
Thanks to the visitor pattern sample, now 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 code in the algorithm for each use case.
...
Create a derived class of
A3DTreeVisitor
Code Block language cpp ... static MY_CHAR acLogFileName[_MAX_PATH * 2]; class myTreeVisitor: public A3DTreeVisitor { public: myTreeVisitor(A3DVisitorContainer* psContainer = NULL) : A3DTreeVisitor(psContainer) {}; ~myTreeVisitor() {}; public: virtual A3DStatus visitEnter(const A3DProductOccurrenceConnector& sConnector) override { A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector); // My processes return iRet; } virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override { A3DStatus iRet = A3D_SUCCESS; // My processes iRet = A3DTreeVisitor::visitLeave(sConnector); return iRet; } }; void traverseModelFile(A3DAsmModelFile* pModelFile) ...
Use the derived
myTreeVisitor
class instead ofA3DTessVisitor
in thetraverseModelFile()
functionCode Block ... // Prepare Tree traverse visitor and set to the container myTreeVisitor *pMyTreeVisitor = new myTreeVisitor(&sA3DVisitorContainer); sA3DVisitorContainer.push(pMyTreeVisitor); ...
Build the project
Make break points breakpoints in the
myTreeVisitor
class and verify that the class is called
Info |
---|
In the In the above sample, you can implement your own processes when Product Occurence Occurrence is traversed by setting as |
The following is connector type lista mapping of Node
types to Connecter
classes
Node type | Connector |
---|---|
A3DAsmModelFile | A3DModelFileConnector |
A3DAsmProductOccurrence | A3DProductOccurrenceConnector |
A3DAsmPartDefinition | A3DPartConnector |
A3DRiRepresentationItem | A3DRiConnector |
A3DRiBrepModel | A3DRiBrepModelConnector |
A3DRiSet | A3DRiSetConnector |
A3DRiPolyBrepModel | A3DPolyRiBrepModelConnector |
...
Add code to log component names in the console
Code Block language cpp ... 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; } ...
Build the project
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. |
Getting component visibility
If you open the Landing_Gear_Assy
in HOOPS Demo Viewer (HDV), you will see a component is invisible in by default.
...
The visibility parameter is bit complex because parent visibility affects to the child components. This problem is managed by using a separate visitor (A3DVisitorColorMaterials
) in the visitor pattern sample.
There These are the following Visitor
classes, and multiple visitors can be called via the visitor container.
...
Add
CONNECT_COLORS
to the visitor containerCode Block language cpp ... #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); ...
Add code to access visibility info
Code Block language cpp ... 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; } ...
Build the project
Verify that
(Hidden)
is added after the Product Occurence Occurrence name
Getting instance transformation
You will see in HDV that some components are used multiple times in the assembly model.
...
Add code to get the transformation of each instance.
...
Info |
---|
The visitor to get |
...
a transformation is already assigned to the visitor container. |
Add an override function of
A3DPartConnector
and get the part transformCode Block language cpp class myTreeVisitor: public A3DTreeVisitor { ... virtual A3DStatus visitEnter(const A3DPartConnector& sConnector) override { A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector); // Get transform connector via transform visitor A3DVisitorTransfo* psVisitorTransfo = static_cast<A3DVisitorTransfo*>(m_psContainer->GetVisitorByName("Transformation")); A3DTransfoConnector* pConnector = psVisitorTransfo->GetTransfoConnector(); A3DMatrix4x4 sTransfo; pConnector->GetGlobalTransfo(sTransfo); delete pConnector; for (unsigned int i = 0; i < m_iLevel; i++) _tprintf(_T("+ ")); _tprintf(_T(" (%.3f, %.3f, %.3f)\n"), sTransfo.m_adM[12], sTransfo.m_adM[13], sTransfo.m_adM[14]); return iRet; } ...
Build the project
Verify that part locations differ by instance
Info |
---|
You will see If you set it as to |
...
Info |
---|
If you refer to the Collision sample, you will see a the usage of Tree traverse Visitor. Hence,
|
...