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 | } |
209 | Prs3d_Root::CurrentGroup (thePresentation)->BeginPrimitives(); |
210 | Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPArray); |
211 | Prs3d_Root::CurrentGroup (thePresentation)->EndPrimitives(); |
212 | } |
213 | return Standard_True; |
214 | } |
a2d5ab2e |
215 | |
216 | // ======================================================================= |
217 | // function : ComputeFaceBoundaries |
218 | // purpose : Compute boundary presentation for faces of the shape. |
219 | // ======================================================================= |
220 | static void ComputeFaceBoundaries (const TopoDS_Shape& theShape, |
221 | const Handle (Prs3d_Presentation)& thePresentation, |
222 | const Handle (Prs3d_Drawer)& theDrawer) |
223 | { |
224 | // collection of all triangulation nodes on edges |
225 | // for computing boundaries presentation |
226 | NCollection_List<Handle(TColgp_HArray1OfPnt)> aNodeCollection; |
227 | Standard_Integer aNodeNumber = 0; |
228 | |
229 | TopLoc_Location aTrsf; |
230 | |
231 | // explore all boundary edges |
232 | TopTools_IndexedDataMapOfShapeListOfShape anEdgesMap; |
233 | TopExp::MapShapesAndAncestors ( |
234 | theShape, TopAbs_EDGE, TopAbs_FACE, anEdgesMap); |
235 | |
236 | Standard_Integer anEdgeIdx = 1; |
237 | for ( ; anEdgeIdx <= anEdgesMap.Extent (); anEdgeIdx++) |
238 | { |
239 | // reject free edges |
240 | const TopTools_ListOfShape& aFaceList = anEdgesMap.FindFromIndex (anEdgeIdx); |
241 | if (aFaceList.Extent() == 0) |
242 | continue; |
243 | |
244 | // take one of the shared edges and get edge triangulation |
245 | const TopoDS_Face& aFace = TopoDS::Face (aFaceList.First ()); |
246 | const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgesMap.FindKey (anEdgeIdx)); |
247 | |
248 | Handle(Poly_Triangulation) aTriangulation = |
249 | BRep_Tool::Triangulation (aFace, aTrsf); |
250 | |
251 | if (aTriangulation.IsNull ()) |
252 | continue; |
253 | |
254 | Handle(Poly_PolygonOnTriangulation) anEdgePoly = |
255 | BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf); |
256 | |
257 | if (anEdgePoly.IsNull ()) |
258 | continue; |
259 | |
260 | // get edge nodes indexes from face triangulation |
261 | const TColgp_Array1OfPnt& aTriNodes = aTriangulation->Nodes (); |
262 | const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes (); |
263 | |
264 | if (anEdgeNodes.Length () < 2) |
265 | continue; |
266 | |
267 | // collect the edge nodes |
268 | Handle(TColgp_HArray1OfPnt) aCollected = |
269 | new TColgp_HArray1OfPnt (anEdgeNodes.Lower (), anEdgeNodes.Upper ()); |
270 | |
271 | Standard_Integer aNodeIdx = anEdgeNodes.Lower (); |
272 | for ( ; aNodeIdx <= anEdgeNodes.Upper (); aNodeIdx++) |
273 | { |
274 | // node index in face triangulation |
275 | Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx); |
276 | |
277 | // get node and apply location transformation to the node |
278 | gp_Pnt aTriNode = aTriNodes.Value (aTriIndex); |
279 | if (!aTrsf.IsIdentity ()) |
280 | aTriNode.Transform (aTrsf); |
281 | |
282 | // add node to the boundary array |
283 | aCollected->SetValue (aNodeIdx, aTriNode); |
284 | } |
285 | |
286 | aNodeNumber += anEdgeNodes.Length (); |
287 | aNodeCollection.Append (aCollected); |
288 | } |
289 | |
290 | // check if it possible to continue building the presentation |
291 | if (aNodeNumber == 0) |
292 | return; |
293 | |
294 | // allocate polyline array for presentation |
295 | Standard_Integer aSegmentEdgeNb = |
296 | (aNodeNumber - aNodeCollection.Extent()) * 2; |
297 | |
298 | Handle(Graphic3d_ArrayOfSegments) aSegments = |
299 | new Graphic3d_ArrayOfSegments (aNodeNumber, aSegmentEdgeNb); |
300 | |
301 | // build presentation for edge bondaries |
302 | NCollection_List<Handle(TColgp_HArray1OfPnt)>::Iterator |
303 | aCollIt (aNodeCollection); |
304 | |
305 | // the edge index is increased in each iteration step to |
306 | // avoid contiguous segments between different face edges. |
307 | for ( ; aCollIt.More(); aCollIt.Next () ) |
308 | { |
309 | const Handle(TColgp_HArray1OfPnt)& aNodeArray = aCollIt.Value (); |
310 | |
311 | Standard_Integer aNodeIdx = aNodeArray->Lower (); |
312 | |
313 | // add first node (this node is not shared with previous segment). |
314 | // for each face edge, indices for sharing nodes |
315 | // between segments begin from the first added node. |
316 | Standard_Integer aSegmentEdge = |
317 | aSegments->AddVertex (aNodeArray->Value (aNodeIdx)); |
318 | |
319 | // add subsequent nodes and provide edge indexes for sharing |
320 | // the nodes between the sequential segments. |
321 | for ( aNodeIdx++; aNodeIdx <= aNodeArray->Upper (); aNodeIdx++ ) |
322 | { |
323 | aSegments->AddVertex (aNodeArray->Value (aNodeIdx)); |
324 | aSegments->AddEdge ( aSegmentEdge); |
325 | aSegments->AddEdge (++aSegmentEdge); |
326 | } |
327 | } |
328 | |
329 | // set up aspect and add polyline data |
330 | Handle(Graphic3d_AspectLine3d) aBoundaryAspect = |
331 | theDrawer->FaceBoundaryAspect ()->Aspect (); |
332 | |
333 | Handle(Graphic3d_Group) aPrsGrp = Prs3d_Root::NewGroup (thePresentation); |
334 | aPrsGrp->SetGroupPrimitivesAspect (aBoundaryAspect); |
335 | aPrsGrp->BeginPrimitives (); |
336 | aPrsGrp->AddPrimitiveArray (aSegments); |
337 | aPrsGrp->EndPrimitives (); |
338 | } |
2bd4c032 |
339 | }; |
340 | |
341 | // ======================================================================= |
342 | // function : Add |
343 | // purpose : |
344 | // ======================================================================= |
345 | void StdPrs_ShadedShape::Add (const Handle(Prs3d_Presentation)& thePresentation, |
346 | const TopoDS_Shape& theShape, |
347 | const Handle(Prs3d_Drawer)& theDrawer) |
348 | { |
349 | gp_Pnt2d aDummy; |
350 | StdPrs_ShadedShape::Add (thePresentation, theShape, theDrawer, |
351 | Standard_False, aDummy, aDummy, aDummy); |
352 | } |
353 | |
354 | // ======================================================================= |
355 | // function : Add |
356 | // purpose : |
357 | // ======================================================================= |
358 | void StdPrs_ShadedShape::Add (const Handle (Prs3d_Presentation)& thePresentation, |
359 | const TopoDS_Shape& theShape, |
360 | const Handle (Prs3d_Drawer)& theDrawer, |
361 | const Standard_Boolean theHasTexels, |
362 | const gp_Pnt2d& theUVOrigin, |
363 | const gp_Pnt2d& theUVRepeat, |
364 | const gp_Pnt2d& theUVScale) |
365 | { |
366 | if (theShape.IsNull()) |
367 | { |
368 | return; |
369 | } |
370 | |
371 | if (theShape.ShapeType() == TopAbs_COMPOUND) |
372 | { |
373 | TopExp_Explorer ex; |
374 | ex.Init (theShape, TopAbs_FACE); |
375 | if (ex.More()) |
376 | { |
377 | TopoDS_Compound CO; |
378 | BRep_Builder aBuilder; |
379 | aBuilder.MakeCompound (CO); |
380 | Standard_Boolean hasElement = Standard_False; |
381 | |
382 | // il faut presenter les edges isoles. |
383 | for (ex.Init (theShape, TopAbs_EDGE, TopAbs_FACE); ex.More(); ex.Next()) |
384 | { |
385 | hasElement = Standard_True; |
386 | aBuilder.Add (CO, ex.Current()); |
387 | } |
388 | // il faut presenter les vertex isoles. |
389 | for (ex.Init (theShape, TopAbs_VERTEX, TopAbs_EDGE); ex.More(); ex.Next()) |
390 | { |
391 | hasElement = Standard_True; |
392 | aBuilder.Add (CO, ex.Current()); |
393 | } |
394 | if (hasElement) |
395 | { |
396 | StdPrs_WFShape::Add (thePresentation, CO, theDrawer); |
397 | } |
398 | } |
399 | else |
400 | { |
401 | StdPrs_WFShape::Add (thePresentation, theShape, theDrawer); |
402 | } |
403 | } |
404 | Standard_Real aDeflection = GetDeflection (theShape, theDrawer); |
405 | |
406 | // Check if it is possible to avoid unnecessary recomputation |
407 | // of shape triangulation |
408 | if (!BRepTools::Triangulation (theShape, aDeflection)) |
409 | { |
410 | BRepTools::Clean (theShape); |
411 | |
412 | // retrieve meshing tool from Factory |
413 | Handle(BRepMesh_DiscretRoot) aMeshAlgo = BRepMesh_DiscretFactory::Get().Discret (theShape, |
414 | aDeflection, |
415 | theDrawer->HLRAngle()); |
416 | if (!aMeshAlgo.IsNull()) |
417 | aMeshAlgo->Perform(); |
418 | } |
419 | |
420 | ShadeFromShape (theShape, thePresentation, theDrawer, |
421 | theHasTexels, theUVOrigin, theUVRepeat, theUVScale); |
2bd4c032 |
422 | |
a2d5ab2e |
423 | if (theDrawer->IsFaceBoundaryDraw ()) |
424 | { |
425 | ComputeFaceBoundaries (theShape, thePresentation, theDrawer); |
426 | } |
427 | } |