2bd4c032 |
1 | // File: StdPrs_ShadedShape.cxx |
2 | // Created: 23 Sep 1993 |
3 | // Author: Jean-Louis FRENKEL |
4 | // Copyright: OPEN CASCADE 2012 |
5 | |
6 | #include <StdPrs_ShadedShape.hxx> |
7 | |
8 | #include <Bnd_Box.hxx> |
9 | #include <BRep_Builder.hxx> |
10 | #include <BRepBndLib.hxx> |
11 | #include <BRepMesh_DiscretFactory.hxx> |
12 | #include <BRepMesh_DiscretRoot.hxx> |
13 | #include <BRepTools.hxx> |
14 | #include <Graphic3d_ArrayOfTriangles.hxx> |
15 | #include <Graphic3d_AspectFillArea3d.hxx> |
16 | #include <Graphic3d_Group.hxx> |
17 | #include <gp_Dir.hxx> |
18 | #include <gp_Vec.hxx> |
19 | #include <gp_Pnt.hxx> |
20 | #include <Precision.hxx> |
21 | #include <Prs3d_Drawer.hxx> |
22 | #include <Prs3d_Presentation.hxx> |
23 | #include <Prs3d_ShadingAspect.hxx> |
24 | #include <Poly_Connect.hxx> |
25 | #include <Poly_Triangulation.hxx> |
26 | #include <StdPrs_ToolShadedShape.hxx> |
27 | #include <StdPrs_WFShape.hxx> |
28 | #include <TopoDS_Shape.hxx> |
29 | #include <TopoDS_Face.hxx> |
30 | #include <TColgp_Array1OfDir.hxx> |
31 | #include <TColgp_Array1OfPnt2d.hxx> |
a2d5ab2e |
32 | #include <TopoDS_Compound.hxx> |
33 | #include <Poly_PolygonOnTriangulation.hxx> |
34 | #include <TopExp.hxx> |
35 | #include <TopTools_ListOfShape.hxx> |
36 | #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx> |
37 | #include <NCollection_List.hxx> |
38 | #include <Graphic3d_ArrayOfSegments.hxx> |
39 | #include <Prs3d_LineAspect.hxx> |
40 | #include <TColgp_HArray1OfPnt.hxx> |
41 | #include <Aspect_PolygonOffsetMode.hxx> |
2bd4c032 |
42 | |
43 | #define MAX2(X, Y) (Abs(X) > Abs(Y) ? Abs(X) : Abs(Y)) |
44 | #define MAX3(X, Y, Z) (MAX2 (MAX2 (X, Y), Z)) |
45 | |
46 | namespace |
47 | { |
48 | // ======================================================================= |
49 | // function : GetDeflection |
50 | // purpose : |
51 | // ======================================================================= |
52 | static Standard_Real GetDeflection (const TopoDS_Shape& theShape, |
53 | const Handle(Prs3d_Drawer)& theDrawer) |
54 | { |
55 | Standard_Real aDeflection = theDrawer->MaximalChordialDeviation(); |
56 | if (theDrawer->TypeOfDeflection() == Aspect_TOD_RELATIVE) |
57 | { |
58 | Bnd_Box aBndBox; |
59 | BRepBndLib::Add (theShape, aBndBox, Standard_False); |
60 | if (!aBndBox.IsVoid()) |
61 | { |
62 | Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; |
63 | aBndBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); |
64 | aDeflection = MAX3 (aXmax-aXmin, aYmax-aYmin, aZmax-aZmin) * theDrawer->DeviationCoefficient() * 4.0; |
65 | } |
66 | } |
67 | return aDeflection; |
68 | } |
69 | |
70 | // ======================================================================= |
71 | // function : ShadeFromShape |
72 | // purpose : |
73 | // ======================================================================= |
74 | static Standard_Boolean ShadeFromShape (const TopoDS_Shape& theShape, |
75 | const Handle (Prs3d_Presentation)& thePresentation, |
76 | const Handle (Prs3d_Drawer)& theDrawer, |
77 | const Standard_Boolean theHasTexels, |
78 | const gp_Pnt2d& theUVOrigin, |
79 | const gp_Pnt2d& theUVRepeat, |
80 | const gp_Pnt2d& theUVScale) |
81 | { |
82 | StdPrs_ToolShadedShape SST; |
83 | Handle(Poly_Triangulation) T; |
84 | TopLoc_Location aLoc; |
85 | gp_Pnt p; |
86 | Standard_Integer decal; |
87 | Standard_Integer t[3], n[3]; |
88 | Standard_Integer nbTriangles = 0, nbVertices = 0; |
89 | Standard_Real aUmin (0.0), aUmax (0.0), aVmin (0.0), aVmax (0.0), dUmax (0.0), dVmax (0.0); |
90 | |
91 | // precision for compare square distances |
08cd2f6b |
92 | const double aPreci = Precision::SquareConfusion(); |
2bd4c032 |
93 | |
94 | if (!theDrawer->ShadingAspectGlobal()) |
95 | { |
96 | Handle(Graphic3d_AspectFillArea3d) anAsp = theDrawer->ShadingAspect()->Aspect(); |
97 | if (StdPrs_ToolShadedShape::IsClosed (theShape)) |
98 | { |
99 | anAsp->SuppressBackFace(); |
100 | } |
101 | else |
102 | { |
103 | anAsp->AllowBackFace(); |
104 | } |
105 | Prs3d_Root::CurrentGroup (thePresentation)->SetGroupPrimitivesAspect (anAsp); |
106 | } |
107 | |
108 | for (SST.Init (theShape); SST.MoreFace(); SST.NextFace()) |
109 | { |
110 | const TopoDS_Face& aFace = SST.CurrentFace(); |
111 | T = SST.Triangulation (aFace, aLoc); |
112 | if (!T.IsNull()) |
113 | { |
114 | nbTriangles += T->NbTriangles(); |
115 | nbVertices += T->NbNodes(); |
116 | } |
117 | } |
118 | |
119 | if (nbVertices > 2 && nbTriangles > 0) |
120 | { |
121 | Handle(Graphic3d_ArrayOfTriangles) aPArray |
122 | = new Graphic3d_ArrayOfTriangles (nbVertices, 3 * nbTriangles, |
123 | Standard_True, Standard_False, theHasTexels, Standard_True); |
124 | for (SST.Init (theShape); SST.MoreFace(); SST.NextFace()) |
125 | { |
126 | const TopoDS_Face& aFace = SST.CurrentFace(); |
127 | T = SST.Triangulation (aFace, aLoc); |
128 | if (T.IsNull()) |
129 | { |
130 | continue; |
131 | } |
132 | const gp_Trsf& aTrsf = aLoc.Transformation(); |
133 | Poly_Connect pc (T); |
134 | // Extracts vertices & normals from nodes |
135 | const TColgp_Array1OfPnt& aNodes = T->Nodes(); |
136 | const TColgp_Array1OfPnt2d& aUVNodes = T->UVNodes(); |
137 | TColgp_Array1OfDir aNormals (aNodes.Lower(), aNodes.Upper()); |
138 | SST.Normal (aFace, pc, aNormals); |
139 | |
140 | if (theHasTexels) |
141 | { |
142 | BRepTools::UVBounds (aFace, aUmin, aUmax, aVmin, aVmax); |
143 | dUmax = (aUmax - aUmin); |
144 | dVmax = (aVmax - aVmin); |
145 | } |
146 | |
147 | decal = aPArray->VertexNumber(); |
148 | for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter) |
149 | { |
150 | p = aNodes (aNodeIter); |
151 | if (!aLoc.IsIdentity()) |
152 | { |
153 | p.Transform (aTrsf); |
154 | aNormals (aNodeIter).Transform (aTrsf); |
155 | } |
156 | |
157 | if (theHasTexels && aUVNodes.Upper() == aNodes.Upper()) |
158 | { |
159 | const gp_Pnt2d aTexel = gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(), |
160 | (-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y()); |
161 | aPArray->AddVertex (p, aNormals (aNodeIter), aTexel); |
162 | } |
163 | else |
164 | { |
165 | aPArray->AddVertex (p, aNormals (aNodeIter)); |
166 | } |
167 | } |
168 | |
169 | // Fill parray with vertex and edge visibillity info |
170 | const Poly_Array1OfTriangle& aTriangles = T->Triangles(); |
171 | for (Standard_Integer aTriIter = 1; aTriIter <= T->NbTriangles(); ++aTriIter) |
172 | { |
173 | pc.Triangles (aTriIter, t[0], t[1], t[2]); |
174 | if (SST.Orientation (aFace) == TopAbs_REVERSED) |
175 | aTriangles (aTriIter).Get (n[0], n[2], n[1]); |
176 | else |
177 | aTriangles (aTriIter).Get (n[0], n[1], n[2]); |
178 | |
179 | gp_Pnt P1 = aNodes (n[0]); |
180 | gp_Pnt P2 = aNodes (n[1]); |
181 | gp_Pnt P3 = aNodes (n[2]); |
182 | |
183 | gp_Vec V1 (P1, P2); |
184 | if (V1.SquareMagnitude() <= aPreci) |
185 | { |
186 | continue; |
187 | } |
188 | gp_Vec V2 (P2, P3); |
189 | if (V2.SquareMagnitude() <= aPreci) |
190 | { |
191 | continue; |
192 | } |
193 | gp_Vec V3 (P3, P1); |
194 | if (V3.SquareMagnitude() <= aPreci) |
195 | { |
196 | continue; |
197 | } |
198 | V1.Normalize(); |
199 | V2.Normalize(); |
200 | V1.Cross (V2); |
201 | if (V1.SquareMagnitude() > aPreci) |
202 | { |
203 | aPArray->AddEdge (n[0] + decal, t[0] == 0); |
204 | aPArray->AddEdge (n[1] + decal, t[1] == 0); |
205 | aPArray->AddEdge (n[2] + decal, t[2] == 0); |
206 | } |
207 | } |
208 | } |
2bd4c032 |
209 | Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPArray); |
2bd4c032 |
210 | } |
211 | return Standard_True; |
212 | } |
a2d5ab2e |
213 | |
214 | // ======================================================================= |
215 | // function : ComputeFaceBoundaries |
216 | // purpose : Compute boundary presentation for faces of the shape. |
217 | // ======================================================================= |
218 | static void ComputeFaceBoundaries (const TopoDS_Shape& theShape, |
219 | const Handle (Prs3d_Presentation)& thePresentation, |
220 | const Handle (Prs3d_Drawer)& theDrawer) |
221 | { |
222 | // collection of all triangulation nodes on edges |
223 | // for computing boundaries presentation |
224 | NCollection_List<Handle(TColgp_HArray1OfPnt)> aNodeCollection; |
225 | Standard_Integer aNodeNumber = 0; |
226 | |
227 | TopLoc_Location aTrsf; |
228 | |
229 | // explore all boundary edges |
230 | TopTools_IndexedDataMapOfShapeListOfShape anEdgesMap; |
231 | TopExp::MapShapesAndAncestors ( |
232 | theShape, TopAbs_EDGE, TopAbs_FACE, anEdgesMap); |
233 | |
234 | Standard_Integer anEdgeIdx = 1; |
235 | for ( ; anEdgeIdx <= anEdgesMap.Extent (); anEdgeIdx++) |
236 | { |
237 | // reject free edges |
238 | const TopTools_ListOfShape& aFaceList = anEdgesMap.FindFromIndex (anEdgeIdx); |
239 | if (aFaceList.Extent() == 0) |
240 | continue; |
241 | |
242 | // take one of the shared edges and get edge triangulation |
243 | const TopoDS_Face& aFace = TopoDS::Face (aFaceList.First ()); |
244 | const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgesMap.FindKey (anEdgeIdx)); |
245 | |
246 | Handle(Poly_Triangulation) aTriangulation = |
247 | BRep_Tool::Triangulation (aFace, aTrsf); |
248 | |
249 | if (aTriangulation.IsNull ()) |
250 | continue; |
251 | |
252 | Handle(Poly_PolygonOnTriangulation) anEdgePoly = |
253 | BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf); |
254 | |
255 | if (anEdgePoly.IsNull ()) |
256 | continue; |
257 | |
258 | // get edge nodes indexes from face triangulation |
259 | const TColgp_Array1OfPnt& aTriNodes = aTriangulation->Nodes (); |
260 | const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes (); |
261 | |
262 | if (anEdgeNodes.Length () < 2) |
263 | continue; |
264 | |
265 | // collect the edge nodes |
266 | Handle(TColgp_HArray1OfPnt) aCollected = |
267 | new TColgp_HArray1OfPnt (anEdgeNodes.Lower (), anEdgeNodes.Upper ()); |
268 | |
269 | Standard_Integer aNodeIdx = anEdgeNodes.Lower (); |
270 | for ( ; aNodeIdx <= anEdgeNodes.Upper (); aNodeIdx++) |
271 | { |
272 | // node index in face triangulation |
273 | Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx); |
274 | |
275 | // get node and apply location transformation to the node |
276 | gp_Pnt aTriNode = aTriNodes.Value (aTriIndex); |
277 | if (!aTrsf.IsIdentity ()) |
278 | aTriNode.Transform (aTrsf); |
279 | |
280 | // add node to the boundary array |
281 | aCollected->SetValue (aNodeIdx, aTriNode); |
282 | } |
283 | |
284 | aNodeNumber += anEdgeNodes.Length (); |
285 | aNodeCollection.Append (aCollected); |
286 | } |
287 | |
288 | // check if it possible to continue building the presentation |
289 | if (aNodeNumber == 0) |
290 | return; |
291 | |
292 | // allocate polyline array for presentation |
293 | Standard_Integer aSegmentEdgeNb = |
294 | (aNodeNumber - aNodeCollection.Extent()) * 2; |
295 | |
296 | Handle(Graphic3d_ArrayOfSegments) aSegments = |
297 | new Graphic3d_ArrayOfSegments (aNodeNumber, aSegmentEdgeNb); |
298 | |
299 | // build presentation for edge bondaries |
300 | NCollection_List<Handle(TColgp_HArray1OfPnt)>::Iterator |
301 | aCollIt (aNodeCollection); |
302 | |
303 | // the edge index is increased in each iteration step to |
304 | // avoid contiguous segments between different face edges. |
305 | for ( ; aCollIt.More(); aCollIt.Next () ) |
306 | { |
307 | const Handle(TColgp_HArray1OfPnt)& aNodeArray = aCollIt.Value (); |
308 | |
309 | Standard_Integer aNodeIdx = aNodeArray->Lower (); |
310 | |
311 | // add first node (this node is not shared with previous segment). |
312 | // for each face edge, indices for sharing nodes |
313 | // between segments begin from the first added node. |
314 | Standard_Integer aSegmentEdge = |
315 | aSegments->AddVertex (aNodeArray->Value (aNodeIdx)); |
316 | |
317 | // add subsequent nodes and provide edge indexes for sharing |
318 | // the nodes between the sequential segments. |
319 | for ( aNodeIdx++; aNodeIdx <= aNodeArray->Upper (); aNodeIdx++ ) |
320 | { |
321 | aSegments->AddVertex (aNodeArray->Value (aNodeIdx)); |
322 | aSegments->AddEdge ( aSegmentEdge); |
323 | aSegments->AddEdge (++aSegmentEdge); |
324 | } |
325 | } |
326 | |
327 | // set up aspect and add polyline data |
328 | Handle(Graphic3d_AspectLine3d) aBoundaryAspect = |
329 | theDrawer->FaceBoundaryAspect ()->Aspect (); |
330 | |
bb27b807 |
331 | Handle(Graphic3d_Group) aPrsGrp = Prs3d_Root::CurrentGroup (thePresentation); |
a2d5ab2e |
332 | aPrsGrp->SetGroupPrimitivesAspect (aBoundaryAspect); |
a2d5ab2e |
333 | aPrsGrp->AddPrimitiveArray (aSegments); |
a2d5ab2e |
334 | } |
2bd4c032 |
335 | }; |
336 | |
337 | // ======================================================================= |
338 | // function : Add |
339 | // purpose : |
340 | // ======================================================================= |
341 | void StdPrs_ShadedShape::Add (const Handle(Prs3d_Presentation)& thePresentation, |
342 | const TopoDS_Shape& theShape, |
343 | const Handle(Prs3d_Drawer)& theDrawer) |
344 | { |
345 | gp_Pnt2d aDummy; |
346 | StdPrs_ShadedShape::Add (thePresentation, theShape, theDrawer, |
347 | Standard_False, aDummy, aDummy, aDummy); |
348 | } |
349 | |
350 | // ======================================================================= |
351 | // function : Add |
352 | // purpose : |
353 | // ======================================================================= |
354 | void StdPrs_ShadedShape::Add (const Handle (Prs3d_Presentation)& thePresentation, |
355 | const TopoDS_Shape& theShape, |
356 | const Handle (Prs3d_Drawer)& theDrawer, |
357 | const Standard_Boolean theHasTexels, |
358 | const gp_Pnt2d& theUVOrigin, |
359 | const gp_Pnt2d& theUVRepeat, |
360 | const gp_Pnt2d& theUVScale) |
361 | { |
362 | if (theShape.IsNull()) |
363 | { |
364 | return; |
365 | } |
366 | |
367 | if (theShape.ShapeType() == TopAbs_COMPOUND) |
368 | { |
369 | TopExp_Explorer ex; |
370 | ex.Init (theShape, TopAbs_FACE); |
371 | if (ex.More()) |
372 | { |
373 | TopoDS_Compound CO; |
374 | BRep_Builder aBuilder; |
375 | aBuilder.MakeCompound (CO); |
376 | Standard_Boolean hasElement = Standard_False; |
377 | |
378 | // il faut presenter les edges isoles. |
379 | for (ex.Init (theShape, TopAbs_EDGE, TopAbs_FACE); ex.More(); ex.Next()) |
380 | { |
381 | hasElement = Standard_True; |
382 | aBuilder.Add (CO, ex.Current()); |
383 | } |
384 | // il faut presenter les vertex isoles. |
385 | for (ex.Init (theShape, TopAbs_VERTEX, TopAbs_EDGE); ex.More(); ex.Next()) |
386 | { |
387 | hasElement = Standard_True; |
388 | aBuilder.Add (CO, ex.Current()); |
389 | } |
390 | if (hasElement) |
391 | { |
392 | StdPrs_WFShape::Add (thePresentation, CO, theDrawer); |
393 | } |
394 | } |
395 | else |
396 | { |
397 | StdPrs_WFShape::Add (thePresentation, theShape, theDrawer); |
398 | } |
399 | } |
400 | Standard_Real aDeflection = GetDeflection (theShape, theDrawer); |
401 | |
402 | // Check if it is possible to avoid unnecessary recomputation |
403 | // of shape triangulation |
404 | if (!BRepTools::Triangulation (theShape, aDeflection)) |
405 | { |
406 | BRepTools::Clean (theShape); |
407 | |
408 | // retrieve meshing tool from Factory |
409 | Handle(BRepMesh_DiscretRoot) aMeshAlgo = BRepMesh_DiscretFactory::Get().Discret (theShape, |
410 | aDeflection, |
411 | theDrawer->HLRAngle()); |
412 | if (!aMeshAlgo.IsNull()) |
413 | aMeshAlgo->Perform(); |
414 | } |
415 | |
416 | ShadeFromShape (theShape, thePresentation, theDrawer, |
417 | theHasTexels, theUVOrigin, theUVRepeat, theUVScale); |
2bd4c032 |
418 | |
a2d5ab2e |
419 | if (theDrawer->IsFaceBoundaryDraw ()) |
420 | { |
421 | ComputeFaceBoundaries (theShape, thePresentation, theDrawer); |
422 | } |
423 | } |