0022900: Problem with shape displaying in shading mode
[occt.git] / src / Prs3d / Prs3d_ShadedShape.gxx
1 // File:        Prs3d_ShadedShape.gxx
2 // Created:     Thu Sep 23 18:47:22 1993
3 // Author:      Jean-Louis FRENKEL
4 //              <jlf@stylox>
5
6 //#define BUC60488//GG_081199 Enable the SuppressBackface() ShadingAspect attribute
7
8 #define G005    //ATS,GG 04/01/01 Use ArrayOfPrimitives instead Sets of primitives
9 //              for performance improvment
10
11 #include <Graphic3d_Vertex.hxx>
12 #include <Graphic3d_VertexN.hxx>
13 #include <Graphic3d_Array1OfVertexN.hxx>
14 #include <Graphic3d_Array1OfVertex.hxx>
15 #include <Aspect_Edge.hxx>
16 #include <Aspect_Array1OfEdge.hxx>
17 #include <gp_Pnt.hxx>
18 #include <gp_Dir.hxx>
19 #include <Prs3d_ShadingAspect.hxx>
20 #include <Graphic3d_Group.hxx>
21 #include <Aspect_TypeOfEdge.hxx>
22 #include <Bnd_Box.hxx>
23 #include <Graphic3d_AspectFillArea3d.hxx>
24 #include <BRepTools.hxx>
25 #include <BRep_Tool.hxx>
26 #include <BRep_Builder.hxx>
27 #include <TopoDS_Compound.hxx>
28 #include <Poly_Triangulation.hxx>
29 #include <TColgp_HArray1OfPnt.hxx>
30 #include <TColgp_Array1OfPnt.hxx>
31 #include <TColgp_Array1OfPnt2d.hxx>
32 #include <TColgp_Array1OfDir.hxx>
33 #include <Poly_Connect.hxx>
34 #include <TopAbs_Orientation.hxx>
35 #include <TColStd_MapOfInteger.hxx>
36 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
37 #include <BRepMesh_FactoryError.hxx>
38 #include <BRepMesh_DiscretRoot.hxx>
39 #include <BRepMesh_DiscretFactory.hxx>
40 #include <BRepMesh_PDiscretRoot.hxx>
41 #include <gp_Vec.hxx>
42 #include <StdPrs_WFShape.hxx>
43 #include <BRepBndLib.hxx>
44 #include <Precision.hxx>
45 #ifdef G005
46 #include <Graphic3d_ArrayOfTriangles.hxx>
47 #endif
48
49
50 #define MAX2(X, Y)      (  Abs(X) > Abs(Y)? Abs(X) : Abs(Y) )
51 #define MAX3(X, Y, Z)   ( MAX2 ( MAX2(X,Y) , Z) )
52
53
54 static Standard_Real GetDeflection(const anyShape&             aShape,
55                                    const Handle(Prs3d_Drawer)& aDrawer)
56 {
57   Standard_Real aDeflection = aDrawer->MaximalChordialDeviation();
58   if (aDrawer->TypeOfDeflection() == Aspect_TOD_RELATIVE) {
59     Bnd_Box B;
60     BRepBndLib::Add(aShape, B, Standard_False);
61     if ( ! B.IsVoid() )
62     {
63       Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
64       B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
65       aDeflection = MAX3( aXmax-aXmin , aYmax-aYmin , aZmax-aZmin) 
66         * aDrawer->DeviationCoefficient()*4;    
67     }
68   }
69   return aDeflection;
70 }
71
72
73 static Standard_Boolean ShadeFromShape(const anyShape&                    aShape,
74                                        const Standard_Real                /*defle*/,
75                                        const Standard_Boolean             /*share*/,
76                                        const Handle (Prs3d_Presentation)& aPresentation,
77                                        const Handle (Prs3d_Drawer)&       aDrawer) 
78 {
79   anyShadedShapeTool SST;
80   Handle(Poly_Triangulation) T;
81   TopLoc_Location loc;
82   gp_Pnt p;
83   Standard_Integer i,j,k,decal ;
84   Standard_Integer t[3], n[3];
85   Standard_Integer nbTriangles = 0, nbVertices = 0;
86
87   // precision for compare square distances
88   double dPreci = Precision::Confusion()*Precision::Confusion();
89
90   if ( !aDrawer->ShadingAspectGlobal() ) {
91
92     Handle(Graphic3d_AspectFillArea3d) Asp = aDrawer->ShadingAspect()->Aspect();
93     if(anyShadedShapeTool::IsClosed(aShape)) {
94       Asp->SuppressBackFace();
95     } else {
96       Asp->AllowBackFace();
97     }
98     Prs3d_Root::CurrentGroup(aPresentation)->SetGroupPrimitivesAspect(Asp);
99   }
100
101 #ifdef G005
102   if( Graphic3d_ArrayOfPrimitives::IsEnable() ) {
103
104     for (SST.Init(aShape); SST.MoreFace(); SST.NextFace()) {
105       const anyTopFace& F = SST.CurrentFace();
106       T = SST.Triangulation(F, loc);
107       if (!T.IsNull()) {
108         nbTriangles += T->NbTriangles();
109         nbVertices += T->NbNodes();
110       }
111     } 
112
113     if (nbVertices > 2 && nbTriangles > 0) {
114       Handle(Graphic3d_ArrayOfTriangles) parray =
115         new Graphic3d_ArrayOfTriangles(nbVertices,3*nbTriangles,
116           Standard_True,Standard_False,Standard_False,Standard_True);
117       for (SST.Init(aShape); SST.MoreFace(); SST.NextFace()) {
118         const anyTopFace& F = SST.CurrentFace();
119         T = SST.Triangulation(F, loc);
120         if (!T.IsNull()) {
121           const gp_Trsf& trsf = loc.Transformation();
122           Poly_Connect pc(T);
123           // Extracts vertices & normals from nodes 
124           const TColgp_Array1OfPnt& Nodes = T->Nodes();
125           TColgp_Array1OfDir NORMAL(Nodes.Lower(), Nodes.Upper());
126           SST.Normal(F, pc, NORMAL);
127
128           decal = parray->VertexNumber();
129           for (i= Nodes.Lower(); i<= Nodes.Upper(); i++) {
130             p = Nodes(i);
131             if( !loc.IsIdentity() ) {
132               p.Transform(trsf);
133               NORMAL(i).Transform(trsf);
134             }
135             parray->AddVertex(p,NORMAL(i));
136           }
137   
138           // Fill parray with vertex and edge visibillity info
139           const Poly_Array1OfTriangle& triangles = T->Triangles();
140           for (i = 1; i <= T->NbTriangles(); i++) {
141             pc.Triangles(i,t[0],t[1],t[2]);
142             if (SST.Orientation(F) == TopAbs_REVERSED) 
143               triangles(i).Get(n[0],n[2],n[1]);
144             else 
145               triangles(i).Get(n[0],n[1],n[2]);
146             gp_Pnt P1 = Nodes(n[0]);
147             gp_Pnt P2 = Nodes(n[1]);
148             gp_Pnt P3 = Nodes(n[2]);
149             gp_Vec V1(P1,P2);
150             if ( V1.SquareMagnitude() > dPreci ) {
151               gp_Vec V2(P2,P3);
152               if ( V2.SquareMagnitude() > dPreci ) {
153                 gp_Vec V3(P3,P1);
154                 if ( V3.SquareMagnitude() > dPreci ) {
155                   V1.Normalize();
156                   V2.Normalize();
157                   V1.Cross(V2);
158                   if ( V1.SquareMagnitude() > dPreci ) {
159                     parray->AddEdge(n[0]+decal,t[0] == 0);
160                     parray->AddEdge(n[1]+decal,t[1] == 0);
161                     parray->AddEdge(n[2]+decal,t[2] == 0);
162                   }
163                 }
164               }
165             }
166           }
167         }
168       }    
169       Prs3d_Root::CurrentGroup(aPresentation)->BeginPrimitives();
170       Prs3d_Root::CurrentGroup(aPresentation)->AddPrimitiveArray(parray);
171       Prs3d_Root::CurrentGroup(aPresentation)->EndPrimitives();
172     }
173     return Standard_True;
174   }
175 #endif
176
177   // phase de comptage:
178   Standard_Integer nt, nnn, n1, n2, n3, nnv, EI;
179   static Standard_Integer plus1mod3[3] = {1, 2, 0};
180   for (SST.Init(aShape); SST.MoreFace(); SST.NextFace()) {
181     const anyTopFace& F = SST.CurrentFace();
182     T = SST.Triangulation(F, loc);
183     if (!T.IsNull()) {
184       nnn = T->NbTriangles();
185       const TColgp_Array1OfPnt& Nodes = T->Nodes();
186       const Poly_Array1OfTriangle& triangles = T->Triangles();
187       for (nt = 1; nt <= nnn; nt++) {
188         if (SST.Orientation(F) == TopAbs_REVERSED) 
189           triangles(nt).Get(n1,n3,n2);
190         else 
191           triangles(nt).Get(n1,n2,n3);
192         const gp_Pnt& P1 = Nodes(n1);
193         const gp_Pnt& P2 = Nodes(n2);
194         const gp_Pnt& P3 = Nodes(n3);
195         gp_Vec V1(P1,P2);
196         if ( V1.SquareMagnitude() > dPreci ) {
197           gp_Vec V2(P2,P3);
198           if (V2.SquareMagnitude() > dPreci ) {
199             gp_Vec V3(P3,P1);
200             if (V3.SquareMagnitude() > dPreci ) {
201               V1.Normalize();
202               V2.Normalize();
203               V1.Cross(V2);
204               if (V1.SquareMagnitude() > dPreci ) {
205                 nbTriangles++;
206               }
207             }
208           }
209         }
210       }
211       nbVertices += T->NbNodes();
212     }
213   }      
214
215   if (nbVertices > 2 && nbTriangles > 0) {
216     Graphic3d_Array1OfVertexN AVN(1, nbVertices);
217     Aspect_Array1OfEdge AE(1, 3*nbTriangles);
218     
219     EI = 1;
220     nnv = 1;
221     
222     for (SST.Init(aShape); SST.MoreFace(); SST.NextFace()) {
223       const anyTopFace& F = SST.CurrentFace();
224       T = SST.Triangulation(F, loc);
225       if (!T.IsNull()) {
226         Poly_Connect pc(T);
227         // 1- les noeuds.
228         const TColgp_Array1OfPnt& Nodes = T->Nodes();
229         TColgp_Array1OfDir NORMAL(Nodes.Lower(), Nodes.Upper());
230         SST.Normal(F, pc, NORMAL);
231         decal = nnv-1;
232        
233         for (j= Nodes.Lower(); j<= Nodes.Upper(); j++) {
234           p = Nodes(j).Transformed(loc.Transformation());
235           AVN(nnv).SetCoord(p.X(), p.Y(), p.Z());
236           AVN(nnv).SetNormal(NORMAL(j).X(), NORMAL(j).Y(), NORMAL(j).Z());
237           nnv++;
238         }
239         // 2- les edges.
240         nbTriangles = T->NbTriangles();
241         const Poly_Array1OfTriangle& triangles = T->Triangles();
242         
243         for (i = 1; i <= nbTriangles; i++) {
244           pc.Triangles(i,t[0],t[1],t[2]);
245           if (SST.Orientation(F) == TopAbs_REVERSED) 
246             triangles(i).Get(n[0],n[2],n[1]);
247           else 
248             triangles(i).Get(n[0],n[1],n[2]);
249           const gp_Pnt& P1 = Nodes(n[0]);
250           const gp_Pnt& P2 = Nodes(n[1]);
251           const gp_Pnt& P3 = Nodes(n[2]);
252           gp_Vec V1(P1,P2);
253           if (V1.SquareMagnitude() > 1.e-10) {
254             gp_Vec V2(P2,P3);
255             if (V2.SquareMagnitude() > 1.e-10) {
256               gp_Vec V3(P3,P1);
257               if (V3.SquareMagnitude() > 1.e-10) {
258                 V1.Normalize();
259                 V2.Normalize();
260                 V1.Cross(V2);
261                 if (V1.SquareMagnitude() > 1.e-10) {
262                   for (j = 0; j < 3; j++) {
263                     k = plus1mod3[j];
264                     if (t[j] == 0)
265                       AE(EI).SetValues(n[j]+decal, n[k]+decal, Aspect_TOE_VISIBLE);
266                     else
267                       AE(EI).SetValues(n[j]+decal, n[k]+decal, Aspect_TOE_INVISIBLE);
268                     EI++;
269                   }
270                 }
271               }
272             }
273           }
274         }    
275       }
276     }
277     Prs3d_Root::CurrentGroup(aPresentation)->TriangleSet(AVN, AE);
278   }
279   return Standard_True;
280 }
281
282
283
284 void Prs3d_ShadedShape::Add(const Handle (Prs3d_Presentation)& aPresentation,
285                             const anyShape&                    aShape,
286                             const Handle (Prs3d_Drawer)&       aDrawer)
287 {
288
289   if (aShape.IsNull()) return;
290
291   TopAbs_ShapeEnum E = aShape.ShapeType();
292   if (E == TopAbs_COMPOUND) {
293     TopExp_Explorer ex;
294
295     ex.Init(aShape, TopAbs_FACE);
296     if (ex.More()) {
297       TopoDS_Compound CO;
298       BRep_Builder B;
299       B.MakeCompound(CO);
300       Standard_Boolean haselement = Standard_False;
301
302       // il faut presenter les edges  isoles.
303       for (ex.Init(aShape, TopAbs_EDGE, TopAbs_FACE); ex.More(); ex.Next()) {
304         haselement = Standard_True;
305         B.Add(CO, ex.Current());
306       }
307       // il faut presenter les vertex isoles.
308       for (ex.Init(aShape, TopAbs_VERTEX, TopAbs_EDGE); ex.More(); ex.Next()) {
309         haselement = Standard_True;
310         B.Add(CO, ex.Current());
311       }
312       if (haselement) StdPrs_WFShape::Add(aPresentation, CO, aDrawer);
313     }
314     else {
315       StdPrs_WFShape::Add(aPresentation, aShape, aDrawer);
316     }
317   }
318   Standard_Real aDeflection = GetDeflection(aShape, aDrawer);
319
320   // Check if it is possible to avoid unnecessary recomputation 
321   // of shape triangulation
322   if (!BRepTools::Triangulation (aShape, aDeflection))
323   {
324     BRepTools::Clean (aShape);
325
326     // retrieve meshing tool from Factory
327     Handle(BRepMesh_DiscretRoot) aMeshAlgo = BRepMesh_DiscretFactory::Get().Discret (aShape,
328                                                                                      aDeflection,
329                                                                                      aDrawer->HLRAngle());
330     if (!aMeshAlgo.IsNull())
331       aMeshAlgo->Perform();
332   }
333
334   ShadeFromShape(aShape, aDeflection, Standard_True, aPresentation, aDrawer);
335 }