0025132: Visualization - treat any TopoDS_Solid as closed volume
[occt.git] / src / StdPrs / StdPrs_ToolShadedShape.cxx
CommitLineData
b311480e 1// Created on: 1993-10-27
2// Created by: Jean-LOuis FRENKEL
3// Copyright (c) 1993-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
b311480e 16
fc9b36d6 17#include <StdPrs_ToolShadedShape.hxx>
9447f912 18
19#include <BRep_Tool.hxx>
20#include <BRepAdaptor_Surface.hxx>
21#include <GeomAbs_SurfaceType.hxx>
22#include <GeomLib.hxx>
23#include <gp_Vec.hxx>
24#include <Poly_Connect.hxx>
7fd59977 25#include <Poly_Triangulation.hxx>
9447f912 26#include <Precision.hxx>
7fd59977 27#include <TColgp_HArray1OfPnt.hxx>
28#include <TColgp_Array1OfPnt.hxx>
29#include <TColgp_Array1OfPnt2d.hxx>
7fd59977 30#include <TopAbs_Orientation.hxx>
7fd59977 31#include <TopLoc_Location.hxx>
32#include <TShort_HArray1OfShortReal.hxx>
33#include <TShort_Array1OfShortReal.hxx>
fc9b36d6 34#include <TColgp_Array1OfDir.hxx>
35#include <TopExp_Explorer.hxx>
36#include <TopoDS.hxx>
7fd59977 37
4769a395 38//=======================================================================
39//function : isTriangulated
40//purpose :
41//=======================================================================
42Standard_Boolean StdPrs_ToolShadedShape::IsTriangulated (const TopoDS_Shape& theShape)
3b1817a9 43{
4769a395 44 TopLoc_Location aLocDummy;
45 for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
3b1817a9 46 {
4769a395 47 const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
48 const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation (aFace, aLocDummy);
49 if (aTri.IsNull())
3b1817a9 50 {
4769a395 51 return Standard_False;
3b1817a9 52 }
3b1817a9 53 }
4769a395 54 return Standard_True;
3b1817a9 55}
56
7fd59977 57//=======================================================================
58//function : IsClosed
9447f912 59//purpose :
7fd59977 60//=======================================================================
9447f912 61Standard_Boolean StdPrs_ToolShadedShape::IsClosed (const TopoDS_Shape& theShape)
7fd59977 62{
3b1817a9 63 if (theShape.IsNull())
64 {
65 return Standard_True;
66 }
67
68 switch (theShape.ShapeType())
69 {
70 case TopAbs_COMPOUND:
71 case TopAbs_COMPSOLID:
72 default:
73 {
74 // check that compound consists of closed solids
75 for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
76 {
77 const TopoDS_Shape& aShape = anIter.Value();
78 if (!IsClosed (aShape))
79 {
80 return Standard_False;
81 }
82 }
83 return Standard_True;
84 }
85 case TopAbs_SOLID:
86 {
4769a395 87 // Check for non-manifold topology first of all:
88 // have to use BRep_Tool::IsClosed() because it checks the face connectivity
89 // inside the shape
90 if (!BRep_Tool::IsClosed (theShape))
91 return Standard_False;
92
3b1817a9 93 for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
94 {
95 const TopoDS_Shape& aShape = anIter.Value();
96 if (aShape.IsNull())
97 {
98 continue;
99 }
100
4769a395 101 if (aShape.ShapeType() == TopAbs_FACE)
3b1817a9 102 {
103 // invalid solid
104 return Standard_False;
105 }
4769a395 106 else if (!IsTriangulated (aShape))
3b1817a9 107 {
108 // mesh contains holes
109 return Standard_False;
110 }
111 }
112 return Standard_True;
113 }
114 case TopAbs_SHELL:
115 case TopAbs_FACE:
116 {
117 // free faces / shell are not allowed
118 return Standard_False;
119 }
120 case TopAbs_WIRE:
121 case TopAbs_EDGE:
122 case TopAbs_VERTEX:
123 {
124 // ignore
125 return Standard_True;
126 }
127 }
7fd59977 128}
129
7fd59977 130//=======================================================================
131//function : Triangulation
9447f912 132//purpose :
7fd59977 133//=======================================================================
9447f912 134Handle(Poly_Triangulation) StdPrs_ToolShadedShape::Triangulation (const TopoDS_Face& theFace,
135 TopLoc_Location& theLoc)
7fd59977 136{
9447f912 137 return BRep_Tool::Triangulation (theFace, theLoc);
7fd59977 138}
139
7fd59977 140//=======================================================================
141//function : Normal
9447f912 142//purpose :
7fd59977 143//=======================================================================
9447f912 144void StdPrs_ToolShadedShape::Normal (const TopoDS_Face& theFace,
145 Poly_Connect& thePolyConnect,
146 TColgp_Array1OfDir& theNormals)
7fd59977 147{
9447f912 148 const Handle(Poly_Triangulation)& aPolyTri = thePolyConnect.Triangulation();
149 const TColgp_Array1OfPnt& aNodes = aPolyTri->Nodes();
150 if (aPolyTri->HasNormals())
151 {
152 // normals pre-computed in triangulation structure
153 const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
154 const Standard_ShortReal* aNormArr = &(aNormals.Value (aNormals.Lower()));
155 for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
156 {
157 const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
158 const gp_Dir aNorm (aNormArr[anId + 0],
159 aNormArr[anId + 1],
160 aNormArr[anId + 2]);
161 theNormals (aNodeIter) = aNorm;
7fd59977 162 }
163
9447f912 164 if (theFace.Orientation() == TopAbs_REVERSED)
165 {
166 for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
167 {
168 theNormals.ChangeValue (aNodeIter).Reverse();
7fd59977 169 }
170 }
9447f912 171 return;
7fd59977 172 }
7fd59977 173
9447f912 174 // take in face the surface location
175 const TopoDS_Face aZeroFace = TopoDS::Face (theFace.Located (TopLoc_Location()));
176 Handle(Geom_Surface) aSurf = BRep_Tool::Surface (aZeroFace);
177 const Standard_Real aTol = Precision::Confusion();
178 Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal (1, aPolyTri->NbNodes() * 3);
179 const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
180 const TColgp_Array1OfPnt2d* aNodesUV = aPolyTri->HasUVNodes() && !aSurf.IsNull()
181 ? &aPolyTri->UVNodes()
182 : NULL;
183 Standard_Integer aTri[3];
184 for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
185 {
186 // try to retrieve normal from real surface first, when UV coordinates are available
187 if (aNodesUV == NULL
188 || GeomLib::NormEstim (aSurf, aNodesUV->Value (aNodeIter), aTol, theNormals (aNodeIter)) > 1)
189 {
190 // compute flat normals
191 gp_XYZ eqPlan (0.0, 0.0, 0.0);
192 for (thePolyConnect.Initialize (aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
193 {
194 aTriangles (thePolyConnect.Value()).Get (aTri[0], aTri[1], aTri[2]);
195 const gp_XYZ v1 (aNodes (aTri[1]).Coord() - aNodes (aTri[0]).Coord());
196 const gp_XYZ v2 (aNodes (aTri[2]).Coord() - aNodes (aTri[1]).Coord());
197 const gp_XYZ vv = v1 ^ v2;
198 const Standard_Real aMod = vv.Modulus();
199 if (aMod >= aTol)
200 {
201 eqPlan += vv / aMod;
202 }
7fd59977 203 }
9447f912 204 const Standard_Real aModMax = eqPlan.Modulus();
205 theNormals (aNodeIter) = (aModMax > aTol) ? gp_Dir (eqPlan) : gp::DZ();
7fd59977 206 }
207
9447f912 208 const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
209 aNormals->SetValue (anId + 1, (Standard_ShortReal )theNormals (aNodeIter).X());
210 aNormals->SetValue (anId + 2, (Standard_ShortReal )theNormals (aNodeIter).Y());
211 aNormals->SetValue (anId + 3, (Standard_ShortReal )theNormals (aNodeIter).Z());
7fd59977 212 }
9447f912 213 aPolyTri->SetNormals (aNormals);
7fd59977 214
9447f912 215 if (theFace.Orientation() == TopAbs_REVERSED)
216 {
217 for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
218 {
219 theNormals.ChangeValue (aNodeIter).Reverse();
7fd59977 220 }
7fd59977 221 }
7fd59977 222}