Salome HOME
5de56ada29a79404a712b5617dc513664c684b73
[modules/shaper.git] / src / ModelGeomAlgo / ModelGeomAlgo_Shape.cpp
1 // Copyright (C) 2014-2020  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 <GeomAPI_Shape.h>
21
22 #include "ModelGeomAlgo_Shape.h"
23
24 #include <ModelAPI_AttributeSelection.h>
25 #include <ModelAPI_CompositeFeature.h>
26 #include <ModelAPI_Feature.h>
27 #include <ModelAPI_Result.h>
28 #include <ModelAPI_ResultBody.h>
29 #include <ModelAPI_ResultConstruction.h>
30
31 #include <GeomAPI_Circ.h>
32 #include <GeomAPI_Ellipse.h>
33 #include <GeomAPI_PlanarEdges.h>
34 #include <GeomAPI_Pnt.h>
35
36
37 #ifdef WIN32
38 #pragma warning(disable : 4996) // for sprintf
39 #endif
40
41 namespace ModelGeomAlgo_Shape
42 {
43   void shapesOfType(const FeaturePtr& theFeature,
44                     const GeomAPI_Shape::ShapeType& theType,
45                     std::set<ResultPtr>& theShapeResults)
46   {
47     theShapeResults.clear();
48     std::list<ResultPtr> aResults = theFeature->results();
49     std::list<ResultPtr>::const_iterator aRIter = aResults.cbegin();
50     for (; aRIter != aResults.cend(); aRIter++) {
51       ResultPtr aResult = *aRIter;
52       GeomShapePtr aShape = aResult->shape();
53       if (aShape.get() && aShape->shapeType() == theType)
54         theShapeResults.insert(aResult);
55     }
56   }
57
58   // Check the point is within shape's bounding box
59   static bool isPointWithinBB(const GeomPointPtr& thePoint,
60                               const GeomShapePtr& theShape,
61                               const double theTolerance)
62   {
63     double aXMin, aXMax, aYMin, aYMax, aZMin, aZMax;
64     return theShape->computeSize(aXMin, aYMin, aZMin, aXMax, aYMax, aZMax) &&
65            thePoint->x() >= aXMin - theTolerance && thePoint->x() <= aXMax + theTolerance &&
66            thePoint->y() >= aYMin - theTolerance && thePoint->y() <= aYMax + theTolerance &&
67            thePoint->z() >= aZMin - theTolerance && thePoint->z() <= aZMax + theTolerance;
68   }
69
70   // Select sub-shape of the given type, which contains the given point
71   static std::list<GeomShapePtr> findSubShape(const GeomShapePtr& theShape,
72                                               const GeomAPI_Shape::ShapeType& theType,
73                                               const GeomPointPtr& thePoint,
74                                               const double theTolerance)
75   {
76     std::list<GeomShapePtr> aFoundSubs;
77     std::list<GeomShapePtr> aSubs = theShape->subShapes(theType);
78     for (std::list<GeomShapePtr>::const_iterator aSubIt = aSubs.begin();
79          aSubIt != aSubs.end(); ++aSubIt) {
80       GeomPointPtr aMiddlePoint = (*aSubIt)->middlePoint();
81       if (aMiddlePoint && aMiddlePoint->distance(thePoint) < theTolerance)
82         aFoundSubs.push_back(*aSubIt);
83     }
84     return aFoundSubs;
85   }
86
87   // Find circular/elliptic edge, which center/focus coincide with the given point
88   static GeomShapePtr findEdgeByCenter(const GeomShapePtr& theBaseShape,
89                                        const GeomPointPtr& theCenter,
90                                        const double theTolerance,
91                                        int& theCenterType)
92   {
93     theCenterType = (int)ModelAPI_AttributeSelection::NOT_CENTER;
94     std::list<GeomShapePtr> anEdges = theBaseShape->subShapes(GeomAPI_Shape::EDGE);
95     for (std::list<GeomShapePtr>::const_iterator anIt = anEdges.begin();
96          anIt != anEdges.end(); ++anIt) {
97       GeomEdgePtr anEdge = (*anIt)->edge();
98       if (!anEdge)
99         continue;
100
101       if (anEdge->isCircle()) {
102         GeomCirclePtr aCircle = anEdge->circle();
103         if (aCircle->center()->distance(theCenter) < theTolerance) {
104           theCenterType = (int)ModelAPI_AttributeSelection::CIRCLE_CENTER;
105           return *anIt;
106         }
107       }
108       else if (anEdge->isEllipse()) {
109         GeomEllipsePtr anEllipse = anEdge->ellipse();
110         if (anEllipse->firstFocus()->distance(theCenter) < theTolerance)
111           theCenterType = (int)ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS;
112         else if (anEllipse->secondFocus()->distance(theCenter) < theTolerance)
113           theCenterType = (int)ModelAPI_AttributeSelection::ELLIPSE_SECOND_FOCUS;
114
115         if (theCenterType != (int)ModelAPI_AttributeSelection::NOT_CENTER)
116           return *anIt;
117       }
118     }
119
120     // not found
121     return GeomShapePtr();
122   }
123
124   static void appendSubshapeOfResult(std::list<SubshapeOfResult>& theList,
125       const ResultPtr& theResult,
126       const GeomShapePtr& theSubshape,
127       int theCenterType = (int)ModelAPI_AttributeSelection::NOT_CENTER)
128   {
129     SubshapeOfResult aSR;
130     aSR.myResult = theResult;
131     aSR.mySubshape = theSubshape;
132     aSR.myCenterType = theCenterType;
133     // compound subshapes from other compounds should be processed as whole results
134     if (aSR.mySubshape && aSR.mySubshape->shapeType() <= GeomAPI_Shape::COMPSOLID) {
135       if (theResult->shape()->isEqual(theSubshape))
136         aSR.mySubshape = GeomShapePtr();
137       else {
138         ResultBodyPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
139         for (int i = 0; aResult && i < aResult->numberOfSubs(); ++i) {
140           ResultBodyPtr aSub = aResult->subResult(i);
141           if (aSub->shape()->isEqual(theSubshape)) {
142             aSR.myResult = aSub;
143             aSR.mySubshape = GeomShapePtr();
144             break;
145           }
146         }
147       }
148     }
149     theList.push_back(aSR);
150   }
151
152   static void appendSubshapeOfResult(std::list<SubshapeOfResult>& theList,
153       const ResultPtr& theResult,
154       const std::list<GeomShapePtr>& theSubshape)
155   {
156     for (std::list<GeomShapePtr>::const_iterator anIt = theSubshape.begin();
157          anIt != theSubshape.end(); ++anIt)
158       appendSubshapeOfResult(theList, theResult, *anIt);
159   }
160
161   static bool findSubshapeInCompsolid(const ResultBodyPtr& theCompsolid,
162                                       const std::shared_ptr<GeomAPI_Pnt>& thePoint,
163                                       const GeomAPI_Shape::ShapeType& theShapeType,
164                                       const double theTolerance,
165                                       std::list<SubshapeOfResult>& theSelected)
166   {
167     bool isSubshapeFound = false;
168     int aNbSolids = theCompsolid->numberOfSubs();
169     for (int i = 0; i < aNbSolids; ++i) {
170       ResultPtr aSubResult = theCompsolid->subResult(i);
171
172       // process subs of compsolid
173       ResultBodyPtr aSubCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aSubResult);
174       if (theShapeType != GeomAPI_Shape::COMPSOLID &&
175           aSubCompSolid && aSubCompSolid->numberOfSubs() > 0) {
176         isSubshapeFound = findSubshapeInCompsolid(aSubCompSolid,
177             thePoint, theShapeType, theTolerance, theSelected);
178       }
179       else {
180         GeomShapePtr aSubSolid = aSubResult->shape();
181         if (aSubSolid && isPointWithinBB(thePoint, aSubSolid, theTolerance)) {
182           std::list<GeomShapePtr> aSubshapes =
183               findSubShape(aSubSolid, theShapeType, thePoint, theTolerance);
184           if (!aSubshapes.empty()) {
185             appendSubshapeOfResult(theSelected, aSubResult, aSubshapes);
186             isSubshapeFound = true;
187           }
188         }
189       }
190     }
191     return isSubshapeFound;
192   }
193
194   bool findSubshapeByPoint(const std::shared_ptr<ModelAPI_Feature>& theFeature,
195                            const std::shared_ptr<GeomAPI_Pnt>& thePoint,
196                            const GeomAPI_Shape::ShapeType& theShapeType,
197                            std::list<SubshapeOfResult>& theSelected)
198   {
199     static const double TOLERANCE = 1.e-6;
200
201     theSelected.clear();
202
203     const std::list<ResultPtr>& aResults = theFeature->results();
204     for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
205          aResIt != aResults.end(); ++aResIt) {
206       bool isSubshapeFound = false;
207       GeomShapePtr aCurShape = (*aResIt)->shape();
208       // first of all, check the point is within bounding box of the result
209       if (!aCurShape || !isPointWithinBB(thePoint, aCurShape, TOLERANCE))
210         continue;
211       // now, process all sub-shapes of the given type and check their inner points,
212       // but skip the case the selected type is COMPOUND and the shape is a list of sketch edges
213       // (it will be processed later)
214       std::shared_ptr<GeomAPI_PlanarEdges> aSketchEdges =
215           std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aCurShape);
216       if (theShapeType != GeomAPI_Shape::COMPOUND || !aSketchEdges) {
217         ResultBodyPtr aCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aResIt);
218         if (aCompSolid) {
219           isSubshapeFound = findSubshapeInCompsolid(aCompSolid,
220               thePoint, theShapeType, TOLERANCE, theSelected);
221         }
222
223         if (!isSubshapeFound) {
224           std::list<GeomShapePtr> aSubshapes =
225               findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE);
226           if (!aSubshapes.empty()) {
227             appendSubshapeOfResult(theSelected, *aResIt, aSubshapes);
228             isSubshapeFound = true;
229           }
230         }
231       }
232       if (isSubshapeFound)
233         continue;
234
235       // special case for ResultConstruction if the FACE is selected
236       ResultConstructionPtr aResConstr =
237           std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIt);
238       if (aResConstr && theShapeType >= GeomAPI_Shape::FACE) {
239         int aNbFaces = aResConstr->facesNum();
240         for (int aFaceInd = 0; aFaceInd < aNbFaces; ++aFaceInd) {
241           GeomFacePtr aCurFace = aResConstr->face(aFaceInd);
242           // check the point is within bounding box of the face
243           if (!isPointWithinBB(thePoint, aCurFace, TOLERANCE))
244             continue;
245           std::list<GeomShapePtr> aSubshapes =
246               findSubShape(aCurFace, theShapeType, thePoint, TOLERANCE);
247           if (!aSubshapes.empty()) {
248             appendSubshapeOfResult(theSelected, *aResIt, aSubshapes);
249             isSubshapeFound = true;
250           }
251         }
252       }
253       if (isSubshapeFound)
254         continue;
255
256       // next special case: the full sketch is selected
257       // the selection type is a COMPOUND
258       if (aSketchEdges && theShapeType == GeomAPI_Shape::COMPOUND &&
259           aSketchEdges->middlePoint()->distance(thePoint) < TOLERANCE) {
260         // select whole result
261         appendSubshapeOfResult(theSelected, *aResIt, GeomShapePtr());
262         continue;
263       }
264
265       // another special case: the center of circle or the focus of ellipse is selected;
266       // return the corresponding edge and a status of the center
267       if (theShapeType == GeomAPI_Shape::VERTEX) {
268         int aCenterType;
269         GeomShapePtr aSubshape = findEdgeByCenter(aCurShape, thePoint, TOLERANCE, aCenterType);
270         if (aSubshape) {
271           appendSubshapeOfResult(theSelected, *aResIt, aSubshape, aCenterType);
272           continue;
273         }
274       }
275     }
276
277     bool processSketch = theSelected.empty() || (theSelected.size() == 1 &&
278         theSelected.front().myCenterType != (int)ModelAPI_AttributeSelection::NOT_CENTER);
279     // one more special case: the selected entity is a separated sketch point
280     // or an auxiliary sketch edge; they are not included into the sketch result;
281     // thus, it is necessary to pass through the sketch sub-features and find selected.
282     if (processSketch && !aResults.empty() &&
283        (theShapeType == GeomAPI_Shape::VERTEX || theShapeType == GeomAPI_Shape::EDGE)) {
284       CompositeFeaturePtr aCF = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
285       std::shared_ptr<GeomAPI_PlanarEdges> aSketchEdges =
286           std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aResults.front()->shape());
287
288       if (aSketchEdges && aCF) {
289         int aNbSubs = aCF->numberOfSubs();
290         for (int aSubInd = 0; aSubInd < aNbSubs; ++aSubInd) {
291           FeaturePtr aSub = aCF->subFeature(aSubInd);
292           const std::list<ResultPtr>& aSubResults = aSub->results();
293           for (std::list<ResultPtr>::const_iterator aSRIt = aSubResults.begin();
294                aSRIt != aSubResults.end(); ++aSRIt) {
295             GeomShapePtr aCurShape = (*aSRIt)->shape();
296             std::list<GeomShapePtr> aSubshapes =
297                 findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE);
298             if (!aSubshapes.empty()) {
299               appendSubshapeOfResult(theSelected, aResults.front(), aSubshapes);
300               break;
301             }
302           }
303         }
304       }
305     }
306
307     return !theSelected.empty();
308   }
309 } // namespace ModelGeomAlgo_Shape