Salome HOME
Finalize implementation of filter "F8: On/In/Out a Solid"
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_SolidClassifier.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
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 <BRepClass3d_SolidClassifier.hxx>
30 #include <BRepExtrema_DistShapeShape.hxx>
31 #include <TopoDS.hxx>
32
33
34 static GeomAlgoAPI_SolidClassifier::State stateToState(const TopAbs_State theState)
35 {
36   GeomAlgoAPI_SolidClassifier::State aResult;
37   switch (theState)
38   {
39   case TopAbs_IN:
40     aResult = GeomAlgoAPI_SolidClassifier::State_IN;
41     break;
42   case TopAbs_ON:
43     aResult = GeomAlgoAPI_SolidClassifier::State_ON;
44     break;
45   case TopAbs_OUT:
46     aResult = GeomAlgoAPI_SolidClassifier::State_OUT;
47     break;
48   default:
49     aResult = GeomAlgoAPI_SolidClassifier::State_ALL;
50     break;
51   }
52   return aResult;
53 }
54
55 static GeomAlgoAPI_SolidClassifier::State
56 classifyMiddlePoint(BRepClass3d_SolidClassifier& theClassifier,
57                     const GeomShapePtr& theShape,
58                     const double theTolerance)
59 {
60   GeomPointPtr aMiddlePoint = theShape->middlePoint();
61   theClassifier.Perform(aMiddlePoint->impl<gp_Pnt>(), theTolerance);
62   return stateToState(theClassifier.State());
63 }
64
65 static GeomAlgoAPI_SolidClassifier::State
66 classifyVertices(BRepClass3d_SolidClassifier& theClassifier,
67                  const GeomShapePtr& theShape,
68                  const double theTolerance)
69 {
70   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
71   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
72   for (TopExp_Explorer anExp(aShape, TopAbs_VERTEX);
73        anExp.More() && aResult != GeomAlgoAPI_SolidClassifier::State_ALL;
74        anExp.Next()) {
75     TopoDS_Vertex aCurV = TopoDS::Vertex(anExp.Current());
76     theClassifier.Perform(BRep_Tool::Pnt(aCurV), theTolerance);
77     aResult |= stateToState(theClassifier.State());
78   }
79   return aResult;
80 }
81
82 static GeomAlgoAPI_SolidClassifier::State
83 classifyVicinityOnEdge(BRepClass3d_SolidClassifier& theClassifier,
84                        const TopoDS_Edge& theEdge,
85                        const double theParameter,
86                        const double theTolerance)
87 {
88   // coefficient to step out of the vicinity of theParameter
89   static const double THE_STEP_COEFF = 2.0;
90
91   BRepAdaptor_Curve aCurve(theEdge);
92   double aParStep = aCurve.Resolution(theTolerance) * THE_STEP_COEFF;
93   double aParams[2] = { theParameter - aParStep, theParameter + aParStep };
94
95   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
96   for (double* anIt = std::begin(aParams); anIt != std::end(aParams); ++anIt) {
97     if (*anIt < aCurve.FirstParameter())
98       *anIt = aCurve.FirstParameter();
99     else if (*anIt > aCurve.LastParameter())
100       *anIt = aCurve.LastParameter();
101
102     gp_Pnt aPnt = aCurve.Value(*anIt);
103     theClassifier.Perform(aPnt, theTolerance);
104     aResult |= stateToState(theClassifier.State());
105   }
106   return aResult;
107 }
108
109 static GeomAlgoAPI_SolidClassifier::State
110 classifyVicinityOnFace(BRepClass3d_SolidClassifier& theClassifier,
111                        const TopoDS_Face& theFace,
112                        const double theU,
113                        const double theV,
114                        const double theTolerance)
115 {
116   // coefficient to step out of the vicinity of parameters
117   static const double THE_STEP_COEFF = 2.0;
118
119   BRepAdaptor_Surface aSurf(theFace);
120   double aStepU = aSurf.UResolution(theTolerance) * THE_STEP_COEFF;
121   double aStepV = aSurf.VResolution(theTolerance) * THE_STEP_COEFF;
122   double aParamsU[3] = { theU - aStepU, theU, theU + aStepU };
123   double aParamsV[3] = { theV - aStepV, theV, theV + aStepV };
124   for (double* aU = std::begin(aParamsU); aU != std::end(aParamsU); ++aU) {
125     if (*aU < aSurf.FirstUParameter())
126       *aU = aSurf.FirstUParameter();
127     else if (*aU > aSurf.LastUParameter())
128       *aU = aSurf.LastUParameter();
129   }
130   for (double* aV = std::begin(aParamsV); aV != std::end(aParamsV); ++aV) {
131     if (*aV < aSurf.FirstVParameter())
132       *aV = aSurf.FirstVParameter();
133     else if (*aV > aSurf.LastVParameter())
134       *aV = aSurf.LastVParameter();
135   }
136
137   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
138   for (double* aU = std::begin(aParamsU); aU != std::end(aParamsU); ++aU)
139     for (double* aV = std::begin(aParamsV); aV != std::end(aParamsV); ++aV) {
140       gp_Pnt aPnt = aSurf.Value(*aU, *aV);
141       theClassifier.Perform(aPnt, theTolerance);
142       aResult |= stateToState(theClassifier.State());
143     }
144   return aResult;
145 }
146
147 static GeomAlgoAPI_SolidClassifier::State
148 classifyByDistance(BRepClass3d_SolidClassifier& theClassifier,
149                    const GeomShapePtr& theSolid,
150                    const GeomShapePtr& theShape,
151                    const double theTolerance)
152 {
153   GeomAlgoAPI_SolidClassifier::State aResult = GeomAlgoAPI_SolidClassifier::State_UNKNOWN;
154
155   const TopoDS_Shape& aSolid = theSolid->impl<TopoDS_Shape>();
156   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
157   for (TopExp_Explorer anExp(aSolid, TopAbs_SHELL); anExp.More(); anExp.Next()) {
158     // compare distance from the shape to the solid's shells
159     BRepExtrema_DistShapeShape aDistance(anExp.Current(), aShape);
160     if (aDistance.Perform() && aDistance.Value() < theTolerance) {
161       aResult |= GeomAlgoAPI_SolidClassifier::State_ON;
162       // classify vicinity of intersection points
163       for (int sol = 1; sol <= aDistance.NbSolution(); ++sol) {
164         if (aDistance.SupportTypeShape2(sol) == BRepExtrema_IsOnEdge) {
165           TopoDS_Edge anEdge = TopoDS::Edge(aDistance.SupportOnShape2(sol));
166           double aParOnEdge;
167           aDistance.ParOnEdgeS2(sol, aParOnEdge);
168
169           aResult |= classifyVicinityOnEdge(theClassifier, anEdge, aParOnEdge, theTolerance);
170         }
171         else if (aDistance.SupportTypeShape2(sol) == BRepExtrema_IsInFace) {
172           TopoDS_Face aFace = TopoDS::Face(aDistance.SupportOnShape2(sol));
173           double aParU, aParV;
174           aDistance.ParOnFaceS2(sol, aParU, aParV);
175
176           aResult |= classifyVicinityOnFace(theClassifier, aFace, aParU, aParV, theTolerance);
177         }
178       }
179     }
180   }
181   return aResult;
182 }
183
184
185 //==================================================================================================
186 GeomAlgoAPI_SolidClassifier::GeomAlgoAPI_SolidClassifier(const GeomSolidPtr theSolid,
187                                                          const GeomShapePtr theShape,
188                                                          const double theTolerance)
189   : myState(State_UNKNOWN)
190 {
191   if (!theSolid || !theShape)
192     return;
193
194   BRepClass3d_SolidClassifier aClassifierAlgo(theSolid->impl<TopoDS_Shape>());
195
196   myState = classifyMiddlePoint(aClassifierAlgo, theShape, theTolerance);
197   if (!theShape->isVertex())
198     myState |= classifyVertices(aClassifierAlgo, theShape, theTolerance);
199   myState |= classifyByDistance(aClassifierAlgo, theSolid, theShape, theTolerance);
200
201   if (myState == State_ALL)
202     myState = State_UNKNOWN;
203 }