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