Youtube lessons

DougB

CAD practitioner
Thank you. I will await your answer. It just seems so peculiar that the name intended for the component label (with entry [0:1:1:1:1]) of the project doc overwrites the label (with entry [0:1:1:2:1]) of the step doc. It makes me think that there is some important detail I am missing when I copy from the source label of the step document to the target label of the project document.
 

natalia

Moderator
Staff member
Hello, DougB


Let me start from the end and firstly answer to your question. You are on the right track. At the same time, it is not enough coded for this model. These are two data not processed: tree nodes(becomes wrong) and absent colors.

Here, if we have absent (not copied) colors, it might be processed by OCCT through using default color for visualization. Another situation with wrong tree nodes values. It makes the OCAF invalid and leads to crashes.

Let’s investigate tree nodes on OCAF tree model when we apply attached code above. On ‘Fig 1’ we have OCAF structure for loaded ‘as1-oc-214.stp’. On ‘Fig 2’ we have new filled document (not yet stored anywhere (nor step, nor xbf), just in memory)

XDE_copied.png

After comparing these documents, the tree nodes inconsistence is found. Let’s have a look at the item selected on the Fig2. It’s a tree node attribute of ‘0:1:1:2:4’. In the property panel(on the right) we see that it relates to several labels and also the ‘0:1:1:1:4’ label. When we open and try to find this item below the ‘0:1:1:1’, we do not found it. This value in the attribute should be corrected to link to new entries.


So, to make this document valid we need to take care about tree nodes attribute.

Also, during comparison, we may notice that label Colors placed on tag ‘0:1:2’ has empty filling in the new created document. It’s not so critical as for tree nodes because some default OCCT color should be used in this case but may be in code asking something of Color tool will give exception due to it’s empty.


These explanation gives us the answer why created XBF is not loaded correctly in CAD Assistant. It eighter asked colors for some of shapes or goes by the tree node items, not found some and crashes so.

To check whether the XBF created might be loaded, call Open for it, do not perform something to display in the viewer, just show the tree in the inspector. The result is on ‘Fig 3.’ We see here that the tree is similar to the same as on ‘Fig2’. It’s possible to expand tree, but, if we click on some item with wrong tree node attributes reference (e.g. 0:1:1:2:4), it crashes (absent soft check to avoid exception…)

I expect the question: why the stored ‘under_top.stp’ file is loaded… Why it’s correctly visualized and even with right colors? When we know, that in initial code we did not copy colors at all. It’s a very curious question) One of rude prediction is the next. When we have your code performed and yet not closed the ‘doc’, we still have two documents in the memory. These are documents from ‘Fig1’ and ‘Fig2’ – the initial and the created one. So, my hypothesis is that when STEP writer processes tree node attribute and in case when it does not find it in the new document, it obtain it from the initial one(or some internal cashed map or other?). It looks like the possible truth when we look at the ‘under_top.stp’ file loaded. The image is ‘Fig4’. If you dig it, and continue investigation, let us know how near the hypothesis to the implementation.

Best regards, Natalia
 
Last edited:

natalia

Moderator
Staff member
Also, may be it would be useful for you. Have a look at implementation of OCC23950 in QABugs_19.cxx. It contains a simple piece of code of XCAF document filling with shapes and colors attached.

Besides, may be it’s worth starting from less complicated STEP file? On one, that you’re using, it’s convenient to check cases with local transformations of shapes due to this tree node linkage)
 

DougB

CAD practitioner
I have made some progress. I modified my code to no longer use this method:
  • ST->AddComponent()
and instead, I have followed the approach taught in Lesson15: Compose-XDE.
Also, I changed it to use TopoDS_Builder instead of BRep_Builder, although I'm not sure if that matters.
This screenshot of CAD Assistant shows the names that were wrong before are now correct.
under-top-fixed.png
Below is my revised code:

C++:
/*
Imports a step file and loads it into an XDE document
as a component of root. The document is then saved in
both step format and .xbf format.
*/
// OpenCascade includes
#include <BRep_Builder.hxx>
#include <Interface_Static.hxx>
#include <TopoDS_Compound.hxx>
#include <BinXCAFDrivers.hxx>
#include <TDF_ChildIterator.hxx>
#include <STEPCAFControl_Reader.hxx>
#include <STEPCAFControl_Writer.hxx>
#include <TDataStd_Name.hxx>
#include <TDocStd_Application.hxx>
#include <TDocStd_Document.hxx>
#include <TDocStd_XLinkTool.hxx>
#include <TNaming_Builder.hxx>
#include <XCAFDoc_ColorTool.hxx>
#include <XCAFDoc_DocumentTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <XSControl_Writer.hxx>
#include <XSControl_WorkSession.hxx>
const char* filename = "../models/as1-oc-214.stp";
const char* savename = "as1-oc-214.stp";
const char* save_step_file_name = "/home/doug/Desktop/under_top_fixed.stp";
const char* save_doc_file_name = "/home/doug/Desktop/under_top_fixed.xbf";
struct t_DocAppStruct
{
  Handle(TDocStd_Document)    doc;
  Handle(TDocStd_Application) app;
};
struct t_prototype
{
  TopoDS_Shape shape;
  TDF_Label    label;
};
namespace
{
  t_DocAppStruct createDoc()
  {
    // Create XDE document
    Handle(TDocStd_Application) app = new TDocStd_Application;
    BinXCAFDrivers::DefineFormat(app);
    //
    Handle(TDocStd_Document) doc;
    app->NewDocument("BinXCAF", doc);
    //
    // Create a DocAppStruct
    t_DocAppStruct docApp;
    docApp.app = app;
    docApp.doc = doc;
    return docApp;
  }
}
int main(int argc, char** argv)
{
  // Step section:
  STEPCAFControl_Reader Reader;
  // Create XDE document and app for step data
  t_DocAppStruct stepDocApp = ::createDoc();
  Handle(TDocStd_Application) stepApp = stepDocApp.app;
  Handle(TDocStd_Document) stepDoc = stepDocApp.doc;
  // Read CAD and associated data from file
  IFSelect_ReturnStatus outcome = Reader.ReadFile(filename);
  //
  if ( outcome != IFSelect_RetDone )
  {
    stepApp->Close(stepDoc);
  }
  if ( !Reader.Transfer(stepDoc) )
  {
    stepApp->Close(stepDoc);
  }
  // Tools for step doc
  Handle(XCAFDoc_ShapeTool)
    SST = XCAFDoc_DocumentTool::ShapeTool( stepDoc->Main() ); // Shape tool.
  Handle(XCAFDoc_ColorTool)
    SCT = XCAFDoc_DocumentTool::ColorTool( stepDoc->Main() ); // Color tool.
  // Get root label of step data to paste (sourceLabel)
  TDF_LabelSequence stepLabels;
  SST->GetShapes(stepLabels);
  TDF_Label sourceLabel = stepLabels.Value(1);
  // Project section:
  // Create XDE document and app for project data
  t_DocAppStruct projDocApp = ::createDoc();
  Handle(TDocStd_Application) app = projDocApp.app;
  Handle(TDocStd_Document) doc = projDocApp.doc;
  // Tools for project doc
  Handle(XCAFDoc_ShapeTool)
    ST = XCAFDoc_DocumentTool::ShapeTool( doc->Main() ); // Shape tool.
  Handle(XCAFDoc_ColorTool)
    CT = XCAFDoc_DocumentTool::ColorTool( doc->Main() ); // Color tool.
  // Create target shape and label
  TopoDS_Compound targetShape;
  TopoDS_Builder tbuilder;
  tbuilder.MakeCompound(targetShape);
  t_prototype targetProto;
  targetProto.shape = targetShape;
  targetProto.label = ST->AddShape(targetShape, true); // Add assy to the document.
  // Create root prototype.
  TopoDS_Compound rootShape;
  TopoDS_Builder rbuilder;
  rbuilder.MakeCompound(rootShape);
  rbuilder.Add(rootShape, targetProto.shape);
  t_prototype rootProto;
  rootProto.shape = rootShape;
  rootProto.label = ST->AddShape(rootShape, true); // Add assy to the document.
  TDataStd_Name::Set( rootProto.label, TCollection_ExtendedString("Root") );
  // Copy source label of step doc to target label of project doc
  TDocStd_XLinkTool XLinkTool;
  XLinkTool.Copy(targetProto.label, sourceLabel);
  ST->UpdateAssemblies();
  // Set names of target label instance
  for ( TDF_ChildIterator cit(rootProto.label); cit.More(); cit.Next() )
  {
    TDataStd_Name::Set(cit.Value(), savename);
  }

  // Save project doc to step file
  STEPCAFControl_Writer Writer;
  // To make subshape names work, we have to turn on the following static
  // variable of OpenCascade.
  Interface_Static::SetIVal("write.stepcaf.subshapes.name", 1);
  // Write XDE document to file
  if ( !Writer.Transfer(doc, STEPControl_AsIs) )
  {
    std::cout << "The document cannot be translated or gives no result" << std::endl;
    app->Close(doc);
  }
  const IFSelect_ReturnStatus ret = Writer.Write(save_step_file_name);
  if ( ret != IFSelect_RetDone )
  {
    std::cout << "The document could not be written to file" << std::endl;
    app->Close(doc);
  }
  std::cout << "Document saved in STEP format." << std::endl;
   // Write doc out to file
  PCDM_StoreStatus sstatus = app->SaveAs(doc, save_doc_file_name);
  //
  if ( sstatus != PCDM_SS_OK )
  {
    app->Close(doc);
    std::cout << "Cannot write XCAF document." << std::endl;
    return 1;
  }
  std::cout << "Wrote XCAF document in .xbf format." << std::endl;
  app->Close(doc);
  return 0;
}

The document was also saved in .xbf format, but CAD Assistant crashed when I tried to load that.

Despite this progress, I feel like I am still guessing about what methods to use in order to allow label copy to work properly. For example, when I try to load the file as1_pe_203.stp, it doesn't work so well. Also, what if I have a document with top assembly already in place as I would if I had used ST->NewShape()? In this case, I am not able to figure out how to code this in order to create a target label under it for copying the step label to.
Are there some generally accepted "Best Practices" that I can learn to make sure that I am getting the best performance out of OpenCascade when copying labels from one document to another?
-Doug
 

natalia

Moderator
Staff member
I have made some progress. I modified my code to no longer use this method:
  • ST->AddComponent()
and instead, I have followed the approach taught in Lesson15: Compose-XDE.
Also, I changed it to use TopoDS_Builder instead of BRep_Builder, although I'm not sure if that matters.
This screenshot of CAD Assistant shows the names that were wrong before are now correct.
View attachment 461
Below is my revised code:

C++:
/*
Imports a step file and loads it into an XDE document
as a component of root. The document is then saved in
both step format and .xbf format.
*/
// OpenCascade includes
#include <BRep_Builder.hxx>
#include <Interface_Static.hxx>
#include <TopoDS_Compound.hxx>
#include <BinXCAFDrivers.hxx>
#include <TDF_ChildIterator.hxx>
#include <STEPCAFControl_Reader.hxx>
#include <STEPCAFControl_Writer.hxx>
#include <TDataStd_Name.hxx>
#include <TDocStd_Application.hxx>
#include <TDocStd_Document.hxx>
#include <TDocStd_XLinkTool.hxx>
#include <TNaming_Builder.hxx>
#include <XCAFDoc_ColorTool.hxx>
#include <XCAFDoc_DocumentTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <XSControl_Writer.hxx>
#include <XSControl_WorkSession.hxx>
const char* filename = "../models/as1-oc-214.stp";
const char* savename = "as1-oc-214.stp";
const char* save_step_file_name = "/home/doug/Desktop/under_top_fixed.stp";
const char* save_doc_file_name = "/home/doug/Desktop/under_top_fixed.xbf";
struct t_DocAppStruct
{
  Handle(TDocStd_Document)    doc;
  Handle(TDocStd_Application) app;
};
struct t_prototype
{
  TopoDS_Shape shape;
  TDF_Label    label;
};
namespace
{
  t_DocAppStruct createDoc()
  {
    // Create XDE document
    Handle(TDocStd_Application) app = new TDocStd_Application;
    BinXCAFDrivers::DefineFormat(app);
    //
    Handle(TDocStd_Document) doc;
    app->NewDocument("BinXCAF", doc);
    //
    // Create a DocAppStruct
    t_DocAppStruct docApp;
    docApp.app = app;
    docApp.doc = doc;
    return docApp;
  }
}
int main(int argc, char** argv)
{
  // Step section:
  STEPCAFControl_Reader Reader;
  // Create XDE document and app for step data
  t_DocAppStruct stepDocApp = ::createDoc();
  Handle(TDocStd_Application) stepApp = stepDocApp.app;
  Handle(TDocStd_Document) stepDoc = stepDocApp.doc;
  // Read CAD and associated data from file
  IFSelect_ReturnStatus outcome = Reader.ReadFile(filename);
  //
  if ( outcome != IFSelect_RetDone )
  {
    stepApp->Close(stepDoc);
  }
  if ( !Reader.Transfer(stepDoc) )
  {
    stepApp->Close(stepDoc);
  }
  // Tools for step doc
  Handle(XCAFDoc_ShapeTool)
    SST = XCAFDoc_DocumentTool::ShapeTool( stepDoc->Main() ); // Shape tool.
  Handle(XCAFDoc_ColorTool)
    SCT = XCAFDoc_DocumentTool::ColorTool( stepDoc->Main() ); // Color tool.
  // Get root label of step data to paste (sourceLabel)
  TDF_LabelSequence stepLabels;
  SST->GetShapes(stepLabels);
  TDF_Label sourceLabel = stepLabels.Value(1);
  // Project section:
  // Create XDE document and app for project data
  t_DocAppStruct projDocApp = ::createDoc();
  Handle(TDocStd_Application) app = projDocApp.app;
  Handle(TDocStd_Document) doc = projDocApp.doc;
  // Tools for project doc
  Handle(XCAFDoc_ShapeTool)
    ST = XCAFDoc_DocumentTool::ShapeTool( doc->Main() ); // Shape tool.
  Handle(XCAFDoc_ColorTool)
    CT = XCAFDoc_DocumentTool::ColorTool( doc->Main() ); // Color tool.
  // Create target shape and label
  TopoDS_Compound targetShape;
  TopoDS_Builder tbuilder;
  tbuilder.MakeCompound(targetShape);
  t_prototype targetProto;
  targetProto.shape = targetShape;
  targetProto.label = ST->AddShape(targetShape, true); // Add assy to the document.
  // Create root prototype.
  TopoDS_Compound rootShape;
  TopoDS_Builder rbuilder;
  rbuilder.MakeCompound(rootShape);
  rbuilder.Add(rootShape, targetProto.shape);
  t_prototype rootProto;
  rootProto.shape = rootShape;
  rootProto.label = ST->AddShape(rootShape, true); // Add assy to the document.
  TDataStd_Name::Set( rootProto.label, TCollection_ExtendedString("Root") );
  // Copy source label of step doc to target label of project doc
  TDocStd_XLinkTool XLinkTool;
  XLinkTool.Copy(targetProto.label, sourceLabel);
  ST->UpdateAssemblies();
  // Set names of target label instance
  for ( TDF_ChildIterator cit(rootProto.label); cit.More(); cit.Next() )
  {
    TDataStd_Name::Set(cit.Value(), savename);
  }

  // Save project doc to step file
  STEPCAFControl_Writer Writer;
  // To make subshape names work, we have to turn on the following static
  // variable of OpenCascade.
  Interface_Static::SetIVal("write.stepcaf.subshapes.name", 1);
  // Write XDE document to file
  if ( !Writer.Transfer(doc, STEPControl_AsIs) )
  {
    std::cout << "The document cannot be translated or gives no result" << std::endl;
    app->Close(doc);
  }
  const IFSelect_ReturnStatus ret = Writer.Write(save_step_file_name);
  if ( ret != IFSelect_RetDone )
  {
    std::cout << "The document could not be written to file" << std::endl;
    app->Close(doc);
  }
  std::cout << "Document saved in STEP format." << std::endl;
   // Write doc out to file
  PCDM_StoreStatus sstatus = app->SaveAs(doc, save_doc_file_name);
  //
  if ( sstatus != PCDM_SS_OK )
  {
    app->Close(doc);
    std::cout << "Cannot write XCAF document." << std::endl;
    return 1;
  }
  std::cout << "Wrote XCAF document in .xbf format." << std::endl;
  app->Close(doc);
  return 0;
}

The document was also saved in .xbf format, but CAD Assistant crashed when I tried to load that.

Despite this progress, I feel like I am still guessing about what methods to use in order to allow label copy to work properly. For example, when I try to load the file as1_pe_203.stp, it doesn't work so well. Also, what if I have a document with top assembly already in place as I would if I had used ST->NewShape()? In this case, I am not able to figure out how to code this in order to create a target label under it for copying the step label to.
Are there some generally accepted "Best Practices" that I can learn to make sure that I am getting the best performance out of OpenCascade when copying labels from one document to another?
-Doug
Hi @DougB

XDE component of OCCT library is described here: https://dev.opencascade.org/doc/overview/html/occt_user_guides__xde.html.
We see that any XDE document has the very strict defined structure.
There are some tools that are used to set/get elements of this structure correctly, these are: XCAFDoc_ShapeTool,
XCAFDoc_ColorTool and other tools from XCAFDoc directory of OCCT.

You may find lots of sample of using them in the sources of this library. The better and initial sample is STEP reader itself (STEPCAFControl_Reader).
So, when we’re talking about copy/paste opportunity of OCAF, it’s not about XDE. To prepare correct document, we should use only these tools. When we copy following your code we break this structure. As a result, the application mentioned by you fails when parsing it. (Prepared document has wrong tree nodes, empty colors defined)

At the same time, we may freely copy/paste in OCAF documents that are not bounded by rules of XDE document structure.
So, here, the solution might be filling your new XDE document with using these tools. Just add shape and set color with using shape/color tool.
It tells us that using of TDocStd_XLinkTool is not correct for XDE type of document.

Best regards, Natalia
 

David

Active CAD practitioner
Here we have the list of lessons that are already published or going to be published on our youtube channel. The list is kinda dynamic, and I do not really have any strict plan or schedule of what & when to publish. Since these lessons are entirely community-driven, feel free to share your ideas on the possible topics right below this post.

OpenCascade lessons done (too late to change...):
  1. Lesson 1: Configure Visual Studio to use OpenCascade
  2. Lesson 2: Bring OpenCascade and VTK together
  3. Lesson 3: Compile OpenCascade with MFC samples
  4. Lesson 4: Use native OpenCascade visualization
  5. Lesson 5: Use OpenCascade from CMake
  6. Lesson 6: OpenCascade in Docker
  7. Lesson 7: OpenCascade in a nutshell
  8. Lesson 8: Meet OpenCascade modules
  9. Lesson 9: OpenCascade’s interactive Draw console: build a prismatic block
  10. Lesson 10: First steps in OCAF
  11. Lesson 11: Design data model with OpenCascade OCAF
  12. Lesson 12: Visualize STEP models with colors and assembly structure
  13. Lesson 13: How to profile performance with Intel VTune Profiler
  14. Lesson 14: Intersect 2D polygons using Intf package
  15. Lesson 15: Export CAD assemblies with colors and names (create an assembly from scratch, put some names and colors, export to STEP)
  16. Lesson 16: OpenCascade in Python (PythonOCC)
  17. Lesson 17: Fast point membership classification (PMC), (see also this topic), 2 parts.
  18. Lesson 18: Bottle exercise: https://dev.opencascade.org/doc/overview/html/occt__tutorial.html
  19. Lesson 19: Handles.
  20. Lesson 20: Offsets (BRepOffsetAPI_MakeOffset).
OpenCascade lessons TODO (well, just random ideas here; feel free to propose down below):http://analysissitus.org/forum/index.php?threads/simple-part-generation-tutorial.183/
  • COMING SOON: Splines in OpenCascade.
  • COMING SOON: Optimization method for cylinder fitting.
  • Simple modeling tutorial
  • GeomFill_Sweep
  • GeomPlate_BuildPlateSurface
  • Corrected Frenet and how to locate profiles along a curve
  • TopoDS-Geom how to
  • Intersect planes with IntAna_QuadQuadGeo
  • Offsets according to [Piegl, L. a., & Tiller, W. (1999). Computing offsets of NURBS curves and surfaces. CAD Computer Aided Design, 31, 147–156. https://doi.org/10.1016/S0010-4485(98)00066-9]
  • Split shapes and curves by ShapeUpgrade_SplitCurve3dContinuity.
  • Intersect edges with BOPs.
  • ThruSection and related problems.
  • OpenCascade threads.
  • Export to IFC model.
  • OCAF: overview of the standard attributes.
  • Slice a model by a stack of planes.
  • Helix in OpenCascade.
  • Convert splines to Bezier (GeomConvert_BSplineCurveToBezierCurve).
  • Viewer initialization on linux (based on Lesson 12) with docker.
  • OpenCascade + VTK without IVtk.
  • How to survive geometric tolerances.
  • Surface trimming in OpenCascade (https://forum.freecadweb.org/viewtopic.php?f=3&t=61832). This would require some advanced healing, maybe surface morphing.
  • Constrained filling of a surface by boundary edges.
  • ShapeAnalysis/ShapeFix.
  • Custom DRAW commands (C++ prototyping).
  • How to organize the non-regression testing system on top of Draw
  • OpenCascade + Qt widgets
  • OpenCascade basic types (smart pointers, geometry, topology)
  • Modeling API
  • FreeCAD modules (https://github.com/qingfengxia/FreeCAD_Mod_Dev_Guide/tree/master/pdf)
  • Use OpenCascade from C# ( https://www.red-gate.com/simple-talk/dotnet/net-development/creating-ccli-wrapper/ )
  • Set up Jenkins as CI/CD for OpenCascade-based project
  • Give Coin3D a try?
CAD lessons TODO:
  • CG quick start.
  • Plug in NetGen mesh generator.
  • BVHs explained.
  • Surface fitting from point clouds (regular, irregular, interp/approx).
  • Voxelization: ADF, F-rep, octrees.
  • Material Removal: distance fields.
Programming lessons done:
  • Using licensecc for protecting commercial software packages.
Programming lessons TODO:
  • Finding missing deps with Dependency Walker.
Analysis Situs highlights done:
  1. Export colored parts to glTF.
  2. Voxelization and point cloud generation.
  3. Thickness analysis.
  4. Shape healing by example of a benchmark model.
  5. Feature suppression ways of usage.
Analysis Situs highlights TODO:
  • Code review of analysis situs code base.
  • Save IGES from SW, open in AS, convert canonical, sew.
  • Export unique CAD parts from a CAD assembly using XDE interfaces in Tcl scripting.
  • Tolerances.
  • Feature recognition basics.
  • STEP -> XDE -> STEP conversion.
  • Mesh refinement.
  • Surface fitting.
  • AAG ways of usage.
I just wanted to say thank you for the excellent support you provide and the awesome lessons.
 

DougB

CAD practitioner
Hello @DougB and welcome to the forum!

Your remark is very valid, although this whole business is very dependent on the architecture of the project where you want to insert your shape. Do you mean that such an existing project is also based on OCAF? If so, then you have some options:
  1. Inject you shape with TNaming_NamedShape attribute into one of the labels reserved in your existing document. This way you loose the metadata such as colors and names, but the hierarchy is sort of preserved in the compound structure of the shape itself.
  2. Represent the entire hierarchy as another OCAF document. In such situation, I would not recommend injecting XDE document structure right into your existing document. The thing here is that XDE is a pretty self-contained and isolated format that was not designed for being embedded. Still, you might have it as a separate document in memory and address its sections from the outside.
Both approaches are used in Analysis Situs. Having said that, I cannot avoid making another remark about assemblies as such. People often prefer storing them separately as databases (e.g., in SQLite or MongoDB) because such storage is just better suited for handling large amounts of data. They also give you a query language and are, all in all, designed for customization (you can easily add tables/records of your domain-specific objects). A good example here is Shapr3D, which arranges the assembly hierarchy as a database while storing all shapes as BLOBs.

I remember you asked (on youtube likely) if we happened to have any documentation on Analysis Situs. Unfortunately, not yet (except for this: http://analysissitus.org/features.html). But you can always ask questions here, and we'll try to guide you the best we can.
@Quaoar, Thanks again for your advice. I have been working on this and considering lots of different options on how to proceed, but before I get too far along, I want to make sure I understand you correctly. Please correct me if I have got this wrong, but for my purpose of finding and using a readily available working document solution, by far the most obvious way to represent an OpenCascade CAD hierarchical assembly structure is with OCAF using the XDE extension. OCAF doesn't provide any alternate way of doing this that I have found. Here is what I have found:

1. Your Lesson 15, in which you show the use of BRepBuilder and ShapeTool to compose an XDE document representing the hierarchical assembly structure of a chassis assembly, which can then be exported to a step file or saved in .xbf format.

2. I did a Google search for these 4 words: hierarchical assembly structure OCAF

3. So far, I haven't found any information on how to represent a CAD assembly structure with OCAF other than by using OCAF/XDE. So unless I have completely misunderstood, this is the format that I should use for my project document. Right? (Remember, I'm lazy. I'm not looking to do this the hard way.)

4. Also, I believe that @natalia's advice about how some OCAF functionality such as copy label using TDocStd_XLinkTool is incompatible with XDE documents is not intended to steer me away from using XDE, but rather to make me aware that XDE doesn't play well with some OCAF functions.

As always, I would be most grateful for any clarification or further advice.
-Doug
 

Quaoar

Administrator
Staff member
by far the most obvious way to represent an OpenCascade CAD hierarchical assembly structure is with OCAF using the XDE extension.
Yes, it's the only readily available solution based on OCAF out there. Just make sure to use the API of XDE (all these "shape tools", "color tools", etc.) when dealing with XDE. The structure of the document cannot be changed randomly, and you cannot freely move labels and attributes around. It's all fixed.

I did a Google search for these 4 words: hierarchical assembly structure OCAF
The HAG concept was introduced by Ari Rappoport (or even earlier), read here: http://quaoar.su/files/books/Grinstein - 1993 - Modeling in Computer Graphics.pdf

So we added nothing new to this concept but tried to employ it in the application to XDE. I probably need to tell you a little story so that you have a full picture of assembly support in OpenCascade. Back in the day, OpenCascade only provided data exchange via STEP/IGES formats at the level of shapes. I.e., if your STEP file had contained a hierarchy, then OpenCascade would have read it as a compound of nested shapes. The problem with such an approach is that it does not communicate colors, names, and other metadata that you would expect to have imported from a STEP file.

In OpenCascade, the only way to associate metadata with shapes is through OCAF (in ACIS and other kernels, it can be different, e.g., attributes are sometimes attached directly to shape elements). So the solution was to employ OCAF for reading and writing metadata from/to STEP. The former data exchange team at OCC sat down and implemented the XDE framework for that. Like the leading guy on this team once told me, it was just a prototype. A kind of experiment to demonstrate that OpenCascade can deal with metadata. But after that, OCC started to use XDE in many projects, and slowly but surely, this XDE format became a de facto standard for metadata-rich data exchange. The worst thing about it is that XDE never stopped being a "prototype" for a data exchange framework, and that is why you see all these horrible interfaces everywhere.

Our take on XDE was (and still is) to wrap the TDocStd_Document with a somewhat eatable interface (read here: http://analysissitus.org/features/features_asm-xde-document.html) and provide a facade for working with assemblies and metadata without a need of any low-level OCAF programming. We interfaced it in one class and started to implement HAG-oriented services, such as instance singling and other. But what we are adding to XDE are only the algorithms, i.e., the mechanics of how labels and attributes are moved around. We do not extend XDE (well, there are some exceptions) and keep it consistent across all modifications. And it is always a separate document, not embedded into any other OCAF document.

So unless I have completely misunderstood, this is the format that I should use for my project document. Right?
It's your choice to use it. I know that many people would prefer to implement such things from scratch and leave OpenCascade for geometric modeling only. In our team, we decided to use XDE, because:
  1. It gives us a quick start and we have time constraints to deliver stuff.
  2. We know how to work with XDE.
  3. We have pre-implemented services (this facade class).
  4. XDE is compatible with OCC translators, and even with CADEX translators.
If 1-4 hadn't been true, I would never have chosen XDE as a framework because its architecture is just bad.
 
Last edited:

DougB

CAD practitioner
@Quaoar said: Just make sure to use the API of XDE (all these "shape tools", "color tools", etc.) when dealing with XDE. The structure of the document cannot be changed randomly, and you cannot freely move labels and attributes around. It's all fixed.
I have seen how tricky it is to use XDE as a project document and I appreciate how easy it is to inadvertently generate a document which won't produce valid .stp or .xbf files. But I have also seen that it might still be possible. For example you have shown in Lesson 15 how BRepBuilder can be used to compose a valid document which can then be saved as a valid file in step or .xbf (or .xml) format. The process for building the document began with building the wheel and axle prototypes first, then the wheel-axle assembly, then finally the chassis. The result was a document in which the top assembly had a tag of 4, since it was added last. (See figure below.) But apparently, this wasn't a problem. When saved in step format, the top assembly tag got changed to 1.
chassis-xml.png
In a similar way, I have:
  1. used BRepBuilder to create a 'target' label under a root assembly label
  2. then copied as1-oc-214.stp to the target label using TDocStd_XLinkTool.
  3. I was then able to save the document as a valid step file
  4. then read the step file back to get a fully valid document.
I know I am bending the rules by trying to push XDE to do more than it was intended to do, but if I could create the target label under an existing root label, I think I might be able to build a valid document for an arbitrarily large project. (Unfortunately, BRepBuilder doesn't do it because it needs to build the root label and add the target label to it.) Do you know of an alternative to BRepBuilder that can add a target label to an existing root label?
 

Quaoar

Administrator
Staff member
When saved in step format, the top assembly tag got changed to 1.
Yes, because when exporting to STEP, OpenCascade will retrace the hierarchy top-down, while the order of labels in the XDE document is nothing but the persistence order. These tags are pretty much like GUIDs of unique records in a database, so the label's tag is quite meaningless here.

I know I am bending the rules by trying to push XDE to do more than it was intended to do, but if I could create the target label under an existing root label, I think I might be able to build a valid document for an arbitrarily large project.
The size of a project is not an issue as long as you have enough memory and it does not slow down other modules of your software (e.g., visualization and UI). Whichever means you use for composing a document, you have to end up with a structure that does not violate XDE rules. As for assemblies, there are always two levels of hierarchy. The top-level labels inside an assembly "folder" represent "prorotypes", i.e., parts or subassemblies that are to be linked together as components (the second level of a hierarchy). This top level is referred to as "declaration level" in the figure below:

1671186940205.png
The second level of this hierarchy is designed to represent components, i.e., lightweight links to other entities from the top level:

1671187020902.png

The hierarchy does not go any deeper, because, from a component level, you're supposed to jump to another top-level label using the provided TreeNode link. There's actually one exception from this rule, where you might have the 3-rd level entities to represent subshapes under parts. Such sublabels are used to assign colors and other metadata to subshapes.

All in all, when composing an XDE document, you need to be sure that these nesting rules are satisfied, and then it does not matter which tools or API you're using. To have a shape under a label, you need to have `TNaming_NamedShape` attribute. It's allocation is done by `TNaming_Builder` tool like this:

Code:
TNaming_Builder NB(yourLabel);
NB.Generated(yourShape);
 

guoyj8

CAD practitioner
The hierarchy does not go any deeper, because, from a component level, you're supposed to jump to another top-level label using the provided TreeNode link.

Dear Quaoar,​

Thanks a lot for your videos -- very informative! Espcially the concepts were taught clearly.
About OCAF and XDE, it sounds like it is a good foundation for a project if it could be used carefully. It was noticed that your Analysis Situs also uses it as the Active Data framework's basis. Just a few straightfoward questions:

1) From your words, it seems that we can have only two levels in the XDE document hierarchy. Does this block us to have multi-level tree nodes in the actual Object Browser? I hope to have possibility to have an assembly/product made up of sub-assemblies which are made of sub-assemblies ...
2) Can OCAF + XDE also be used to manage some parts/sources made with VTK? If not, can we make the final Data Objects presented in the Object Browser from both OCAF/XDE (managing the gometries) and other sources like VTK or other special data?

Thanks a lot!
Yongjin
 

Quaoar

Administrator
Staff member
Thanks for your kind words and feedback, very appreciated.

  1. Nope, you can have any depth of assembly structure using just 2-level hierarchy in TDF Labels. This 2-level hierarchy is a hierarchy of components, i.e., parents-to-children. Children then act as parents, and so it goes.
  2. I'm not an advanced VTK user and have very little idea how they manage persistent objects. With OCAF, you can introduce your specific attributes, and they can be VTK-aware. The only thing is that you'll need to provide functions to store such custom data to files and read it back (if you are going to have persistence).
 

frankpian

CAD practitioner
Yes, because when exporting to STEP, OpenCascade will retrace the hierarchy top-down, while the order of labels in the XDE document is nothing but the persistence order. These tags are pretty much like GUIDs of unique records in a database, so the label's tag is quite meaningless here.


The size of a project is not an issue as long as you have enough memory and it does not slow down other modules of your software (e.g., visualization and UI). Whichever means you use for composing a document, you have to end up with a structure that does not violate XDE rules. As for assemblies, there are always two levels of hierarchy. The top-level labels inside an assembly "folder" represent "prorotypes", i.e., parts or subassemblies that are to be linked together as components (the second level of a hierarchy). This top level is referred to as "declaration level" in the figure below:

View attachment 481
The second level of this hierarchy is designed to represent components, i.e., lightweight links to other entities from the top level:

View attachment 482

The hierarchy does not go any deeper, because, from a component level, you're supposed to jump to another top-level label using the provided TreeNode link. There's actually one exception from this rule, where you might have the 3-rd level entities to represent subshapes under parts. Such sublabels are used to assign colors and other metadata to subshapes.

All in all, when composing an XDE document, you need to be sure that these nesting rules are satisfied, and then it does not matter which tools or API you're using. To have a shape under a label, you need to have `TNaming_NamedShape` attribute. It's allocation is done by `TNaming_Builder` tool like this:

Code:
TNaming_Builder NB(yourLabel);
NB.Generated(yourShape);
Can I understand it this way?
In different documents, TDocStd_XLinkTool can only copy the root label. Copying sub-label is difficult to ensure a correct tree structure.
 

Quaoar

Administrator
Staff member
To be honest, I have never used XLinkTool. But it kinda makes perfect sense that you link one self-consistent document to another, and not refer to any individual components (sublabels, etc).

As a side note, what also makes a lot of sense is to invest a bit of time in understanding the internal logic behind XDE structure. Then you'll get the luxury of applying direct OCAF manipulations without worrying about breaking subtle things.
 

frankpian

CAD practitioner
@Quaoar
When I saw this posting, I was excited at first. I have the same requirement as guyj8, we try to take a complex multi-layer nested step assembly and copy it into another file as a component. I thought OCCT should have an easy way to do this. But it doesn't look that way.
I've gotten lost between traversing assemblies and references layer by layer.(×_×)
 
Top