0028945: Visualization - StdPrs_ToolTriangulatedShape::ComputeNormals() is extremely...
authorkgv <kgv@opencascade.com>
Tue, 25 Jul 2017 12:49:53 +0000 (15:49 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 27 Jul 2017 11:00:24 +0000 (14:00 +0300)
StdPrs_ToolTriangulatedShape::ComputeNormals() now calls Poly::ComputeNormals() for triangulation-only surfaces.
Poly::ComputeNormals() now averages normal considering triangle size.

src/Poly/Poly.cxx
src/StdPrs/StdPrs_ToolTriangulatedShape.cxx

index 63db724..06272fa 100644 (file)
@@ -445,69 +445,72 @@ Handle(Poly_Polygon2D) Poly::ReadPolygon2D(Standard_IStream& IS)
 //function : ComputeNormals
 //purpose  :
 //=======================================================================
-
-void  Poly::ComputeNormals(const Handle(Poly_Triangulation)& Tri)
+void Poly::ComputeNormals (const Handle(Poly_Triangulation)& theTri)
 {
-  const TColgp_Array1OfPnt&     arrNodes = Tri->Nodes();
-  const Poly_Array1OfTriangle & arrTri   = Tri->Triangles();
-  Standard_Integer              nbNormVal  = Tri->NbNodes() * 3;
-  const Handle(TShort_HArray1OfShortReal) Normals =
-    new TShort_HArray1OfShortReal(1, nbNormVal);
-  Normals->Init(0.F);
-
-  Standard_ShortReal            * arrNormal = &(Normals->ChangeValue(1));
-
-  Standard_Real                 aCoord[3];
-  Standard_Integer              iNode[3] = {0, 0, 0};
-  Standard_Integer              iN, iTri;
-  const Standard_Real eps2 = gp::Resolution();
-
-  for (iTri = 1; iTri <= arrTri.Length(); iTri++) {
-    // Get the nodes of the current triangle
-    arrTri(iTri).Get (iNode[0], iNode[1], iNode[2]);
-      const gp_XYZ aVec[2] = {
-        arrNodes(iNode[1]).XYZ() - arrNodes(iNode[0]).XYZ(),
-        arrNodes(iNode[2]).XYZ() - arrNodes(iNode[0]).XYZ()
-      };
-
-    // Find the normal vector of the current triangle
-    gp_XYZ aNorm = aVec[0] ^ aVec[1];
-    const Standard_Real aMod = aNorm.SquareModulus();
-    if (aMod > eps2) {
-      aNorm /= sqrt(aMod);
-      aNorm.Coord (aCoord[0], aCoord[1], aCoord[2]);
-      iNode[0] = (iNode[0]-1)*3;
-      iNode[1] = (iNode[1]-1)*3;
-      iNode[2] = (iNode[2]-1)*3;
-      arrNormal[iNode[0]+0] += (Standard_ShortReal)aCoord[0];
-      arrNormal[iNode[0]+1] += (Standard_ShortReal)aCoord[1];
-      arrNormal[iNode[0]+2] += (Standard_ShortReal)aCoord[2];
-      arrNormal[iNode[1]+0] += (Standard_ShortReal)aCoord[0];
-      arrNormal[iNode[1]+1] += (Standard_ShortReal)aCoord[1];
-      arrNormal[iNode[1]+2] += (Standard_ShortReal)aCoord[2];
-      arrNormal[iNode[2]+0] += (Standard_ShortReal)aCoord[0];
-      arrNormal[iNode[2]+1] += (Standard_ShortReal)aCoord[1];
-      arrNormal[iNode[2]+2] += (Standard_ShortReal)aCoord[2];
+  const TColgp_Array1OfPnt& aNodes   = theTri->Nodes();
+  const Standard_Integer    aNbNodes = aNodes.Size();
+
+  const Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, aNbNodes * 3);
+  aNormals->Init (0.0f);
+  Standard_ShortReal* aNormArr = &aNormals->ChangeFirst();
+
+  Standard_Integer anElem[3] = {0, 0, 0};
+  const Standard_Real anEps2 = gp::Resolution();
+  for (Poly_Array1OfTriangle::Iterator aTriIter (theTri->Triangles()); aTriIter.More(); aTriIter.Next())
+  {
+    aTriIter.Value().Get (anElem[0], anElem[1], anElem[2]);
+    const gp_Pnt& aNode0 = aNodes.Value (anElem[0]);
+    const gp_Pnt& aNode1 = aNodes.Value (anElem[1]);
+    const gp_Pnt& aNode2 = aNodes.Value (anElem[2]);
+
+    const gp_XYZ aVec01 = aNode1.XYZ() - aNode0.XYZ();
+    const gp_XYZ aVec02 = aNode2.XYZ() - aNode0.XYZ();
+    gp_XYZ aTriNorm = aVec01 ^ aVec02;
+    /*if (theToIgnoreTriangleSize)
+    {
+      const Standard_Real aMod = aTriNorm.SquareModulus();
+      if (aMod > anEps2)
+      {
+        aTriNorm /= Sqrt (aMod);
+      }
+      else
+      {
+        continue;
+      }
+    }*/
+
+    for (Standard_Integer aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
+    {
+      const Standard_Size anIndex = (anElem[aNodeIter] - 1) * 3;
+      aNormArr[anIndex + 0] += Standard_ShortReal(aTriNorm.X());
+      aNormArr[anIndex + 1] += Standard_ShortReal(aTriNorm.Y());
+      aNormArr[anIndex + 2] += Standard_ShortReal(aTriNorm.Z());
     }
   }
+
   // Normalize all vectors
-  for (iN = 0; iN < nbNormVal; iN+=3) {
-    Standard_Real aMod (arrNormal[iN+0]*arrNormal[iN+0] +
-                        arrNormal[iN+1]*arrNormal[iN+1] +
-                        arrNormal[iN+2]*arrNormal[iN+2]);
-    if (aMod < eps2) {
-      arrNormal[iN+0] = 0.f;
-      arrNormal[iN+1] = 0.f;
-      arrNormal[iN+2] = 1.f;
-    } else {
-      aMod = sqrt(aMod);
-      arrNormal[iN+0] = Standard_ShortReal(arrNormal[iN+0]/aMod);
-      arrNormal[iN+1] = Standard_ShortReal(arrNormal[iN+1]/aMod);
-      arrNormal[iN+2] = Standard_ShortReal(arrNormal[iN+2]/aMod);
+  gp_XYZ aNormXYZ;
+  for (Standard_Integer aNodeIter = 0; aNodeIter < aNbNodes; ++aNodeIter)
+  {
+    const Standard_Size anIndex = aNodeIter * 3;
+    aNormXYZ.SetCoord (aNormArr[anIndex + 0], aNormArr[anIndex + 1], aNormArr[anIndex + 2]);
+    const Standard_Real aMod2 = aNormXYZ.SquareModulus();
+    if (aMod2 < anEps2)
+    {
+      aNormArr[anIndex + 0] = 0.0f;
+      aNormArr[anIndex + 1] = 0.0f;
+      aNormArr[anIndex + 2] = 1.0f;
+    }
+    else
+    {
+      aNormXYZ /= Sqrt (aMod2);
+      aNormArr[anIndex + 0] = Standard_ShortReal(aNormXYZ.X());
+      aNormArr[anIndex + 1] = Standard_ShortReal(aNormXYZ.Y());
+      aNormArr[anIndex + 2] = Standard_ShortReal(aNormXYZ.Z());
     }
   }
 
-  Tri->SetNormals(Normals);
+  theTri->SetNormals (aNormals);
 }
 
 //=======================================================================
index e53be8e..743bc97 100644 (file)
@@ -23,6 +23,7 @@
 #include <GeomAbs_SurfaceType.hxx>
 #include <GeomLib.hxx>
 #include <gp_XYZ.hxx>
+#include <Poly.hxx>
 #include <Poly_Connect.hxx>
 #include <Poly_Triangulation.hxx>
 #include <Precision.hxx>
@@ -145,22 +146,26 @@ void StdPrs_ToolTriangulatedShape::ComputeNormals (const TopoDS_Face& theFace,
   }
 
   // take in face the surface location
-  const TopoDS_Face      aZeroFace = TopoDS::Face (theFace.Located (TopLoc_Location()));
-  Handle(Geom_Surface)   aSurf     = BRep_Tool::Surface (aZeroFace);
-  const Standard_Real    aTol      = Precision::Confusion();
-  Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, theTris->NbNodes() * 3);
+  const TopoDS_Face    aZeroFace = TopoDS::Face (theFace.Located (TopLoc_Location()));
+  Handle(Geom_Surface) aSurf     = BRep_Tool::Surface (aZeroFace);
   const Poly_Array1OfTriangle& aTriangles = theTris->Triangles();
-  const TColgp_Array1OfPnt2d*  aNodesUV   = theTris->HasUVNodes() && !aSurf.IsNull()
-                                          ? &theTris->UVNodes()
-                                          : NULL;
+  if (!theTris->HasUVNodes() || aSurf.IsNull())
+  {
+    // compute normals by averaging triangulation normals sharing the same vertex
+    Poly::ComputeNormals (theTris);
+    return;
+  }
+
+  const Standard_Real aTol = Precision::Confusion();
+  Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, theTris->NbNodes() * 3);
+  const TColgp_Array1OfPnt2d& aNodesUV = theTris->UVNodes();
   Standard_Integer aTri[3];
   const TColgp_Array1OfPnt& aNodes = theTris->Nodes();
   gp_Dir aNorm;
   for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
   {
     // try to retrieve normal from real surface first, when UV coordinates are available
-    if (aNodesUV == NULL
-     || GeomLib::NormEstim (aSurf, aNodesUV->Value (aNodeIter), aTol, aNorm) > 1)
+    if (GeomLib::NormEstim (aSurf, aNodesUV.Value (aNodeIter), aTol, aNorm) > 1)
     {
       if (thePolyConnect.Triangulation() != theTris)
       {