]> OCCT Git - occt.git/commitdiff
0030421: Data Exchange - Standard_RangeError exception while reading VRML files with...
authorskl <skl@opencascade.com>
Fri, 6 Nov 2020 08:16:22 +0000 (11:16 +0300)
committerbugmaster <bugmaster@opencascade.com>
Sat, 21 Nov 2020 09:19:43 +0000 (12:19 +0300)
Import of arbitrary polygon is implemented in VrmlData_IndexedFaceSet.
Class IFCCAFControl_Triangulator has been moved to BRepMesh_Triangulator.
New Draw test /bugs/stlvrml/bug30421 is added.

src/BRepMesh/BRepMesh_Triangulator.cxx [new file with mode: 0644]
src/BRepMesh/BRepMesh_Triangulator.hxx [new file with mode: 0644]
src/BRepMesh/FILES
src/VrmlData/VrmlData_IndexedFaceSet.cxx
src/VrmlData/VrmlData_Scene.cxx
tests/bugs/stlvrml/bug30421 [new file with mode: 0644]

diff --git a/src/BRepMesh/BRepMesh_Triangulator.cxx b/src/BRepMesh/BRepMesh_Triangulator.cxx
new file mode 100644 (file)
index 0000000..7d84feb
--- /dev/null
@@ -0,0 +1,284 @@
+// Created: 2017-12-28
+// 
+// Copyright (c) 2017 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 <BRepMesh_Triangulator.hxx>
+#include <Precision.hxx>
+#include <ProjLib.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <BRepMesh_Delaun.hxx>
+
+#ifdef CHECK_PERF
+#include <MoniTool_Timer.hxx>
+#include <MoniTool_TimerSentry.hxx>
+#endif
+
+namespace
+{
+  //=======================================================================
+  //function : wireNodesNb
+  //purpose  : 
+  //=======================================================================
+  inline Standard_Integer wireNodesNb (const NCollection_List<TColStd_SequenceOfInteger>& theWires)
+  {
+    Standard_Integer nbNodes = 0;
+    NCollection_List<TColStd_SequenceOfInteger>::Iterator itW(theWires);
+    for (Standard_Integer i = 1; itW.More(); itW.Next(), i++)
+    {
+      nbNodes += itW.Value().Length();
+    }
+
+    return nbNodes;
+  }
+
+  //=======================================================================
+  //function : appendTriangle
+  //purpose  : 
+  //=======================================================================
+  inline void appendTriangle (const int theNode1, const int theNode2, const int theNode3,
+                              const TColStd_SequenceOfInteger& theW,
+                              NCollection_List<Poly_Triangle>& thePolyTriangles)
+  {
+    const Poly_Triangle aT1(theW(theNode1) + 1, theW(theNode2) + 1, theW(theNode3) + 1);
+    thePolyTriangles.Append(aT1);
+  }
+}
+
+//=======================================================================
+//function : ToPolyTriangulation
+//purpose  : 
+//=======================================================================
+Handle(Poly_Triangulation) BRepMesh_Triangulator::ToPolyTriangulation (
+  const TColgp_Array1OfPnt&              theNodes,
+  const NCollection_List<Poly_Triangle>& thePolyTriangles)
+{
+  Poly_Array1OfTriangle aTriangles (1, thePolyTriangles.Extent());
+  NCollection_List<Poly_Triangle>::Iterator itT(thePolyTriangles);
+  for (Standard_Integer i = 1; itT.More(); itT.Next(), i++)
+  {
+    aTriangles.SetValue(i, itT.Value());
+  }
+
+  return new Poly_Triangulation(theNodes, aTriangles);
+}
+
+//=======================================================================
+//function : Constructor
+//purpose  : 
+//=======================================================================
+BRepMesh_Triangulator::BRepMesh_Triangulator (
+    const NCollection_Vector<gp_XYZ>&                  theXYZs,
+    const NCollection_List<TColStd_SequenceOfInteger>& theWires,
+    const gp_Dir&                                      theNorm)
+  : myXYZs  (theXYZs)
+  , myWires (theWires)
+  , myPlane (gp::Origin (), theNorm)
+{
+}
+
+//=======================================================================
+//function : Perform
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepMesh_Triangulator::Perform (NCollection_List<Poly_Triangle>& thePolyTriangles)
+{
+#ifdef CHECK_PERF
+  MoniTool_TimerSentry MTS01("BRepMesh_Triangulator::Perform");
+#endif
+
+  if (myMess.IsNull())
+  {
+    myMess = Message::DefaultMessenger();
+  }
+
+  if (myWires.Extent() == 1)
+  {
+    const TColStd_SequenceOfInteger& aTmpWire = myWires.First();
+    if (aTmpWire.Length() < 5)
+    {
+      // prepare triangles from simple wire (3 or 4 points)
+      addTriange34(aTmpWire, thePolyTriangles);
+      return Standard_True;
+    }
+  }
+
+  if (!prepareMeshStructure ())
+  {
+    return Standard_False;
+  }
+
+  if (!triangulate (thePolyTriangles))
+  {
+    return Standard_False;
+  }
+
+#ifdef CHECK_PERF
+  MTS01.Stop();
+#endif
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : addTriange34
+//purpose  : auxilary for makeTrianglesUsingBRepMesh
+//=======================================================================
+void BRepMesh_Triangulator::addTriange34(
+  const TColStd_SequenceOfInteger&  theW,
+  NCollection_List<Poly_Triangle>&  thePolyTriangles)
+{
+  // prepare triangles from simple wire (3 or 4 points)
+  if (theW.Length() == 3)
+  {
+    Poly_Triangle aT(theW(1) + 1, theW(2) + 1, theW(3) + 1);
+    thePolyTriangles.Append(aT);
+  }
+  else if (theW.Length() == 4)
+  {
+    Standard_Real d13 = (myXYZs.Value(theW(1)) - myXYZs.Value(theW(3))).SquareModulus();
+    Standard_Real d24 = (myXYZs.Value(theW(2)) - myXYZs.Value(theW(4))).SquareModulus();
+    Standard_Boolean use13 = Standard_True;
+    if (d24 < d13)
+    {
+      // additional check for inner corner
+      static int aPivotNodes[4] = { 2, 4, 1, 3 };
+      use13 =  checkCondition (aPivotNodes, theW);
+    }
+    else
+    {
+      static int aPivotNodes[4] = { 1, 3, 2, 4 };
+      use13 = !checkCondition (aPivotNodes, theW);
+    }
+
+    if (use13)
+    {
+      appendTriangle (1, 2, 3, theW, thePolyTriangles);
+      appendTriangle (3, 4, 1, theW, thePolyTriangles);
+    }
+    else
+    {
+      appendTriangle (1, 2, 4, theW, thePolyTriangles);
+      appendTriangle (2, 3, 4, theW, thePolyTriangles);
+    }
+  }
+}
+
+//=======================================================================
+//function : checkCondition
+//purpose  : auxilary for addTriange34
+//=======================================================================
+Standard_Boolean BRepMesh_Triangulator::checkCondition(
+  const int                       (&theNodes)[4],
+  const TColStd_SequenceOfInteger&  theW)
+{
+  const gp_XYZ aV0 = myXYZs.Value(theW(theNodes[1])) - myXYZs.Value(theW(theNodes[0]));
+  const gp_XYZ aV1 = myXYZs.Value(theW(theNodes[2])) - myXYZs.Value(theW(theNodes[0]));
+  const gp_XYZ aV2 = myXYZs.Value(theW(theNodes[3])) - myXYZs.Value(theW(theNodes[0]));
+
+  const gp_XYZ aCross1 = aV0.Crossed(aV1);
+  const gp_XYZ aCross2 = aV0.Crossed(aV2);
+  return (aCross1.SquareModulus() < Precision::SquareConfusion() ||
+          aCross2.SquareModulus() < Precision::SquareConfusion() ||
+          gp_Dir(aCross1).IsEqual(gp_Dir(aCross2), 0.01));
+}
+
+//=======================================================================
+//function : prepareMeshStructure
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepMesh_Triangulator::prepareMeshStructure ()
+{
+  myIndices = new IMeshData::VectorOfInteger (wireNodesNb(myWires));
+  myMeshStructure = new BRepMesh_DataStructureOfDelaun (new NCollection_IncAllocator);
+
+  // fill this structure created BRepMesh_Vertexes using 2d points recieved
+  // by projection initial 3d point on plane.
+  try
+  {
+    Standard_Integer aNumNode = 0;
+    NCollection_List<TColStd_SequenceOfInteger>::Iterator itW(myWires);
+    for (Standard_Integer i = 1; itW.More(); itW.Next(), i++)
+    {
+      const TColStd_SequenceOfInteger& aW = itW.Value();
+      for (Standard_Integer nn = 1; nn <= aW.Length(); ++nn, ++aNumNode)
+      {
+        const gp_Pnt2d aP2d = ProjLib::Project(myPlane, gp_Pnt(myXYZs(aW(nn))));
+        const BRepMesh_Vertex aVertex(aP2d.XY(), aNumNode, BRepMesh_Frontier);
+        const Standard_Integer nnn = myMeshStructure->AddNode(aVertex);
+        myIndices->SetValue(aNumNode, nnn);
+        myTmpMap.Bind(aNumNode + 1, aW(nn) + 1);
+      }
+
+      const Standard_Integer aOffset = aNumNode - aW.Length ();
+      for (Standard_Integer nn = 1; nn <= aW.Length (); ++nn)
+      {
+        const BRepMesh_Edge anEdge(myIndices->Value(aOffset + (nn - 1)),
+                                   myIndices->Value(aOffset + (nn % aW.Length ())), BRepMesh_Frontier);
+        myMeshStructure->AddLink(anEdge);
+      }
+    }
+  }
+  catch (...)
+  {
+    myMess->Send("makeTrianglesUsingBRepMesh: Exception raised during filling of BRepMesh_DataStructureOfDelaun", Message_Fail);
+    return Standard_False;
+  }
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : triangulate
+//purpose  : auxilary
+//=======================================================================
+Standard_Boolean BRepMesh_Triangulator::triangulate (NCollection_List<Poly_Triangle>& thePolyTriangles)
+{
+  try
+  {
+    // perform triangulation used created aMeshStructure
+    BRepMesh_Delaun aTriangulation(myMeshStructure, *myIndices);
+    const IMeshData::MapOfInteger& aTriangles = myMeshStructure->ElementsOfDomain();
+    if (aTriangles.Extent() < 1)
+    {
+      return Standard_False;
+    }
+
+    // prepare Poly_Triangles from result triangles and add to returned list
+    for (IMeshData::IteratorOfMapOfInteger aTriIter(aTriangles); aTriIter.More(); aTriIter.Next())
+    {
+      const Standard_Integer aTriangleId = aTriIter.Key();
+      const BRepMesh_Triangle& aTriangle = myMeshStructure->GetElement(aTriangleId);
+      if (aTriangle.Movability() == BRepMesh_Deleted)
+      {
+        continue;
+      }
+      Standard_Integer aTri2d[3];
+      myMeshStructure->ElementNodes(aTriangle, aTri2d);
+
+      const Poly_Triangle aT(myTmpMap.Find(aTri2d[0]), myTmpMap.Find(aTri2d[1]), myTmpMap.Find(aTri2d[2]));
+      thePolyTriangles.Append(aT);
+    }
+  }
+  catch (Standard_Failure const& aFailure)
+  {
+    TCollection_AsciiString aStr("makeTrianglesUsingBRepMesh: Exception raised during polygon triangulation: ");
+    aStr.AssignCat(aFailure.GetMessageString());
+    myMess->Send(aStr.ToCString(), Message_Fail);
+    return Standard_False;
+  }
+
+  return Standard_True;
+}
diff --git a/src/BRepMesh/BRepMesh_Triangulator.hxx b/src/BRepMesh/BRepMesh_Triangulator.hxx
new file mode 100644 (file)
index 0000000..ad56df3
--- /dev/null
@@ -0,0 +1,96 @@
+// Created: 2017-12-28 
+// 
+// Copyright (c) 2017 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.
+
+#ifndef _BRepMesh_Triangulator_HeaderFile
+#define _BRepMesh_Triangulator_HeaderFile
+
+#include <gp_XYZ.hxx>
+#include <gp_Dir.hxx>
+#include <gp_Pln.hxx>
+#include <Poly_Triangle.hxx>
+#include <Poly_Triangulation.hxx>
+#include <IMeshData_Types.hxx>
+#include <NCollection_Vector.hxx>
+#include <NCollection_List.hxx>
+#include <NCollection_Shared.hxx>
+#include <TColStd_SequenceOfInteger.hxx>
+#include <TColStd_DataMapOfIntegerInteger.hxx>
+#include <BRepMesh_DataStructureOfDelaun.hxx>
+
+class Message_Messenger;
+
+//! Auxilary tool to generate triangulation
+class BRepMesh_Triangulator
+{
+public:
+
+  DEFINE_STANDARD_ALLOC
+
+  //! Performs conversion of the given list of triangles to Poly_Triangulation.
+  Standard_EXPORT static Handle(Poly_Triangulation) ToPolyTriangulation(
+    const TColgp_Array1OfPnt&              theNodes,
+    const NCollection_List<Poly_Triangle>& thePolyTriangles);
+
+public:
+
+  //! Constructor. Initialized tool by the given parameters.
+  Standard_EXPORT BRepMesh_Triangulator (
+    const NCollection_Vector<gp_XYZ>&                  theXYZs,
+    const NCollection_List<TColStd_SequenceOfInteger>& theWires,
+    const gp_Dir&                                      theNorm);
+
+  //! Perfroms triangulation of source wires and stores triangles the the output list.
+  Standard_EXPORT Standard_Boolean Perform (NCollection_List<Poly_Triangle>& thePolyTriangles);
+
+  //! Set messenger for output information
+  //! without this Message::DefaultMessenger() will be used
+  void SetMessenger(const Handle(Message_Messenger)& theMess)
+  {
+    myMess = theMess;
+  }
+
+  BRepMesh_Triangulator& operator =(const BRepMesh_Triangulator& theOther);
+
+private:
+
+  // auxilary for makeTrianglesUsingBRepMesh
+  void addTriange34 (
+    const TColStd_SequenceOfInteger&  theW,
+    NCollection_List<Poly_Triangle>&  thePolyTriangles);
+
+  // auxilary for addTriange34
+  Standard_Boolean checkCondition(
+    const int                       (&theNodes)[4],
+    const TColStd_SequenceOfInteger&  theWire);
+
+  // performs initialization of mesh data structure.
+  Standard_Boolean prepareMeshStructure();
+
+  // auxilary for triangulation
+  Standard_Boolean triangulate (NCollection_List<Poly_Triangle>& thePolyTriangles);
+
+private:
+
+  const NCollection_Vector<gp_XYZ>&                  myXYZs;
+  const NCollection_List<TColStd_SequenceOfInteger>& myWires;
+  gp_Pln                                             myPlane;
+  Handle(Message_Messenger)                          myMess;
+
+  Handle(BRepMesh_DataStructureOfDelaun)             myMeshStructure;
+  TColStd_DataMapOfIntegerInteger                    myTmpMap;
+  Handle(IMeshData::VectorOfInteger)                 myIndices;
+};
+
+#endif // _BRepMesh_Triangulator_HeaderFile
index 90df7c410b002b10eb30068ec21942ac43aedef6..d1d2fa3511ff4a65780b840c390ed104793b517e 100755 (executable)
@@ -94,3 +94,5 @@ BRepMesh_DelabellaBaseMeshAlgo.hxx
 BRepMesh_DelabellaBaseMeshAlgo.cxx
 BRepMesh_DelabellaMeshAlgoFactory.hxx
 BRepMesh_DelabellaMeshAlgoFactory.cxx
+BRepMesh_Triangulator.cxx
+BRepMesh_Triangulator.hxx
index 0e5f8c4fe8358e58b1cacf2f05814c1d7f734343..a513281edb02761fcb38d4e0fe06b975630c1c8c 100644 (file)
@@ -18,6 +18,7 @@
 #include <VrmlData_UnknownNode.hxx>
 #include <Poly_Triangulation.hxx>
 #include <BRep_TFace.hxx>
+#include <BRepMesh_Triangulator.hxx>
 #include <VrmlData_Coordinate.hxx>
 #include <VrmlData_Color.hxx>
 #include <VrmlData_Normal.hxx>
@@ -28,6 +29,8 @@
 #include <NCollection_DataMap.hxx>
 #include <Poly.hxx>
 #include <TShort_HArray1OfShortReal.hxx>
+#include <TColgp_SequenceOfXYZ.hxx>
+#include <TColStd_SequenceOfInteger.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(VrmlData_IndexedFaceSet,VrmlData_Faceted)
 
@@ -78,138 +81,198 @@ VrmlData_ErrorStatus VrmlData_Faceted::readData (VrmlData_InBuffer& theBuffer)
 const Handle(TopoDS_TShape)& VrmlData_IndexedFaceSet::TShape ()
 {
   if (myNbPolygons == 0)
+  {
     myTShape.Nullify();
-  else if (myIsModified) {
-    // Create an empty topological Face
-    const gp_XYZ * arrNodes = myCoords->Values();
-    Standard_Integer i, nTri(0);
-
-    NCollection_DataMap <int, int> mapNodeId;
-
-    // Count non-degenerated triangles
-    const int nNodes = (int)myCoords->Length();
-    for (i = 0; i < (int)myNbPolygons; i++) {
-      const Standard_Integer * arrIndice;
-      if (Polygon(i, arrIndice) == 3) {
-        //Check indices for out of bound
-        if (arrIndice[0] < 0 ||
-            arrIndice[0] >= nNodes ||
-            arrIndice[1] >= nNodes ||
-            arrIndice[2] >= nNodes)
-        {
-            continue;
-        }
-        const gp_XYZ aVec[2] = {
-          arrNodes[arrIndice[1]] - arrNodes[arrIndice[0]],
-          arrNodes[arrIndice[2]] - arrNodes[arrIndice[0]]
-        };
-        if ((aVec[0] ^ aVec[1]).SquareModulus() >
-            Precision::SquareConfusion())
-          ++nTri;
-        else {
-          const_cast<Standard_Integer&> (arrIndice[0]) = -1;
-          continue;
-        }
+    return myTShape;
+  }
+  else if (!myIsModified) {
+    return myTShape;
+  }
+
+  // list of nodes:
+  const gp_XYZ * arrNodes = myCoords->Values();
+  const int nNodes = (int)myCoords->Length();
+
+  NCollection_Map <int> mapNodeId;
+  NCollection_Map <int> mapPolyId;
+  NCollection_List<TColStd_SequenceOfInteger> aPolygons;
+  NCollection_List<gp_Dir> aNorms;
+  Standard_Integer i = 0;
+  for (; i < (int)myNbPolygons; i++)
+  {
+    const Standard_Integer * arrIndice = myArrPolygons[i];
+    Standard_Integer nn = arrIndice[0];
+    if (nn < 3)
+    {
+      // bad polygon
+      continue;
+    }
+    TColStd_SequenceOfInteger aPolygon;
+    int in = 1;
+    for (; in <= nn; in++)
+    {
+      if (arrIndice[in] > nNodes)
+      {
+        break;
       }
-      if (mapNodeId.IsBound (arrIndice[0]) == Standard_False)
-        mapNodeId.Bind (arrIndice[0], 0);
-      if (mapNodeId.IsBound (arrIndice[1]) == Standard_False)
-        mapNodeId.Bind (arrIndice[1], 0);
-      if (mapNodeId.IsBound (arrIndice[2]) == Standard_False)
-        mapNodeId.Bind (arrIndice[2], 0);
+      aPolygon.Append(arrIndice[in]);
     }
-    const Standard_Integer nbNodes (mapNodeId.Extent());
-    if (!nbNodes)
+    if (in <= nn)
     {
-        myIsModified = Standard_False;
-        myTShape.Nullify();
-        return myTShape;
+      // bad index of node in polygon
+      continue;
     }
-
-    Handle(Poly_Triangulation) aTriangulation =
-      new Poly_Triangulation (nbNodes, nTri, Standard_False);
-    Handle(BRep_TFace) aFace = new BRep_TFace();
-    aFace->Triangulation (aTriangulation);
-    myTShape = aFace;
-
-    // Copy the triangulation vertices
-    TColgp_Array1OfPnt& aNodes = aTriangulation->ChangeNodes();
-    NCollection_DataMap <int, int>::Iterator anIterN(mapNodeId);
-    for (i = 1; anIterN.More(); anIterN.Next()) {
-      const int aKey = anIterN.Key();
-      const gp_XYZ& aNodePnt = arrNodes[aKey];
-      aNodes(i) = gp_Pnt (aNodePnt);
-      anIterN.ChangeValue() = i++;
+    // calculate normal
+    gp_XYZ aSum;
+    gp_XYZ aPrevP = arrNodes[aPolygon(1)];
+    for (in = 2; in < aPolygon.Length(); in++)
+    {
+      gp_XYZ aP1 = arrNodes[aPolygon(in)];
+      gp_XYZ aP2 = arrNodes[aPolygon(in + 1)];
+      gp_XYZ aV1 = aP1 - aPrevP;
+      gp_XYZ aV2 = aP2 - aPrevP;
+      gp_XYZ S = aV1.Crossed(aV2);
+      aSum += S;
     }
-
-    // Copy the triangles. Only the triangle-type polygons are supported.
-    // In this loop we also get rid of any possible degenerated triangles.
-    Poly_Array1OfTriangle& aTriangles = aTriangulation->ChangeTriangles();
-    nTri = 0;
-    for (i = 0; i < (int)myNbPolygons; i++) {
-      const Standard_Integer * arrIndice;
-      if (Polygon (i, arrIndice) == 3)
-        if (arrIndice[0] >= 0 &&
-            arrIndice[0] < nNodes &&
-            arrIndice[1] < nNodes &&
-            arrIndice[2] < nNodes)  // check to avoid previously skipped faces
-          aTriangles(++nTri).Set (mapNodeId(arrIndice[0]),
-                                  mapNodeId(arrIndice[1]),
-                                  mapNodeId(arrIndice[2]));
+    if (aSum.Modulus() < Precision::Confusion())
+    {
+      // degenerate polygon
+      continue;
+    }
+    gp_Dir aNormal(aSum);
+    mapPolyId.Add(i);
+    aPolygons.Append(aPolygon);
+    aNorms.Append(aNormal);
+    // collect info about used indices
+    for (in = 1; in <= aPolygon.Length(); in++)
+    {
+      mapNodeId.Add(arrIndice[in]);
     }
+  }
 
-    // Normals should be defined; if they are not, compute them
-    if (myNormals.IsNull ()) {
-      //aTriangulation->ComputeNormals();
-      Poly::ComputeNormals(aTriangulation);
+  const Standard_Integer nbNodes(mapNodeId.Extent());
+  if (!nbNodes)
+  {
+    myIsModified = Standard_False;
+    myTShape.Nullify();
+    return myTShape;
+  }
+  // prepare vector of nodes
+  NCollection_Vector<gp_XYZ> aNodes;
+  NCollection_DataMap <int, int> mapIdId;
+  for (i = 0; i < nNodes; i++)
+  {
+    if(mapNodeId.Contains(i))
+    {
+      const gp_XYZ& aN1 = arrNodes[i];
+      mapIdId.Bind(i, aNodes.Length());
+      aNodes.Append(aN1);
     }
-    else {
-      // Copy the normals. Currently only normals-per-vertex are supported.
-      Handle(TShort_HArray1OfShortReal) Normals =
-        new TShort_HArray1OfShortReal (1, 3*nbNodes);
-      if (myNormalPerVertex) {
-        if (myArrNormalInd == 0L) {
-          NCollection_DataMap <int, int>::Iterator anIterNN (mapNodeId);
-          for (; anIterNN.More (); anIterNN.Next ()) {
-            Standard_Integer anIdx = (anIterNN.Value() - 1) * 3 + 1;
-            const gp_XYZ& aNormal = myNormals->Normal (anIterNN.Key ());
-            Normals->SetValue (anIdx + 0, Standard_ShortReal (aNormal.X ()));
-            Normals->SetValue (anIdx + 1, Standard_ShortReal (aNormal.Y ()));
-            Normals->SetValue (anIdx + 2, Standard_ShortReal (aNormal.Z ()));
-          }
+  }
+  // update polygon indices
+  NCollection_List<TColStd_SequenceOfInteger>::Iterator itP(aPolygons);
+  for (; itP.More(); itP.Next())
+  {
+    TColStd_SequenceOfInteger& aPolygon = itP.ChangeValue();
+    for (int in = 1; in <= aPolygon.Length(); in++)
+    {
+      Standard_Integer newIdx = mapIdId.Find(aPolygon.Value(in));
+      aPolygon.ChangeValue(in) = newIdx;
+    }
+  }
+  // calculate triangles
+  NCollection_List<Poly_Triangle> aTriangles;
+  itP.Init(aPolygons);
+  for (NCollection_List<gp_Dir>::Iterator itN(aNorms); itP.More(); itP.Next(), itN.Next())
+  {
+    NCollection_List<Poly_Triangle> aTrias;
+    try
+    {
+      NCollection_List<TColStd_SequenceOfInteger> aPList;
+      aPList.Append(itP.Value());
+      BRepMesh_Triangulator aTriangulator(aNodes, aPList, itN.Value());
+      aTriangulator.Perform(aTrias);
+      aTriangles.Append(aTrias);
+    }
+    catch (...)
+    {
+      continue;
+    }
+  }
+  if (aTriangles.IsEmpty())
+  {
+    return myTShape;
+  }
+
+  // Triangulation creation
+  Handle(Poly_Triangulation) aTriangulation =
+    new Poly_Triangulation(aNodes.Length(), aTriangles.Extent(), Standard_False);
+  // Copy the triangulation vertices
+  TColgp_Array1OfPnt& aTNodes = aTriangulation->ChangeNodes();
+  for (i = 0; i < aNodes.Length(); i++)
+  {
+    aTNodes.SetValue(i + 1, gp_Pnt(aNodes(i)));
+  }
+  // Copy the triangles.
+  Poly_Array1OfTriangle& aTTriangles = aTriangulation->ChangeTriangles();
+  NCollection_List<Poly_Triangle>::Iterator itT(aTriangles);
+  for (i = 1; itT.More(); itT.Next(), i++)
+  {
+    aTTriangles.SetValue(i, itT.Value());
+  }
+
+  Handle(BRep_TFace) aFace = new BRep_TFace();
+  aFace->Triangulation(aTriangulation);
+  myTShape = aFace;
+
+  // Normals should be defined; if they are not, compute them
+  if (myNormals.IsNull()) {
+    Poly::ComputeNormals(aTriangulation);
+  }
+  else {
+    // Copy the normals. Currently only normals-per-vertex are supported.
+    Handle(TShort_HArray1OfShortReal) Normals =
+      new TShort_HArray1OfShortReal(1, 3 * nbNodes);
+    if (myNormalPerVertex) {
+      if (myArrNormalInd == 0L) {
+        for (i = 0; i < nbNodes; i++)
+        {
+          Standard_Integer anIdx = i * 3 + 1;
+          const gp_XYZ& aNormal = myNormals->Normal(i);
+          Normals->SetValue(anIdx + 0, Standard_ShortReal(aNormal.X()));
+          Normals->SetValue(anIdx + 1, Standard_ShortReal(aNormal.Y()));
+          Normals->SetValue(anIdx + 2, Standard_ShortReal(aNormal.Z()));
         }
-        else
+      }
+      else
+      {
+        for (i = 0; i < (int)myNbPolygons; i++)
         {
-          for (i = 0; i < (int)myNbPolygons; i++) 
+          if(mapPolyId.Contains(i)) // check to avoid previously skipped faces
           {
             const Standard_Integer * anArrNodes;
-            if (Polygon(i, anArrNodes) == 3 &&
-              anArrNodes[0] >= 0 &&
-              anArrNodes[0] < nNodes &&
-              anArrNodes[1] < nNodes &&
-              anArrNodes[2] < nNodes)  // check to avoid previously skipped faces
-            {
-              const Standard_Integer * arrIndice;
-              if (IndiceNormals(i, arrIndice) == 3) {
-                for (Standard_Integer j = 0; j < 3; j++) {
-                  const gp_XYZ& aNormal = myNormals->Normal (arrIndice[j]);
-                  Standard_Integer anInd = (mapNodeId(anArrNodes[j]) - 1) * 3 + 1;
-                  Normals->SetValue (anInd + 0, Standard_ShortReal (aNormal.X()));
-                  Normals->SetValue (anInd + 1, Standard_ShortReal (aNormal.Y()));
-                  Normals->SetValue (anInd + 2, Standard_ShortReal (aNormal.Z()));
-                }
-              }
+            Polygon(i, anArrNodes);
+            const Standard_Integer * arrIndice;
+            int nbn = IndiceNormals(i, arrIndice);
+            for (Standard_Integer j = 0; j < nbn; j++) {
+              const gp_XYZ& aNormal = myNormals->Normal(arrIndice[j]);
+              Standard_Integer anInd = mapIdId(anArrNodes[j]) * 3 + 1;
+              Normals->SetValue(anInd + 0, Standard_ShortReal(aNormal.X()));
+              Normals->SetValue(anInd + 1, Standard_ShortReal(aNormal.Y()));
+              Normals->SetValue(anInd + 2, Standard_ShortReal(aNormal.Z()));
             }
           }
         }
-      } else {
-        //TODO ..
       }
-      aTriangulation->SetNormals(Normals);
     }
-
-    myIsModified = Standard_False;
+    else {
+      //TODO ..
+    }
+    aTriangulation->SetNormals(Normals);
   }
+
+  myIsModified = Standard_False;
+
   return myTShape;
 }
 
@@ -279,8 +342,21 @@ VrmlData_ErrorStatus VrmlData_IndexedFaceSet::Read(VrmlData_InBuffer& theBuffer)
       aStatus = ReadBoolean (theBuffer, myColorPerVertex);
     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "normalPerVertex"))
       aStatus = ReadBoolean (theBuffer, myNormalPerVertex);
-    else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "coordIndex"))
-      aStatus = aScene.ReadArrIndex (theBuffer, myArrPolygons, myNbPolygons);
+    else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "coordIndex"))
+    {
+      aStatus = aScene.ReadArrIndex(theBuffer, myArrPolygons, myNbPolygons);
+      //for (int i = 0; i < myNbPolygons; i++)
+      //{
+      //  const Standard_Integer * anArray = myArrPolygons[i];
+      //  Standard_Integer nbPoints = anArray[0];
+      //  std::cout << "i = " << i << "  indexes:";
+      //  for (int ip = 1; ip <= nbPoints; ip++)
+      //  {
+      //    std::cout << " " << anArray[ip];
+      //  }
+      //  std::cout << std::endl;
+      //}
+    }
     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "colorIndex"))
       aStatus = aScene.ReadArrIndex (theBuffer, myArrColorInd, myNbColors);
     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "normalIndex"))
index 60edbb97bbbe97d52f42f9163540894cd229d0f4..332757ce2ee1e45c5ad10d1a3d1bc1f8dab1add3 100644 (file)
@@ -821,8 +821,19 @@ VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
           isMore = Standard_False;
         }
         if (anIntValue >= 0)
+        {
+          if (vecInt.Length() > 2)
+          {
+            // additional check for redundant point:
+            // ignore last point which is a dublicate of first point
+            if (anIntValue == vecInt[0])
+            {
+              continue;
+            }
+          }
           // The input value is a node index, store it in the buffer vector
-          vecInt.Append (static_cast<Standard_Integer> (anIntValue));
+          vecInt.Append(static_cast<Standard_Integer> (anIntValue));
+        }
         if ((anIntValue < 0 || isMore == Standard_False)
             && vecInt.Length() > 0)
         {
diff --git a/tests/bugs/stlvrml/bug30421 b/tests/bugs/stlvrml/bug30421
new file mode 100644 (file)
index 0000000..793bbab
--- /dev/null
@@ -0,0 +1,8 @@
+puts "================"
+puts "0030421: Data Exchange - Standard_RangeError  e x c e p t i o n  while reading VRML files with polygons"
+puts "================"
+puts ""
+
+loadvrml result [locate_data_file bug30421.wrl]
+
+checkview -display result -3d -path ${imagedir}/${test_image}.png