b1179c2d116f081fd381578f68b8bdb638b7f4a1
[occt.git] / src / StdPrs / StdPrs_ToolShadedShape.cxx
1 // Created on: 1993-10-27
2 // Created by: Jean-LOuis FRENKEL
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <StdPrs_ToolShadedShape.hxx>
18
19 #include <BRep_Tool.hxx>
20 #include <BRepAdaptor_Surface.hxx>
21 #include <GeomAbs_SurfaceType.hxx>
22 #include <GeomLib.hxx>
23 #include <gp_Vec.hxx>
24 #include <Poly_Connect.hxx>
25 #include <Poly_Triangulation.hxx>
26 #include <Precision.hxx>
27 #include <TColgp_HArray1OfPnt.hxx>
28 #include <TColgp_Array1OfPnt.hxx>
29 #include <TColgp_Array1OfPnt2d.hxx>
30 #include <TopAbs_Orientation.hxx>
31 #include <TopLoc_Location.hxx>
32 #include <TShort_HArray1OfShortReal.hxx>
33 #include <TShort_Array1OfShortReal.hxx>
34 #include <TColgp_Array1OfDir.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TopoDS.hxx>
37
38 namespace
39 {
40   //=======================================================================
41   //function : isTriangulated
42   //purpose  : Returns true if all faces within shape are triangulated.
43   //           Same as BRepTools::Triangulation() but without extra checks.
44   //=======================================================================
45   static Standard_Boolean isTriangulated (const TopoDS_Shape& theShape)
46   {
47     TopLoc_Location aLocDummy;
48     for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
49     {
50       const TopoDS_Face&                aFace = TopoDS::Face (aFaceIter.Current());
51       const Handle(Poly_Triangulation)& aTri  = BRep_Tool::Triangulation (aFace, aLocDummy);
52       if (aTri.IsNull())
53       {
54         return Standard_False;
55       }
56     }
57     return Standard_True;
58   }
59 }
60
61 //=======================================================================
62 //function : IsClosed
63 //purpose  :
64 //=======================================================================
65 Standard_Boolean StdPrs_ToolShadedShape::IsClosed (const TopoDS_Shape& theShape)
66 {
67   if (theShape.IsNull())
68   {
69     return Standard_True;
70   }
71
72   switch (theShape.ShapeType())
73   {
74     case TopAbs_COMPOUND:
75     case TopAbs_COMPSOLID:
76     default:
77     {
78       // check that compound consists of closed solids
79       for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
80       {
81         const TopoDS_Shape& aShape = anIter.Value();
82         if (!IsClosed (aShape))
83         {
84           return Standard_False;
85         }
86       }
87       return Standard_True;
88     }
89     case TopAbs_SOLID:
90     {
91       for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
92       {
93         const TopoDS_Shape& aShape = anIter.Value();
94         if (aShape.IsNull())
95         {
96           continue;
97         }
98
99         if (aShape.ShapeType() == TopAbs_SHELL
100         && !aShape.Closed())
101         {
102           return Standard_False;
103         }
104         else if (aShape.ShapeType() == TopAbs_FACE)
105         {
106           // invalid solid
107           return Standard_False;
108         }
109         else if (!isTriangulated (aShape))
110         {
111           // mesh contains holes
112           return Standard_False;
113         }
114       }
115       return Standard_True;
116     }
117     case TopAbs_SHELL:
118     case TopAbs_FACE:
119     {
120       // free faces / shell are not allowed
121       return Standard_False;
122     }
123     case TopAbs_WIRE:
124     case TopAbs_EDGE:
125     case TopAbs_VERTEX:
126     {
127       // ignore
128       return Standard_True;
129     }
130   }
131 }
132
133 //=======================================================================
134 //function : Triangulation
135 //purpose  :
136 //=======================================================================
137 Handle(Poly_Triangulation) StdPrs_ToolShadedShape::Triangulation (const TopoDS_Face& theFace,
138                                                                   TopLoc_Location&   theLoc)
139 {
140   return BRep_Tool::Triangulation (theFace, theLoc);
141 }
142
143 //=======================================================================
144 //function : Normal
145 //purpose  :
146 //=======================================================================
147 void StdPrs_ToolShadedShape::Normal (const TopoDS_Face&  theFace,
148                                      Poly_Connect&       thePolyConnect,
149                                      TColgp_Array1OfDir& theNormals)
150 {
151   const Handle(Poly_Triangulation)& aPolyTri = thePolyConnect.Triangulation();
152   const TColgp_Array1OfPnt&         aNodes   = aPolyTri->Nodes();
153   if (aPolyTri->HasNormals())
154   {
155     // normals pre-computed in triangulation structure
156     const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
157     const Standard_ShortReal*       aNormArr = &(aNormals.Value (aNormals.Lower()));
158     for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
159     {
160       const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
161       const gp_Dir aNorm (aNormArr[anId + 0],
162                           aNormArr[anId + 1],
163                           aNormArr[anId + 2]);
164       theNormals (aNodeIter) = aNorm;
165     }
166
167     if (theFace.Orientation() == TopAbs_REVERSED)
168     {
169       for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
170       {
171         theNormals.ChangeValue (aNodeIter).Reverse();
172       }
173     }
174     return;
175   }
176
177   // take in face the surface location
178   const TopoDS_Face      aZeroFace = TopoDS::Face (theFace.Located (TopLoc_Location()));
179   Handle(Geom_Surface)   aSurf     = BRep_Tool::Surface (aZeroFace);
180   const Standard_Real    aTol      = Precision::Confusion();
181   Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, aPolyTri->NbNodes() * 3);
182   const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
183   const TColgp_Array1OfPnt2d*  aNodesUV   = aPolyTri->HasUVNodes() && !aSurf.IsNull()
184                                           ? &aPolyTri->UVNodes()
185                                           : NULL;
186   Standard_Integer aTri[3];
187   for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
188   {
189     // try to retrieve normal from real surface first, when UV coordinates are available
190     if (aNodesUV == NULL
191      || GeomLib::NormEstim (aSurf, aNodesUV->Value (aNodeIter), aTol, theNormals (aNodeIter)) > 1)
192     {
193       // compute flat normals
194       gp_XYZ eqPlan (0.0, 0.0, 0.0);
195       for (thePolyConnect.Initialize (aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
196       {
197         aTriangles (thePolyConnect.Value()).Get (aTri[0], aTri[1], aTri[2]);
198         const gp_XYZ v1 (aNodes (aTri[1]).Coord() - aNodes (aTri[0]).Coord());
199         const gp_XYZ v2 (aNodes (aTri[2]).Coord() - aNodes (aTri[1]).Coord());
200         const gp_XYZ vv = v1 ^ v2;
201         const Standard_Real aMod = vv.Modulus();
202         if (aMod >= aTol)
203         {
204           eqPlan += vv / aMod;
205         }
206       }
207       const Standard_Real aModMax = eqPlan.Modulus();
208       theNormals (aNodeIter) = (aModMax > aTol) ? gp_Dir (eqPlan) : gp::DZ();
209     }
210
211     const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
212     aNormals->SetValue (anId + 1, (Standard_ShortReal )theNormals (aNodeIter).X());
213     aNormals->SetValue (anId + 2, (Standard_ShortReal )theNormals (aNodeIter).Y());
214     aNormals->SetValue (anId + 3, (Standard_ShortReal )theNormals (aNodeIter).Z());
215   }
216   aPolyTri->SetNormals (aNormals);
217
218   if (theFace.Orientation() == TopAbs_REVERSED)
219   {
220     for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
221     {
222       theNormals.ChangeValue (aNodeIter).Reverse();
223     }
224   }
225 }