[返回博客](/cn/blog) # 单位转换和导出到 IFC

Ilya Kovaldov 四月 30, 2020 [\#ifc](/cn/blog/tag/ifc)

<a class="a2a_button_facebook"></a><a class="a2a_button_twitter"></a><a class="a2a_button_linkedin"></a>

有时，成员在使用 TB\_IfcExport 模块导出到 .ifc 文件时会遇到单位转换问题。本文包含一个处理单位并将其导出到 .ifc 文件的示例。

#### 创建项目单位分配

OdIfcExportImpl::createDefaultUnits() 函数创建一个 IfcUnitAssignment。这是一个很长的单位列表，用于将内部 BimRv 单位转换为已知单位。

##### 基于转换的单位

例如，考虑使用长度单位创建基于转换的单位的算法。

1\. 使用 UnitsTracking Manager 和 FormatOptions 获取内部单位：

```
OdBmUnitsTrackingPtr pUnitsTracking = m_database->getAppInfo(OdBm::ManagerType::UnitsTracking);
OdBmUnitsElemPtr pUnitsElem = pUnitsTracking->getUnitsElemId().safeOpenObject();
OdBmAUnitsPtr pAUnits = pUnitsElem->getUnits();
OdBmFormatOptionsPtrArray aFormatOptions;
pAUnits->getFormatOptionsArr(aFormatOptions);

OdDAIObjectId lenSIBaseUnit;
{
  bool lenConversionBased = false;
  bool lenUseDefault = false;

  OdAnsiString lenConvName;
  OdAnsiString lenUnitType = "LENGTHUNIT";
  OdAnsiString lenPrefix;
  OdAnsiString lenUnitName = "METRE";

  OdBmFormatOptionsPtr pFormatOptions = aFormatOptions[OdBm::UnitType::UT_Length];

  switch (pFormatOptions->getDisplayUnits())
  {
  case OdBm::DisplayUnitType::DUT_METERS:
  case OdBm::DisplayUnitType::DUT_METERS_CENTIMETERS:
    break;
  case OdBm::DisplayUnitType::DUT_CENTIMETERS:
    lenPrefix = "CENTI";
    break;
  case OdBm::DisplayUnitType::DUT_MILLIMETERS:
    lenPrefix = "MILLI";
    break;
  case OdBm::DisplayUnitType::DUT_DECIMAL_FEET:
  case OdBm::DisplayUnitType::DUT_FEET_FRACTIONAL_INCHES:
  {
    if (exportToCOBIE)
      lenConvName = "foot";
    else
      lenConvName = "FOOT";
    lenConversionBased = true;
  }
  break;
  case OdBm::DisplayUnitType::DUT_FRACTIONAL_INCHES:
  case OdBm::DisplayUnitType::DUT_DECIMAL_INCHES:
  {
    if (exportToCOBIE)
      lenConvName = "inch";
    else
      lenConvName = "INCH";
  }
  lenConversionBased = true;
  break;
  default:
  {
    //Couldn't find display unit type conversion -- assuming foot
    if (exportToCOBIE)
      lenConvName = "foot";
    else
      lenConvName = "FOOT";
    lenConversionBased = true;
    lenUseDefault = true;
  }
  break;
  }
```

2\. 如有必要，创建基本 SI 单位实例和带前缀的 SI 单位实例：

```
OdDAIObjectId lenSIUnit = OdInstanceExporter::createSIUnit(m_model, lenUnitType, lenPrefix, 
    lenUnitName);
  if (lenPrefix.isEmpty())
    lenSIBaseUnit = lenSIUnit;
  else
    lenSIBaseUnit = OdInstanceExporter::createSIUnit(m_model, lenUnitType, NULL, lenUnitName);
```

3\. 使用 BmUnitUtils 获取长度比例因子：

```
double lengthScaleFactor = OdBmUnitUtils::convertFromInternalUnits(1.0, lenUseDefault ? 
  OdBm::DisplayUnitType::DUT_DECIMAL_FEET : pFormatOptions->getDisplayUnits());

// If BIM Units differ from SI Units, for example Inches or Foots using for length measure, creating // Base Conversion Unit. First getting Conversion Scale Factor using OdBmUnitUtils:

if (lenConversionBased)
{
  double lengthSIScaleFactor = OdBmUnitUtils::convertFromInternalUnits(1.0, 
    OdBm::DisplayUnitType::DUT_METERS) / lengthScaleFactor;
```

4\. 创建一个维度指数实例（长度的一个维度）：

```
OdDAIObjectId lenDims = OdInstanceExporter::createDimensionalExponents(m_model, 1, 0, 0,
   0, 0, 0, 0); 
```

5\. 创建一个带测量单位的对象，该对象确定要转换的单位（SI 长度单位）以及如何转换（lengthSIScaleFactor 比率）：

```
ODIFC_CREATE_AS_RATIO_MEASURE(supVal, lengthSIScaleFactor)
OdDAIObjectId lenConvFactor = OdInstanceExporter::createMeasureWithUnit(m_model, supVal, lenSIUnit);
```

6\. 创建一个基于转换的度量单位，其属性是之前创建的维度指数对象和带测量单位的对象。

```

lenSIUnit = OdInstanceExporter::createConversionBasedUnit(m_model, lenDims, lenUnitType, 
  lenConvName, lenConvFactor);
```

7\. 将 SI 单位对象添加到 UnitSet 数组：

```
unitSet.push_back(lenSIUnit);
```

8\. 将 SI 单位和比例因子添加到单位缓存：

```
OdExporterCacheManager::getUnitsCache()->addUnit(OdBm::UnitType::UT_Length,
  lenSIUnit,lengthScaleFactor, 0.0);
```

##### 表达式单位

例如，考虑使用质量密度单位创建表达式单位的算法。

1\. 创建一个质量 SI 单位：

```
OdDAIObjectId massSIUnit;
{
  massSIUnit = createSIUnit(OdBm::UnitType::UT_Mass, "MASSUNIT", "GRAM", "KILO", 
    OdBm::DisplayUnitType::DUT_UNDEFINED);
  unitSet.push_back(massSIUnit);
```

}

2\. 使用千克（1 次方）和米（-3 次方）创建导出单位元素。导出单位元素的属性是上面创建的 SI 单位对象：质量 SI 单位和长度 SI 单位。

```
OdDAIObjectIds elements;
elements.push_back(OdInstanceExporter::createDerivedUnitElement(m_model, massSIUnit, 1));
elements.push_back(OdInstanceExporter::createDerivedUnitElement(m_model, lenSIBaseUnit, -3));
```

3\. 使用导出单位元素创建 kg/(m^3) 导出单位：

```
OdDAIObjectId massDensityUnit = OdInstanceExporter::createDerivedUnit(m_model, elements, "MASSDENSITYUNIT", NULL);
```

4\. 将创建的导出单位和比例因子添加到单位缓存中，以将 UnitSet 数组投影到其中：

```
unitSet.push_back(massDensityUnit);
double massDensityFactor = OdBmUnitUtils::convertFromInternalUnits(1.0, OdBm::DisplayUnitType::DUT_KILOGRAMS_PER_CUBIC_METER);
OdExporterCacheManager::getUnitsCache()->addUnit(OdBm::UnitType::UT_MassDensity, massDensityUnit, 
  massDensityFactor, 0.0);
```

5\. 以相同的方式重复填充其他单位：面积、体积、平面角、时间、频率、温度等。

6\. 最后，在填充 UnitSet 数组后，创建一个项目 UnitAssignment 实例：

```
OdInstanceExporter::createUnitAssignment(m_model, unitSet);
```

##### 在导出过程中使用 UnitsCache 和 UnitUtils 进行单位转换

在导出对象的过程中，将从 BimRv API 获取的测量单位转换为 IFC 项目单位。为此目的创建了一个缓存以及使用此缓存的实用程序。在下一个级别导出示例中考虑它们的应用。

```
// …
// some code to fill levels array from database 
// …

OdBmLevelPtr level = levels[ii];
double elev = level->getElevation(); // elevation in internal units
```

1\. 使用 ScaleLength() 工具将高程从 BimRv 单位转换为 IFC 单位：

```
double elevation = OdUnitUtil::ScaleLength(elev);
```

2\. 使用转换后的高程创建建筑楼层的局部放置和建筑楼层：

```
OdGeVector3d orig(0.0, 0.0, elevation);
OdDAIObjectId placement = OdExporterUtil::createLocalPlacement(m_model, buildingPlacement, &orig, 
  NULL, NULL);
OdDAIObjectId buildingStorey = OdInstanceExporter::createBuildingStorey(m_model, level, 
  OdExporterCacheManager::getOwnerHistoryHandle(),
  bsObjectType, placement, "ELEMENT", elevation);
```

##### 导出结果

导出结果是，文件包含以下行。

1\. 长度单位（SI 中的 METRE 和 BimRv 数据库中的 FOOT）：

```
#21=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#22=IFCDIMENSIONALEXPONENTS(1,0,0,0,0,0,0);
#23=IFCMEASUREWITHUNIT(IFCRATIOMEASURE(0.30480000000000035),#21);
#24=IFCCONVERSIONBASEDUNIT(#22,.LENGTHUNIT.,'FOOT',#23);
```

2\. 质量和质量密度单位：

```
#37=IFCSIUNIT(*,.MASSUNIT.,.KILO.,.GRAM.);
#38=IFCDERIVEDUNITELEMENT(#37,1);
#39=IFCDERIVEDUNITELEMENT(#21,-3);
#40=IFCDERIVEDUNIT((#38,#39),.MASSDENSITYUNIT.,'');
```

3\. 项目单位分配：

```
#73=IFCUNITASSIGNMENT((#24,#28,#32,#36,#37,#40,#41,#42,#44,#48,#52,#53,#54,#55,#56,#57,#58,#59,#64,#67,#68,#72));
```

4\. 建筑楼层：

```
#76=IFCCARTESIANPOINT((0.00000000000000000,0.00000000000000000,-800.00000000000000));
#77=IFCAXIS2PLACEMENT3D(#76,$,$);
#78=IFCLOCALPLACEMENT(#16,#77);
#79=IFCBUILDINGSTOREY('1i_YYDONP3AgUe36R0EAL1',#20,'Foundation','','8mm Head',#78,$,'Foundation',.ELEMENT.,-800.00000000000068);
```

## 今天就开始行动

**免费试用 ODA 软件 60 天。  
无风险，无需信用卡。**

[免费试用](https://www.opendesign.com/cn/free-trial)
