Convert OdDb Geometry and SAT Data to DirectShape

Stanislav Baklanov

August 27, 2021

This article explains how to convert OdDb entities based on B-Reps (e.g. OdDb3dSolid, OdDbRegion, etc.) and SAT data to BimRv DirectShape entities.

Just like any other conversion, the conversion is performed using OdBrepBuilderFiller. However, OdDb entity topology is very different from a DirectShape entity. DirectShape doesn't allow for periodic faces and edges, so entities such as a full sphere or a full circle are impossible. Moreover, OdDb topology can have separation loops so there are no seam edges, and complex fixes are required. The conversion is performed using intermediate conversion to ODA Solid Modeler's OdMdBody. OdMdBody has restrictions between OdDb and DirectShape; while it allows for periodic faces and edges, it forbids separation loops and requires seam edges.

Colors and Materials Conversion

DirectShape doesn't have colors but materials instead. OdDb face materials are not supported currently, but face colors are supported in both RGB and color indices. To convert them, pass an instance of OdBaseMaterialAndColorHelper to OdBrepBuilderFiller. You can use OdDb2BmMaterialAndColorHelper to convert entities from a .dwg file to OdMdBody and from OdMdBody to DirectShape. If you work with SAT data, you can use OdSat2MdForBmMaterialAndColorHelper and OdMd2BmFromSatMaterialAndColorHelper for conversion from SAT to OdMdBody and from OdMdBody to DirectShape respectively. Face color is converted to OdMdBody as-is. A new material with this color is created for the DirectShape. The input entity color is passed to the DirectShape directly, bypassing OdMdBody.

Algorithm

The following section contains an example conversion to DirectShape.

  1. Get OdBrBrep from an input file.
    For .dwg files, use the brep() method:
    OdDbDatabasePtr pDwgDb = pHostApp->readFile(fileName);
    OdDbBlockTableRecordPtr pMs = pDwgDb->getModelSpaceId().safeOpenObject(OdDb::kForWrite);
    for (OdDbObjectIteratorPtr pObjIt = pMs->newIterator(); !pObjIt->done(); pObjIt->step())
    {
      OdDbEntityPtr inputEntity = pObjIt->entity();
      if (!inputEntity.isNull())
      {
        OdBrBrep brep;
        BrepType bType = kOpenShell;
        if (inputEntity->isA() == OdDbRegion::desc())
        {
          OdDbRegionPtr pBody = inputEntity;
          pBody->brep(brep);
        }
        /*other geometry types of OdDbEntity*/
    
        /*conversion*/
      }
    }
    For SAT files, use the acisIn() method to get an OdDbEntity or use ISATConverter:
    for (unsigned idx = 0; idx < out.size(); ++idx)
    {
      OdBrBrep brep;
      ISATConverter* pIS = out[idx];
      brep.set(pIS->getIBr());
      /*conversion*/
    }
  2. Convert OdBrBrep to OdMdBody using OdBrepBuilderFiller:
    OdBrepBuilder mdBrepBuilder;
    std::unique_ptr attribSetter(createDwgAttribSetter());
    initMDBrepBuilder(mdBrepBuilder, bType, attribSetter.get());
    
    OdGeMatrix3d mx;
    bool hasTransform = brep.getTransformation(mx);
    
    OdBrepBuilderFiller BBFiller;
    BBFiller.params().setupFor(OdBrepBuilderFillerParams::kBrepAcisDwg, OdBrepBuilderFillerParams::kBrepMd);
    OdResult res = BBFiller.initFrom(mdBrepBuilder, brep);
    if (res == eOk)
    {
      mdBrepBuilder.enableValidator(false);
      OdMdBodyResultPtr pMdBody;
      try
      {
        pMdBody = OdMdBodyResult::cast(mdBrepBuilder.finish());
      }
      catch (...)
      {
        res = eGeneralModelingFailure;
      }
    }
  3. Change the topology in OdMdBody to the BimRv format and get a new OdBrBrep:
    OdBrBrep mdBrep;
    if (eOk == res && !pMdBody.isNull())
    {
      if (hasTransform)
        res = transformMdBody(pMdBody, mx);
      if (eOk == res)
      {
        res = convertToBimRvFormat(pMdBody);
        if (eOk == res)
        {
          res = getBrepFromMdBody(pMdBody, mdBrep);
        }
      }
    }
  4. Convert OdBrBrep to DirectShape and add it to a BimRv database:
    OdBrepBuilder bmBrepBuilder;
    res = pBmDb->appServices()->brepBuilder(bmBrepBuilder, bType);
    if (res == eOk)
    {
      BBFiller.params().setupFor(OdBrepBuilderFillerParams::kBrepAcisDwg, pDwgDb, pBmDb);
      res = BBFiller.initFrom(bmBrepBuilder, mdBrep, bmMaterialHelper);
      if (res == eOk)
      {
        try
        {
          OdBmGeometryPtr resultGeometry = OdBmGeometry::cast(bmBrepBuilder.finish());
          if (!resultGeometry.isNull())
          {
            OdArray aFaces;
            resultGeometry->getFaces(aFaces);
            OdArray aEdges;
            resultGeometry->getEdges(aEdges);
            if (aFaces.size() != 0 || aEdges.size() != 0) 
            {
              ODBM_TRANSACTION_BEGIN(t, pBmDb)
                t.start();
                 OdBmGNodePtrArray nodes;
                nodes.append(resultGeometry);
                OdBmDirectShapePtr pDirectShape = OdBmDirectShape::createObject();
                OdBmObjectId retId = pBmDb->addElement(pDirectShape);
                pDirectShape->setOwningElementId(pBmDb->getOwnerFamilyId());
                res = pDirectShape->setShape(nodes);
                t.commit();
              ODBM_TRANSACTION_END()
            }
          }
        }
        catch (...)
        {
          res = eGeneralModelingFailure;
        }
      }
    }

Examples

You can find examples in the DwgDirectShapeImportEx and SatDirectShapeImportEx samples, which are provided with the archives and can be found in the CommonApplications/BimRv directory. These examples contain code that convert OdDb entities that are based on B-Rep entities in .dwg files or SAT data in SAT files to DirectShapes in RVT or RFA files. They require an empty RFA or RVT file to get the BimRv's input database.