Introduction
In this article, we’re going to describe updating the PRC model file structure using the example of splitting a multi-body part into an assembly model.
If you import helloworld.stp in <HOOPS_Exchange_Publish SDK dir>\samples\data\step using HOOPS Demo Viewer (HDV), you will see the part has 10 bodies. Through this article, you can split the multi-body part into an assembly model, including multiple parts.
Instructions
Workbench project preparation
- Refer How-to: Traverse PRC model file using Visitor pattern for rapid prototyping article and create a workbench project (form [Workbench project preparation] to [Implement tree traverse function])
Derived class creation
Create a derived class of A3DTreeVisitor for this use case.
- Create a derived class of A3DTreeVisitor including
visitEnter
method forA3DPartConnector
...
static MY_CHAR acLogFileName[_MAX_PATH * 2];
class bodyOperationVisitor: public A3DTreeVisitor
{
public:
bodyOperationVisitor(A3DVisitorContainer* psContainer = NULL) : A3DTreeVisitor(psContainer) {};
~bodyOperationVisitor() {};
public:
virtual A3DStatus visitEnter(const A3DPartConnector& sConnector) override
{
A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector);
// My processes
return iRet;
}
};
void traverseModelFile(A3DAsmModelFile* pModelFile)
...
- Use the derived
bodyOperationVisitor
class instead ofA3DTessVisitor
in thetraverseModelFile
function
...
// Prepare body operation visitor and set to the container
bodyOperationVisitor *pBodyOpVisitor = new bodyOperationVisitor(&sA3DVisitorContainer);
sA3DVisitorContainer.push(pBodyOpVisitor);
...
- Build the project
- Create break points in the
bodyOperationVisitor
class and verify that the class is called during run time
Thanks to the bodyOperationVisitor
, you can add inquiry and update functions while model file traversing.
Implementing functions and timing for splitting multi body part will be the following image:
Detecting a multi body part and splitting the parts
If m_uiRepItemsSize
of the Part Definition is more than 1, it means you have a multi body part.
- Add code to detect multi body part and split into individual parts
...
public:
virtual A3DStatus visitEnter(const A3DPartConnector& sConnector) override
{
A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector);
// Get the PartDefiniiton data
A3DAsmPartDefinitionData sData = sConnector.m_sPartData;
// Detect multi body part
if (1 < sData.m_uiRepItemsSize)
{
// It is multi body part
}
return iRet;
}
...
- Split the multi body into new parts
...
private:
int m_iBodyCnt;
A3DAsmPartDefinition** m_ppPart;
public:
virtual A3DStatus visitEnter(const A3DPartConnector& sConnector) override
{
A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector);
// Get the PartDefiniiton data
A3DAsmPartDefinitionData sData = sConnector.m_sPartData;
// Detect multi body part
m_iBodyCnt = 0;
if (1 < sData.m_uiRepItemsSize)
{
m_iBodyCnt = sData.m_uiRepItemsSize;
// Create new Parts for each body
m_ppPart = new A3DAsmPartDefinition*[m_iBodyCnt];
for (A3DUns32 ui = 0; ui < m_iBodyCnt; ui++)
{
// Create a new part and set body
A3DAsmPartDefinitionData sNewPartData;
A3D_INITIALIZE_DATA(A3DAsmPartDefinitionData, sNewPartData);
sNewPartData.m_uiRepItemsSize = 1;
sNewPartData.m_ppRepItems = &sData.m_ppRepItems[ui];
iRet = A3DAsmPartDefinitionCreate(&sNewPartData, &m_ppPart[ui]);
}
}
return iRet;
}
...
Creating an assembly model file
In the above code, when a multi body part is detected, the m_iBodyCnt
member variable is set. The first visitLeave
of Product Occurrence after setting the body count will be the Product Occurrence of the target part.
- Add
visitLeave
method of Product Occurrence and create an assembly model including the split parts whenm_iBodyCnt
is greater than 1.
...
private:
int m_iBodyCnt;
A3DAsmPartDefinition** m_ppPart;
A3DAsmProductOccurrence* m_pAssyPO = NULL;
...
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
// Get the ProductOccurrence (PO)
const A3DEntity* pEntity = sConnector.GetA3DEntity();
A3DAsmProductOccurrence* pPO = (A3DAsmProductOccurrence*)pEntity;
// Get PO data
A3DAsmProductOccurrenceData sData = sConnector.m_sProductOccurrenceData;
// Get RootBaseData of the PO
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(pPO, &sRootBaseData);
// If multi body part
if (m_iBodyCnt)
{
// Create new POs of the new parts
A3DAsmProductOccurrence **ppPO;
ppPO = new A3DAsmProductOccurrence*[m_iBodyCnt];
for (A3DUns32 ui = 0; ui < m_iBodyCnt; ui++)
{
// Create new PO
A3DAsmProductOccurrenceData sPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sPOData);
sPOData.m_dUnit = sData.m_dUnit;
sPOData.m_pPart = m_ppPart[ui];
iRet = A3DAsmProductOccurrenceCreate(&sPOData, &ppPO[ui]);
// Set part name (org name - id)
char name[1024];
sprintf_s(name, sizeof(name), "%s - %d", sRootBaseData.m_pcName, ui + 1);
A3DRootBaseData sNewBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sNewBaseData);
sNewBaseData.m_pcName = name;
iRet = A3DRootBaseSet(ppPO[ui], &sNewBaseData);
}
// Create a new assembly PO for split parts
A3DAsmProductOccurrenceData sNewPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sNewPOData);
sNewPOData.m_uiPOccurrencesSize = m_iBodyCnt;
sNewPOData.m_dUnit = sData.m_dUnit;
sNewPOData.m_ppPOccurrences = ppPO;
sNewPOData.m_pLocation = sData.m_pLocation;
iRet = A3DAsmProductOccurrenceCreate(&sNewPOData, &m_pAssyPO);
iRet = A3DRootBaseSet(m_pAssyPO, &sRootBaseData);
}
iRet = A3DTreeVisitor::visitLeave(sConnector);
return iRet;
}
...
- Add
visitLeave
method of model file and create a new model file when an assembly model is created in the previous process.
...
static MY_CHAR acLogFileName[_MAX_PATH * 2];
static A3DAsmModelFile *s_pNewModelFile = NULL;
class bodyOperationVisitor : public A3DTreeVisitor
{
...
virtual A3DStatus visitLeave(const A3DModelFileConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
const A3DEntity* pEntity = sConnector.GetA3DEntity();
A3DAsmModelFile* pModelFile = (A3DAsmModelFile*)pEntity;
A3DAsmModelFileData sData = sConnector.m_sModelFileData;
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(pModelFile, &sRootBaseData);
if (m_pAssyPO)
{
// Create assemly pModelFile
A3DAsmModelFileData sModelFileData = sConnector.m_sModelFileData;
sModelFileData.m_bUnitFromCAD = sData.m_bUnitFromCAD;
sModelFileData.m_dUnit = sData.m_dUnit;
sModelFileData.m_eModellerType = kA3DModellerPrc;
sModelFileData.m_uiPOccurrencesSize = 1;
sModelFileData.m_ppPOccurrences = &m_pAssyPO;
iRet = A3DAsmModelFileCreate(&sModelFileData, &s_pNewModelFile);
// Set root made data of original model file
iRet = A3DRootBaseSet(s_pNewModelFile, &sRootBaseData);
m_pAssyPO = NULL;
}
return iRet;
}
...
If you update a node of model file, it is necessary to update it at end of traversing (
visitLeave
) . If you update a node at beginning of traversing (visitEnter
), it affect its child nodes traversing and cause of application crash.
Replacing the model file
Apart from the imported model file, a new model file (s_pNewModelFile
) is created in the above code.
- After traversing the model file, replace the original model file when the new model file is created.
...
traverseModelFile(sHoopsExchangeLoader.m_psModelFile);
if (NULL != s_pNewModelFile)
{
A3DStatus iRet = A3DAsmModelFileDelete(sHoopsExchangeLoader.m_psModelFile);
sHoopsExchangeLoader.m_psModelFile = s_pNewModelFile;
s_pNewModelFile = NULL;
}
...
- Build the project
- Verify that multi body part is split into assembly model
Multi body parts in assembly model
The above code just supports multi body part model file. If you open the _LandingGear.CATProduct in the ‘<HOOPS_Exchange_Publish SDK dir>\samples\data\catiaV5\CV5_Landing Gear Model’ directory using the HDV, you will see some multi body parts in the assembly model file.
In an assembly model file, though it is necessary to replace detected multi body part (step 4 in below image) to assembly model (step 6), the timing (step 13) is a bit complicated.
- Prepare member array of struct to keep target POs and assembly models
...
#include <sstream>
#include <vector>
...
class bodyOperationVisitor : public A3DTreeVisitor
{
...
A3DAsmProductOccurrence* m_pAssyPO = NULL;
struct SplitPart
{
const A3DAsmProductOccurrence *parentPO;
A3DAsmProductOccurrence *oldPartPO;
A3DAsmProductOccurrence *newAssyPO;
};
std::vector<SplitPart> m_aSplitPart;
...
- Try to get father PO to check whether the model file is part model file or assembly model file
...
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
...
// If multi body part
if (m_iBodyCnt)
{
...
iRet = A3DAsmProductOccurrenceCreate(&sNewPOData, &m_pAssyPO);
iRet = A3DRootBaseSet(m_pAssyPO, &sRootBaseData);
// Access father PO
const A3DAsmProductOccurrence *pParentPO = sConnector.GetProductOccurrenceFather();
// If father PO isn't null, it is assembly model file
if (NULL != pParentPO)
{
// Keep the target POs
SplitPart splitPart;
splitPart.parentPO = sConnector.GetProductOccurrenceFather();
splitPart.oldPartPO = pPO;
splitPart.newAssyPO = m_pAssyPO;
m_aSplitPart.push_back(splitPart);
m_pAssyPO = NULL;
}
// No father PO maens that it is part model file
}
...
- Replace multi body part to assembly model in proper timing
...
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
...
// If multi body part
if (m_iBodyCnt)
{
...
}
else
{
// Check whether current PO is in a targets
for (int i = 0; i < m_aSplitPart.size(); i++)
{
SplitPart splitPart = m_aSplitPart[i];
if (pPO == splitPart.parentPO)
{
// Find target multi body part PO and replace to assembly PO
for (A3DUns32 ui = 0; ui < sData.m_uiPOccurrencesSize; ui++)
{
if (sData.m_ppPOccurrences[ui] == splitPart.oldPartPO)
{
sData.m_ppPOccurrences[ui] = splitPart.newAssyPO;
break;
}
}
iRet = A3DAsmProductOccurrenceEdit(&sData, pPO);
}
}
}
iRet = A3DTreeVisitor::visitLeave(sConnector);
return iRet;
}
...
- Build the project
- Verify that multi body parts in the assembly model are split into assembly models
Detecting part instances
If you look at converted model in the model browser, you will see some components are instanced.
To manage part instances, each part instance points abstract product occurrence so called “prototype“.
- Add code to get prototype info
...
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
...
// If multi body part
if (m_iBodyCnt)
{
// Get prototype
A3DAsmProductOccurrence *pProtoPO = sData.m_pPrototype;
A3DAsmProductOccurrenceData sProtoData;
A3DRootBaseData sProtoBaseData;
if (NULL != pProtoPO)
{
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sProtoData);
iRet = A3DAsmProductOccurrenceGet(pProtoPO, &sProtoData);
A3D_INITIALIZE_DATA(A3DRootBaseData, sProtoBaseData);
iRet = A3DRootBaseGet(pProtoPO, &sProtoBaseData);
}
// Create new POs of the new parts
...
- Build the project
- Create a break point and verify that prototype info is received
- Keep the prototype pointer and instance transform in a member variable and detect part instance
..
struct SplitPart
{
const A3DAsmProductOccurrence *parentPO;
A3DAsmProductOccurrence *oldPartPO;
A3DAsmProductOccurrence *newAssyPO;
A3DAsmProductOccurrence *protoPO;
A3DMiscTransformation *instanceTransform;
A3DRootBaseData instanceBaseData;
};
...
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
...
// If multi body part
if (m_iBodyCnt)
{
...
if (NULL != pProtoPO)
{
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sProtoData);
iRet = A3DAsmProductOccurrenceGet(pProtoPO, &sProtoData);
A3D_INITIALIZE_DATA(A3DRootBaseData, sProtoBaseData);
iRet = A3DRootBaseGet(pProtoPO, &sProtoBaseData);
// Chenck whether the same part is detected
for (int i = 0; i < m_aSplitPart.size(); i++)
{
if (pProtoPO == m_aSplitPart[i].protoPO)
{
// Keep the target POs
SplitPart splitPart;
splitPart.parentPO = sConnector.GetProductOccurrenceFather();
splitPart.oldPartPO = pPO;
splitPart.newAssyPO = m_aSplitPart[i].newAssyPO;
splitPart.instanceTransform = sData.m_pLocation;
splitPart.instanceBaseData = sRootBaseData;
m_aSplitPart.push_back(splitPart);
return iRet;
}
}
}
...
// Create a new assembly PO for split parts
A3DAsmProductOccurrenceData sNewPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sNewPOData);
sNewPOData.m_uiPOccurrencesSize = m_iBodyCnt;
sNewPOData.m_dUnit = sData.m_dUnit;
sNewPOData.m_ppPOccurrences = ppPO;
// sNewPOData.m_pLocation = sData.m_pLocation; <= comment out this line
...
// If father PO isn't null, it is assembly model file
if (NULL != pParentPO)
{
if (NULL != pProtoPO)
{
// Set prototype's RootBaseData
iRet = A3DRootBaseSet(m_pAssyPO, &sProtoBaseData);
}
// Keep the target POs
SplitPart splitPart;
splitPart.parentPO = sConnector.GetProductOccurrenceFather();
splitPart.oldPartPO = pPO;
splitPart.newAssyPO = m_pAssyPO;
splitPart.protoPO = pProtoPO;
splitPart.instanceTransform = sData.m_pLocation;
splitPart.instanceBaseData = sRootBaseData;
...
- Build the project
- Create a break and verify that part instance is detected
Replacement using sub-assembly prototype
Multi body part should be replaced using sub-assembly prototype like below image
- Update part replacement code
...
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
...
else
{
// Check whether current PO is in a targets
for (int i = 0; i < m_aSplitPart.size(); i++)
{
SplitPart splitPart = m_aSplitPart[i];
if (pPO == splitPart.parentPO)
{
// Find target multi body part PO and replace to assembly PO
for (A3DUns32 ui = 0; ui < sData.m_uiPOccurrencesSize; ui++)
{
if (sData.m_ppPOccurrences[ui] == splitPart.oldPartPO)
{
// Create new sub-assembly instance
A3DAsmProductOccurrenceData sAssyInstData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sAssyInstData);
sAssyInstData.m_pLocation = splitPart.instanceTransform;
sAssyInstData.m_pPrototype = splitPart.newAssyPO;
A3DAsmProductOccurrence *pAssyInstPO;
iRet = A3DAsmProductOccurrenceCreate(&sAssyInstData, &pAssyInstPO);
// Set RootBaseData of the instance
iRet = A3DRootBaseSet(pAssyInstPO, &splitPart.instanceBaseData);
// Replace part instance to sub-assembly instance
sData.m_ppPOccurrences[ui] = pAssyInstPO;
break;
}
}
iRet = A3DAsmProductOccurrenceEdit(&sData, pPO);
}
}
}
...
- Build the project
- Verify that multi body parts in the assembly model are split into assembly models
Here is full source code of ImportExport.cpp for this article
/***********************************************************************************************************************
*
* Copyright (c) 2017 by Tech Soft 3D, LLC.
* The information contained herein is confidential and proprietary to Tech Soft 3D, LLC., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, LLC. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
/*
* This sample demonstrates how to load a model and export it as a model file of a different format. The chosen
* format is determined by the file extension of the output file name.
*/
#define INITIALIZE_A3D_API
#include <A3DSDKIncludes.h>
#include "common.hpp"
#include <sstream>
#include <vector>
#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];
static A3DAsmModelFile *s_pNewModelFile = NULL;
class bodyOperationVisitor : public A3DTreeVisitor
{
public:
bodyOperationVisitor(A3DVisitorContainer* psContainer = NULL) : A3DTreeVisitor(psContainer) {};
~bodyOperationVisitor() {};
private:
int m_iBodyCnt;
A3DAsmPartDefinition** m_ppPart;
A3DAsmProductOccurrence* m_pAssyPO = NULL;
struct SplitPart
{
const A3DAsmProductOccurrence *parentPO;
A3DAsmProductOccurrence *oldPartPO;
A3DAsmProductOccurrence *newAssyPO;
A3DAsmProductOccurrence *protoPO;
A3DMiscTransformation *instanceTransform;
A3DRootBaseData instanceBaseData;
};
std::vector<SplitPart> m_aSplitPart;
public:
virtual A3DStatus visitEnter(const A3DPartConnector& sConnector) override
{
A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector);
// Get the PartDefiniiton data
A3DAsmPartDefinitionData sData = sConnector.m_sPartData;
// Detect multi body part
m_iBodyCnt = 0;
if (1 < sData.m_uiRepItemsSize)
{
m_iBodyCnt = sData.m_uiRepItemsSize;
// Create new Parts for each body
m_ppPart = new A3DAsmPartDefinition*[m_iBodyCnt];
for (A3DUns32 ui = 0; ui < m_iBodyCnt; ui++)
{
// Create a new part and set body
A3DAsmPartDefinitionData sNewPartData;
A3D_INITIALIZE_DATA(A3DAsmPartDefinitionData, sNewPartData);
sNewPartData.m_uiRepItemsSize = 1;
sNewPartData.m_ppRepItems = &sData.m_ppRepItems[ui];
iRet = A3DAsmPartDefinitionCreate(&sNewPartData, &m_ppPart[ui]);
}
}
return iRet;
}
virtual A3DStatus visitLeave(const A3DProductOccurrenceConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
// Get the ProductOccurrence (PO)
const A3DEntity* pEntity = sConnector.GetA3DEntity();
A3DAsmProductOccurrence* pPO = (A3DAsmProductOccurrence*)pEntity;
// Get PO data
A3DAsmProductOccurrenceData sData = sConnector.m_sProductOccurrenceData;
// Get RootBaseData of the PO
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(pPO, &sRootBaseData);
// If multi body part
if (m_iBodyCnt)
{
// Get prototype
A3DAsmProductOccurrence *pProtoPO = sData.m_pPrototype;
A3DAsmProductOccurrenceData sProtoData;
A3DRootBaseData sProtoBaseData;
if (NULL != pProtoPO)
{
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sProtoData);
iRet = A3DAsmProductOccurrenceGet(pProtoPO, &sProtoData);
A3D_INITIALIZE_DATA(A3DRootBaseData, sProtoBaseData);
iRet = A3DRootBaseGet(pProtoPO, &sProtoBaseData);
// Chenck whether the same part is detected
for (int i = 0; i < m_aSplitPart.size(); i++)
{
if (pProtoPO == m_aSplitPart[i].protoPO)
{
// Keep the target POs
SplitPart splitPart;
splitPart.parentPO = sConnector.GetProductOccurrenceFather();
splitPart.oldPartPO = pPO;
splitPart.newAssyPO = m_aSplitPart[i].newAssyPO;
splitPart.instanceTransform = sData.m_pLocation;
splitPart.instanceBaseData = sRootBaseData;
m_aSplitPart.push_back(splitPart);
return iRet;
}
}
}
// Create new POs of the new parts
A3DAsmProductOccurrence **ppPO;
ppPO = new A3DAsmProductOccurrence*[m_iBodyCnt];
for (A3DUns32 ui = 0; ui < m_iBodyCnt; ui++)
{
// Create new PO
A3DAsmProductOccurrenceData sPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sPOData);
sPOData.m_dUnit = sData.m_dUnit;
sPOData.m_pPart = m_ppPart[ui];
iRet = A3DAsmProductOccurrenceCreate(&sPOData, &ppPO[ui]);
// Set part name (org name - id)
char name[1024];
sprintf_s(name, sizeof(name), "%s - %d", sRootBaseData.m_pcName, ui + 1);
A3DRootBaseData sNewBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sNewBaseData);
sNewBaseData.m_pcName = name;
iRet = A3DRootBaseSet(ppPO[ui], &sNewBaseData);
}
// Create a new assembly PO for split parts
A3DAsmProductOccurrenceData sNewPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sNewPOData);
sNewPOData.m_uiPOccurrencesSize = m_iBodyCnt;
sNewPOData.m_dUnit = sData.m_dUnit;
sNewPOData.m_ppPOccurrences = ppPO;
// sNewPOData.m_pLocation = sData.m_pLocation;
iRet = A3DAsmProductOccurrenceCreate(&sNewPOData, &m_pAssyPO);
iRet = A3DRootBaseSet(m_pAssyPO, &sRootBaseData);
// Access father PO
const A3DAsmProductOccurrence *pParentPO = sConnector.GetProductOccurrenceFather();
// If father PO isn't null, it is assembly model file
if (NULL != pParentPO)
{
if (NULL != pProtoPO)
{
// Set prototype's RootBaseData
iRet = A3DRootBaseSet(m_pAssyPO, &sProtoBaseData);
}
// Keep the target POs
SplitPart splitPart;
splitPart.parentPO = sConnector.GetProductOccurrenceFather();
splitPart.oldPartPO = pPO;
splitPart.newAssyPO = m_pAssyPO;
splitPart.protoPO = pProtoPO;
splitPart.instanceTransform = sData.m_pLocation;
splitPart.instanceBaseData = sRootBaseData;
m_aSplitPart.push_back(splitPart);
m_pAssyPO = NULL;
}
// No father PO maens that it is part model file
}
else
{
// Check whether current PO is in a targets
for (int i = 0; i < m_aSplitPart.size(); i++)
{
SplitPart splitPart = m_aSplitPart[i];
if (pPO == splitPart.parentPO)
{
// Find target multi body part PO and replace to assembly PO
for (A3DUns32 ui = 0; ui < sData.m_uiPOccurrencesSize; ui++)
{
if (sData.m_ppPOccurrences[ui] == splitPart.oldPartPO)
{
// Create new sub-assembly instance
A3DAsmProductOccurrenceData sAssyInstData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sAssyInstData);
sAssyInstData.m_pLocation = splitPart.instanceTransform;
sAssyInstData.m_pPrototype = splitPart.newAssyPO;
A3DAsmProductOccurrence *pAssyInstPO;
iRet = A3DAsmProductOccurrenceCreate(&sAssyInstData, &pAssyInstPO);
// Set RootBaseData of the instance
iRet = A3DRootBaseSet(pAssyInstPO, &splitPart.instanceBaseData);
// Replace part instance to sub-assembly instance
sData.m_ppPOccurrences[ui] = pAssyInstPO;
break;
}
}
iRet = A3DAsmProductOccurrenceEdit(&sData, pPO);
}
}
}
iRet = A3DTreeVisitor::visitLeave(sConnector);
return iRet;
}
virtual A3DStatus visitLeave(const A3DModelFileConnector& sConnector) override
{
A3DStatus iRet = A3D_SUCCESS;
const A3DEntity* pEntity = sConnector.GetA3DEntity();
A3DAsmModelFile* pModelFile = (A3DAsmModelFile*)pEntity;
A3DAsmModelFileData sData = sConnector.m_sModelFileData;
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(pModelFile, &sRootBaseData);
if (m_pAssyPO)
{
// Create assemly pModelFile
A3DAsmModelFileData sModelFileData = sConnector.m_sModelFileData;
sModelFileData.m_bUnitFromCAD = sData.m_bUnitFromCAD;
sModelFileData.m_dUnit = sData.m_dUnit;
sModelFileData.m_eModellerType = kA3DModellerPrc;
sModelFileData.m_uiPOccurrencesSize = 1;
sModelFileData.m_ppPOccurrences = &m_pAssyPO;
iRet = A3DAsmModelFileCreate(&sModelFileData, &s_pNewModelFile);
// Set root made data of original model file
iRet = A3DRootBaseSet(s_pNewModelFile, &sRootBaseData);
m_pAssyPO = NULL;
}
return iRet;
}
};
void traverseModelFile(A3DAsmModelFile* pModelFile)
{
// Prepare Visitor container
A3DVisitorContainer sA3DVisitorContainer(CONNECT_TRANSFO);
sA3DVisitorContainer.SetTraverseInstance(true);
// Prepare Tree traverse visitor and set to the container
bodyOperationVisitor *pBodyOpVisitor = new bodyOperationVisitor(&sA3DVisitorContainer);
sA3DVisitorContainer.push(pBodyOpVisitor);
// Prepare model file connector and call Traverse
A3DModelFileConnector sModelFileConnector(pModelFile);
A3DStatus sStatus = sModelFileConnector.Traverse(&sA3DVisitorContainer);
}
//######################################################################################################################
#ifdef _MSC_VER
int wmain(A3DInt32 iArgc, A3DUniChar** ppcArgv)
#else
int main(A3DInt32 iArgc, A3DUTF8Char** ppcArgv)
#endif
{
//
// ### COMMAND LINE ARGUMENTS
//
if (iArgc < 2)
{
MY_PRINTF2("Usage:\n %s [input CAD file] [output CAD file] [output LOG file]\n", ppcArgv[0]);
MY_PRINTF(" Default output CAD file is [input CAD file].prc\n");
MY_PRINTF(" Default output LOG file is [output CAD file]_Log.txt\n\n");
return A3D_ERROR;
}
if (iArgc > 1) MY_STRCPY(acSrcFileName, ppcArgv[1]);
else MY_STRCPY(acSrcFileName, DEFAULT_INPUT_CAD);
if (iArgc > 2) MY_STRCPY(acDstFileName, ppcArgv[2]);
else MY_SPRINTF(acDstFileName, "%s.prc", acSrcFileName);
if (iArgc > 3) MY_STRCPY(acLogFileName, ppcArgv[3]);
else MY_SPRINTF(acLogFileName, "%s_Log.txt", acDstFileName);
GetLogFile(acLogFileName); // Initialize log file
//
// ### 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());
CHECK_RET(sHoopsExchangeLoader.m_eSDKStatus);
// Uncomment these lines to track memory leaks
//CHECK_RET(A3DDllSetCallbacksMemory(CheckMalloc, CheckFree));
CHECK_RET(A3DDllSetCallbacksReport(PrintLogMessage, PrintLogWarning, PrintLogError));
//
// ### PROCESS SAMPLE CODE
//
// specify input file
A3DImport sImport(acSrcFileName); // see A3DSDKInternalConvert.hxx for import and export detailed parameters
// specify output file
A3DExport sExport(acDstFileName); // see A3DSDKInternalConvert.hxx for import and export detailed parameters
// perform conversion
CHECK_RET(sHoopsExchangeLoader.Import(sImport));
traverseModelFile(sHoopsExchangeLoader.m_psModelFile);
if (NULL != s_pNewModelFile)
{
A3DStatus iRet = A3DAsmModelFileDelete(sHoopsExchangeLoader.m_psModelFile);
sHoopsExchangeLoader.m_psModelFile = s_pNewModelFile;
s_pNewModelFile = NULL;
}
CHECK_RET(sHoopsExchangeLoader.Export(sExport));
//
// ### TERMINATE HOOPS EXCHANGE
//
// Check memory allocations
//if (siCheckMallocCounter != 0)
// fprintf(GetLogFile(), "stiMallocCounter=%d", siCheckMallocCounter);
return A3D_SUCCESS;
}