Files
2025-05-18 13:04:45 +08:00

2114 lines
60 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "TechSoftFileParser.h"
#include "CADFileData.h"
#include "CADOptions.h"
#include "TechSoftUtils.h"
#include "TechSoftUtilsPrivate.h"
#include "TUniqueTechSoftObj.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformTime.h"
#ifndef CADKERNEL_DEV
#include "Serialization/JsonSerializer.h"
#include "Serialization/JsonWriter.h"
#include "Tasks/Task.h"
#endif
#include "Templates/UnrealTemplate.h"
namespace CADLibrary
{
#ifdef USE_TECHSOFT_SDK
namespace ProductOccurrence
{
bool HasNoPartNoChildButHasReference(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return ((OccurrenceData.m_pPrototype != nullptr || OccurrenceData.m_pExternalData != nullptr) && OccurrenceData.m_pPart == nullptr && OccurrenceData.m_uiPOccurrencesSize == 0);
}
bool HasNoPartButHasReference(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return ((OccurrenceData.m_pPrototype != nullptr || OccurrenceData.m_pExternalData != nullptr) && OccurrenceData.m_pPart == nullptr);
}
bool HasNoChildButHasReference(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return ((OccurrenceData.m_pPrototype != nullptr || OccurrenceData.m_pExternalData != nullptr) && OccurrenceData.m_uiPOccurrencesSize == 0);
}
bool HasNoPartNoChild(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return (OccurrenceData.m_pPart == nullptr && OccurrenceData.m_uiPOccurrencesSize == 0);
}
bool HasPartOrChild(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return (OccurrenceData.m_pPart != nullptr || OccurrenceData.m_uiPOccurrencesSize != 0);
}
bool PrototypeIsValid(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return (OccurrenceData.m_pPrototype != nullptr || OccurrenceData.m_pExternalData != nullptr);
}
A3DAsmProductOccurrence* GetReference(const A3DAsmProductOccurrenceData& OccurrenceData)
{
return OccurrenceData.m_pPrototype ? OccurrenceData.m_pPrototype : OccurrenceData.m_pExternalData;
}
}
namespace TechSoftFileParserImpl
{
// This code is a duplication code of CADFileReader::FindFile
// This is done in 5.0.3 to avoid public header modification.
// However this need to be rewrite in the next version. (Jira UE-152626)
bool UpdateFileDescriptor(FFileDescriptor& File)
{
const FString& FileName = File.GetFileName();
FString FilePath = FPaths::GetPath(File.GetSourcePath());
FString RootFilePath = File.GetRootFolder();
// Basic case: File exists at the initial path
if (IFileManager::Get().FileExists(*File.GetSourcePath()))
{
return true;
}
// Advance case: end of FilePath is in a upper-folder of RootFilePath
// e.g.
// FilePath = D:\\data temp\\Unstructured project\\Folder2\\Added_Object.SLDPRT
// ----------------------------
// RootFilePath = D:\\data\\CAD Files\\SolidWorks\\p033 - Unstructured project\\Folder1
// ------------------------------------------------------------
// NewPath = D:\\data\\CAD Files\\SolidWorks\\p033 - Unstructured project\\Folder2\\Added_Object.SLDPRT
TArray<FString> RootPaths;
RootPaths.Reserve(30);
do
{
RootFilePath = FPaths::GetPath(RootFilePath);
RootPaths.Emplace(RootFilePath);
} while (!FPaths::IsDrive(RootFilePath) && !RootFilePath.IsEmpty());
TArray<FString> FilePaths;
FilePaths.Reserve(30);
FilePaths.Emplace(FileName);
while (!FPaths::IsDrive(FilePath) && !FilePath.IsEmpty())
{
FString FolderName = FPaths::GetCleanFilename(FilePath);
FilePath = FPaths::GetPath(FilePath);
FilePaths.Emplace(FPaths::Combine(FolderName, FilePaths.Last()));
};
for (int32 IndexFolderPath = 0; IndexFolderPath < RootPaths.Num(); IndexFolderPath++)
{
for (int32 IndexFilePath = 0; IndexFilePath < FilePaths.Num(); IndexFilePath++)
{
FString NewFilePath = FPaths::Combine(RootPaths[IndexFolderPath], FilePaths[IndexFilePath]);
if (IFileManager::Get().FileExists(*NewFilePath))
{
File.SetSourceFilePath(NewFilePath);
return true;
};
}
}
return false;
}
// Functions to clean metadata
inline void RemoveUnwantedChar(FString& StringToClean, TCHAR UnwantedChar)
{
FString NewString;
NewString.Reserve(StringToClean.Len());
for (const TCHAR& Char : StringToClean)
{
if (Char != UnwantedChar)
{
NewString.AppendChar(Char);
}
}
StringToClean = MoveTemp(NewString);
}
// Functions used in traverse model process
void TraverseAttribute(const A3DMiscAttributeData& AttributeData, TMap<FString, FString>& OutMetaData)
{
FString AttributeFamillyName;
if (AttributeData.m_bTitleIsInt)
{
A3DUns32 UnsignedValue = 0;
memcpy(&UnsignedValue, AttributeData.m_pcTitle, sizeof(A3DUns32));
AttributeFamillyName = FString::Printf(TEXT("%u"), UnsignedValue);
}
else if (AttributeData.m_pcTitle && AttributeData.m_pcTitle[0] != '\0')
{
AttributeFamillyName = UTF8_TO_TCHAR(AttributeData.m_pcTitle);
}
for (A3DUns32 Index = 0; Index < AttributeData.m_uiSize; ++Index)
{
FString AttributeName = AttributeFamillyName;
{
FString AttributeTitle = UTF8_TO_TCHAR(AttributeData.m_asSingleAttributesData[Index].m_pcTitle);
if (AttributeTitle.Len())
{
AttributeName += TEXT(" ") + AttributeTitle;
}
else if(Index > 0)
{
AttributeName += TEXT(" ") + FString::FromInt((int32)Index);
}
}
FString AttributeValue;
switch (AttributeData.m_asSingleAttributesData[Index].m_eType)
{
case kA3DModellerAttributeTypeTime:
case kA3DModellerAttributeTypeInt:
{
A3DInt32 Value;
memcpy(&Value, AttributeData.m_asSingleAttributesData[Index].m_pcData, sizeof(A3DInt32));
AttributeValue = FString::Printf(TEXT("%d"), Value);
break;
}
case kA3DModellerAttributeTypeReal:
{
A3DDouble Value;
memcpy(&Value, AttributeData.m_asSingleAttributesData[Index].m_pcData, sizeof(A3DDouble));
AttributeValue = FString::Printf(TEXT("%f"), Value);
break;
}
case kA3DModellerAttributeTypeString:
{
if (AttributeData.m_asSingleAttributesData[Index].m_pcData && AttributeData.m_asSingleAttributesData[Index].m_pcData[0] != '\0')
{
AttributeValue = UTF8_TO_TCHAR(AttributeData.m_asSingleAttributesData[Index].m_pcData);
}
break;
}
default:
break;
}
if (AttributeName.Len())
{
OutMetaData.Emplace(AttributeName, AttributeValue);
}
}
}
void SetIOOption(A3DImport& Importer)
{
using namespace CADLibrary;
// A3DRWParamsGeneralData Importer.m_sGeneral
Importer.m_sLoadData.m_sGeneral.m_bReadSolids = A3D_TRUE;
Importer.m_sLoadData.m_sGeneral.m_bReadSurfaces = A3D_TRUE;
Importer.m_sLoadData.m_sGeneral.m_bReadWireframes = A3D_FALSE;
Importer.m_sLoadData.m_sGeneral.m_bReadPmis = A3D_FALSE;
Importer.m_sLoadData.m_sGeneral.m_bReadAttributes = A3D_TRUE;
Importer.m_sLoadData.m_sGeneral.m_bReadHiddenObjects = A3D_TRUE;
Importer.m_sLoadData.m_sGeneral.m_bReadConstructionAndReferences = A3D_FALSE;
Importer.m_sLoadData.m_sGeneral.m_bReadActiveFilter = A3D_FALSE;
Importer.m_sLoadData.m_sGeneral.m_eReadingMode2D3D = kA3DRead_3D;
Importer.m_sLoadData.m_sGeneral.m_eReadGeomTessMode = kA3DReadGeomAndTess/*kA3DReadGeomOnly*/;
Importer.m_sLoadData.m_sGeneral.m_bReadFeature = A3D_FALSE;
Importer.m_sLoadData.m_sGeneral.m_bReadConstraints = A3D_FALSE;
Importer.m_sLoadData.m_sGeneral.m_iNbMultiProcess = 1;
Importer.m_sLoadData.m_sIncremental.m_bLoadNoDependencies = FImportParameters::bGEnableCADCache && GMaxImportThreads != 1;
Importer.m_sLoadData.m_sIncremental.m_bLoadStructureOnly = false;
}
void UpdateIOOptionAccordingToFormat(const CADLibrary::ECADFormat Format, A3DImport& Importer, bool& OutForceSew)
{
switch (Format)
{
case CADLibrary::ECADFormat::IGES:
{
OutForceSew = true;
break;
}
case CADLibrary::ECADFormat::CATIA:
{
break;
}
case CADLibrary::ECADFormat::SOLIDWORKS:
{
Importer.m_sLoadData.m_sSpecifics.m_sSolidworks.m_bLoadAllConfigsData = true;
break;
}
case CADLibrary::ECADFormat::JT:
{
Importer.m_sLoadData.m_sIncremental.m_bLoadNoDependencies = false;
if (FImportParameters::bGPreferJtFileEmbeddedTessellation)
{
Importer.m_sLoadData.m_sGeneral.m_eReadGeomTessMode = kA3DReadTessOnly;
Importer.m_sLoadData.m_sSpecifics.m_sJT.m_eReadTessellationLevelOfDetail = A3DEJTReadTessellationLevelOfDetail::kA3DJTTessLODHigh;
}
break;
}
case CADLibrary::ECADFormat::N_X:
{
Importer.m_sLoadData.m_sGeneral.m_bReadActiveFilter = A3D_TRUE;
// jira UE-159972
Importer.m_sLoadData.m_sIncremental.m_bLoadNoDependencies = false;
break;
}
case CADLibrary::ECADFormat::INVENTOR:
case CADLibrary::ECADFormat::CATIA_3DXML:
{
Importer.m_sLoadData.m_sIncremental.m_bLoadNoDependencies = false;
break;
}
default:
break;
};
}
double ExtractUniformScale(FVector3d& Scale)
{
double UniformScale = (Scale.X + Scale.Y + Scale.Z) / 3.;
double Tolerance = UniformScale * DOUBLE_KINDA_SMALL_NUMBER;
if (!FMath::IsNearlyEqual(UniformScale, Scale.X, Tolerance) && !FMath::IsNearlyEqual(UniformScale, Scale.Y, Tolerance))
{
// non uniform scale
// Used in format like IFC or DGN to define pipe by their diameter and their length
// we remove the diameter component of the scale to have a scale like (Length/diameter, 1, 1) to have a mesh tessellated according the meshing parameters
if (FMath::IsNearlyEqual((double)Scale.X, (double)Scale.Y, Tolerance) || (FMath::IsNearlyEqual((double)Scale.X, (double)Scale.Z, Tolerance)))
{
UniformScale = Scale.X;
}
else if (FMath::IsNearlyEqual((double)Scale.Y, (double)Scale.Z, Tolerance))
{
UniformScale = Scale.Y;
}
}
Scale.X /= UniformScale;
Scale.Y /= UniformScale;
Scale.Z /= UniformScale;
return UniformScale;
}
} // namespace TechSoftFileParserImpl
#endif
FTechSoftFileParser::FTechSoftFileParser(FCADFileData& InCADData, const FString& EnginePluginsPath)
: CADFileData(InCADData)
, SceneGraph(InCADData.GetSceneGraphArchive())
, TechSoftInterface(FTechSoftInterface::Get())
{
TechSoftInterface.InitializeKernel(*EnginePluginsPath);
}
#ifdef USE_TECHSOFT_SDK
ECADParsingResult FTechSoftFileParser::Process()
{
bProcessIsRunning = true;
#ifndef CADKERNEL_DEV
TArray<UE::Tasks::FTask> Checkers;
if(FImportParameters::bValidationProcess)
{
Checkers.Emplace(UE::Tasks::Launch(TEXT("MemoryChecker"), [&]() { CheckMemory(); }));
}
#endif
//FPlatformMemoryStats StartMem = FPlatformMemory::GetStats();
uint64 StartTime = FPlatformTime::Cycles64();
const FFileDescriptor& File = CADFileData.GetCADFileDescription();
FImportRecord& ProcessReport = CADFileData.GetRecord();
if (File.GetPathOfFileToLoad().IsEmpty())
{
return ECADParsingResult::FileNotFound;
}
A3DImport Import(TCHAR_TO_UTF8(*File.GetPathOfFileToLoad()));
TechSoftFileParserImpl::SetIOOption(Import);
// Add specific options according to format
Format = File.GetFileFormat();
TechSoftFileParserImpl::UpdateIOOptionAccordingToFormat(Format, Import, bForceSew);
A3DStatus LoadStatus = A3DStatus::A3D_SUCCESS;
ModelFile = TechSoftInterface::LoadModelFileFromFile(Import, LoadStatus);
ProcessReport.ImportTime += FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartTime);
if (!ModelFile.IsValid())
{
switch (LoadStatus)
{
case A3DStatus::A3D_LOAD_FILE_TOO_OLD:
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s hasn't been loaded because the version is less than the oldest supported version."), *File.GetFileName()));
break;
}
case A3DStatus::A3D_LOAD_FILE_TOO_RECENT:
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s hasn't been loaded because the version is more recent than supported version."), *File.GetFileName()));
break;
}
case A3DStatus::A3D_LOAD_CANNOT_ACCESS_CADFILE:
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s hasn't been loaded because the input path cannot be opened by the running process for reading."), *File.GetFileName()));
break;
}
case A3DStatus::A3D_LOAD_INVALID_FILE_FORMAT:
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s hasn't been loaded because the format is not supported."), *File.GetFileName()));
break;
}
default:
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s hasn't been loaded because an error occured while reading the file."), *File.GetFileName()));
break;
}
};
return ECADParsingResult::ProcessFailed;
}
{
TUniqueTSObj<A3DAsmModelFileData> ModelFileData(ModelFile.Get());
if (!ModelFileData.IsValid())
{
return ECADParsingResult::ProcessFailed;
}
ModelerType = (EModelerType) ModelFileData->m_eModellerType;
FileUnit = TechSoftInterface::GetModelFileUnit(ModelFile.Get());
}
// save the file for the next load
if (CADFileData.IsCacheDefined())
{
uint64 StartSaveTime = FPlatformTime::Cycles64();
FString CacheFilePath = CADFileData.GetCADCachePath();
if (CacheFilePath != File.GetPathOfFileToLoad())
{
TechSoftUtils::SaveModelFileToPrcFile(ModelFile.Get(), CacheFilePath);
}
ProcessReport.SavePrcTime = FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartSaveTime);
}
// Adapt BRep to UE::CADKernel
{
uint64 StartAdaptTime = FPlatformTime::Cycles64();
if (AdaptBRepModel() != A3D_SUCCESS)
{
return ECADParsingResult::ProcessFailed;
}
ProcessReport.AdaptBRepTime = FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartAdaptTime);
}
// Some formats (like IGES) require a sew all the time. In this case, bForceSew = true
if (bForceSew || CADFileData.GetImportParameters().GetStitchingTechnique() == StitchingSew)
{
uint64 StartSewTime = FPlatformTime::Cycles64();
SewModel();
ProcessReport.SewTime = FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartSewTime);
}
uint64 StartTraversTime = FPlatformTime::Cycles64();
ReserveCADFileData();
ReadMaterialsAndColors();
ECADParsingResult Result = TraverseModel();
ProcessReport.ImportTime += FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartTraversTime);
if (Result == ECADParsingResult::ProcessOk)
{
GenerateBodyMeshes();
if (bConvertionFailed)
{
Result = ECADParsingResult::ProcessFailed;
}
FString TechSoftVersion = TechSoftInterface::GetTechSoftVersion();
if (!TechSoftVersion.IsEmpty())
{
FArchiveReference* RootReference = SceneGraph.GetRootReference();
if (ensureMsgf(RootReference, TEXT("FTechSoftFileParser expected root Reference in the Scene Graph")))
{
RootReference->MetaData.Add(TEXT("TechsoftVersion"), TechSoftVersion);
}
}
}
ModelFile.Reset();
ProcessReport.LoadProcessTime = FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartTime);
bProcessIsRunning = false;
#ifndef CADKERNEL_DEV
UE::Tasks::Wait(Checkers);
#endif
return Result;
}
void FTechSoftFileParser::SewModel()
{
CADLibrary::TUniqueTSObj<A3DSewOptionsData> SewData;
SewData->m_bComputePreferredOpenShellOrientation = false;
TechSoftInterface::SewModel(ModelFile.Get(), CADLibrary::FImportParameters::GStitchingTolerance, SewData.GetPtr());
}
void FTechSoftFileParser::GenerateBodyMeshes()
{
uint64 StartGenerateBodyMeshesTime = FPlatformTime::Cycles64();
for (TPair<A3DRiRepresentationItem*, FCadId>& Entry : RepresentationItemsCache)
{
A3DRiRepresentationItem* RepresentationItemPtr = Entry.Key;
FArchiveBody& Body = SceneGraph.GetBody(Entry.Value);
if (!Body.bIsFromCad)
{
FTechSoftFileParser::GenerateBodyMesh(RepresentationItemPtr, Body);
}
else
{
GenerateBodyMesh(RepresentationItemPtr, Body);
}
if (bConvertionFailed)
{
return;
}
}
CADFileData.GetRecord().MeshTime = FPlatformTime::ToMilliseconds64(FPlatformTime::Cycles64() - StartGenerateBodyMeshesTime);
}
void FTechSoftFileParser::GenerateBodyMesh(A3DRiRepresentationItem* Representation, FArchiveBody& Body)
{
FBodyMesh& BodyMesh = CADFileData.AddBodyMesh(Body.Id, Body);
uint32 NewBRepCount = 0;
A3DRiBrepModel** NewBReps = nullptr;
if (CADFileData.GetImportParameters().GetStitchingTechnique() == StitchingHeal)
{
TUniqueTSObj<A3DSewOptionsData> SewData;
SewData->m_bComputePreferredOpenShellOrientation = false;
const uint32 BRepCount = 1;
A3DStatus Status = TechSoftInterface::SewBReps(&Representation, BRepCount, CADLibrary::FImportParameters::GStitchingTolerance, FileUnit, SewData.GetPtr(), &NewBReps, NewBRepCount);
if (Status != A3DStatus::A3D_SUCCESS)
{
CADFileData.LogWarning(TEXT("A body healing failed. A body could be missing."));
}
}
if (NewBRepCount > 0)
{
for (uint32 Index = 0; Index < NewBRepCount; ++Index)
{
TechSoftUtils::FillBodyMesh(NewBReps[Index], CADFileData.GetImportParameters(), Body.Unit, BodyMesh);
}
}
else
{
TechSoftUtils::FillBodyMesh(Representation, CADFileData.GetImportParameters(), Body.Unit, BodyMesh);
}
if (BodyMesh.TriangleCount == 0)
{
// the mesh of the body is empty, the body is deleted.
Body.Delete();
}
// Convert material
for (FTessellationData& Tessellation : BodyMesh.Faces)
{
// Don't add material of empty face (i.e. face with empty tessellation
if (Tessellation.VertexIndices.Num() == 0)
{
continue;
}
// Extract proper color or material based on style index
FMaterialUId CachedStyleIndex = Tessellation.MaterialUId;
Tessellation.MaterialUId = 0;
if (CachedStyleIndex != FTechSoftDefaultValue::Style)
{
ExtractGraphStyleProperties(CachedStyleIndex, Tessellation);
}
Tessellation.DefineGraphicsPropertiesFromNoOverwrite(Body);
BodyMesh.AddGraphicPropertiesFrom(Tessellation);
}
Body.ColorFaceSet = BodyMesh.ColorSet;
Body.MaterialFaceSet = BodyMesh.MaterialSet;
if (Body.ColorUId == 0 && Body.ColorFaceSet.Num())
{
Body.ColorUId = *Body.ColorFaceSet.begin();
}
if (Body.MaterialUId == 0 && Body.MaterialFaceSet.Num())
{
Body.MaterialUId = *Body.MaterialFaceSet.begin();
}
// Write part's representation as Prc file if it is a BRep
A3DEEntityType Type;
A3DEntityGetType(Representation, &Type);
if (Type == kA3DTypeRiBrepModel)
{
#ifndef CADKERNEL_DEV
FString FilePath = CADFileData.GetBodyCachePath(Body.MeshActorUId);
if (!FilePath.IsEmpty())
{
TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
// Save body unit and default color and material attributes in a json string
// This will be used when the file is reloaded
JsonObject->SetNumberField(JSON_ENTRY_BODY_UNIT, Body.Unit);
if(Body.ColorUId)
{
JsonObject->SetNumberField(JSON_ENTRY_COLOR_NAME, Body.ColorUId);
}
if(Body.MaterialUId)
{
JsonObject->SetNumberField(JSON_ENTRY_MATERIAL_NAME, Body.MaterialUId);
}
FString JsonString;
TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> JsonWriter = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonString);
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), JsonWriter);
TechSoftUtils::SaveBodiesToPrcFile(&Representation, 1, FilePath, JsonString);
}
#endif
}
}
void FTechSoftFileParser::ReserveCADFileData()
{
// TODO: Could be more accurate
CountUnderModel();
CADFileData.ReserveBodyMeshes(ComponentCount[EComponentType::Body]);
SceneGraph.Reserve(ComponentCount);
uint32 MaterialNum = CountColorAndMaterial();
SceneGraph.MaterialHIdToMaterial.Reserve(MaterialNum);
}
void FTechSoftFileParser::CountUnderModel()
{
TUniqueTSObj<A3DAsmModelFileData> ModelFileData(ModelFile.Get());
if (!ModelFileData.IsValid())
{
return;
}
ComponentCount[EComponentType::Reference] ++;
for (uint32 Index = 0; Index < ModelFileData->m_uiPOccurrencesSize; ++Index)
{
if (IsConfigurationSet(ModelFileData->m_ppPOccurrences[Index]))
{
CountUnderConfigurationSet(ModelFileData->m_ppPOccurrences[Index]);
}
else
{
CountUnderOccurrence(ModelFileData->m_ppPOccurrences[Index]);
CountUnderOverrideOccurrence(ModelFileData->m_ppPOccurrences[Index]);
}
}
ReferenceCache.Empty();
}
ECADParsingResult FTechSoftFileParser::TraverseModel()
{
TUniqueTSObj<A3DAsmModelFileData> ModelFileData(ModelFile.Get());
if (!ModelFileData.IsValid())
{
return ECADParsingResult::ProcessFailed;
}
FArchiveInstance EmptyInstance;
FArchiveReference& Reference = SceneGraph.AddReference(EmptyInstance);
ExtractSpecificMetaData(ModelFile.Get(), Reference);
Reference.Unit = FileUnit;
if(ModelFileData->m_uiPOccurrencesSize == 0)
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s is empty."), *CADFileData.GetCADFileDescription().GetFileName()));
return ECADParsingResult::ProcessFailed;
}
if (ModelFileData->m_uiPOccurrencesSize > 1)
{
CADFileData.LogWarning(FString::Printf(TEXT("File %s has many root components, only the first is loaded."), *CADFileData.GetCADFileDescription().GetFileName()));
}
if (IsConfigurationSet(ModelFileData->m_ppPOccurrences[0]))
{
TraverseConfigurationSet(ModelFileData->m_ppPOccurrences[0], Reference);
}
else
{
TraverseReference(ModelFileData->m_ppPOccurrences[0], Reference);
}
return ECADParsingResult::ProcessOk;
}
void FTechSoftFileParser::TraverseConfigurationSet(const A3DAsmProductOccurrence* ConfigurationSetPtr, FArchiveReference& Reference)
{
TUniqueTSObj<A3DAsmProductOccurrenceData> ConfigurationSetData(ConfigurationSetPtr);
if (!ConfigurationSetData.IsValid())
{
return;
}
ExtractMetaData(ConfigurationSetPtr, Reference);
ExtractSpecificMetaData(ConfigurationSetPtr, Reference);
BuildReferenceName(Reference);
const FString& ConfigurationToLoad = CADFileData.GetCADFileDescription().GetConfiguration();
A3DMiscTransformation* Transform = ConfigurationSetData->m_pLocation;
ExtractTransformation(Transform, Reference);
TUniqueTSObj<A3DAsmProductOccurrenceData> ConfigurationData;
for (unsigned int Index = 0; Index < ConfigurationSetData->m_uiPOccurrencesSize; ++Index)
{
ConfigurationData.FillFrom(ConfigurationSetData->m_ppPOccurrences[Index]);
if (!ConfigurationData.IsValid())
{
continue;
}
if (ConfigurationData->m_uiProductFlags & A3D_PRODUCT_FLAG_CONFIG)
{
bool bIsConfigurationToLoad = false;
if (!ConfigurationToLoad.IsEmpty())
{
FArchiveCADObject Configuration;
ExtractMetaData(ConfigurationSetData->m_ppPOccurrences[Index], Configuration);
if (!Configuration.Label.IsEmpty())
{
bIsConfigurationToLoad = (Configuration.Label.Equals(ConfigurationToLoad));
}
}
else
{
bIsConfigurationToLoad = ConfigurationData->m_uiProductFlags & A3D_PRODUCT_FLAG_DEFAULT;
}
if (bIsConfigurationToLoad)
{
TraverseReference(ConfigurationSetData->m_ppPOccurrences[Index], Reference);
return;
}
}
}
if (ConfigurationToLoad.IsEmpty())
{
// no default configuration, traverse the first occurrence
for (unsigned int Index = 0; Index < ConfigurationSetData->m_uiPOccurrencesSize; ++Index)
{
ConfigurationData.FillFrom(ConfigurationSetData->m_ppPOccurrences[Index]);
if (!ConfigurationData.IsValid())
{
return;
}
if (ConfigurationData->m_uiProductFlags & A3D_PRODUCT_FLAG_CONFIG)
{
TraverseReference(ConfigurationSetData->m_ppPOccurrences[Index], Reference);
}
}
}
}
void FTechSoftFileParser::CountUnderConfigurationSet(const A3DAsmProductOccurrence* ConfigurationSetPtr)
{
TUniqueTSObj<A3DAsmProductOccurrenceData> ConfigurationSetData(ConfigurationSetPtr);
if (!ConfigurationSetData.IsValid())
{
return;
}
const FString& ConfigurationToLoad = CADFileData.GetCADFileDescription().GetConfiguration();
TUniqueTSObj<A3DAsmProductOccurrenceData> ConfigurationData;
for (unsigned int Index = 0; Index < ConfigurationSetData->m_uiPOccurrencesSize; ++Index)
{
ConfigurationData.FillFrom(ConfigurationSetData->m_ppPOccurrences[Index]);
if (!ConfigurationData.IsValid())
{
continue;
}
if (ConfigurationData->m_uiProductFlags & A3D_PRODUCT_FLAG_CONFIG)
{
bool bIsConfigurationToLoad = false;
if (!ConfigurationToLoad.IsEmpty())
{
FArchiveCADObject Configuration;
ExtractMetaData(ConfigurationSetData->m_ppPOccurrences[Index], Configuration);
if (!Configuration.Label.IsEmpty())
{
bIsConfigurationToLoad = (Configuration.Label.Equals(ConfigurationToLoad));
}
}
else
{
bIsConfigurationToLoad = ConfigurationData->m_uiProductFlags & A3D_PRODUCT_FLAG_DEFAULT;
}
if (bIsConfigurationToLoad)
{
CountUnderOccurrence(ConfigurationSetData->m_ppPOccurrences[Index]);
CountUnderOverrideOccurrence(ConfigurationSetData->m_ppPOccurrences[Index]);
return;
}
}
}
if (ConfigurationToLoad.IsEmpty())
{
// no default configuration, traverse the first configuration
for (unsigned int Index = 0; Index < ConfigurationSetData->m_uiPOccurrencesSize; ++Index)
{
ConfigurationData.FillFrom(ConfigurationSetData->m_ppPOccurrences[Index]);
if (!ConfigurationData.IsValid())
{
return;
}
if (ConfigurationData->m_uiProductFlags & A3D_PRODUCT_FLAG_CONFIG)
{
CountUnderOccurrence(ConfigurationSetData->m_ppPOccurrences[Index]);
CountUnderOverrideOccurrence(ConfigurationSetData->m_ppPOccurrences[Index]);
}
}
}
}
void FTechSoftFileParser::TraverseReference(const A3DAsmProductOccurrence* A3DReferencePtr, FArchiveReference& Reference)
{
TUniqueTSObj<A3DAsmProductOccurrenceData> ReferenceData(A3DReferencePtr);
if (!ReferenceData.IsValid())
{
SceneGraph.RemoveLastReference();
return;
}
ExtractMetaData(A3DReferencePtr, Reference);
if (Reference.bIsRemoved || !Reference.bShow)
{
if (Reference.bIsRemoved)
{
// Keep node in the SceneGraph if occurrence is not removed but just not visible
SceneGraph.RemoveLastReference();
}
return;
}
ExtractSpecificMetaData(A3DReferencePtr, Reference);
BuildReferenceName(Reference);
FMatrix ReferenceMatrix = FMatrix::Identity;
A3DMiscTransformation* Transform = ReferenceData->m_pLocation;
ExtractTransformation(Transform, Reference);
Reference.TransformMatrix = Reference.TransformMatrix * ReferenceMatrix;
FArchiveInstance EmptyInstance;
ProcessReference(A3DReferencePtr, EmptyInstance, Reference);
}
void FTechSoftFileParser::ProcessUnloadedReference(const FArchiveInstance& Instance, FArchiveUnloadedReference& Reference)
{
// Make sure that the ExternalFile path is right otherwise try to find the file and update.
TechSoftFileParserImpl::UpdateFileDescriptor(Reference.ExternalFile);
switch (Format)
{
case ECADFormat::SOLIDWORKS:
if (const FString* ConfigurationName = Instance.MetaData.Find(TEXT("ConfigurationName")))
{
Reference.ExternalFile.SetConfiguration(*ConfigurationName);
}
break;
default:
break;
}
SceneGraph.AddExternalReferenceFile(Reference);
}
void FTechSoftFileParser::TraverseOccurrence(const A3DAsmProductOccurrence* OccurrencePtr, FArchiveReference& ParentReference)
{
// first product occurrence with m_pPart != nullptr || m_uiPOccurrencesSize > 0
const A3DAsmProductOccurrence* CachedOccurrencePtr = OccurrencePtr;
TUniqueTSObj<A3DAsmProductOccurrenceData> OccurrenceData(OccurrencePtr);
if (!OccurrenceData.IsValid())
{
return;
}
bool bContinueTraverse = OccurrenceData->m_pPrototype
|| OccurrenceData->m_pExternalData
|| OccurrenceData->m_pPart
|| OccurrenceData->m_uiPOccurrencesSize > 0;
if (!bContinueTraverse)
{
return;
}
FArchiveInstance& Instance = SceneGraph.AddInstance(ParentReference);
ExtractMetaData(OccurrencePtr, Instance);
Instance.DefineGraphicsPropertiesFromNoOverwrite(ParentReference);
if (Instance.bIsRemoved)
{
SceneGraph.RemoveLastInstance();
return;
}
ParentReference.AddChild(Instance.Id);
ExtractSpecificMetaData(OccurrencePtr, Instance);
BuildInstanceName(Instance, ParentReference);
A3DMiscTransformation* Transform = OccurrenceData->m_pLocation;
A3DAsmProductOccurrence* ReferencePtr = ProductOccurrence::GetReference(*OccurrenceData);
// Is the Reference already processed ?
if(ReferencePtr)
{
FCadId* ReferenceId = ReferenceCache.Find(ReferencePtr);
if (ReferenceId != nullptr)
{
Instance.ReferenceNodeId = *ReferenceId;
if (SceneGraph.IsAUnloadedReference(Instance.ReferenceNodeId))
{
Instance.bIsExternalReference = true;
}
ExtractTransformation(Transform, Instance);
double ReferenceUnit = 1;
if (SceneGraph.IsAReference(Instance.ReferenceNodeId))
{
FArchiveReference& Reference = SceneGraph.GetReference(Instance.ReferenceNodeId);
ReferenceUnit = Reference.Unit;
}
else if (SceneGraph.IsAUnloadedReference(Instance.ReferenceNodeId))
{
FArchiveUnloadedReference& Reference = SceneGraph.GetUnloadedReference(Instance.ReferenceNodeId);
ReferenceUnit = Reference.Unit;
}
// check if the instance unit is nearly equal to the existing reference unit, otherwise add a scale component to the instance transform
double Scale = 1;
if (!FMath::IsNearlyZero(ReferenceUnit))
{
Scale = Instance.Unit / ReferenceUnit;
if (!FMath::IsNearlyEqual(Scale, 1.))
{
// Commented as the result was discarded
// Instance.TransformMatrix = Instance.TransformMatrix.ApplyScale(Scale);
}
}
return;
}
}
FArchiveUnloadedReference& UnloadedReference = SceneGraph.AddUnloadedReference(Instance);
bool bIsUnloaded = OccurrenceData->m_uiProductFlags & A3D_PRODUCT_FLAG_EXTERNAL_REFERENCE;
// Extract metadata and define if it's an unloaded reference or not
if (ReferencePtr)
{
ProcessPrototype(ReferencePtr, UnloadedReference, &Transform);
}
else
{
UnloadedReference.bIsUnloaded = false;
}
ExtractTransformation(Transform, Instance);
UnloadedReference.Unit = Instance.Unit;
if (UnloadedReference.bIsUnloaded)
{
ProcessUnloadedReference(Instance, UnloadedReference);
}
else
{
FArchiveReference& NewReference = SceneGraph.AddReference(UnloadedReference);
Instance.bIsExternalReference = false;
ProcessReference(OccurrencePtr, Instance, NewReference);
}
if(ReferencePtr)
{
ReferenceCache.Add(ReferencePtr, Instance.ReferenceNodeId);
}
for (uint32 Index = 0; Index < OccurrenceData->m_uiPOccurrencesSize; ++Index)
{
ExtractOverrideOccurrenceSubtree(OccurrenceData->m_ppPOccurrences[Index], Instance);
}
}
void FTechSoftFileParser::ExtractOverrideOccurrenceSubtree(const A3DAsmProductOccurrence* OccurrencePtr, FArchiveWithOverridenChildren& Parent)
{
TUniqueTSObj<A3DAsmProductOccurrenceData> OccurrenceData(OccurrencePtr);
if (OccurrenceData->m_uiProductFlags & A3D_PRODUCT_FLAG_INTERNAL)
{
return;
}
FArchiveOverrideOccurrence& OverrideOccurrence = SceneGraph.AddOverrideOccurrence(Parent);
ExtractMetaData(OccurrencePtr, OverrideOccurrence);
Parent.AddOverridenChild(OverrideOccurrence.Id);
FArchiveReference Reference;
BuildInstanceName(OverrideOccurrence, Reference);
A3DMiscTransformation* Transform = OccurrenceData->m_pLocation;
ExtractTransformation(Transform, OverrideOccurrence);
for (uint32 Index = 0; Index < OccurrenceData->m_uiPOccurrencesSize; ++Index)
{
ExtractOverrideOccurrenceSubtree(OccurrenceData->m_ppPOccurrences[Index], OverrideOccurrence);
}
}
void FTechSoftFileParser::CountUnderOverrideOccurrence(const A3DAsmProductOccurrence* Occurrence)
{
TUniqueTSObj<A3DAsmProductOccurrenceData> OccurrenceData(Occurrence);
if (Occurrence && OccurrenceData.IsValid())
{
ComponentCount[EComponentType::OverriddeOccurence]++;
uint32 ChildrenCount = OccurrenceData->m_uiPOccurrencesSize;
A3DAsmProductOccurrence** Children = OccurrenceData->m_ppPOccurrences;
for (uint32 Index = 0; Index < ChildrenCount; ++Index)
{
CountUnderOverrideOccurrence(Children[Index]);
}
}
}
void FTechSoftFileParser::ProcessReference(const A3DAsmProductOccurrence* OccurrencePtr, FArchiveInstance& Instance, FArchiveReference& Reference)
{
const A3DAsmProductOccurrence* CachedOccurrencePtr = OccurrencePtr;
TUniqueTSObj<A3DAsmProductOccurrenceData> OccurrenceData(OccurrencePtr);
// If the prototype hasn't name, set its name with the name of the instance
if (!Reference.IsNameDefined())
{
Reference.Label = Instance.Label;
}
while (ProductOccurrence::HasNoPartNoChildButHasReference(*OccurrenceData))
{
CachedOccurrencePtr = ProductOccurrence::GetReference(*OccurrenceData);
OccurrenceData.FillFrom(CachedOccurrencePtr);
}
if(ProductOccurrence::HasNoPartNoChild(*OccurrenceData))
{
return;
}
// Add part
while (ProductOccurrence::HasNoPartButHasReference(*OccurrenceData))
{
OccurrenceData.FillFrom(ProductOccurrence::GetReference(*OccurrenceData));
}
if (OccurrenceData->m_pPart != nullptr)
{
A3DAsmPartDefinition* PartDefinition = OccurrenceData->m_pPart;
TraversePartDefinition(PartDefinition, Reference);
}
// Add Occurrence's Children
OccurrenceData.FillFrom(CachedOccurrencePtr);
while (ProductOccurrence::HasNoChildButHasReference(*OccurrenceData))
{
OccurrenceData.FillFrom(ProductOccurrence::GetReference(*OccurrenceData));
}
uint32 ChildrenCount = OccurrenceData->m_uiPOccurrencesSize;
A3DAsmProductOccurrence** Children = OccurrenceData->m_ppPOccurrences;
for (uint32 Index = 0; Index < ChildrenCount; ++Index)
{
TraverseOccurrence(Children[Index], Reference);
}
}
void FTechSoftFileParser::CountUnderOccurrence(const A3DAsmProductOccurrence* Occurrence)
{
TUniqueTSObj<A3DAsmProductOccurrenceData> OccurrenceData(Occurrence);
if (Occurrence && OccurrenceData.IsValid())
{
ComponentCount[EComponentType::Instance]++;
A3DAsmProductOccurrence* ReferencePtr = ProductOccurrence::GetReference(*OccurrenceData);
// Is the Reference already processed ?
if(ReferencePtr)
{
FCadId* ReferenceId = ReferenceCache.Find(ReferencePtr);
if (ReferenceId != nullptr)
{
return;
}
ReferenceCache.Add(ReferencePtr, 1);
}
ComponentCount[EComponentType::Reference]++;
const A3DAsmProductOccurrence* CachedOccurrencePtr = Occurrence;
while (ProductOccurrence::HasNoPartNoChildButHasReference(*OccurrenceData))
{
CachedOccurrencePtr = ProductOccurrence::GetReference(*OccurrenceData);
OccurrenceData.FillFrom(CachedOccurrencePtr);
}
if (ProductOccurrence::HasNoPartNoChild(*OccurrenceData))
{
return;
}
// count under part
while (ProductOccurrence::HasNoPartButHasReference(*OccurrenceData))
{
OccurrenceData.FillFrom(ProductOccurrence::GetReference(*OccurrenceData));
}
if (OccurrenceData->m_pPart != nullptr)
{
CountUnderPartDefinition(OccurrenceData->m_pPart);
}
// count under Occurrence
OccurrenceData.FillFrom(CachedOccurrencePtr);
while (ProductOccurrence::HasNoChildButHasReference(*OccurrenceData))
{
OccurrenceData.FillFrom(ProductOccurrence::GetReference(*OccurrenceData));
}
uint32 ChildrenCount = OccurrenceData->m_uiPOccurrencesSize;
A3DAsmProductOccurrence** Children = OccurrenceData->m_ppPOccurrences;
for (uint32 Index = 0; Index < ChildrenCount; ++Index)
{
CountUnderOccurrence(Children[Index]);
CountUnderOverrideOccurrence(Children[Index]);
}
}
}
void FTechSoftFileParser::ProcessPrototype(const A3DAsmProductOccurrence* InPrototypePtr, FArchiveUnloadedReference& OutReference, A3DMiscTransformation** OutTransform)
{
const A3DAsmProductOccurrence* PrototypePtr = InPrototypePtr;
TUniqueTSObj<A3DAsmProductOccurrenceData> PrototypeData;
while (PrototypePtr)
{
PrototypeData.FillFrom(PrototypePtr);
if (!PrototypeData.IsValid())
{
return;
}
ExtractMetaData(PrototypePtr, OutReference);
ExtractSpecificMetaData(PrototypePtr, OutReference);
if (OutReference.ExternalFile.IsEmpty())
{
TUniqueTSObj<A3DUTF8Char*> FilePathUTF8Ptr;
FilePathUTF8Ptr.FillWith(&TechSoftInterface::GetFilePathName, PrototypePtr);
if (!FilePathUTF8Ptr.IsValid() || *FilePathUTF8Ptr == nullptr)
{
FilePathUTF8Ptr.FillWith(&TechSoftInterface::GetOriginalFilePathName, PrototypePtr);
}
if (FilePathUTF8Ptr.IsValid() && *FilePathUTF8Ptr != nullptr)
{
FString FilePath = UTF8_TO_TCHAR(*FilePathUTF8Ptr);
FPaths::NormalizeFilename(FilePath);
FString FileName = FPaths::GetCleanFilename(FilePath);
if (!FileName.IsEmpty() && FileName != CADFileData.GetCADFileDescription().GetFileName())
{
OutReference.ExternalFile = FFileDescriptor(*FilePath, nullptr, *CADFileData.GetCADFileDescription().GetRootFolder());
}
}
}
if (ProductOccurrence::HasPartOrChild(*PrototypeData) )
{
OutReference.bIsUnloaded = false;
PrototypePtr = nullptr;
}
else
{
PrototypePtr = ProductOccurrence::GetReference(*PrototypeData);
}
if (!*OutTransform)
{
*OutTransform = PrototypeData->m_pLocation;
}
}
if (!*OutTransform)
{
while (PrototypeData->m_pLocation == nullptr && ProductOccurrence::PrototypeIsValid(*PrototypeData))
{
PrototypeData.FillFrom(ProductOccurrence::GetReference(*PrototypeData));
}
if (PrototypeData.IsValid())
{
*OutTransform = PrototypeData->m_pLocation;
}
}
if (OutReference.bIsUnloaded)
{
if(OutReference.Label.IsEmpty())
{
OutReference.Label = OutReference.ExternalFile.GetFileName();
}
}
else
{
OutReference.ExternalFile.Empty();
}
BuildReferenceName(OutReference);
}
void FTechSoftFileParser::TraversePartDefinition(const A3DAsmPartDefinition* PartDefinitionPtr, FArchiveReference& Part)
{
ExtractMetaData(PartDefinitionPtr, Part);
if (Part.bIsRemoved || !Part.bShow)
{
return;
}
ExtractSpecificMetaData(PartDefinitionPtr, Part);
BuildPartName(Part);
TUniqueTSObj<A3DAsmPartDefinitionData> PartData(PartDefinitionPtr);
if (PartData.IsValid())
{
for (A3DUns32 Index = 0; Index < PartData->m_uiRepItemsSize; ++Index)
{
TraverseRepresentationItem(PartData->m_ppRepItems[Index], Part);
}
}
}
void FTechSoftFileParser::CountUnderPartDefinition(const A3DAsmPartDefinition* PartDefinition)
{
TUniqueTSObj<A3DAsmPartDefinitionData> PartData(PartDefinition);
if (PartDefinition && PartData.IsValid())
{
ComponentCount[EComponentType::Reference] ++;
ComponentCount[EComponentType::Instance] ++;
for (unsigned int Index = 0; Index < PartData->m_uiRepItemsSize; ++Index)
{
CountUnderRepresentationItem(PartData->m_ppRepItems[Index]);
}
}
}
void FTechSoftFileParser::TraverseRepresentationItem(A3DRiRepresentationItem* RepresentationItem, FArchiveReference& Part)
{
if (!RepresentationItem)
{
return;
}
if (FCadId* BodyIndexPtr = RepresentationItemsCache.Find(RepresentationItem))
{
Part.AddChild(*BodyIndexPtr);
return;
}
A3DEEntityType Type;
A3DEntityGetType(RepresentationItem, &Type);
switch (Type)
{
case kA3DTypeRiSet:
return TraverseRepresentationSet(RepresentationItem, Part);
case kA3DTypeRiBrepModel:
return TraverseBRepModel(RepresentationItem, Part);
case kA3DTypeRiPolyBrepModel:
return TraversePolyBRepModel(RepresentationItem, Part);
default:
break;
}
}
void FTechSoftFileParser::CountUnderRepresentationItem(const A3DRiRepresentationItem* RepresentationItem)
{
A3DEEntityType Type;
A3DEntityGetType(RepresentationItem, &Type);
switch (Type)
{
case kA3DTypeRiSet:
CountUnderRepresentationSet(RepresentationItem);
break;
case kA3DTypeRiBrepModel:
case kA3DTypeRiPolyBrepModel:
ComponentCount[EComponentType::Body] ++;
break;
default:
break;
}
}
void FTechSoftFileParser::TraverseRepresentationSet(const A3DRiSet* RepresentationSetPtr, FArchiveReference& Parent)
{
TUniqueTSObj<A3DRiSetData> RepresentationSetData(RepresentationSetPtr);
if (!RepresentationSetData.IsValid())
{
return;
}
FCadId RepresentationSetId = 0;
FArchiveReference& RepresentationSet = SceneGraph.AddOccurrence(Parent);
ExtractMetaData(RepresentationSetPtr, RepresentationSet);
RepresentationSet.DefineGraphicsPropertiesFromNoOverwrite(Parent);
BuildRepresentationSetName(RepresentationSet, Parent);
if (RepresentationSet.bIsRemoved || !RepresentationSet.bShow)
{
Parent.RemoveLastChild();
SceneGraph.RemoveLastOccurrence();
return;
}
for (A3DUns32 Index = 0; Index < RepresentationSetData->m_uiRepItemsSize; ++Index)
{
TraverseRepresentationItem(RepresentationSetData->m_ppRepItems[Index], RepresentationSet);
}
}
void FTechSoftFileParser::CountUnderRepresentationSet(const A3DRiSet* RepresentationSet)
{
TUniqueTSObj<A3DRiSetData> RepresentationSetData(RepresentationSet);
if (RepresentationSet && RepresentationSetData.IsValid())
{
ComponentCount[EComponentType::Instance] ++;
ComponentCount[EComponentType::Reference] ++;
for (A3DUns32 Index = 0; Index < RepresentationSetData->m_uiRepItemsSize; ++Index)
{
CountUnderRepresentationItem(RepresentationSetData->m_ppRepItems[Index]);
}
}
}
void FTechSoftFileParser::TraverseBRepModel(A3DRiBrepModel* BRepModelPtr, FArchiveReference& Parent)
{
FArchiveBody& BRep = SceneGraph.AddBody(Parent, CADFileData.GetImportParameters().GetMesher());
ExtractMetaData(BRepModelPtr, BRep);
BRep.DefineGraphicsPropertiesFromNoOverwrite(Parent);
ExtractSpecificMetaData(BRepModelPtr, BRep);
if (!BRep.bShow || BRep.bIsRemoved)
{
SceneGraph.RemoveLastBody();
return;
}
Parent.AddChild(BRep.Id);
RepresentationItemsCache.Add(BRepModelPtr, BRep.Id);
TUniqueTSObj<A3DRiBrepModelData> BRepModelData(BRepModelPtr);
BRep.bIsASolid = (bool)BRepModelData->m_bSolid;
BuildBodyName(BRep, Parent);
TUniqueTSObj<A3DRiRepresentationItemData> RepresentationData(BRepModelPtr);
ExtractCoordinateSystem(RepresentationData->m_pCoordinateSystem, BRep);
}
void FTechSoftFileParser::TraversePolyBRepModel(A3DRiPolyBrepModel* PolygonalPtr, FArchiveReference& Parent)
{
FArchiveBody& BRep = SceneGraph.AddBody(Parent, EMesher::TechSoft);
BRep.bIsFromCad = false;
ExtractMetaData(PolygonalPtr, BRep);
BRep.DefineGraphicsPropertiesFromNoOverwrite(Parent);
ExtractSpecificMetaData(PolygonalPtr, BRep);
if (!BRep.bShow || BRep.bIsRemoved)
{
SceneGraph.RemoveLastBody();
return;
}
Parent.AddChild(BRep.Id);
RepresentationItemsCache.Add(PolygonalPtr, BRep.Id);
TUniqueTSObj<A3DRiPolyBrepModelData> BRepModelData(PolygonalPtr);
BRep.bIsASolid = (bool)BRepModelData->m_bIsClosed;
BuildBodyName(BRep, Parent);
TUniqueTSObj<A3DRiRepresentationItemData> RepresentationData(PolygonalPtr);
ExtractCoordinateSystem(RepresentationData->m_pCoordinateSystem, BRep);
}
void FTechSoftFileParser::ExtractMetaData(const A3DEntity* Entity, FArchiveCADObject& OutObject)
{
TUniqueTSObj<A3DRootBaseData> MetaData(Entity);
if (MetaData.IsValid())
{
if (OutObject.Label.IsEmpty() && MetaData->m_pcName && MetaData->m_pcName[0] != '\0')
{
FString Name = UTF8_TO_TCHAR(MetaData->m_pcName);
if(Name != TEXT("unnamed")) // "unnamed" is create by Techsoft. This name is ignored
{
Name = TechSoftUtils::CleanLabel(Name);
OutObject.Label = Name;
}
}
TUniqueTSObj<A3DMiscAttributeData> AttributeData;
for (A3DUns32 Index = 0; Index < MetaData->m_uiSize; ++Index)
{
AttributeData.FillFrom(MetaData->m_ppAttributes[Index]);
if (AttributeData.IsValid())
{
TechSoftFileParserImpl::TraverseAttribute(*AttributeData, OutObject.MetaData);
}
}
}
if (A3DEntityIsBaseWithGraphicsType(Entity))
{
TUniqueTSObj<A3DRootBaseWithGraphicsData> MetaDataWithGraphics(Entity);
if (MetaDataWithGraphics.IsValid())
{
if (MetaDataWithGraphics->m_pGraphics != NULL)
{
ExtractGraphicProperties(MetaDataWithGraphics->m_pGraphics, OutObject);
}
}
}
}
void FTechSoftFileParser::BuildReferenceName(FArchiveCADObject& ReferenceData)
{
TMap<FString, FString>& MetaData = ReferenceData.MetaData;
FString* NamePtr = MetaData.Find(TEXT("InstanceName"));
if (NamePtr != nullptr && !NamePtr->IsEmpty())
{
if (Format == ECADFormat::CATIA)
{
ReferenceData.Label = TechSoftUtils::CleanCatiaReferenceLabel(*NamePtr);
}
else
{
ReferenceData.Label = *NamePtr;
}
return;
}
if (ReferenceData.SetNameWithAttributeValue(TEXT("PartNumber")))
{
return;
}
switch (Format)
{
case ECADFormat::CATIA_3DXML:
ReferenceData.Label = TechSoftUtils::Clean3dxmlReferenceLabel(ReferenceData.Label);
break;
case ECADFormat::SOLIDWORKS:
ReferenceData.Label = TechSoftUtils::CleanSwReferenceLabel(ReferenceData.Label);
break;
default:
break;
}
}
void FTechSoftFileParser::BuildInstanceName(FArchiveCADObject& InstanceData, const FArchiveReference& Parent)
{
TMap<FString, FString>& MetaData = InstanceData.MetaData;
if (InstanceData.SetNameWithAttributeValue(TEXT("InstanceName")))
{
return;
}
if (InstanceData.IsNameDefined())
{
switch (Format)
{
case ECADFormat::CATIA:
InstanceData.Label = TechSoftUtils::CleanCatiaInstanceLabel(InstanceData.Label);
break;
case ECADFormat::CATIA_3DXML:
InstanceData.Label = TechSoftUtils::Clean3dxmlInstanceLabel(InstanceData.Label);
break;
case ECADFormat::SOLIDWORKS:
InstanceData.Label = TechSoftUtils::CleanSwInstanceLabel(InstanceData.Label);
break;
default:
break;
}
return;
}
if (InstanceData.Label.IsEmpty())
{
InstanceData.Label = Parent.Label + "_" + FString::FromInt(Parent.Children.Num());
}
}
void FTechSoftFileParser::BuildPartName(FArchiveCADObject& PartData)
{
if (PartData.SetNameWithAttributeValue(TEXT("PartNumber")))
{
return;
}
}
void FTechSoftFileParser::BuildBodyName(FArchiveBody& Body, const FArchiveReference& Parent)
{
if (Format == ECADFormat::CREO)
{
Body.Label = TechSoftUtils::CleanCreoLabel(Body.Label);
}
if(Body.IsNameDefined())
{
return;
}
if (Format == ECADFormat::CATIA)
{
if(Body.SetNameWithAttributeValue(TEXT("BodyID")))
{
return;
}
}
FString& Label = Body.Label;
if (Parent.IsNameDefined())
{
Label = Parent.Label + TEXT("_body");
}
else
{
if (Body.bIsASolid)
{
Label = TEXT("Solid");
}
else
{
Label = TEXT("Shell");
}
}
Label += FString::FromInt(Parent.Children.Num());
}
void FTechSoftFileParser::BuildRepresentationSetName(FArchiveCADObject& Occurrence, const FArchiveReference& Parent)
{
if (Occurrence.IsNameDefined())
{
return;
}
FString& Label = Occurrence.Label;
if (Parent.IsNameDefined())
{
Label = Parent.Label;
}
else
{
Label = TEXT("Product");
}
Label += FString::FromInt(Parent.Children.Num());
}
void FTechSoftFileParser::ExtractSpecificMetaData(const A3DAsmProductOccurrence* Occurrence, FArchiveCADObject& OutMetaData)
{
//----------- Export Specific information per CAD format -----------
switch (ModelerType)
{
case ModelerSlw:
{
TUniqueTSObj<A3DAsmProductOccurrenceDataSLW> SolidWorksSpecificData(Occurrence);
if (SolidWorksSpecificData.IsValid())
{
if (SolidWorksSpecificData->m_psCfgName)
{
FString ConfigurationName = UTF8_TO_TCHAR(SolidWorksSpecificData->m_psCfgName);
OutMetaData.MetaData.Emplace(TEXT("ConfigurationName"), ConfigurationName);
FString ConfigurationIndex = FString::FromInt(SolidWorksSpecificData->m_iIndexCfg);
OutMetaData.MetaData.Emplace(TEXT("ConfigurationIndex"), ConfigurationIndex);
}
}
break;
}
case ModelerUnigraphics:
{
#ifdef WIP
TUniqueTSObj<A3DAsmProductOccurrenceDataUg> UnigraphicsSpecificData(Occurrence);
if (UnigraphicsSpecificData.IsValid())
{
if (UnigraphicsSpecificData->m_psPartUID)
{
FString PartUID = UTF8_TO_TCHAR(UnigraphicsSpecificData->m_psPartUID);
OutMetaData.MetaData.Emplace(TEXT("UnigraphicsPartUID"), PartUID);
}
if (UnigraphicsSpecificData->m_psFileName)
{
FString FileName = UTF8_TO_TCHAR(UnigraphicsSpecificData->m_psFileName);
OutMetaData.MetaData.Emplace(TEXT("UnigraphicsFileName"), FileName);
}
if (UnigraphicsSpecificData->m_psInstanceFileName)
{
FString InstanceFileName = UTF8_TO_TCHAR(UnigraphicsSpecificData->m_psInstanceFileName);
OutMetaData.MetaData.Emplace(TEXT("UnigraphicsInstanceFileName"), InstanceFileName);
}
if (UnigraphicsSpecificData->m_psRefSet)
{
FString RefSet = UTF8_TO_TCHAR(UnigraphicsSpecificData->m_psRefSet);
OutMetaData.MetaData.Emplace(TEXT("UnigraphicsInstanceRefSet"), RefSet);
}
if (UnigraphicsSpecificData->m_psPartUID)
{
FString PartUID = UTF8_TO_TCHAR(UnigraphicsSpecificData->m_psPartUID);
OutMetaData.MetaData.Emplace(TEXT("UnigraphicsInstancePartUID"), PartUID);
}
if (UnigraphicsSpecificData->m_uiInstanceTag)
{
FString InstanceTag = FString::FromInt(UnigraphicsSpecificData->m_uiInstanceTag);
OutMetaData.MetaData.Emplace(TEXT("UnigraphicsInstanceTag"), InstanceTag);
}
for (uint32 Index = 0; Index < UnigraphicsSpecificData->m_uiPromotedBodiesSize; ++Index)
{
A3DPromotedBodyUg PromotedBody = UnigraphicsSpecificData->m_asPromotedBodies[Index];
}
for (uint32 Index = 0; Index < UnigraphicsSpecificData->m_uiChildrenByRefsetsSize; ++Index)
{
A3DElementsByRefsetUg Refset = UnigraphicsSpecificData->m_asChildrenByRefsets[Index];
}
if(UnigraphicsSpecificData->m_uiSolidsByRefsetsSize)
{
for (uint32 Index = 0; Index < UnigraphicsSpecificData->m_uiSolidsByRefsetsSize; ++Index)
{
A3DElementsByRefsetUg Refset = UnigraphicsSpecificData->m_asSolidsByRefsets[Index];
FString ReferenceSetName = UTF8_TO_TCHAR(Refset.m_psRefset);
if (ReferenceSetName == CADFileData.GetCADFileDescription().GetConfiguration())
{
UnigraphicsReferenceSet.Reserve(Refset.m_uiElementsSize);
for (uint32 Andex = 0; Andex < Refset.m_uiElementsSize; ++Andex)
{
UnigraphicsReferenceSet.Add(Refset.m_auiElements[Andex]);
}
}
}
}
}
#endif
break;
}
case ModelerCatiaV5:
{
TUniqueTSObj<A3DAsmProductOccurrenceDataCV5> CatiaV5SpecificData(Occurrence);
if (CatiaV5SpecificData.IsValid())
{
if (CatiaV5SpecificData->m_psVersion)
{
FString Version = UTF8_TO_TCHAR(CatiaV5SpecificData->m_psVersion);
OutMetaData.MetaData.Emplace(TEXT("CatiaVersion"), Version);
}
if (CatiaV5SpecificData->m_psPartNumber)
{
FString PartNumber = UTF8_TO_TCHAR(CatiaV5SpecificData->m_psPartNumber);
OutMetaData.MetaData.Emplace(TEXT("CatiaPartNumber"), PartNumber);
}
}
break;
}
default:
break;
}
}
FArchiveColor& FTechSoftFileParser::FindOrAddColor(uint32 ColorIndex, uint8 Alpha)
{
FMaterialUId ColorHId = BuildColorFastUId(ColorIndex, Alpha);
if (FArchiveColor* Color = CADFileData.FindColor(ColorHId))
{
return *Color;
}
FArchiveColor& NewColor = CADFileData.AddColor(ColorHId);
NewColor.Color = TechSoftUtils::GetColorAt(ColorIndex);
NewColor.Color.A = Alpha;
NewColor.UEMaterialUId = BuildColorUId(NewColor.Color);
return NewColor;
}
FArchiveMaterial& FTechSoftFileParser::AddMaterialAt(uint32 MaterialIndexToSave, uint32 GraphMaterialIndex, const A3DGraphStyleData& GraphStyleData)
{
FArchiveMaterial& NewMaterial = CADFileData.AddMaterial(GraphMaterialIndex);
FCADMaterial& Material = NewMaterial.Material;
TUniqueTSObjFromIndex<A3DGraphMaterialData> MaterialData(MaterialIndexToSave);
if(MaterialData.IsValid())
{
Material.Diffuse = TechSoftUtils::GetColorAt(MaterialData->m_uiDiffuse);
Material.Ambient = TechSoftUtils::GetColorAt(MaterialData->m_uiAmbient);
Material.Specular = TechSoftUtils::GetColorAt(MaterialData->m_uiSpecular);
Material.Shininess = MaterialData->m_dShininess;
if(GraphStyleData.m_bIsTransparencyDefined)
{
Material.Transparency = 1. - GraphStyleData.m_ucTransparency/255.;
}
// todo: find how to convert Emissive color into ? reflexion coef...
// Material.Emissive = GetColor(MaterialData->m_uiEmissive);
// Material.Reflexion;
}
NewMaterial.UEMaterialUId = BuildMaterialUId(Material);
return NewMaterial;
}
// Look at TechSoftUtils::BuildCADMaterial if any loigc changes in this method
// or any of the methods it calls
FArchiveMaterial& FTechSoftFileParser::FindOrAddMaterial(FMaterialUId MaterialIndex, const A3DGraphStyleData& GraphStyleData)
{
if (FArchiveMaterial* MaterialArchive = CADFileData.FindMaterial(MaterialIndex))
{
return *MaterialArchive;
}
bool bIsTexture = TechSoftInterface::IsMaterialTexture(MaterialIndex);
if (bIsTexture)
{
TUniqueTSObjFromIndex<A3DGraphTextureApplicationData> TextureData(MaterialIndex);
if (TextureData.IsValid())
{
return AddMaterialAt(TextureData->m_uiMaterialIndex, MaterialIndex, GraphStyleData);
#ifdef NOTYETDEFINE
TUniqueTSObj<A3DGraphTextureDefinitionData> TextureDefinitionData(TextureData->m_uiTextureDefinitionIndex);
if (TextureDefinitionData.IsValid())
{
TUniqueTSObj<A3DGraphPictureData> PictureData(TextureDefinitionData->m_uiPictureIndex);
}
#endif
}
return AddMaterialAt(MaterialIndex, 0, GraphStyleData);
}
else
{
return AddMaterial(MaterialIndex, GraphStyleData);
}
}
void FTechSoftFileParser::ExtractGraphicProperties(const A3DGraphics* Graphics, FArchiveCADObject& OutMetaData)
{
TUniqueTSObj<A3DGraphicsData> GraphicsData(Graphics);
if (!GraphicsData.IsValid())
{
return;
}
OutMetaData.bIsRemoved = GraphicsData->m_usBehaviour & kA3DGraphicsRemoved;
OutMetaData.bShow = GraphicsData->m_usBehaviour & kA3DGraphicsShow;
if (GraphicsData->m_usBehaviour & kA3DGraphicsFatherHeritColor)
{
OutMetaData.Inheritance = ECADGraphicPropertyInheritance::FatherHerit;
}
else if (GraphicsData->m_usBehaviour & kA3DGraphicsSonHeritColor)
{
OutMetaData.Inheritance = ECADGraphicPropertyInheritance::ChildHerit;
}
if (GraphicsData->m_uiStyleIndex == A3D_DEFAULT_STYLE_INDEX)
{
return;
}
ExtractGraphStyleProperties(GraphicsData->m_uiStyleIndex, OutMetaData);
}
// Please review TechSoftUtils::GetMaterialValues if anything changes
// in this method or the methods it calls
void FTechSoftFileParser::ExtractGraphStyleProperties(uint32 StyleIndex, FArchiveGraphicProperties& OutGraphicProperties)
{
TUniqueTSObjFromIndex<A3DGraphStyleData> GraphStyleData(StyleIndex);
if (GraphStyleData.IsValid())
{
if (GraphStyleData->m_bMaterial)
{
FArchiveMaterial& MaterialArchive = FindOrAddMaterial(GraphStyleData->m_uiRgbColorIndex, *GraphStyleData);
OutGraphicProperties.MaterialUId = MaterialArchive.UEMaterialUId;
}
else
{
uint8 Alpha = 255;
if (GraphStyleData->m_bIsTransparencyDefined)
{
Alpha = GraphStyleData->m_ucTransparency;
}
FArchiveColor& ColorArchive = FindOrAddColor(GraphStyleData->m_uiRgbColorIndex, Alpha);
OutGraphicProperties.ColorUId = ColorArchive.UEMaterialUId;
}
}
}
void FTechSoftFileParser::ExtractTransformation3D(const A3DMiscTransformation* CartesianTransformation, FArchiveCADObject& Component)
{
TUniqueTSObj<A3DMiscCartesianTransformationData> CartesianTransformationData(CartesianTransformation);
if (CartesianTransformationData.IsValid())
{
FVector Origin(CartesianTransformationData->m_sOrigin.m_dX, CartesianTransformationData->m_sOrigin.m_dY, CartesianTransformationData->m_sOrigin.m_dZ);
FVector XVector(CartesianTransformationData->m_sXVector.m_dX, CartesianTransformationData->m_sXVector.m_dY, CartesianTransformationData->m_sXVector.m_dZ);;
FVector YVector(CartesianTransformationData->m_sYVector.m_dX, CartesianTransformationData->m_sYVector.m_dY, CartesianTransformationData->m_sYVector.m_dZ);;
FVector ZVector = XVector ^ YVector;
Origin *= Component.Unit * FImportParameters::GUnitScale;
const A3DVector3dData& A3DScale = CartesianTransformationData->m_sScale;
FVector3d Scale(A3DScale.m_dX, A3DScale.m_dY, A3DScale.m_dZ);
double UniformScale = TechSoftFileParserImpl::ExtractUniformScale(Scale);
XVector *= Scale.X;
YVector *= Scale.Y;
ZVector *= Scale.Z;
Component.Unit *= UniformScale;
Component.TransformMatrix = FMatrix(XVector, YVector, ZVector, FVector::ZeroVector);
if (CartesianTransformationData->m_ucBehaviour & kA3DTransformationMirror)
{
Component.TransformMatrix.M[2][0] *= -1;
Component.TransformMatrix.M[2][1] *= -1;
Component.TransformMatrix.M[2][2] *= -1;
}
Component.TransformMatrix.SetOrigin(Origin);
}
else
{
Component.TransformMatrix = FMatrix::Identity;
}
}
void FTechSoftFileParser::ExtractGeneralTransformation(const A3DMiscTransformation* GeneralTransformation, FArchiveCADObject& Component)
{
TUniqueTSObj<A3DMiscGeneralTransformationData> GeneralTransformationData(GeneralTransformation);
if (GeneralTransformationData.IsValid())
{
FMatrix Matrix = FMatrix::Identity;;
int32 Index = 0;
for (int32 Andex = 0; Andex < 4; ++Andex)
{
for (int32 Bndex = 0; Bndex < 4; ++Bndex, ++Index)
{
Matrix.M[Andex][Bndex] = GeneralTransformationData->m_adCoeff[Index];
}
}
FTransform3d Transform(Matrix);
FVector3d Scale = Transform.GetScale3D();
if (Scale.Equals(FVector3d::OneVector, DOUBLE_KINDA_SMALL_NUMBER))
{
const double TranslationScale = Component.Unit * FImportParameters::GUnitScale;
for (Index = 0; Index < 3; ++Index)
{
Matrix.M[3][Index] *= TranslationScale;
}
Component.TransformMatrix = Matrix;
}
else
{
FVector3d Translation = Transform.GetTranslation();
Translation *= Component.Unit * FImportParameters::GUnitScale;
double UniformScale = TechSoftFileParserImpl::ExtractUniformScale(Scale);
Component.Unit *= UniformScale;
FQuat4d Rotation = Transform.GetRotation();
FTransform3d NewTransform;
NewTransform.SetScale3D(Scale);
NewTransform.SetRotation(Rotation);
Component.TransformMatrix = NewTransform.ToMatrixWithScale();
Component.TransformMatrix.SetOrigin(Translation);
}
}
else
{
Component.TransformMatrix = FMatrix::Identity;
}
}
void FTechSoftFileParser::ExtractTransformation(const A3DMiscTransformation* Transformation3D, FArchiveCADObject& Component)
{
if (Transformation3D == NULL)
{
return;
}
A3DEEntityType Type = kA3DTypeUnknown;
A3DEntityGetType(Transformation3D, &Type);
if (Type == kA3DTypeMiscCartesianTransformation)
{
ExtractTransformation3D(Transformation3D, Component);
}
else if (Type == kA3DTypeMiscGeneralTransformation)
{
ExtractGeneralTransformation(Transformation3D, Component);
}
}
void FTechSoftFileParser::ExtractCoordinateSystem(const A3DRiCoordinateSystem* CoordinateSystem, FArchiveCADObject& OutMetaData)
{
TUniqueTSObj<A3DRiCoordinateSystemData> CoordinateSystemData(CoordinateSystem);
if (CoordinateSystemData.IsValid())
{
ExtractTransformation(CoordinateSystemData->m_pTransformation, OutMetaData);
}
else
{
OutMetaData.TransformMatrix = FMatrix::Identity;
}
}
bool FTechSoftFileParser::IsConfigurationSet(const A3DAsmProductOccurrence* Occurrence)
{
switch (Format)
{
case ECADFormat::CATIAV4:
case ECADFormat::N_X:
case ECADFormat::SOLIDWORKS:
{
TUniqueTSObj<A3DAsmProductOccurrenceData> OccurrenceData(Occurrence);
if (!OccurrenceData.IsValid())
{
return false;
}
return OccurrenceData->m_uiProductFlags & A3D_PRODUCT_FLAG_CONTAINER;
}
default :
return false;
}
}
uint32 FTechSoftFileParser::CountColorAndMaterial()
{
A3DGlobal* GlobalPtr = TechSoftInterface::GetGlobalPointer();
if (GlobalPtr == nullptr)
{
return 0;
}
A3DInt32 iRet = A3D_SUCCESS;
TUniqueTSObj<A3DGlobalData> GlobalData(GlobalPtr);
if (!GlobalData.IsValid())
{
return 0;
}
uint32 ColorCount = GlobalData->m_uiColorsSize;
uint32 MaterialCount = GlobalData->m_uiMaterialsSize;
uint32 TextureDefinitionCount = GlobalData->m_uiTextureDefinitionsSize;
return ColorCount + MaterialCount + TextureDefinitionCount;
}
void ExtractTextureDefinition(const A3DGraphTextureDefinitionData& TextureDefinitionData)
{
// To do
//TextureDefinitionData.m_uiPictureIndex;
//TextureDefinitionData.m_ucTextureDimension;
//TextureDefinitionData.m_eMappingType;
//TextureDefinitionData.m_eMappingOperator;
//TextureDefinitionData.m_pOperatorTransfo;
//TextureDefinitionData.m_uiMappingAttributes;
//TextureDefinitionData.m_uiMappingAttributesIntensitySize,
//TextureDefinitionData.m_pdMappingAttributesIntensity;
//TextureDefinitionData.m_uiMappingAttributesComponentsSize,
//TextureDefinitionData.m_pucMappingAttributesComponents;
//TextureDefinitionData.m_eTextureFunction;
//TextureDefinitionData.m_dRed;
//TextureDefinitionData.m_dGreen;
//TextureDefinitionData.m_dBlue;
//TextureDefinitionData.m_dAlpha;
//TextureDefinitionData.m_eBlend_src_RGB;
//TextureDefinitionData.m_eBlend_dst_RGB;
//TextureDefinitionData.m_eBlend_src_Alpha;
//TextureDefinitionData.m_eBlend_dst_Alpha;
//TextureDefinitionData.m_ucTextureApplyingMode;
//TextureDefinitionData.m_eTextureAlphaTest;
//TextureDefinitionData.m_dAlphaTestReference;
//TextureDefinitionData.m_eTextureWrappingModeS;
//TextureDefinitionData.m_eTextureWrappingModeT;
//if (TextureDefinitionData.m_pTextureTransfo != nullptr)
//{
// TUniqueTSObj<A3DGraphTextureTransformationData> TransfoData(TextureDefinitionData.m_pTextureTransfo);
//}
}
void FTechSoftFileParser::ReadMaterialsAndColors()
{
A3DGlobal* GlobalPtr = TechSoftInterface::GetGlobalPointer();
if (GlobalPtr == nullptr)
{
return;
}
A3DInt32 iRet = A3D_SUCCESS;
TUniqueTSObj<A3DGlobalData> GlobalData(GlobalPtr);
if (!GlobalData.IsValid())
{
return;
}
{
uint32 TextureDefinitionCount = GlobalData->m_uiTextureDefinitionsSize;
if (TextureDefinitionCount)
{
TUniqueTSObjFromIndex<A3DGraphTextureDefinitionData> TextureDefinitionData;
for (uint32 TextureIndex = 0; TextureIndex < TextureDefinitionCount; ++TextureIndex)
{
TextureDefinitionData.FillFrom(TextureIndex);
ExtractTextureDefinition(*TextureDefinitionData);
}
}
}
{
uint32 PictureCount = GlobalData->m_uiPicturesSize;
if (PictureCount)
{
TUniqueTSObjFromIndex<A3DGraphPictureData> PictureData;
for (uint32 PictureIndex = 0; PictureIndex < PictureCount; ++PictureIndex)
{
A3DEntity* PicturePtr = TechSoftInterface::GetPointerFromIndex(PictureIndex, kA3DTypeGraphPicture);
if (PicturePtr)
{
FArchiveCADObject PictureMetaData;
ExtractMetaData(PicturePtr, PictureMetaData);
}
PictureData.FillFrom(PictureIndex);
// To do
}
}
}
}
#ifndef CADKERNEL_DEV
void FTechSoftFileParser::CheckMemory()
{
CADFileData.GetRecord().StartMemoryUsed = FPlatformMemory::GetStats().UsedPhysical;
uint64& MaxMemoryUsed = CADFileData.GetRecord().MaxMemoryUsed;
while (bProcessIsRunning)
{
FPlatformProcess::Sleep(0.1);
const uint64 MemoryUsed = FPlatformMemory::GetStats().UsedPhysical;
if (MaxMemoryUsed < MemoryUsed)
{
MaxMemoryUsed = MemoryUsed;
}
}
}
#endif
#endif
} // ns CADLibrary