0029296: Data Exchange - implement import of mesh data from files in OBJ format
[occt.git] / src / RWObj / RWObj_TriangulationReader.cxx
diff --git a/src/RWObj/RWObj_TriangulationReader.cxx b/src/RWObj/RWObj_TriangulationReader.cxx
new file mode 100644 (file)
index 0000000..1c4b703
--- /dev/null
@@ -0,0 +1,223 @@
+// Author: Kirill Gavrilov
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <RWObj_TriangulationReader.hxx>
+
+#include <BRep_Builder.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Iterator.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(RWObj_TriangulationReader, RWObj_Reader)
+
+//================================================================
+// Function : addMesh
+// Purpose  :
+//================================================================
+Standard_Boolean RWObj_TriangulationReader::addMesh (const RWObj_SubMesh& theMesh,
+                                                     const RWObj_SubMeshReason theReason)
+{
+  if (!myToCreateShapes)
+  {
+    return Standard_False;
+  }
+
+  const RWObj_Material* aMaterial = myMaterials.Seek (theMesh.Material);
+  if (Handle(Poly_Triangulation) aTris = GetTriangulation())
+  {
+    myNodes.Clear();
+    myNodesUV.Clear();
+    myNormals.Clear();
+    myTriangles.Clear();
+    if (theMesh.Group != myLastGroupName)
+    {
+      // flush previous group and start a new one
+      if (addSubShape (myLastObjectShape, myLastGroupShape, Standard_False))
+      {
+        if (myShapeReceiver != NULL)
+        {
+          myShapeReceiver->BindNamedShape (myLastGroupShape, theMesh.Group, myLastGroupShape.ShapeType() == TopAbs_FACE ? aMaterial : NULL, Standard_False);
+        }
+      }
+      myLastGroupShape = TopoDS_Shape();
+      myLastGroupName = theMesh.Group;
+    }
+
+    TopoDS_Face aNewFace;
+    BRep_Builder aBuilder;
+    aBuilder.MakeFace (aNewFace, aTris);
+    addSubShape (myLastGroupShape, aNewFace, Standard_True);
+    if (myShapeReceiver != NULL)
+    {
+      myShapeReceiver->BindNamedShape (aNewFace, "", aMaterial, Standard_False);
+    }
+  }
+
+  if (theReason == RWObj_SubMeshReason_NewObject)
+  {
+    // forced flush at the end of the object
+    if (addSubShape (myLastObjectShape, myLastGroupShape, Standard_False))
+    {
+      if (myShapeReceiver != NULL)
+      {
+        myShapeReceiver->BindNamedShape (myLastGroupShape, theMesh.Group, myLastGroupShape.ShapeType() == TopAbs_FACE ? aMaterial : NULL, Standard_False);
+      }
+    }
+    myLastGroupShape = TopoDS_Shape();
+    myLastGroupName.Clear();
+
+    if (addSubShape (myResultShape, myLastObjectShape, Standard_False))
+    {
+      if (myShapeReceiver != NULL)
+      {
+        myShapeReceiver->BindNamedShape (myLastObjectShape, theMesh.Object, NULL, Standard_True);
+      }
+    }
+    myLastObjectShape = TopoDS_Compound();
+  }
+  return Standard_True;
+}
+
+// =======================================================================
+// function : addSubShape
+// purpose  :
+// =======================================================================
+Standard_Boolean RWObj_TriangulationReader::addSubShape (TopoDS_Shape& theParent,
+                                                         const TopoDS_Shape& theSubShape,
+                                                         const Standard_Boolean theToExpandCompound)
+{
+  if (theSubShape.IsNull())
+  {
+    return Standard_False;
+  }
+
+  BRep_Builder aBuilder;
+  if (theParent.IsNull()
+   && theToExpandCompound)
+  {
+    theParent = theSubShape;
+    return Standard_True;
+  }
+
+  TopoDS_Compound aComp;
+  if (!theParent.IsNull()
+    && theParent.ShapeType() == TopAbs_COMPOUND)
+  {
+    aComp = TopoDS::Compound (theParent);
+  }
+  else
+  {
+    aBuilder.MakeCompound (aComp);
+    if (!theParent.IsNull())
+    {
+      aBuilder.Add (aComp, theParent);
+    }
+  }
+  aBuilder.Add (aComp, theSubShape);
+  theParent = aComp;
+  return Standard_True;
+}
+
+//=============================================================================
+//function : GetTriangulation
+//purpose  :
+//=============================================================================
+Handle(Poly_Triangulation) RWObj_TriangulationReader::GetTriangulation()
+{
+  if (myTriangles.IsEmpty())
+  {
+    return Handle(Poly_Triangulation)();
+  }
+
+  const Standard_Boolean hasNormals = myNodes.Length() == myNormals.Length();
+  const Standard_Boolean hasUV      = myNodes.Length() == myNodesUV.Length();
+
+  Handle(Poly_Triangulation) aPoly = new Poly_Triangulation (myNodes.Length(), myTriangles.Length(), hasUV);
+  for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter)
+  {
+    const gp_Pnt& aNode = myNodes.Value (aNodeIter);
+    aPoly->ChangeNode (aNodeIter + 1) = aNode;
+  }
+  if (hasUV)
+  {
+    for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter)
+    {
+      const Graphic3d_Vec2& aNode = myNodesUV.Value (aNodeIter);
+      aPoly->ChangeUVNode (aNodeIter + 1).SetCoord (aNode.x(), aNode.y());
+    }
+  }
+  if (hasNormals)
+  {
+    const Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, myNodes.Length() * 3);
+    Standard_ShortReal* aNormArr = &aNormals->ChangeFirst();
+    Standard_Integer aNbInvalid = 0;
+    for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter)
+    {
+      const Graphic3d_Vec3& aNorm = myNormals.Value (aNodeIter);
+      const float aMod2 = aNorm.SquareModulus();
+      if (aMod2 > 0.001f)
+      {
+        aNormArr[aNodeIter * 3 + 0] = aNorm.x();
+        aNormArr[aNodeIter * 3 + 1] = aNorm.y();
+        aNormArr[aNodeIter * 3 + 2] = aNorm.z();
+      }
+      else
+      {
+        ++aNbInvalid;
+        aNormArr[aNodeIter * 3 + 0] = 0.0f;
+        aNormArr[aNodeIter * 3 + 1] = 0.0f;
+        aNormArr[aNodeIter * 3 + 2] = 1.0f;
+      }
+    }
+    if (aNbInvalid != myNodes.Length())
+    {
+      aPoly->SetNormals (aNormals);
+    }
+  }
+
+  for (Standard_Integer aTriIter = 0; aTriIter < myTriangles.Size(); ++aTriIter)
+  {
+    aPoly->ChangeTriangle (aTriIter + 1) = myTriangles (aTriIter);
+  }
+
+  return aPoly;
+}
+
+//================================================================
+// Function : ResultShape
+// Purpose  :
+//================================================================
+TopoDS_Shape RWObj_TriangulationReader::ResultShape()
+{
+  if (!myToCreateShapes)
+  {
+    if (Handle(Poly_Triangulation) aTris = GetTriangulation())
+    {
+      TopoDS_Face aFace;
+      BRep_Builder aBuilder;
+      aBuilder.MakeFace (aFace, aTris);
+      return aFace;
+    }
+    return TopoDS_Shape();
+  }
+
+  if (!myResultShape.IsNull()
+    && myResultShape.ShapeType() == TopAbs_COMPOUND
+    && myResultShape.NbChildren() == 1
+    && myActiveSubMesh.Object.IsEmpty())
+  {
+    TopoDS_Iterator aChildIter (myResultShape);
+    return aChildIter.Value();
+  }
+  return myResultShape;
+}