/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "RxObjectImpl.h" #include "daiValidationCommon.h" #include "daiValidationTask.h" #include "daiSet.h" #include "daiUtils/daiUnset.h" #include "daiStepFile.h" #include "IfcFile.h" #include "IfcEntity.h" #include "IfcPSDQTOValidationTask.h" using namespace OdDAI; using namespace OdIfc; bool toInt64(const OdAnsiString& text, OdInt64& value) { if (text.getLength() == 0) return false; char* _EndPtr; errno = 0; value = strtoll(text.c_str(), &_EndPtr, 10); if (errno) return false; return true; } bool toDouble(const OdAnsiString& text, double& value) { if (text.getLength() == 0) return false; errno = 0; value = odStrToD(text.c_str()); if (errno) return false; return true; } bool toADB(OdTCKind kind, const OdAnsiString& text, ADB_Value& value) { union { OdInt64 i; double d; } u; switch (kind) { case tkLong: if (toInt64(text, u.i)) { value.setValue((int)u.i); return true; } break; case tkDouble: case tkUnion: if (toDouble(text, u.d)) { value.setValue(u.d); return true; } break; case tkBoolean: if (text == "true") value.setValue(OdDAI::Boolean::True); else if (text == "false") value.setValue(OdDAI::Boolean::False); else return false; return true; case tkLogical: if (text == "true") value.setValue(OdDAI::Logical::True); else if (text == "false") value.setValue(OdDAI::Logical::False); else if (text == "unknown") value.setValue(OdDAI::Logical::Unknown); else return false; return true; case tkString: case tkEnum: value.setValue(text); return true; case tkNumber: if (toDouble(text, u.d)) { Number number; number.setReal(u.d); value.setValue(number); return true; } default: break; } return false; } bool compareSelectValue(const Select& select, const ADB_Value& value) { OdTCKind kind = select.kind(); if (kind != value.type()) { return false; } switch (kind) { case tkNull: { return true; } break; case tkObjectId: { OdDAIObjectId id; if (value.getValue(id)) { return select.getHandleId() == id.getHandle(); } } break; case tkLong: { int leftValue; int rightValue; if (select.getInt32(leftValue) && value.getValue(rightValue)) { return leftValue == rightValue; } } break; case tkBoolean: { bool leftValue; bool rightValue; if (select.getBool(leftValue) && value.getValue(rightValue)) { return leftValue == rightValue; } } break; case tkDouble: { double leftValue; double rightValue; if (select.getDouble(leftValue) && value.getValue(rightValue)) { return OdEqual(leftValue, rightValue, 1e-7); } } break; case tkString: { OdAnsiString leftValue; OdAnsiString rightValue; if (select.getString(leftValue) && value.getValue(rightValue)) { return leftValue == rightValue; } } break; case tkNumber: { OdDAI::Number leftValue; OdDAI::Number rightValue; if (select.getNumber(leftValue) && value.getValue(rightValue)) { return leftValue == rightValue; } } break; case tkBinary: { OdDAI::Binary leftValue; OdDAI::Binary rightValue; if (select.getBinary(leftValue) && value.getValue(rightValue)) { return leftValue == rightValue; } } break; case tkLogical: { OdDAI::Logical leftValue; OdDAI::Logical rightValue; if (select.getLogical(leftValue) && value.getValue(rightValue)) { return leftValue == rightValue; } } break; case tkSequence: { OdDAI::Aggr* leftValue = nullptr; select.getAggr(leftValue); OdDAI::Aggr* rightValue = nullptr; value.getValue(rightValue); return (leftValue && rightValue) && (*leftValue == *rightValue); } break; case tkEnum: { OdDAI::EnumValueInfo leftEnum; OdDAI::EnumValueInfo rightEnum; if (select.getEnum(leftEnum) && value.getValue(rightEnum)) {// TODO char* == char* return leftEnum.value == rightEnum.value; } } break; default: { ODA_ASSERT(0 && "new or corrupted type."); } break; } return false; } OdDAI::ApplicationInstancePtr findIfcProperty(OdDAI::ApplicationInstance* pTestItem, const char* name) { OdDAI::Aggr* hasProperties = nullptr; if (!(pTestItem->getAttr("hasproperties") >> hasProperties)) pTestItem->getAttr("quantities") >> hasProperties; if (hasProperties) { int count = hasProperties->getMemberCount(); OdDAI::ConstIteratorPtr itp = hasProperties->createConstIterator(); while (itp->next()) { OdDAIObjectId itemId; itp->getCurrentMember() >> itemId; if (!itemId.isNull()) { OdDAI::ApplicationInstancePtr itemAttr = itemId.openObject(); OdAnsiString attrName; itemAttr->getAttr("name") >> attrName; if (attrName == name) return itemAttr; } } } return OdDAI::ApplicationInstancePtr(); } inline OdDAI::ApplicationInstancePtr getInstanceFromAttr(OdDAI::ApplicationInstance* pItem, const char* attrName) { ODA_ASSERT(pItem && attrName); OdDAIObjectId id; pItem->getAttr(attrName) >> id; return id.openObject(); } OdDAI::ApplicationInstancePtr getInstanceFromAttr(OdDAI::ApplicationInstance* pItem, const char* attrName, OdDAI::ValidationTask::InvalidRxArrayValidationParams* pInvalidIds) { ODA_ASSERT(pItem && attrName && pInvalidIds); OdDAIObjectId id; if (pItem->testAttr(attrName)) { if ((pItem->getAttr(attrName) >> id)) return id.openObject(); } else { pInvalidIds->addData(OdDAI::ValidationTask::InvalidRxObjectsValidationParams({ pItem }, OdAnsiString().format("Attribute '%s' not exists.", attrName), OdDAI::Logical::False) ); } return OdDAI::ApplicationInstancePtr(); } OdAnsiString getDataType(OdDAI::ApplicationInstance* propertyType) { ODA_ASSERT(propertyType); OdAnsiString dataTypeString; OdDAI::ApplicationInstancePtr dataType = getInstanceFromAttr(propertyType, "datatype"); if (!dataType.isNull()) { dataType->getAttr("datatype") >> dataTypeString; } return dataTypeString; } bool checkSelectDataType(const OdAnsiString& dataType, Select* pSelect, OdAnsiString& errorText) { if (pSelect->exists()) { const NamedType* namedType = pSelect->type(); const OdAnsiString& selectTypeName = namedType->originalName(); if (dataType != selectTypeName) { errorText = OdAnsiString().format("Type is '%s', must be '%s'.", selectTypeName.c_str(), dataType.c_str()); return false; } } else { errorText = OdAnsiString().format("Type is unset, must be '%s'.", dataType.c_str()); return false; } return true; } bool checkDataType(const OdAnsiString& dataType, OdDAI::ApplicationInstance* ifcProperty, OdAnsiString& errorText) { errorText.empty(); OdRxValue val = ifcProperty->getAttr("nominalvalue"); if (val.type().isSelect()) { Select* pSelect = *rxvalue_cast(&val); return checkSelectDataType(dataType, pSelect, errorText); } OdAnsiString typePathString = val.typePath(); if (dataType != typePathString) { errorText = OdAnsiString().format("Type is '%s', must be '%s'.", typePathString.c_str(), dataType.c_str()); return false; } return true; } bool checkDataType(OdDAI::ApplicationInstance* propertyType, OdDAI::ApplicationInstance* ifcProperty, OdAnsiString& errorText) { ODA_ASSERT(ifcProperty); if (!propertyType) return true; errorText.empty(); OdDAI::ApplicationInstancePtr dataType = getInstanceFromAttr(propertyType, "datatype"); if (!dataType.isNull()) { OdAnsiString dataTypeString = getDataType(propertyType); if (dataTypeString.getLength() > 0) { bool res = checkDataType(dataTypeString, ifcProperty, errorText); return res; } } return true; } bool checkUnitType(OdDAI::ApplicationInstance* propertyType, OdDAI::ApplicationInstance* ifcProperty, OdAnsiString& errorText) { errorText.empty(); OdDAI::ApplicationInstancePtr unitType = getInstanceFromAttr(propertyType, "unittype"); if (!unitType.isNull()) { OdAnsiString strUnitType; OdAnsiString strCurrencyType; OdAnsiString ifcUnitType; unitType->getAttr("unittype") >> strUnitType; unitType->getAttr("currencytype") >> strCurrencyType; OdDAI::ApplicationInstancePtr ifcUnit = getInstanceFromAttr(ifcProperty, "unit"); if (ifcUnit.isNull()) { errorText = "Unit is missing."; return false; } if (!OdDAI::Utils::isUnset(strUnitType)) { if (!(ifcUnit->getAttr("unittype") >> ifcUnitType && (strUnitType == ifcUnitType))) { errorText = OdAnsiString().format("Unit must be '%s' type.", strUnitType.c_str()); return false; } } if (!OdDAI::Utils::isUnset(strCurrencyType)) { // TODO Check Currency //if (errorText.getLength() > 0) // errorText += ' '; //errorText += OdAnsiString().format("Currency must be '%s'.", strCurrencyType.c_str()); } } return true; } bool checkBoundValue(OdDAI::ApplicationInstance* pBoundValue, Select* pIfcBoundValue, OdAnsiString& errorText) { if (!pBoundValue) return true; if (!pIfcBoundValue) { errorText = "Value is null"; return false; } OdAnsiString valueStr; AttributeDataBlock adb; pBoundValue->getAttr("boundvalue") >> valueStr; OdTCKind kind = pIfcBoundValue->kind(); if (toADB(kind, valueStr, adb.value)) { if (compareSelectValue(*pIfcBoundValue, adb.value)) { return true; } OdString tmp = _subToString(pIfcBoundValue, OdRxValueType::kStringFormatGlobal); errorText = OdAnsiString().format("Value is '%ls', must be '%s'.", tmp.c_str(), valueStr.c_str()); return false; } else { errorText = "Error converting value to AttributeDataBlock"; return false; } } ODRX_VALIDATION_CONS_DEFINE_MEMBERS(IfcPSDQTOValidationTask, ExtentValidationTask, RXIMPL_CONSTR); IfcPSDQTOValidationTask::IfcPSDQTOValidationTask() { m_extentName = "ifcroot"; } OdAnsiString IfcPSDQTOValidationTask::description() const { return "Property Set/Quantity Take Off assignment validation."; } OdDAI::Logical IfcPSDQTOValidationTask::initializeValidation(OdDAI::ValidationContext* validationContext, OdDAIHostAppServicesBase* pServices, OdSharedPtr& invalidParams) { OdAnsiString psdqtoShemaName; InvalidRxArrayValidationParams* pInvalidIds = new InvalidRxArrayValidationParams; invalidParams = pInvalidIds; const OdAnsiString& schemaName = validationContext->pModel->underlyingSchemaName(); if (schemaName.find("IFC4X3") == 0) { psdqtoShemaName = "psdqto4x3.spf"; } else if (schemaName.find("IFC4") == 0) { psdqtoShemaName = "psdqto4x.spf"; } else {// Default name psdqtoShemaName = "psdqto4x.spf"; } // TODO DEBUG >>> Test code. Loading from file 4x, 4x3 PSD and QTO m_psdqto.Clear(); OdDAI::ModelPtr model = m_psdqto.getModel(); OdString path = pServices->findFile(psdqtoShemaName); OdResult ret = m_psdqto.readFile(path); if (ret != eOk) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ }, "Loading PSDQTO from SPF file failed.", OdDAI::Logical::False)); return OdDAI::Logical::False; } // TODO DEBUG <<< return OdDAI::Logical::True; } OdDAI::Logical IfcPSDQTOValidationTask::validate(OdDAI::InstanceValidationContext* pInstanceCtx, OdSharedPtr& invalidParams) { InvalidRxArrayValidationParams* pInvalidIds = new InvalidRxArrayValidationParams; invalidParams = pInvalidIds; //const OdAnsiString& schemaName = m_model->underlyingSchemaName(); OdDAIObjectIds propertySetDefs; m_instance = pInstanceCtx->pInstance; if (m_psdqto.getApplicable(m_instance, propertySetDefs)) { OdDAIObjectIds ids; if (!(m_instance->getAttr("isdefinedby") >> ids)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ m_instance }, "Internal error. Instance::getAttr('IsDefinedBy') error.", OdDAI::Logical::False)); return OdDAI::Logical::False; } PropertySetMap propertySets; for (OdDAIObjectId& relDefinesByPropertiesId : ids) { if (!relDefinesByPropertiesId.isNull()) { OdDAI::ApplicationInstancePtr relDefinesByProperties = relDefinesByPropertiesId.openObject(); OdDAIObjectId ifcPropertySetId; relDefinesByProperties->getAttr("relatingpropertydefinition") >> ifcPropertySetId; if (!ifcPropertySetId.isNull()) { OdDAI::ApplicationInstancePtr pIfcPropertySet = ifcPropertySetId.openObject(); if (!pIfcPropertySet.isNull()) { OdAnsiString propName; pIfcPropertySet->getAttr("name") >> propName; propertySets[propName] = ifcPropertySetId; } } } } ids.clear(); if ((m_instance->getAttr("istypedby") >> ids)) { for (OdDAIObjectId& id : ids) { if (!id.isNull()) { OdIfcInstancePtr entity = id.openObject(); OdDAIObjectId relatingTypeId; entity->getAttr("relatingtype") >> relatingTypeId; if (!relatingTypeId.isNull()) { OdIfcInstancePtr relatingType = relatingTypeId.openObject(); OdDAIObjectIds propertySetIds; relatingType->getAttr("haspropertysets") >> propertySetIds; for (OdDAIObjectId& ifcPropertySetId : propertySetIds) { OdDAI::ApplicationInstancePtr pIfcPropertySet = ifcPropertySetId.openObject(); if (!pIfcPropertySet.isNull()) { OdAnsiString propName; pIfcPropertySet->getAttr("name") >> propName; if (propertySets.find(propName) != propertySets.cend()) { propertySets[propName] = ifcPropertySetId; } } } } } } } for (const OdDAIObjectId& psdqtoId : propertySetDefs) { OdDAI::ApplicationInstancePtr psdqtoInst = psdqtoId.openObject(); if (psdqtoInst->isKindOf("PropertySetDef")) { if (!validatePropertySet(psdqtoInst, &propertySets, pInvalidIds)) return OdDAI::Logical::False; } else if (psdqtoInst->isKindOf("QtoSetDef")) { if (!validateQtoSet(psdqtoInst, &propertySets, pInvalidIds)) return OdDAI::Logical::False; } } } return invalidParams->invalidItemsCount() ? OdDAI::Logical::False : OdDAI::Logical::True; } bool IfcPSDQTOValidationTask::validatePropertySet(OdDAI::ApplicationInstance* pPropertySetDef, PropertySetMap* pIfcProperties, InvalidRxArrayValidationParams* pInvalidIds) { ODA_ASSERT(pPropertySetDef && pIfcProperties && pInvalidIds); OdAnsiString str; OdAnsiString name; if (!(pPropertySetDef->getAttr("name") >> name)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ pPropertySetDef }, "Internal error. PropertySetDef::getAttr('name') error.", OdDAI::Logical::False)); return false; } PropertySetMapIterator testIfcIt = pIfcProperties->find(name); if (testIfcIt == pIfcProperties->cend()) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ m_instance }, OdAnsiString().format("PropertySet '%s' not found on instance or entity.", name.c_str()), OdDAI::Logical::False) ); return true; } OdDAI::Aggr* propertyDefs = nullptr; if (!(pPropertySetDef->getAttr("propertydefs") >> propertyDefs)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ pPropertySetDef }, "Internal error. PropertySetDef::getAttr('PropertyDefs') error.", OdDAI::Logical::False)); return false; } if (propertyDefs && propertyDefs->getMemberCount() > 0) { OdAnsiString testName; OdDAIObjectId id; OdDAI::ApplicationInstancePtr item; OdDAI::ApplicationInstancePtr testIfcItem = testIfcIt->second.openObject(); pIfcProperties->erase(name); OdDAI::ConstIteratorPtr it = propertyDefs->createConstIterator(); while (it->next()) { it->getCurrentMember() >> id; if (id.isNull()) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ pPropertySetDef }, "Internal error. PropertyDef object is null.", OdDAI::Logical::False)); return false; } item = id.openObject(); if (!(item->getAttr("name") >> testName)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ item }, "Internal error. PropertyDef::getAttr('name') error.", OdDAI::Logical::False)); return false; } OdDAI::ApplicationInstancePtr testIfcProperty = findIfcProperty(testIfcItem, testName); if (testIfcProperty.isNull()) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s' not found.", name.c_str(), testName.c_str()), OdDAI::Logical::False) ); continue; } OdDAI::ApplicationInstancePtr propertyType = getInstanceFromAttr(item, "propertytype", pInvalidIds); if (!propertyType.isNull()) { OdAnsiString errorString; OdAnsiString propertyTypeTypeName; propertyTypeTypeName = propertyType->typeName(); if (propertyTypeTypeName == "typepropertysinglevalue") { if (testIfcProperty->typeName() != "ifcpropertysinglevalue") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcPropertySingleValue"), OdDAI::Logical::False) ); continue; } if (!checkDataType(propertyType, testIfcProperty, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } if (!checkUnitType(propertyType, testIfcProperty, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } } else if (propertyTypeTypeName == "typepropertyenumeratedvalue") { if (testIfcProperty->typeName() != "ifcpropertyenumeratedvalue") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcPropertyEnumeratedValue"), OdDAI::Logical::False) ); continue; } // IfcPropertyEnumeratedValue OdDAI::Aggr* testIfcAggr = nullptr; if ((testIfcProperty->getAttr("enumerationvalues") >> testIfcAggr)) { if (testIfcAggr->getMemberCount() > 0) { OdAnsiString itemIfcValue; OdAnsiString enumItemName; OdDAIObjectId id; OdDAI::Aggr* enumListAggr = nullptr; propertyType->getAttr("enumlist") >> enumListAggr; OdDAI::ConstIteratorPtr it0 = testIfcAggr->createConstIterator(); while (it0->next()) { if (it0->getCurrentMember() >> itemIfcValue) { bool testOk = false; OdDAI::ConstIteratorPtr it1 = enumListAggr->createConstIterator(); while (it1->next()) { if (it1->getCurrentMember() >> enumItemName) { if (itemIfcValue == enumItemName) { testOk = true; break; } } } if (!testOk) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Property '%s'. Value '%s' is invalid.", name.c_str(), testName.c_str(), itemIfcValue.c_str()), OdDAI::Logical::False) ); } } } } } } else if (propertyTypeTypeName == "typepropertylistvalue") { if (testIfcProperty->typeName() != "ifcpropertylistvalue") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcPropertyListValue"), OdDAI::Logical::False) ); continue; } // IfcPropertyListValue test OdDAIObjectId id; propertyType->getAttr("listvalue") >> id; if (id.isValid()) { OdDAI::ApplicationInstancePtr listValueInst = id.openObject(); OdAnsiString dataTypeString = getDataType(listValueInst); if (!checkUnitType(propertyType, testIfcProperty, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } if (dataTypeString.getLength() > 0) { OdDAI::ApplicationInstancePtr listItemPtr; OdDAI::Aggr* ifcListValuesAggr = nullptr; testIfcProperty->getAttr("listvalues") >> ifcListValuesAggr; OdDAI::ConstIteratorPtr it0 = ifcListValuesAggr->createConstIterator(); while (it0->next()) { OdDAI::Select* select; if ((it0->getCurrentMember() >> select) && select) { const OdAnsiString& typeName = select->type()->originalName(); if (dataTypeString != typeName) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ listItemPtr }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Type is '%s', must be '%s'.", name.c_str(), testName.c_str(), typeName.c_str(), dataTypeString.c_str()), OdDAI::Logical::False) ); } } } } } } else if (propertyTypeTypeName == "typepropertyboundedvalue") { if (testIfcProperty->typeName() != "ifcpropertyboundedvalue") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcPropertyBoundedValue"), OdDAI::Logical::False) ); continue; } OdAnsiString dataTypeString = getDataType(propertyType); if (dataTypeString.getLength() > 0) { Select* ifcLowerValue; Select* ifcUpperValue; testIfcProperty->getAttr("lowerboundvalue") >> ifcLowerValue; testIfcProperty->getAttr("upperboundvalue") >> ifcUpperValue; if (ifcLowerValue && !checkSelectDataType(dataTypeString, ifcLowerValue, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Check LowerBoundValue error. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } if (ifcUpperValue && !checkSelectDataType(dataTypeString, ifcUpperValue, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Check UpperBoundValue error. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } OdDAI::ApplicationInstancePtr valueRangeDefPtr = getInstanceFromAttr(propertyType, "valuerangedef"); if (!valueRangeDefPtr.isNull()) { OdDAI::ApplicationInstancePtr boundValuePtr; boundValuePtr = getInstanceFromAttr(valueRangeDefPtr, "lowerboundvalue"); if (!checkBoundValue(boundValuePtr, ifcLowerValue, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Check LowerBoundValue error. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } boundValuePtr = getInstanceFromAttr(valueRangeDefPtr, "upperboundvalue"); if (!checkBoundValue(boundValuePtr, ifcUpperValue, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Check UpperBoundValue error. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } } } if (!checkUnitType(propertyType, testIfcProperty, errorString)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Check UpperBoundValue error. %s.", name.c_str(), testName.c_str(), errorString.c_str()), OdDAI::Logical::False) ); } } else if (propertyTypeTypeName == "typepropertytablevalue") { if (testIfcProperty->typeName() != "ifcpropertytablevalue") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcPropertyTableValue"), OdDAI::Logical::False) ); continue; } OdAnsiString propertyExpression; propertyType->getAttr("expression") >> propertyExpression; if (propertyExpression.getLength()) { OdAnsiString ifcExpression; testIfcProperty->getAttr("expression") >> ifcExpression; if (propertyExpression != ifcExpression) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Expression '%s' is not equal user expression '%s'.", name.c_str(), testName.c_str(), propertyExpression.c_str(), ifcExpression.c_str()), OdDAI::Logical::False) ); } } // TODO DefiningValue // TODO DefinedValue // IfcPropertyTableValue test } else if (propertyTypeTypeName == "typepropertyreferencevalue") { if (testIfcProperty->typeName() != "ifcpropertyreferencevalue") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcPropertyReferenceValue"), OdDAI::Logical::False) ); continue; } // IfcPropertyReferenceValue test } else if (propertyTypeTypeName == "typecomplexproperty") { if (testIfcProperty->typeName() != "ifccomplexproperty") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), testIfcProperty->getInstanceType()->originalName().c_str(), "IfcComplexProperty"), OdDAI::Logical::False) ); continue; } // IfcComplexProperty test } else { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Attribute '%s'. Unqnown type '%s'.", name.c_str(), testName.c_str(), propertyTypeTypeName.c_str()), OdDAI::Logical::False) ); } } } } return true; } bool IfcPSDQTOValidationTask::validateQtoSet(OdDAI::ApplicationInstance* pQtoSetDef, PropertySetMap* pProperties, InvalidRxArrayValidationParams* pInvalidIds) { ODA_ASSERT(pQtoSetDef && pProperties && pInvalidIds); OdAnsiString name; if (!(pQtoSetDef->getAttr("name") >> name)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ pQtoSetDef }, "Internal error. QtoSetDef::getAttr('name') error.", OdDAI::Logical::False)); return false; } PropertySetMapIterator testIt = pProperties->find(name); if (testIt == pProperties->cend()) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ m_instance }, OdAnsiString().format("QtoSet '%s' not found on instance or entity.", name.c_str()), OdDAI::Logical::False) ); return true; } OdDAI::Aggr* qtoDefs = nullptr; if (!(pQtoSetDef->getAttr("qtodefs") >> qtoDefs)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ pQtoSetDef }, "Internal error. QtoSetDef::getAttr('QtoDefs') error.", OdDAI::Logical::False)); return false; } if (qtoDefs && qtoDefs->getMemberCount() > 0) { OdAnsiString testName; OdDAIObjectId qtoId; OdDAI::ApplicationInstancePtr item; OdDAI::ApplicationInstancePtr testIfcItem = testIt->second.openObject(); OdDAI::ConstIteratorPtr it = qtoDefs->createConstIterator(); while (it->next()) { it->getCurrentMember() >> qtoId; if (qtoId.isNull()) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ pQtoSetDef }, "Internal error. QtoDef object is null.", OdDAI::Logical::False)); return false; } item = qtoId.openObject(); if (!(item->getAttr("name") >> testName)) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ item }, "Internal error. QtoDef::getAttr('name') error.", OdDAI::Logical::False)); return false; } OdDAI::ApplicationInstancePtr itemAttr = findIfcProperty(testIfcItem, testName); if (itemAttr.isNull()) { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("QtoSet '%s'. Attribute '%s' not found.", name.c_str(), testName.c_str()), OdDAI::Logical::False) ); continue; } OdAnsiString qtoTypeName; if (item->getAttr("qtotype") >> qtoTypeName) { //Q_AREA, Q_COUNT, Q_LENGTH, Q_TIME, Q_VOLUME, Q_WEIGHT if (qtoTypeName == "Q_AREA") { if (itemAttr->typeName() != "ifcquantityarea") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), itemAttr->getInstanceType()->originalName().c_str(), "IfcQuantityArea"), OdDAI::Logical::False) ); continue; } } else if (qtoTypeName == "Q_COUNT") { if (itemAttr->typeName() != "ifcquantitycount") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), itemAttr->getInstanceType()->originalName().c_str(), "IfcQuantityCount"), OdDAI::Logical::False) ); continue; } } else if (qtoTypeName == "Q_LENGTH") { if (itemAttr->typeName() != "ifcquantitylength") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), itemAttr->getInstanceType()->originalName().c_str(), "IfcQuantityLength"), OdDAI::Logical::False) ); continue; } } else if (qtoTypeName == "Q_TIME") { if (itemAttr->typeName() != "ifcquantitytime") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), itemAttr->getInstanceType()->originalName().c_str(), "IfcQuantityTime"), OdDAI::Logical::False) ); continue; } } else if (qtoTypeName == "Q_VOLUME") { if (itemAttr->typeName() != "ifcquantityvolume") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), itemAttr->getInstanceType()->originalName().c_str(), "IfcQuantityVolume"), OdDAI::Logical::False) ); continue; } } else if (qtoTypeName == "Q_WEIGHT") { if (itemAttr->typeName() != "ifcquantityweight") { pInvalidIds->addData(InvalidRxObjectsValidationParams({ testIfcItem }, OdAnsiString().format("PropertySet '%s'. Type of attribute '%s' is %s but must be %s.", name.c_str(), testName.c_str(), itemAttr->getInstanceType()->originalName().c_str(), "IfcQuantityWeight"), OdDAI::Logical::False) ); continue; } } } } } return true; }