step file conversion obj example

I wrote a demo according to WriteObj function. But it exits at RWObj_CafWriter.Perform() No errors are indicated.

#include <TDocStd_Document.hxx>
#include <TDocStd_Application.hxx>
#include <DDocStd.hxx>
#include <STEPCAFControl_Reader.hxx>
#include <TColStd_IndexedDataMapOfStringString.hxx>
#include <RWMesh_CoordinateSystem.hxx>
#include <UnitsMethods.hxx>
#include <RWObj_CafWriter.hxx>
#include <Message_ProgressIndicator.hxx>

int main()
{
    Handle(TDocStd_Document) aDoc;
    Handle(TDocStd_Application) anApp = DDocStd::GetApplication();
    TColStd_IndexedDataMapOfStringString aFileInfo;
    Standard_Real aFileUnitFactor = 1.0;
    RWMesh_CoordinateSystem aSystemCoordSys = RWMesh_CoordinateSystem_Zup, aFileCoordSys = RWMesh_CoordinateSystem_Yup;
    Handle(Message_ProgressIndicator) progress = Handle(Message_ProgressIndicator)();

    anApp->NewDocument(TCollection_ExtendedString("BinXCAF"), aDoc);
    STEPCAFControl_Reader theStepReader;
    theStepReader.SetColorMode(true);
    theStepReader.SetNameMode(true);
    IFSelect_ReturnStatus status = theStepReader.ReadFile("test.step");
    if (status != IFSelect_RetDone) {
        std::cout << "read step fail" << std::endl;
        std::cout << status << std::endl;
        return 1;
    }
    if (theStepReader.Transfer(aDoc)) {
        std::cout << "Transfer sccuess" << std::endl;
    }
    else {
        std::cout << "Transfer fail" << std::endl;
        return 1;
    }

    aFileInfo.Add("Author", "frank");

    const Standard_Real aSystemUnitFactor = UnitsMethods::GetCasCadeLengthUnit() * 0.001;
    RWObj_CafWriter aWriter(TCollection_AsciiString("test.obj"));
    aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit(aSystemUnitFactor);
    aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(aSystemCoordSys);
    aWriter.ChangeCoordinateSystemConverter().SetOutputLengthUnit(aFileUnitFactor);
    aWriter.ChangeCoordinateSystemConverter().SetOutputCoordinateSystem(aFileCoordSys);
    aWriter.Perform(aDoc, aFileInfo, progress->Start());

    std::cout << "complete" << std::endl;
    return 0;
}
Dmitrii Pasukhin's picture

Hello.

Obj writer work only with Mesh. That is why you need to create mesh for imported document. Step format work with BRep and Mesh. I think only BRep exists in your file.

For more detailed help, tell me which version or branch of OCCT you are using. Additionally, please attach the STEP file.

To update a document to create a mesh you can use:

  TDF_LabelSequence aRootLabels;
  myDoc.ShapeTool()->GetFreeShapes (aRootLabels);

  TopoDS_Compound aCompound;
  BRep_Builder    aBuildTool;
  aBuildTool.MakeCompound (aCompound);
  for (TDF_LabelSequence::Iterator aLabIter (aRootLabels); aLabIter.More(); aLabIter.Next())
  {
    TopoDS_Shape     aShape;
    const TDF_Label& aLabel = aLabIter.Value();
    if (XCAFDoc_ShapeTool::GetShape (aLabel, aShape))
    {
      aBuildTool.Add (aCompound, aShape);
    }
  }

  Bnd_Box aBndBox;
  BRepBndLib::Add (aCompound, aBndBox, Standard_False);
  if (aBndBox.IsVoid())
  {
    return false;
  }

  NCollection_Vec3<double> aMin, aMax;
  aBndBox.Get (aMin.x(), aMin.y(), aMin.z(), aMax.x(), aMax.y(), aMax.z());
  const NCollection_Vec3<double> aBndDelta = aMax - aMin;

  BRepMesh_IncrementalMesh anAlgo;
  anAlgo.ChangeParameters().Deflection = aBndDelta.maxComp() * myLinearDeflection * 4.0;
  anAlgo.ChangeParameters().Angle      = myAngularDeflection;
  anAlgo.ChangeParameters().InParallel = Standard_True;
  anAlgo.SetShape (aCompound);
  anAlgo.Perform();

Best regards,

Dmitrii.

frank pian's picture

Thank you for reply!

Dmitrii Pasukhin's picture

Hello,

In this case we need more information.

Please attache a step file or created .xbf document. You can save your document using next code:

anApp->SaveAs(aDoc, "D:/test.xbf);

Best regards,

Dmitrii.

frank pian's picture

Thanks.
I have solved it. It's my fault.

Arman Rashoyan's picture

Hello Dear Frank, how did you manage to do it, I have the same problem. Can you share your experience?

Dmitrii Pasukhin's picture

Hello, can you describe your problem?

Best regards, Dmitrii.

Arman Rashoyan's picture

Thanks for the reply Dmitrii.
I want to convert STEP to OBJ and when I try to do
aWriter.Perform(aDoc, aFileInfo, progress->Start())
Return "No mesh data to save."

Dmitrii Pasukhin's picture

Please check my first response on this topic with code sample.

Do you do the same? Before writing you need to generate mesh to write. You can use commercial EMesh or public IncrementalMesh

Best regards, Dmitrii.

Arman Rashoyan's picture

I do as you described, I use BRepMesh_IncrementalMesh while creating a STEP file, after which I use
const writer = new oc.STEPControl_Writer();
writer.Transfer()
writer.Write("test.step" )
then I use
const theStepReader = new oc.STEPCAFControl_Reader();
theStepReader.Transfer(aDoc);
then I create aWriter
const aWriter = new oc.RWObj_CafWriter(fileName);
aWriter.Perform(aDoc, aFileInfo);

I have only presented here the main steps that I take.

Dmitrii Pasukhin's picture

To export to the STEP format you don't need to make tessellation.

You need to call BRepMesh_IncrementalMesh before export to Obj. You need to tesslated result of STEPCAFControl_Reader.

Best regards, Dmitrii.

Arman Rashoyan's picture

I got it all. Thanks a lot

Thien Vu Van's picture
Handle(TDocStd_Document) aDoc;
    
Handle(TDocStd_Application) anApp = DDocStd::GetApplication();
anApp->NewDocument(TCollection_ExtendedString("BinXCAF"), aDoc);
STEPCAFControl_Reader theStepReader;
    theStepReader.SetColorMode(true);
    theStepReader.SetNameMode(true);
    IFSelect_ReturnStatus status = theStepReader.ReadFile(theFileName.ToCString());
if (status == IFSelect_RetDone )
    {
      bool isFailsonly = false;
      //aReader.PrintCheckLoad( isFailsonly, IFSelect_ItemsByEntity );

      //int aNbRoot = aReader.NbRootsForTransfer();
      //aReader.PrintCheckTransfer( isFailsonly, IFSelect_ItemsByEntity );

      //aReader.TransferEntity(aDoc);

      theStepReader.Transfer(aDoc);

      TDF_LabelSequence aRootLabels;
      Handle(XCAFDoc_ShapeTool) Assembly = XCAFDoc_DocumentTool::ShapeTool(aDoc->Main());
      //myDoc->ShapeTool()->GetFreeShapes(aRootLabels);
      
      Assembly->GetFreeShapes(aRootLabels);

      TopoDS_Compound aCompound;
      BRep_Builder    aBuildTool;
      aBuildTool.MakeCompound(aCompound);
      for (TDF_LabelSequence::Iterator aLabIter(aRootLabels); aLabIter.More(); aLabIter.Next())
      {
          TopoDS_Shape     aShape;
          const TDF_Label& aLabel = aLabIter.Value();
          if (XCAFDoc_ShapeTool::GetShape(aLabel, aShape))
          {
              BRepMesh_IncrementalMesh(aShape, 0.01).Perform();
              //aBuildTool.Add(aCompound, aShape);
          }
      }

Standard_Real aFileUnitFactor = 1.0;
      RWMesh_CoordinateSystem aSystemCoordSys = RWMesh_CoordinateSystem_Zup, aFileCoordSys = RWMesh_CoordinateSystem_Yup;
      Handle(Message_ProgressIndicator) progress = Handle(Message_ProgressIndicator)();

      TColStd_IndexedDataMapOfStringString aFileInfo;



      aFileInfo.Add("Author", "sky");
      const Standard_Real aSystemUnitFactor = UnitsMethods::GetCasCadeLengthUnit() * 0.001;
      RWObj_CafWriter aWriter(TCollection_AsciiString("test.obj"));
      aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit(aSystemUnitFactor);
      aWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(aSystemCoordSys);
      aWriter.ChangeCoordinateSystemConverter().SetOutputLengthUnit(aFileUnitFactor);
      aWriter.ChangeCoordinateSystemConverter().SetOutputCoordinateSystem(aFileCoordSys);
      aWriter.Perform(aDoc, aFileInfo, progress->Start());

I am working on 7.7.0 version. And my application is crash  at aWrite.Perform(). Please review and lets me know my fault.

Thanks!

Dmitrii Pasukhin's picture

I found out only one problem - creating  null handle of progress. Default constructore create NULL object, null object don't be able to have ->Start() method.

You need to use operator new for creating "Handle" objects.

>> Handle(Message_ProgressIndicator) progress = Handle(Message_ProgressIndicator)();

Best regards, Dmitrii.

Thien Vu Van's picture

Thanks Dmitrii,

My source code exited this constructor (my code is not clean so it hard reviewing a bit). I have compared very carefully your suggestions code but I did not find what I was missing.

RWMesh_CoordinateSystem aSystemCoordSys = RWMesh_CoordinateSystem_Zup, aFileCoordSys = RWMesh_CoordinateSystem_Yup;

Handle(Message_ProgressIndicator) progress = Handle(Message_ProgressIndicator)();

TColStd_IndexedDataMapOfStringString aFileInfo;

Please lets me know if you have any comment to help me resolve this issue.

Thanks.

Dmitrii Pasukhin's picture

I don't give you any code. I just spot the error.

You need to use "new" to create a Handle.

Handle(Message_ProgressIndicator) progress = new Message_ProgressIndicator();

Best regards, Dmitrii.

Thien Vu Van's picture

Thanks Dmitrii,

Sorry I don't understand your meaning correctly.
I have tried your suggestion, but I see Message_ProgressIndicator constructor is protected.
Please lets me know if you have any information.
BTW,I am concerning about my function is written in CLI/C++ class. I wrapper source code to use in C# project.

Thanks.

Dmitrii Pasukhin's picture

Oh, Sorry, Which version do you use?

bool RWObj_CafWriter::Perform (const Handle(TDocStd_Document)& theDocument,
                               const TColStd_IndexedDataMapOfStringString& theFileInfo,
                               const Message_ProgressRange& theProgress)

the last parameter as a stack object. You need to create a default object by default constructor. Why do you use Handle?

If you don't want to use progress indicator you should use the next code:

aWriter.Perform(aDoc, aFileInfo, Message_ProgressRange());

Best regards, Dmitrii.

Thien Vu Van's picture

Thanks Dmitrii, I change source as your suggestion

Message_ProgressRange theProgress;
aWriter.Perform(aDoc, aFileInfo, theProgress);

Then it worked.  I am working on 7.7.0 version

Why do you use Handle?

I have newbie with this platform so I copied source code from other guy to check result first.

BTW, As I know after export to Obj then we have got two files : one is *.obj and other is .mtl (material). But I see my result just only one file.

Please lets me know if you have comment for this one.

Thanks.

Dmitrii Pasukhin's picture

Creating of ".mtl" file calls only if one or more of your faces have FaceColour or (Material AND UV-points)

Best regards, Dmitrii.

gkv311 n's picture

Thien Vu Van wrote:

BTW, As I know after export to Obj then we have got two files : one is *.obj and other is .mtl (material). But I see my result just only one file.

Material file is created when document has materials / colors assigned to shapes. Try this workflow on a STEP file that defines some colors.

Thien Vu Van's picture

Thanks gkv311 and Dmitrii,

Today, I have tried new challenge is load Step file by Unity directory (don't via *.obj file).
I have read and known Unity3D rendering base on the Mesh that includes Vertex and Normal and triangles.
So, I have tried use the above way to read Step file then looking for way to get above information then put to Unity.
However, I didn't see any sample code to get Vertex and Normal and triangles information from step file.
Please lets me know if you have any information about this one!
Thanks.

Dmitrii Pasukhin's picture

From step file directly it is complex with just OCCT. But you be able to exctact Poly_Triangulation from TopoDS_Face as a part of OCCT model imported from STEP file.

There a lot of samples for that. You can look into, for example, RWObj_Writer to understand how to work with mesh from OCCT data model.

Best regards, Dmitrii.