// Copyright Epic Games, Inc. All Rights Reserved. #include "MetaData.h" #include "Utils/ElementTools.h" #include "Utils/Element2String.h" #include "Version.h" #include "SyncData.h" #if AC_VERSION > 27 #include "ACAPI/IFCObjectAccessor.hpp" #include "ACAPI/IFCPropertyAccessor.hpp" #endif BEGIN_NAMESPACE_UE_AC static const GS::UniString StringTrue("True"); static const GS::UniString StringFalse("False"); static const GS::UniString StringUndefined("Undefined"); inline bool IsEqual(const TSharedPtr< IDatasmithKeyValueProperty >& InProperty1, const TSharedPtr< IDatasmithKeyValueProperty >& InProperty2) { if (!InProperty1.IsValid()) { return !InProperty2.IsValid(); } return InProperty1->GetPropertyType() == InProperty2->GetPropertyType() && FCString::Strcmp(InProperty1->GetName(), InProperty2->GetName()) == 0 && FCString::Strcmp(InProperty1->GetValue(), InProperty2->GetValue()) == 0; } inline bool IsEqual(const TSharedPtr< IDatasmithMetaDataElement >& InMetaData1, const TSharedPtr< IDatasmithMetaDataElement >& InMetaData2) { if (!InMetaData1.IsValid()) { return !InMetaData2.IsValid(); } if (InMetaData1->GetAssociatedElement() != InMetaData2->GetAssociatedElement() || FCString::Strcmp(InMetaData1->GetName(), InMetaData2->GetName()) != 0) { return false; } int32 PropertiesCount1 = InMetaData1->GetPropertiesCount(); int32 PropertiesCount2 = InMetaData2->GetPropertiesCount(); if (PropertiesCount1 != PropertiesCount2) { return false; } for (int32 IndexProperty = 0; IndexProperty < PropertiesCount1; ++IndexProperty) { if (!IsEqual(InMetaData1->GetProperty(IndexProperty), InMetaData2->GetProperty(IndexProperty))) { return false; } } return true; } FMetaData::FMetaData(const TSharedPtr< IDatasmithElement >& InElement) : MetaData(FDatasmithSceneFactory::CreateMetaData(TEXT(""))) { UE_AC_Assert(InElement.IsValid()); MetaData->SetAssociatedElement(InElement); MetaData->SetName(*FString::Printf(TEXT("MetaData_%s"), InElement->GetName())); } bool FMetaData::SetOrUpdate(TSharedPtr< IDatasmithMetaDataElement >* IOPtr, IDatasmithScene* IOScene) { UE_AC_TestPtr(IOPtr); if (IOPtr->IsValid()) { TSharedRef< IDatasmithMetaDataElement > CurrentMetaData = IOPtr->ToSharedRef(); CurrentMetaData->SetAssociatedElement(MetaData->GetAssociatedElement()); if (!IsEqual(CurrentMetaData, MetaData)) { #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION == 26 // We replace because on 4.26 there no way to remove/replace properties IOScene->RemoveMetaData(CurrentMetaData); *IOPtr = MetaData; IOScene->AddMetaData(MetaData); #else CurrentMetaData->ResetProperties(); int32 PropertiesCount = MetaData->GetPropertiesCount(); for (int32 IndexProperty = 0; IndexProperty < PropertiesCount; ++IndexProperty) { const TSharedPtr< IDatasmithKeyValueProperty >& Property = MetaData->GetProperty(IndexProperty); TSharedRef< IDatasmithKeyValueProperty > NewProperty = FDatasmithSceneFactory::CreateKeyValueProperty(Property->GetName()); NewProperty->SetPropertyType(Property->GetPropertyType()); NewProperty->SetValue(Property->GetValue()); CurrentMetaData->AddProperty(NewProperty); } #endif return true; // Metadata has changed } } else { *IOPtr = MetaData; IOScene->AddMetaData(MetaData); return true; // Metadata has changed } return false; // Metadata hasn't changed } void FMetaData::AddProperty(const TCHAR* InPropKey, EDatasmithKeyValuePropertyType InPropertyValueType, const TCHAR* InValue) { TSharedRef< IDatasmithKeyValueProperty > MetaDataProperty = FDatasmithSceneFactory::CreateKeyValueProperty(InPropKey); MetaDataProperty->SetValue(InValue); MetaDataProperty->SetPropertyType(InPropertyValueType); MetaData->AddProperty(MetaDataProperty); } void FMetaData::ExportMetaData(const GS::Guid& InElementID) { UE_AC_Assert(FString::Printf(TEXT("MetaData_%s"), GSStringToUE(InElementID.ToUniString())) == MetaData->GetName()); const API_Guid& ElementId(GSGuid2APIGuid(InElementID)); ExportElementIDProperty(ElementId); ExportClassifications(ElementId); ExportCategories(ElementId); ExportIFCType(ElementId); ExportIFCProperties(ElementId); ExportIFCAttributes(ElementId); } void FMetaData::AddMetaDataProperty(API_VariantType variantType, const GS::UniString& PropertyKey, const GS::UniString& PropertyValue) { static const GS::UniString StringUndefinedLocalized(GetGSName(kName_Undefined)); #if AC_VERSION > 27 if (PropertyValue.IsEmpty() || PropertyValue.IsEqual(StringUndefined, GS::CaseInsensitive) || PropertyValue.IsEqual(StringUndefinedLocalized, GS::CaseInsensitive)) #else if (PropertyValue.IsEmpty() || PropertyValue.IsEqual(StringUndefined, GS::UniString::CaseInsensitive) || PropertyValue.IsEqual(StringUndefinedLocalized, GS::UniString::CaseInsensitive)) #endif return; EDatasmithKeyValuePropertyType PropertyValueType; // = EDatasmithKeyValuePropertyType::String; switch (variantType) { case API_PropertyIntegerValueType: PropertyValueType = EDatasmithKeyValuePropertyType::Float; break; case API_PropertyRealValueType: PropertyValueType = EDatasmithKeyValuePropertyType::Float; break; case API_PropertyStringValueType: PropertyValueType = EDatasmithKeyValuePropertyType::String; break; case API_PropertyBooleanValueType: PropertyValueType = EDatasmithKeyValuePropertyType::Bool; break; case API_PropertyGuidValueType: PropertyValueType = EDatasmithKeyValuePropertyType::String; break; default: PropertyValueType = EDatasmithKeyValuePropertyType::String; break; } TSharedRef< IDatasmithKeyValueProperty > metaDataProperty = FDatasmithSceneFactory::CreateKeyValueProperty(GSStringToUE(PropertyKey)); metaDataProperty->SetValue(GSStringToUE(PropertyValue)); metaDataProperty->SetPropertyType(PropertyValueType); MetaData->AddProperty(metaDataProperty); } void FMetaData::ExportElementIDProperty(const API_Guid& ElementId) { FAutoMemo AutoMemo(ElementId, APIMemoMask_ElemInfoString); if (AutoMemo.GSErr == NoError && AutoMemo.Memo.elemInfoString != nullptr) { AddMetaDataProperty(API_PropertyStringValueType, "ID", *AutoMemo.Memo.elemInfoString); } } void FMetaData::ExportClassifications(const API_Guid& ElementId) { GS::Array< GS::Pair< API_ClassificationSystem, API_ClassificationItem > > ApiClassifications; GSErrCode GSErr = FElementTools::GetElementClassifications(ApiClassifications, ElementId); if (GSErr == NoError) { for (const GS::Pair< API_ClassificationSystem, API_ClassificationItem >& Classification : ApiClassifications) { AddMetaDataProperty(API_PropertyStringValueType, Classification.first.name + "_ID", Classification.second.id); AddMetaDataProperty(API_PropertyStringValueType, Classification.first.name + "_Name", Classification.second.name); AddMetaDataProperty(API_PropertyStringValueType, Classification.first.name + "_Description", Classification.second.description); } } else { UE_AC_DebugF("FMetaData::ExportClassifications - FElementTools::GetElementClassifications returned error %s\n", GetErrorName(GSErr)); } } void FMetaData::ExportCategories(const API_Guid& ElementId) { static const GS::UniString StringCategory("CAT_"); GS::Array< API_ElemCategory > CategoryList; GSErrCode GSErr = ACAPI_Database(APIDb_GetElementCategoriesID, &CategoryList); if (GSErr == NoError) { for (const API_ElemCategory& Category : CategoryList) { API_ElemCategoryValue ElemCategoryValue; GSErr = ACAPI_Element_GetCategoryValue(ElementId, Category, &ElemCategoryValue); if (GSErr == NoError) { AddMetaDataProperty(API_PropertyStringValueType, StringCategory + GS::UniString(ElemCategoryValue.category.name), GS::UniString(ElemCategoryValue.name)); } else { if (GSErr != APIERR_BADPARS) { UE_AC_DebugF("FMetaData::ExportCategories - ACAPI_Element_GetCategoryValue returned error %s\n", GetErrorName(GSErr)); } } } } else { UE_AC_DebugF("FMetaData::ExportCategories - APIDb_GetElementCategoriesID returned error %s\n", GetErrorName(GSErr)); } } void FMetaData::ExportIFCType(const API_Guid& ElementId) { #if AC_VERSION < 28 GS::UniString IfcType; GS::UniString TypeObjectIfcType; GSErrCode GSErr = ACAPI_Element_GetIFCType(ElementId, &IfcType, &TypeObjectIfcType); if (GSErr == NoError) { if (!IfcType.IsEmpty()) { static const GS::UniString KeyIfcType("IFC_Type"); AddMetaDataProperty(API_PropertyStringValueType, KeyIfcType, IfcType); } if (!TypeObjectIfcType.IsEmpty()) { static const GS::UniString KeyTypeObjectIfcType("IFC_ObjectType"); AddMetaDataProperty(API_PropertyStringValueType, KeyTypeObjectIfcType, TypeObjectIfcType); } } else { UE_AC_DebugF("FMetaData::ExportIFCType - ACAPI_Element_GetIFCType returned error %s", GetErrorName(GSErr)); } #else API_Elem_Head Head{}; Head.guid = ElementId; auto ElementObjectID = IFCAPI::GetObjectAccessor().CreateElementObjectID(Head); if (ElementObjectID.IsOk()) { auto IfcType = IFCAPI::GetObjectAccessor().GetIFCType(*ElementObjectID); if (IfcType.IsOk()) { static const GS::UniString KeyIfcType("IFC_Type"); AddMetaDataProperty(API_PropertyStringValueType, KeyIfcType, *IfcType); } else { UE_AC_DebugF("FMetaData::ExportIFCType - IFCAPI::GetObjectAccessor().GetIFCType returned error %s", GetErrorName(IfcType.UnwrapErr().kind)); } auto TypeObjectIfcType = IFCAPI::GetObjectAccessor().GetTypeObjectIFCType(*ElementObjectID); if (TypeObjectIfcType.IsOk()) { static const GS::UniString KeyIfcType("IFC_ObjectType"); AddMetaDataProperty(API_PropertyStringValueType, KeyIfcType, *TypeObjectIfcType); } else { UE_AC_DebugF("FMetaData::ExportIFCType - IFCAPI::GetObjectAccessor().GetTypeObjectIFCType returned error %s", GetErrorName(TypeObjectIfcType.UnwrapErr().kind)); } } #endif } void FMetaData::ExportIFCProperties(const API_Guid& ElementId) { static const GS::UniString StringIFC("IFC_"); static const GS::UniString StringLower("_lower"); static const GS::UniString StringUpper("_upper"); static const GS::UniString SetPoint("_setpoint"); GS::Array< API_IFCProperty > IFCProperties; #if AC_VERSION < 28 GSErrCode GSErr = ACAPI_Element_GetIFCProperties(ElementId, false, &IFCProperties); if (GSErr == NoError) { for (const API_IFCProperty& IFCProperty : IFCProperties) { GS::UniString KeyName = StringIFC + IFCProperty.head.propertyName; GS::UniString ValueName; switch (IFCProperty.head.propertyType) { case API_IFCPropertySingleValueType: ValueName = GetPropertyValueString(IFCProperty.singleValue.nominalValue); AddMetaDataProperty(API_PropertyStringValueType, KeyName, ValueName); break; case API_IFCPropertyListValueType: { Int32 i = 0; for (API_IFCPropertyValue value : IFCProperty.listValue.listValues) { ValueName = GetPropertyValueString(value); AddMetaDataProperty(API_PropertyStringValueType, KeyName + '_' + GS::ValueToUniString(++i), ValueName); } break; } case API_IFCPropertyBoundedValueType: ValueName = GetPropertyValueString(IFCProperty.boundedValue.lowerBoundValue); AddMetaDataProperty(API_PropertyStringValueType, KeyName + "_" + StringLower, ValueName); ValueName = GetPropertyValueString(IFCProperty.boundedValue.upperBoundValue); AddMetaDataProperty(API_PropertyStringValueType, KeyName + "_" + StringUpper, ValueName); break; case API_IFCPropertyEnumeratedValueType: { Int32 i = 0; for (API_IFCPropertyValue value : IFCProperty.enumeratedValue.enumerationValues) { ValueName = GetPropertyValueString(value); AddMetaDataProperty(API_PropertyStringValueType, KeyName + '_' + GS::ValueToUniString(++i), ValueName); } break; } case API_IFCPropertyTableValueType: { Int32 i = 0; for (API_IFCPropertyValue DefiningValue : IFCProperty.tableValue.definingValues) { ValueName = GetPropertyValueString(IFCProperty.tableValue.definedValues[i++]); AddMetaDataProperty(API_PropertyStringValueType, KeyName + '_' + GetPropertyValueString(DefiningValue), ValueName); } break; } default: break; } } } else { if (GSErr != APIERR_BADPARS) { UE_AC_DebugF("FMetaData::ExportIFCProperties - ACAPI_Element_GetIFCProperties returned error %s\n", GetErrorName(GSErr)); } } #else API_Elem_Head Head{}; Head.guid = ElementId; const auto ElementObjectID = IFCAPI::GetObjectAccessor().CreateElementObjectID(Head); if (ElementObjectID.IsOk()) { const auto LocalProperties = IFCAPI::PropertyAccessor(*ElementObjectID).GetLocalProperties(); if (LocalProperties.IsOk()) { for (const auto& Property : *LocalProperties) { auto PropertyVariant = Property.GetTyped(); GS::UniString KeyName = StringIFC + Property.GetName(); GS::UniString ValueName; if (std::holds_alternative(PropertyVariant)) { const auto& PropertyCast = std::get(PropertyVariant); ValueName = FElement2String::PropertyValueToString(PropertyCast.GetNominalValue()); AddMetaDataProperty(API_PropertyStringValueType, KeyName, ValueName); } else if (std::holds_alternative(PropertyVariant)) { const auto& PropertyCast = std::get(PropertyVariant); Int32 i = 0; for (const auto& value : PropertyCast.GetListValues()) { ValueName = FElement2String::PropertyValueToString(value); AddMetaDataProperty(API_PropertyStringValueType, KeyName + '_' + GS::ValueToUniString(++i), ValueName); } } else if (std::holds_alternative(PropertyVariant)) { const auto& PropertyCast = std::get(PropertyVariant); ValueName = FElement2String::PropertyValueToString(PropertyCast.GetLowerBoundValue()); AddMetaDataProperty(API_PropertyStringValueType, KeyName + "_" + StringLower, ValueName); ValueName = FElement2String::PropertyValueToString(PropertyCast.GetUpperBoundValue()); AddMetaDataProperty(API_PropertyStringValueType, KeyName + "_" + StringUpper, ValueName); ValueName = FElement2String::PropertyValueToString(PropertyCast.GetSetPointValue()); AddMetaDataProperty(API_PropertyStringValueType, KeyName + "_" + SetPoint, ValueName); } else if (std::holds_alternative(PropertyVariant)) { const auto& PropertyCast = std::get(PropertyVariant); Int32 i = 0; for (const auto& value : PropertyCast.GetEnumerationValues()) { ValueName = FElement2String::PropertyValueToString(value); AddMetaDataProperty(API_PropertyStringValueType, KeyName + '_' + GS::ValueToUniString(++i), ValueName); } } else { const auto& PropertyCast = std::get(PropertyVariant); auto DefiningValues = PropertyCast.GetDefiningValues(); auto DefinedValues = PropertyCast.GetDefinedValues(); for (size_t i = 0; i < DefiningValues.size(); ++i) { ValueName = FElement2String::PropertyValueToString(DefinedValues[i]); AddMetaDataProperty(API_PropertyStringValueType, KeyName + '_' + FElement2String::PropertyValueToString(DefiningValues[i]), ValueName); } } } } else if (LocalProperties.UnwrapErr().kind != APIERR_BADPARS) { UE_AC_DebugF("FElement2String::GetIFCPropertiesAsString - IFCAPI::PropertyAccessor().GetLocalProperties returned error %s\n", GetErrorName(LocalProperties.UnwrapErr().kind)); } } else if (ElementObjectID.UnwrapErr().kind != APIERR_BADPARS) { UE_AC_DebugF("FElement2String::GetIFCPropertiesAsString - IFCAPI::GetObjectAccessor().CreateElementObjectID returned error %s\n", GetErrorName(ElementObjectID.UnwrapErr().kind)); } #endif } void FMetaData::ExportIFCAttributes(const API_Guid& ElementId) { static const GS::UniString StringIFCAttribute("IFC_Attribute_"); #if AC_VERSION < 28 GS::Array< API_IFCAttribute > IFCAttributes; GSErrCode GSErr = ACAPI_Element_GetIFCAttributes(ElementId, false, &IFCAttributes); if (GSErr == NoError) { for (const API_IFCAttribute& IfcAttribute : IFCAttributes) { AddMetaDataProperty(API_PropertyStringValueType, StringIFCAttribute + IfcAttribute.attributeName, IfcAttribute.attributeValue); } } else { if (GSErr != APIERR_BADPARS) { UE_AC_DebugF("FMetaData::ExportIFCAttributes - ACAPI_Element_GetIFCAttributes returned error %s\n", GetErrorName(GSErr)); } } #else API_Elem_Head Head{}; Head.guid = ElementId; auto ElementObjectID = IFCAPI::GetObjectAccessor().CreateElementObjectID(Head); if (ElementObjectID.IsOk()) { auto IFCAttributes = IFCAPI::PropertyAccessor(*ElementObjectID).GetAttributes(); if (IFCAttributes.IsOk()) { for (const auto& IfcAttribute : *IFCAttributes) { if (IfcAttribute.GetValue().has_value()) { AddMetaDataProperty(API_PropertyStringValueType, StringIFCAttribute + IfcAttribute.GetName(), IfcAttribute.GetValue().value()); } } } else if (IFCAttributes.UnwrapErr().kind != APIERR_BADPARS) { UE_AC_DebugF("FMetaData::ExportIFCAttributes - IFCAPI::PropertyAccessor().GetAttributes() returned error %s\n", GetErrorName(IFCAttributes.UnwrapErr().kind)); } } else if (ElementObjectID.UnwrapErr().kind != APIERR_BADPARS) { UE_AC_DebugF("FMetaData::ExportIFCAttributes - IFCAPI::GetObjectAccessor().CreateElementObjectID returned error %s\n", GetErrorName(ElementObjectID.UnwrapErr().kind)); } #endif } void FMetaData::ExportProperties(const API_Guid& ElementId) { static const GS::UniString StringProperty("PROP_"); GS::Array< API_Property > Properties; GSErrCode GSErr = FElementTools::GetElementProperties(Properties, ElementId); if (GSErr == NoError) { for (const API_Property& Property : Properties) { GS::UniString PropertyKey = StringProperty + Property.definition.name; GS::UniString PropertyValue; switch (Property.definition.collectionType) { case API_PropertySingleCollectionType: PropertyValue = GetPropertyValueString(Property.value.singleVariant.variant); AddMetaDataProperty(Property.definition.valueType, PropertyKey, PropertyValue); break; case API_PropertyListCollectionType: { Int32 i = 0; for (API_Variant variant : Property.value.listVariant.variants) { PropertyValue = GetPropertyValueString(variant); AddMetaDataProperty(Property.definition.valueType, PropertyKey + '_' + GS::ValueToUniString(++i), PropertyValue); } break; } #if AC_VERSION < 25 case API_PropertySingleChoiceEnumerationCollectionType: PropertyValue = GetPropertyValueString(Property.value.singleEnumVariant.displayVariant); AddMetaDataProperty(Property.definition.valueType, PropertyKey, PropertyValue); break; case API_PropertyMultipleChoiceEnumerationCollectionType: { Int32 i = 0; for (API_SingleEnumerationVariant enumVariant : Property.value.multipleEnumVariant.variants) { PropertyValue = GetPropertyValueString(enumVariant.displayVariant); AddMetaDataProperty(Property.definition.valueType, PropertyKey + '_' + GS::ValueToUniString(++i), PropertyValue); } break; } #endif case API_PropertyUndefinedCollectionType: PropertyValue = StringUndefined; break; default: PropertyValue = ""; break; } } } else { UE_AC_DebugF("FMetaData::ExportProperties - FElementTools::GetElementProperties returned error %s\n", GetErrorName(GSErr)); } } GS::UniString FMetaData::GetPropertyValueString(const API_IFCPropertyValue& InIFCPropertyValue) { GS::UniString PropertyValue = ""; switch (InIFCPropertyValue.value.primitiveType) { case API_IFCPropertyAnyValueIntegerType: if (InIFCPropertyValue.value.intValue != 0) PropertyValue = GS::ValueToUniString(InIFCPropertyValue.value.intValue); break; case API_IFCPropertyAnyValueRealType: if (InIFCPropertyValue.value.doubleValue != 0) PropertyValue = GS::ValueToUniString(InIFCPropertyValue.value.doubleValue); break; case API_IFCPropertyAnyValueBooleanType: PropertyValue = InIFCPropertyValue.value.boolValue ? StringTrue : StringFalse; break; case API_IFCPropertyAnyValueLogicalType: PropertyValue = InIFCPropertyValue.value.boolValue ? StringTrue : StringFalse; break; case API_IFCPropertyAnyValueStringType: PropertyValue = InIFCPropertyValue.value.stringValue; break; default: // PropertyValue = ""; break; } return PropertyValue; } GS::UniString FMetaData::GetPropertyValueString(const API_Variant& InVariant) { GS::UniString PropertyValue = ""; switch (InVariant.type) { case API_PropertyIntegerValueType: if (InVariant.intValue != 0) PropertyValue = GS::ValueToUniString(InVariant.intValue); break; case API_PropertyRealValueType: if (InVariant.doubleValue != 0.0) PropertyValue = GS::ValueToUniString(InVariant.doubleValue); break; case API_PropertyStringValueType: PropertyValue = InVariant.uniStringValue; break; case API_PropertyBooleanValueType: PropertyValue = InVariant.boolValue ? StringTrue : StringFalse; break; case API_PropertyGuidValueType: PropertyValue = APIGuidToString(InVariant.guidValue); break; default: PropertyValue = InVariant.uniStringValue; break; } return PropertyValue; } END_NAMESPACE_UE_AC