0027596: Visualization, StdPrs_WFShape - pack isolines into single group of primitives
[occt.git] / src / StdPrs / StdPrs_WFShape.cxx
1 // Created on: 2014-10-14
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <StdPrs_WFShape.hxx>
17
18 #include <BRep_Tool.hxx>
19 #include <BRepAdaptor_Curve.hxx>
20 #include <BRepAdaptor_Surface.hxx>
21 #include <BRepAdaptor_HSurface.hxx>
22 #include <StdPrs_DeflectionCurve.hxx>
23 #include <StdPrs_ToolTriangulatedShape.hxx>
24 #include <StdPrs_Isolines.hxx>
25 #include <Standard_ErrorHandler.hxx>
26 #include <Prs3d_ShapeTool.hxx>
27 #include <Prs3d_IsoAspect.hxx>
28 #include <Prs3d.hxx>
29 #include <Poly_Connect.hxx>
30 #include <Poly_PolygonOnTriangulation.hxx>
31 #include <Poly_Polygon3D.hxx>
32 #include <Poly_Triangulation.hxx>
33 #include <Graphic3d_AspectLine3d.hxx>
34 #include <Graphic3d_ArrayOfSegments.hxx>
35 #include <Graphic3d_ArrayOfPoints.hxx>
36 #include <gp_Pnt.hxx>
37 #include <TColgp_HSequenceOfPnt.hxx>
38 #include <TColStd_Array1OfInteger.hxx>
39 #include <TopoDS_Edge.hxx>
40 #include <TopoDS_Face.hxx>
41 #include <TopoDS.hxx>
42 #include <TopTools_ListIteratorOfListOfShape.hxx>
43
44 // =========================================================================
45 // function : Add
46 // purpose  :
47 // =========================================================================
48 void StdPrs_WFShape::Add (const Handle (Prs3d_Presentation)& thePresentation,
49                           const TopoDS_Shape&                theShape,
50                           const Handle (Prs3d_Drawer)&       theDrawer)
51 {
52   if (theShape.IsNull())
53   {
54     return;
55   }
56
57   Prs3d_ShapeTool aTool (theShape, theDrawer->VertexDrawMode() == Prs3d_VDM_All);
58
59   // Explore shape elements.
60   TopTools_ListOfShape aLFree, aLUnFree, aLWire;
61   for (aTool.InitCurve(); aTool.MoreCurve(); aTool.NextCurve())
62   {
63     const TopoDS_Edge& anEdge = aTool.GetCurve();
64     switch (aTool.Neighbours())
65     {
66       case 0:  aLWire.Append (anEdge);   break;
67       case 1:  aLFree.Append (anEdge);   break;
68       default: aLUnFree.Append (anEdge); break;
69     }
70   }
71
72   Standard_Real aShapeDeflection = Prs3d::GetDeflection (theShape, theDrawer);
73
74   // Draw shape elements
75   {
76     TopTools_ListOfShape aDiscreteFaces;
77     for (aTool.InitFace(); aTool.MoreFace(); aTool.NextFace())
78     {
79       if (!aTool.HasSurface())
80       {
81         aDiscreteFaces.Append (aTool.GetFace());
82       }
83     }
84     addEdgesOnTriangulation (thePresentation, aDiscreteFaces, theDrawer->FreeBoundaryAspect());
85   }
86
87   Prs3d_NListOfSequenceOfPnt aCommonPolylines;
88   const Handle(Prs3d_LineAspect)& aWireAspect = theDrawer->WireAspect();
89
90   // Draw isolines
91   {
92     Prs3d_NListOfSequenceOfPnt  aUPolylines, aVPolylines;
93     Prs3d_NListOfSequenceOfPnt* aUPolylinesPtr = &aUPolylines;
94     Prs3d_NListOfSequenceOfPnt* aVPolylinesPtr = &aVPolylines;
95
96     const Handle(Prs3d_LineAspect)& anIsoAspectU = theDrawer->UIsoAspect();
97     const Handle(Prs3d_LineAspect)& anIsoAspectV = theDrawer->VIsoAspect();
98     if (anIsoAspectV->Aspect()->IsEqual (*anIsoAspectU->Aspect()))
99     {
100       aVPolylinesPtr = aUPolylinesPtr;
101     }
102     if (anIsoAspectU->Aspect()->IsEqual (*aWireAspect->Aspect()))
103     {
104       aUPolylinesPtr = &aCommonPolylines;
105     }
106     if (anIsoAspectV->Aspect()->IsEqual (*aWireAspect->Aspect()))
107     {
108       aVPolylinesPtr = &aCommonPolylines;
109     }
110
111     for (aTool.InitFace(); aTool.MoreFace(); aTool.NextFace())
112     {
113       if (aTool.IsPlanarFace() && !theDrawer->IsoOnPlane())
114       {
115         continue;
116       }
117
118       StdPrs_Isolines::Add (aTool.GetFace(), theDrawer, aShapeDeflection, *aUPolylinesPtr, *aVPolylinesPtr);
119     }
120
121     Prs3d::AddPrimitivesGroup (thePresentation, anIsoAspectU, aUPolylines);
122     Prs3d::AddPrimitivesGroup (thePresentation, anIsoAspectV, aVPolylines);
123   }
124
125   if (!aLWire.IsEmpty() && theDrawer->WireDraw())
126   {
127     addEdges (aLWire, theDrawer, aShapeDeflection, aCommonPolylines);
128   }
129
130   if (!aLUnFree.IsEmpty() && theDrawer->UnFreeBoundaryDraw())
131   {
132     const Handle(Prs3d_LineAspect)& aLineAspect = theDrawer->UnFreeBoundaryAspect();
133     if (!aLineAspect->Aspect()->IsEqual (*aWireAspect->Aspect()))
134     {
135       Prs3d_NListOfSequenceOfPnt aPolylines;
136       addEdges (aLUnFree, theDrawer, aShapeDeflection, aPolylines);
137       Prs3d::AddPrimitivesGroup (thePresentation, aLineAspect, aPolylines);
138     }
139     else
140     {
141       addEdges (aLUnFree, theDrawer, aShapeDeflection, aCommonPolylines);
142     }
143   }
144
145   if (!aLFree.IsEmpty() && theDrawer->FreeBoundaryDraw())
146   {
147     const Handle(Prs3d_LineAspect)& aLineAspect = theDrawer->FreeBoundaryAspect();
148     if (!aLineAspect->Aspect()->IsEqual (*aWireAspect->Aspect()))
149     {
150       Prs3d_NListOfSequenceOfPnt aPolylines;
151       addEdges (aLFree, theDrawer, aShapeDeflection, aPolylines);
152       Prs3d::AddPrimitivesGroup (thePresentation, aLineAspect, aPolylines);
153     }
154     else
155     {
156       addEdges (aLFree, theDrawer, aShapeDeflection, aCommonPolylines);
157     }
158   }
159
160   Prs3d::AddPrimitivesGroup (thePresentation, theDrawer->WireAspect(), aCommonPolylines);
161
162   {
163     TColgp_SequenceOfPnt aShapeVertices;
164     for (aTool.InitVertex(); aTool.MoreVertex(); aTool.NextVertex())
165     {
166       aShapeVertices.Append (BRep_Tool::Pnt (aTool.GetVertex()));
167     }
168     if (!aShapeVertices.IsEmpty())
169     {
170       addVertices (thePresentation, aShapeVertices, theDrawer->PointAspect());
171     }
172   }
173 }
174
175 // =========================================================================
176 // function : AddEdges
177 // purpose  :
178 // =========================================================================
179 void StdPrs_WFShape::addEdges (const TopTools_ListOfShape&  theEdges,
180                                const Handle (Prs3d_Drawer)& theDrawer,
181                                const Standard_Real          theShapeDeflection,
182                                Prs3d_NListOfSequenceOfPnt&  thePolylines)
183 {
184   TopTools_ListIteratorOfListOfShape anEdgesIter;
185   for (anEdgesIter.Initialize (theEdges); anEdgesIter.More(); anEdgesIter.Next())
186   {
187     const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgesIter.Value());
188     if (BRep_Tool::Degenerated (anEdge))
189     {
190       continue;
191     }
192
193     Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt;
194
195     TopLoc_Location aLocation;
196     Handle(Poly_Triangulation)          aTriangulation;
197     Handle(Poly_PolygonOnTriangulation) anEdgeIndicies;
198     BRep_Tool::PolygonOnTriangulation (anEdge, anEdgeIndicies, aTriangulation, aLocation);
199     Handle(Poly_Polygon3D) aPolygon;
200
201     if (!anEdgeIndicies.IsNull())
202     {
203       // Presentation based on triangulation of a face.
204       const TColStd_Array1OfInteger& anIndices = anEdgeIndicies->Nodes();
205       const TColgp_Array1OfPnt&      aNodes    = aTriangulation->Nodes();
206
207       Standard_Integer anIndex = anIndices.Lower();
208       if (aLocation.IsIdentity())
209       {
210         for (; anIndex <= anIndices.Upper(); ++anIndex)
211         {
212           aPoints->Append (aNodes (anIndices (anIndex)));
213         }
214       }
215       else
216       {
217         for (; anIndex <= anIndices.Upper(); ++anIndex)
218         {
219           aPoints->Append (aNodes (anIndices (anIndex)).Transformed (aLocation));
220         }
221       }
222     }
223     else if (!(aPolygon = BRep_Tool::Polygon3D (anEdge, aLocation)).IsNull())
224     {
225       // Presentation based on triangulation of the free edge on a surface.
226       const TColgp_Array1OfPnt& aNodes = aPolygon->Nodes();
227       Standard_Integer anIndex = aNodes.Lower();
228       if (aLocation.IsIdentity())
229       {
230         for (; anIndex <= aNodes.Upper(); ++anIndex)
231         {
232           aPoints->Append (aNodes.Value (anIndex));
233         }
234       }
235       else
236       {
237         for (; anIndex <= aNodes.Upper(); ++anIndex)
238         {
239           aPoints->Append (aNodes.Value (anIndex).Transformed (aLocation));
240         }
241       }
242     }
243     else if (BRep_Tool::IsGeometric (anEdge))
244     {
245       // Default presentation for edges without triangulation.
246       BRepAdaptor_Curve aCurve (anEdge);
247       StdPrs_DeflectionCurve::Add (Handle(Prs3d_Presentation)(),
248                                    aCurve,
249                                    theShapeDeflection,
250                                    theDrawer,
251                                    aPoints->ChangeSequence(),
252                                    Standard_False);
253     }
254
255     if (!aPoints->IsEmpty())
256     {
257       thePolylines.Append (aPoints);
258     }
259   }
260 }
261
262 // =========================================================================
263 // function : AddEdgesOnTriangulation
264 // purpose  :
265 // =========================================================================
266 void StdPrs_WFShape::addEdgesOnTriangulation (const Handle(Prs3d_Presentation)& thePresentation,
267                                               const TopTools_ListOfShape&       theFaces,
268                                               const Handle (Prs3d_LineAspect)&  theAspect)
269 {
270   TColgp_SequenceOfPnt aSurfPoints;
271
272   TopLoc_Location aLocation;
273   TopTools_ListIteratorOfListOfShape aFaceIter;
274   for (aFaceIter.Initialize (theFaces); aFaceIter.More(); aFaceIter.Next())
275   {
276     const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value());
277
278     Handle(Poly_Triangulation) T = BRep_Tool::Triangulation (aFace, aLocation);
279     if (T.IsNull())
280     {
281       continue;
282     }
283
284     const TColgp_Array1OfPnt& aNodes = T->Nodes();
285
286     // Build the connect tool.
287     Poly_Connect aPolyConnect (T);
288
289     Standard_Integer aNbTriangles = T->NbTriangles();
290     Standard_Integer aT[3];
291     Standard_Integer aN[3];
292
293     // Count the free edges.
294     Standard_Integer aNbFree = 0;
295     for (Standard_Integer anI = 1; anI <= aNbTriangles; ++anI)
296     {
297       aPolyConnect.Triangles (anI, aT[0], aT[1], aT[2]);
298       for (Standard_Integer aJ = 0; aJ < 3; ++aJ)
299       {
300         if (aT[aJ] == 0)
301         {
302           ++aNbFree;
303         }
304       }
305     }
306
307     // Allocate the arrays.
308     TColStd_Array1OfInteger aFree (1, 2 * aNbFree);
309     Standard_Integer aNbInternal = (3 * aNbTriangles - aNbFree) / 2;
310     TColStd_Array1OfInteger anInternal (0, 2 * aNbInternal);
311
312     Standard_Integer aFreeIndex = 1, anIntIndex = 1;
313     const Poly_Array1OfTriangle& aTriangles = T->Triangles();
314     for (Standard_Integer anI = 1; anI <= aNbTriangles; ++anI)
315     {
316       aPolyConnect.Triangles (anI, aT[0], aT[1], aT[2]);
317       aTriangles (anI).Get (aN[0], aN[1], aN[2]);
318       for (Standard_Integer aJ = 0; aJ < 3; aJ++)
319       {
320         Standard_Integer k = (aJ + 1) % 3;
321         if (aT[aJ] == 0)
322         {
323           aFree (aFreeIndex)     = aN[aJ];
324           aFree (aFreeIndex + 1) = aN[k];
325           aFreeIndex += 2;
326         }
327         // internal edge if this triangle has a lower index than the adjacent.
328         else if (anI < aT[aJ])
329         {
330           anInternal (anIntIndex)     = aN[aJ];
331           anInternal (anIntIndex + 1) = aN[k];
332           anIntIndex += 2;
333         }
334       }
335     }
336
337     // free edges
338     Standard_Integer aFreeHalfNb = aFree.Length() / 2;
339     for (Standard_Integer anI = 1; anI <= aFreeHalfNb; ++anI)
340     {
341       gp_Pnt aPoint1 = aNodes (aFree (2 * anI - 1)).Transformed (aLocation);
342       gp_Pnt aPoint2 = aNodes (aFree (2 * anI    )).Transformed (aLocation);
343       aSurfPoints.Append (aPoint1);
344       aSurfPoints.Append (aPoint2);
345     }
346   }
347
348   if (aSurfPoints.Length() < 2)
349   {
350     return;
351   }
352
353   Standard_Integer aNbVertices = aSurfPoints.Length();
354   Handle(Graphic3d_ArrayOfSegments) aSurfArray = new Graphic3d_ArrayOfSegments (aNbVertices);
355   for (Standard_Integer anI = 1; anI <= aNbVertices; anI += 2)
356   {
357     aSurfArray->AddVertex (aSurfPoints.Value (anI));
358     aSurfArray->AddVertex (aSurfPoints.Value (anI + 1));
359   }
360   Handle(Graphic3d_Group) aGroup = Prs3d_Root::NewGroup (thePresentation);
361   aGroup->SetPrimitivesAspect (theAspect->Aspect());
362   aGroup->AddPrimitiveArray (aSurfArray);
363 }
364
365 // =========================================================================
366 // function : AddPoints
367 // purpose  :
368 // =========================================================================
369 void StdPrs_WFShape::addVertices (const Handle (Prs3d_Presentation)& thePresentation,
370                                   const TColgp_SequenceOfPnt&        theVertices,
371                                   const Handle (Prs3d_PointAspect)&  theAspect)
372 {
373   Standard_Integer aNbVertices = theVertices.Length();
374   if (aNbVertices < 1)
375   {
376     return;
377   }
378
379   Handle(Graphic3d_ArrayOfPoints) aVertexArray = new Graphic3d_ArrayOfPoints (aNbVertices);
380   for (Standard_Integer anI = 1; anI <= aNbVertices; ++anI)
381   {
382     aVertexArray->AddVertex (theVertices.Value (anI));
383   }
384
385   Handle(Graphic3d_Group) aGroup = Prs3d_Root::NewGroup (thePresentation);
386   aGroup->SetPrimitivesAspect (theAspect->Aspect());
387   aGroup->AddPrimitiveArray (aVertexArray);
388 }