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