Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Workbench project preparation

  1. Refer How-Toto: 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])

...

  1. Create a derived class of A3DTreeVisitor including visitEnter method for A3DPartConnector

    Code Block
    languagecpp
    ...
    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)
    ...

  2. Use the derived bodyOperationVisitor class instead of A3DTessVisitor in the traverseModelFile function

    Code Block
    languagecpp
    ...
    	// Prepare body operation visitor and set to the container
    	bodyOperationVisitor *pBodyOpVisitor = new bodyOperationVisitor(&sA3DVisitorContainer);
    	sA3DVisitorContainer.push(pBodyOpVisitor);
    ...

  3. Build the project

  4. Create break points in the bodyOperaitonVisitor bodyOperationVisitor class and verify that the class is called during run time

...

Code Block
languagecpp
/***********************************************************************************************************************
*
* 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;
}

How-Toto: Traverse PRC model file using Visitor pattern for rapid prototyping

...