Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_SolidClassifier.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GeomAlgoAPI_SolidClassifier.h"
21
22 #include <GeomAPI_Pnt.h>
23 #include <GeomAPI_Shape.h>
24 #include <GeomAPI_Solid.h>
25
26 #include <BRep_Tool.hxx>
27 #include <BRepAdaptor_Curve.hxx>
28 #include <BRepAdaptor_Surface.hxx>
29 #include <BRepBuilderAPI_MakeVertex.hxx>
30 #include <BRepClass_FaceClassifier.hxx>
31 #include <BRepClass3d_SolidClassifier.hxx>
32 #include <BRepExtrema_DistShapeShape.hxx>
33 #include <TopoDS.hxx>
34
35
36 static GeomAlgoAPI_SolidClassifier::State stateToState(const TopAbs_State theState)
37 {
38   GeomAlgoAPI_SolidClassifier::State aResult;
39   switch (theState)
40   {
41   case TopAbs_IN:
42     aResult = GeomAlgoAPI_SolidClassifier::State_IN;
43     break;
44   case TopAbs_ON:
45     aResult = GeomAlgoAPI_SolidClassifier::State_ON;
46     break;
47   case TopAbs_OUT:
48     aResult = GeomAlgoAPI_SolidClassifier::State_OUT;
49     break;
50   default:
51     aResult = GeomAlgoAPI_SolidClassifier::State_ALL;
52     break;
53   }
54   return aResult;
55 }
56
57 static GeomAlgoAPI_SolidClassifier::State
58 classifyMiddlePoint(BRepClass3d_SolidClassifier& theClassifier,
59                     const GeomShapePtr& theShape,
60                     const double theTolerance)
61 {
62   GeomPointPtr aMiddlePoint = theShape->middlePoint();
63   gp_Pnt aPointOnFace = aMiddlePoint->impl<gp_Pnt>();
64   if (theShape->shapeType() == GeomAPI_Shape::FACE) {
65     // middle point may be out of face (within a hole),
66     // in this case, find the nearest point on the face
67     const TopoDS_Face& aFace = theShape->impl<TopoDS_Face>();
68     BRepClass_FaceClassifier aFaceClassifier(aFace, aPointOnFace, theTolerance);
69     if (aFaceClassifier.State() == TopAbs_OUT) {
70       BRepBuilderAPI_MakeVertex aVertex(aPointOnFace);
71       BRepExtrema_DistShapeShape aDistance(aVertex.Vertex(), aFace);
72       if (aDistance.NbSolution())
73         aPointOnFace = aDistance.PointOnShape2(1);
74     }
75   }
76   theClassifier.Perform(aPointOnFace, theTolerance);
77   return stateToState(theClassifier.State());
78 }
79
80 static GeomAlgoAPI_SolidClassifier::State
81 classifyVertices(BRepClass3d_SolidClassifier& theClassifier,
82                  const GeomShapePtr& theShape,
83                  const double theTolerance)
84 {
85   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
86   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
87   for (TopExp_Explorer anExp(aShape, TopAbs_VERTEX);
88        anExp.More() && aResult != GeomAlgoAPI_SolidClassifier::State_ALL;
89        anExp.Next()) {
90     TopoDS_Vertex aCurV = TopoDS::Vertex(anExp.Current());
91     theClassifier.Perform(BRep_Tool::Pnt(aCurV), theTolerance);
92     aResult |= stateToState(theClassifier.State());
93   }
94   return aResult;
95 }
96
97 static GeomAlgoAPI_SolidClassifier::State
98 classifyVicinityOnEdge(BRepClass3d_SolidClassifier& theClassifier,
99                        const TopoDS_Edge& theEdge,
100                        const double theParameter,
101                        const double theTolerance)
102 {
103   // coefficient to step out of the vicinity of theParameter
104   static const double THE_STEP_COEFF = 2.0;
105
106   BRepAdaptor_Curve aCurve(theEdge);
107   double aParStep = aCurve.Resolution(theTolerance) * THE_STEP_COEFF;
108   double aParams[2] = { theParameter - aParStep, theParameter + aParStep };
109
110   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
111   for (double* anIt = std::begin(aParams); anIt != std::end(aParams); ++anIt) {
112     if (*anIt < aCurve.FirstParameter())
113       *anIt = aCurve.FirstParameter();
114     else if (*anIt > aCurve.LastParameter())
115       *anIt = aCurve.LastParameter();
116
117     gp_Pnt aPnt = aCurve.Value(*anIt);
118     theClassifier.Perform(aPnt, theTolerance);
119     aResult |= stateToState(theClassifier.State());
120   }
121   return aResult;
122 }
123
124 static GeomAlgoAPI_SolidClassifier::State
125 classifyVicinityOnFace(BRepClass3d_SolidClassifier& theClassifier,
126                        const TopoDS_Face& theFace,
127                        const double theU,
128                        const double theV,
129                        const double theTolerance)
130 {
131   // coefficient to step out of the vicinity of parameters
132   static const double THE_STEP_COEFF = 2.0;
133
134   BRepAdaptor_Surface aSurf(theFace);
135   double aStepU = aSurf.UResolution(theTolerance) * THE_STEP_COEFF;
136   double aStepV = aSurf.VResolution(theTolerance) * THE_STEP_COEFF;
137   double aParamsU[3] = { theU - aStepU, theU, theU + aStepU };
138   double aParamsV[3] = { theV - aStepV, theV, theV + aStepV };
139   for (double* aU = std::begin(aParamsU); aU != std::end(aParamsU); ++aU) {
140     if (*aU < aSurf.FirstUParameter())
141       *aU = aSurf.FirstUParameter();
142     else if (*aU > aSurf.LastUParameter())
143       *aU = aSurf.LastUParameter();
144   }
145   for (double* aV = std::begin(aParamsV); aV != std::end(aParamsV); ++aV) {
146     if (*aV < aSurf.FirstVParameter())
147       *aV = aSurf.FirstVParameter();
148     else if (*aV > aSurf.LastVParameter())
149       *aV = aSurf.LastVParameter();
150   }
151
152   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
153   for (double* aU = std::begin(aParamsU); aU != std::end(aParamsU); ++aU)
154     for (double* aV = std::begin(aParamsV); aV != std::end(aParamsV); ++aV) {
155       gp_Pnt aPnt = aSurf.Value(*aU, *aV);
156       theClassifier.Perform(aPnt, theTolerance);
157       aResult |= stateToState(theClassifier.State());
158     }
159   return aResult;
160 }
161
162 static GeomAlgoAPI_SolidClassifier::State
163 classifyByDistance(BRepClass3d_SolidClassifier& theClassifier,
164                    const GeomShapePtr& theSolid,
165                    const GeomShapePtr& theShape,
166                    const double theTolerance)
167 {
168   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
169
170   const TopoDS_Shape& aSolid = theSolid->impl<TopoDS_Shape>();
171   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
172   for (TopExp_Explorer anExp(aSolid, TopAbs_SHELL); anExp.More(); anExp.Next()) {
173     // compare distance from the shape to the solid's shells
174     BRepExtrema_DistShapeShape aDistance(anExp.Current(), aShape);
175     if (aDistance.Perform() && aDistance.Value() < theTolerance) {
176       aResult |= GeomAlgoAPI_SolidClassifier::State_ON;
177       // classify vicinity of intersection points
178       for (int sol = 1; sol <= aDistance.NbSolution(); ++sol) {
179         if (aDistance.SupportTypeShape2(sol) == BRepExtrema_IsOnEdge) {
180           TopoDS_Edge anEdge = TopoDS::Edge(aDistance.SupportOnShape2(sol));
181           double aParOnEdge;
182           aDistance.ParOnEdgeS2(sol, aParOnEdge);
183
184           aResult |= classifyVicinityOnEdge(theClassifier, anEdge, aParOnEdge, theTolerance);
185         }
186         else if (aDistance.SupportTypeShape2(sol) == BRepExtrema_IsInFace) {
187           TopoDS_Face aFace = TopoDS::Face(aDistance.SupportOnShape2(sol));
188           double aParU, aParV;
189           aDistance.ParOnFaceS2(sol, aParU, aParV);
190
191           aResult |= classifyVicinityOnFace(theClassifier, aFace, aParU, aParV, theTolerance);
192         }
193       }
194     }
195   }
196   return aResult;
197 }
198
199
200 //==================================================================================================
201 GeomAlgoAPI_SolidClassifier::GeomAlgoAPI_SolidClassifier(const GeomSolidPtr theSolid,
202                                                          const GeomShapePtr theShape,
203                                                          const double theTolerance)
204   : myState(State_UNKNOWN)
205 {
206   if (!theSolid || !theShape)
207     return;
208
209   BRepClass3d_SolidClassifier aClassifierAlgo(theSolid->impl<TopoDS_Shape>());
210
211   myState = classifyMiddlePoint(aClassifierAlgo, theShape, theTolerance);
212   if (!theShape->isVertex())
213     myState |= classifyVertices(aClassifierAlgo, theShape, theTolerance);
214   myState |= classifyByDistance(aClassifierAlgo, theSolid, theShape, theTolerance);
215
216   if (myState == State_ALL)
217     myState = State_UNKNOWN;
218 }