0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / BRepPrimAPI / BRepPrimAPI_MakeHalfSpace.cxx
1 // Created on: 1995-03-08
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1995-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 under
9 // the terms of the GNU Lesser General Public License 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.
16
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <BRepBuilderAPI_MakeVertex.hxx>
21 #include <BRepExtrema_DistShapeShape.hxx>
22 #include <BRepLProp_SLProps.hxx>
23 #include <BRepPrimAPI_MakeHalfSpace.hxx>
24 #include <gp.hxx>
25 #include <gp_Dir.hxx>
26 #include <gp_Pnt.hxx>
27 #include <StdFail_NotDone.hxx>
28 #include <TopExp_Explorer.hxx>
29 #include <TopoDS.hxx>
30 #include <TopoDS_Face.hxx>
31 #include <TopoDS_Shell.hxx>
32 #include <TopoDS_Solid.hxx>
33 #include <TopoDS_Vertex.hxx>
34
35 //=======================================================================
36 //function : getNormalOnFace
37 //purpose  : 
38 //=======================================================================
39
40 static gp_Dir getNormalOnFace(const TopoDS_Face& theFace,
41                               const Standard_Real theU,
42                               const Standard_Real theV)
43 {
44   Standard_Real aPrec = gp::Resolution();
45   BRepLProp_SLProps aProps(BRepAdaptor_Surface(theFace), theU, theV, 2, aPrec);
46   gp_Dir aNormal = aProps.Normal();
47   if (theFace.Orientation() == TopAbs_REVERSED)
48     aNormal.Reverse();
49   return aNormal;
50 }
51
52 //=======================================================================
53 //function : getNormalFromEdge
54 //purpose  : Get average normal at the point with the given parameter on the edge
55 //=======================================================================
56
57 static Standard_Boolean  getNormalFromEdge(const TopoDS_Shape& theShape,
58                                            const TopoDS_Edge& theEdge,
59                                            const Standard_Real thePar,
60                                            gp_Dir& theNormal)
61 {
62   gp_XYZ aSum;
63   TopExp_Explorer ex(theShape, TopAbs_FACE);
64   for (; ex.More(); ex.Next()) {
65     const TopoDS_Face& aF = TopoDS::Face(ex.Current());
66     TopExp_Explorer ex1(aF, TopAbs_EDGE);
67     for (; ex1.More(); ex1.Next()) {
68       if (ex1.Current().IsSame(theEdge)) {
69         Standard_Real f, l;
70         Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theEdge, aF, f, l);
71         gp_Pnt2d aP2d = aC2d->Value(thePar);
72         gp_Dir aNorm = getNormalOnFace(aF, aP2d.X(), aP2d.Y());
73         aSum += aNorm.XYZ();
74       }
75     }
76   }
77   if (aSum.SquareModulus() > gp::Resolution()) {
78     theNormal = aSum;
79     return Standard_True;
80   }
81   return Standard_False;
82 }
83
84 //=======================================================================
85 //function : getNormalFromVertex
86 //purpose  : Get average normal at the point of the vertex
87 //=======================================================================
88
89 static Standard_Boolean  getNormalFromVertex(const TopoDS_Shape& theShape,
90                                              const TopoDS_Vertex& theVer,
91                                              gp_Dir& theNormal)
92 {
93   gp_XYZ aSum;
94   TopExp_Explorer ex(theShape, TopAbs_FACE);
95   for (; ex.More(); ex.Next()) {
96     const TopoDS_Face& aF = TopoDS::Face(ex.Current());
97     TopExp_Explorer ex1(aF, TopAbs_VERTEX);
98     for (; ex1.More(); ex1.Next()) {
99       if (ex1.Current().IsSame(theVer)) {
100         gp_Pnt2d aP2d = BRep_Tool::Parameters(theVer, aF);
101         gp_Dir aNorm = getNormalOnFace(aF, aP2d.X(), aP2d.Y());
102         aSum += aNorm.XYZ();
103       }
104     }
105   }
106   if (aSum.SquareModulus() > gp::Resolution()) {
107     theNormal = aSum;
108     return Standard_True;
109   }
110   return Standard_False;
111 }
112
113 //=======================================================================
114 //function : FindExtrema
115 //purpose  : This finction is called to find the nearest normal projection
116 //           of a point <aPnt> on a shape <aShape>.
117 //           1) return true if extrema is found.
118 //           2) Set in:
119 //             - theMinPnt : The solution point
120 //             - theNormal : The normal direction to the shape at projection point
121 //=======================================================================
122 static Standard_Boolean FindExtrema(const gp_Pnt&        thePnt,
123                                     const TopoDS_Shape&  theShape,
124                                     gp_Pnt&              theMinPnt,
125                                     gp_Dir&              theNormal)
126 {
127   TopoDS_Vertex aRefVertex = BRepBuilderAPI_MakeVertex(thePnt);
128   
129   BRepExtrema_DistShapeShape ext(aRefVertex, theShape);
130   
131   if (!ext.IsDone() || ext.NbSolution() == 0)
132     return Standard_False;
133
134   // the point projection exist
135   Standard_Integer nbext = ext.NbSolution();
136   // try to find a projection on face
137   for (Standard_Integer iext = 1; iext <= nbext; iext++) {
138     if (ext.SupportTypeShape2(iext) == BRepExtrema_IsInFace) {
139       TopoDS_Face aF = TopoDS::Face(ext.SupportOnShape2(iext));
140       theMinPnt = ext.PointOnShape2(iext);
141       Standard_Real aU, aV;
142       ext.ParOnFaceS2(iext, aU, aV);
143       theNormal = getNormalOnFace(aF, aU, aV);
144       return Standard_True;
145     }
146   }
147
148   // if not found then take any edge or vertex solution
149   for (Standard_Integer iext = 1; iext <= nbext; iext++) {
150     if (ext.SupportTypeShape2(iext) == BRepExtrema_IsOnEdge) {
151       theMinPnt = ext.PointOnShape2(iext);
152       Standard_Real aPar;
153       ext.ParOnEdgeS2(iext, aPar);
154       TopoDS_Edge aE = TopoDS::Edge(ext.SupportOnShape2(iext));
155       if (getNormalFromEdge(theShape, aE, aPar, theNormal))
156         return Standard_True;
157     }
158     else if (ext.SupportTypeShape2(iext) == BRepExtrema_IsVertex) {
159       theMinPnt = ext.PointOnShape2(iext);
160       TopoDS_Vertex aV = TopoDS::Vertex(ext.SupportOnShape2(iext));
161       if (getNormalFromVertex(theShape, aV, theNormal))
162         return Standard_True;
163     }
164   }
165   return Standard_False;
166 }
167
168 //=======================================================================
169 //function : isOutside
170 //purpose  : 
171 //=======================================================================
172
173 static Standard_Boolean isOutside(const gp_Pnt&      thePnt,
174                                   const gp_Pnt&      thePonF,
175                                   const gp_Dir&      theNormal)
176 {
177   gp_Dir anOppRef(thePnt.XYZ() - thePonF.XYZ());
178   Standard_Real aSca = theNormal * anOppRef;
179   // outside if same directions
180   return aSca > 0.;
181 }
182
183 //=======================================================================
184 //function : BRepPrimAPI_MakeHalfSpace
185 //purpose  : 
186 //=======================================================================
187
188 BRepPrimAPI_MakeHalfSpace::BRepPrimAPI_MakeHalfSpace(const TopoDS_Face& theFace,
189                                                      const gp_Pnt&      theRefPnt)
190 {
191   // Set the flag is <IsDone> to False.
192   NotDone();
193
194   TopoDS_Shell aShell;
195
196   gp_Pnt aMinPnt;
197   gp_Dir aNormal;
198   if (FindExtrema(theRefPnt, theFace, aMinPnt, aNormal)) {
199     Standard_Boolean toReverse = isOutside(theRefPnt, aMinPnt, aNormal);
200
201     // Construction of the open solid.
202     BRep_Builder().MakeShell(aShell);
203     BRep_Builder().Add(aShell, theFace);
204     BRep_Builder().MakeSolid(mySolid);
205     if (toReverse) {
206       aShell.Reverse();
207     }
208     BRep_Builder().Add(mySolid, aShell);
209     myShape = mySolid;
210     Done();
211   }
212 }
213
214
215 //=======================================================================
216 //function : BRepPrimAPI_MakeHalfSpace
217 //purpose  : 
218 //=======================================================================
219
220 BRepPrimAPI_MakeHalfSpace::BRepPrimAPI_MakeHalfSpace(const TopoDS_Shell& theShell,
221                                                      const gp_Pnt&       theRefPnt)
222 {
223   // Set the flag is <IsDone> to False.
224   NotDone();
225
226   // Find the point of the skin closest to the reference point.
227   gp_Pnt aMinPnt;
228   gp_Dir aNormal;
229   if (FindExtrema(theRefPnt, theShell, aMinPnt, aNormal)) {
230     Standard_Boolean toReverse = isOutside(theRefPnt, aMinPnt, aNormal);
231
232     // Construction of the open solid.
233     TopoDS_Shell aShell = theShell;
234     BRep_Builder().MakeSolid(mySolid);
235     if (toReverse) {
236       aShell.Reverse();
237     }
238     BRep_Builder().Add(mySolid, aShell);
239     myShape = mySolid;
240     Done();
241   }
242 }
243
244
245 //=======================================================================
246 //function : Solid
247 //purpose  : 
248 //=======================================================================
249
250 const TopoDS_Solid& BRepPrimAPI_MakeHalfSpace::Solid() const
251 {
252   StdFail_NotDone_Raise_if( !IsDone(), "BRepPrimAPI_MakeHalfSpace::Solid");
253   return mySolid;
254 }
255
256
257
258 //=======================================================================
259 //function : TopoDS_Solid
260 //purpose  : 
261 //=======================================================================
262
263 BRepPrimAPI_MakeHalfSpace::operator TopoDS_Solid() const
264 {
265   return Solid();
266 }