Salome HOME
Merge remote-tracking branch 'origin/CEA_2019'
[modules/shaper.git] / src / ModelGeomAlgo / ModelGeomAlgo_Shape.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 <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::COMPOUND &&
135         !theResult->shape()->isEqual(theSubshape)) {
136       ResultBodyPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
137       for (int i = 0; aResult && i < aResult->numberOfSubs(); ++i) {
138         ResultBodyPtr aSub = aResult->subResult(i);
139         if (aSub->shape()->isEqual(theSubshape)) {
140           aSR.myResult = aSub;
141           aSR.mySubshape = GeomShapePtr();
142           break;
143         }
144       }
145     }
146     theList.push_back(aSR);
147   }
148
149   static void appendSubshapeOfResult(std::list<SubshapeOfResult>& theList,
150       const ResultPtr& theResult,
151       const std::list<GeomShapePtr>& theSubshape)
152   {
153     for (std::list<GeomShapePtr>::const_iterator anIt = theSubshape.begin();
154          anIt != theSubshape.end(); ++anIt)
155       appendSubshapeOfResult(theList, theResult, *anIt);
156   }
157
158   static bool findSubshapeInCompsolid(const ResultBodyPtr& theCompsolid,
159                                       const std::shared_ptr<GeomAPI_Pnt>& thePoint,
160                                       const GeomAPI_Shape::ShapeType& theShapeType,
161                                       const double theTolerance,
162                                       std::list<SubshapeOfResult>& theSelected)
163   {
164     bool isSubshapeFound = false;
165     int aNbSolids = theCompsolid->numberOfSubs();
166     for (int i = 0; i < aNbSolids; ++i) {
167       ResultPtr aSubResult = theCompsolid->subResult(i);
168
169       // process subs of compsolid
170       ResultBodyPtr aSubCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aSubResult);
171       if (theShapeType != GeomAPI_Shape::COMPSOLID &&
172           aSubCompSolid && aSubCompSolid->numberOfSubs() > 0) {
173         isSubshapeFound = findSubshapeInCompsolid(aSubCompSolid,
174             thePoint, theShapeType, theTolerance, theSelected);
175       }
176       else {
177         GeomShapePtr aSubSolid = aSubResult->shape();
178         if (aSubSolid && isPointWithinBB(thePoint, aSubSolid, theTolerance)) {
179           std::list<GeomShapePtr> aSubshapes =
180               findSubShape(aSubSolid, theShapeType, thePoint, theTolerance);
181           if (!aSubshapes.empty()) {
182             appendSubshapeOfResult(theSelected, aSubResult, aSubshapes);
183             isSubshapeFound = true;
184           }
185         }
186       }
187     }
188     return isSubshapeFound;
189   }
190
191   bool findSubshapeByPoint(const std::shared_ptr<ModelAPI_Feature>& theFeature,
192                            const std::shared_ptr<GeomAPI_Pnt>& thePoint,
193                            const GeomAPI_Shape::ShapeType& theShapeType,
194                            std::list<SubshapeOfResult>& theSelected)
195   {
196     static const double TOLERANCE = 1.e-6;
197
198     theSelected.clear();
199
200     const std::list<ResultPtr>& aResults = theFeature->results();
201     for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
202          aResIt != aResults.end(); ++aResIt) {
203       bool isSubshapeFound = false;
204       GeomShapePtr aCurShape = (*aResIt)->shape();
205       // first of all, check the point is within bounding box of the result
206       if (!aCurShape || !isPointWithinBB(thePoint, aCurShape, TOLERANCE))
207         continue;
208       // now, process all sub-shapes of the given type and check their inner points,
209       // but skip the case the selected type is COMPOUND and the shape is a list of sketch edges
210       // (it will be processed later)
211       std::shared_ptr<GeomAPI_PlanarEdges> aSketchEdges =
212           std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aCurShape);
213       if (theShapeType != GeomAPI_Shape::COMPOUND || !aSketchEdges) {
214         ResultBodyPtr aCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aResIt);
215         if (aCompSolid) {
216           isSubshapeFound = findSubshapeInCompsolid(aCompSolid,
217               thePoint, theShapeType, TOLERANCE, theSelected);
218         }
219
220         if (!isSubshapeFound) {
221           std::list<GeomShapePtr> aSubshapes =
222               findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE);
223           if (!aSubshapes.empty()) {
224             appendSubshapeOfResult(theSelected, *aResIt, aSubshapes);
225             isSubshapeFound = true;
226           }
227         }
228       }
229       if (isSubshapeFound)
230         continue;
231
232       // special case for ResultConstruction if the FACE is selected
233       ResultConstructionPtr aResConstr =
234           std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIt);
235       if (aResConstr && theShapeType >= GeomAPI_Shape::FACE) {
236         int aNbFaces = aResConstr->facesNum();
237         for (int aFaceInd = 0; aFaceInd < aNbFaces; ++aFaceInd) {
238           GeomFacePtr aCurFace = aResConstr->face(aFaceInd);
239           // check the point is within bounding box of the face
240           if (!isPointWithinBB(thePoint, aCurFace, TOLERANCE))
241             continue;
242           std::list<GeomShapePtr> aSubshapes =
243               findSubShape(aCurFace, theShapeType, thePoint, TOLERANCE);
244           if (!aSubshapes.empty()) {
245             appendSubshapeOfResult(theSelected, *aResIt, aSubshapes);
246             isSubshapeFound = true;
247           }
248         }
249       }
250       if (isSubshapeFound)
251         continue;
252
253       // next special case: the full sketch is selected
254       // the selection type is a COMPOUND
255       if (aSketchEdges && theShapeType == GeomAPI_Shape::COMPOUND &&
256           aSketchEdges->middlePoint()->distance(thePoint) < TOLERANCE) {
257         // select whole result
258         appendSubshapeOfResult(theSelected, *aResIt, GeomShapePtr());
259         continue;
260       }
261
262       // another special case: the center of circle or the focus of ellipse is selected;
263       // return the corresponding edge and a status of the center
264       if (theShapeType == GeomAPI_Shape::VERTEX) {
265         int aCenterType;
266         GeomShapePtr aSubshape = findEdgeByCenter(aCurShape, thePoint, TOLERANCE, aCenterType);
267         if (aSubshape) {
268           appendSubshapeOfResult(theSelected, *aResIt, aSubshape, aCenterType);
269           continue;
270         }
271       }
272     }
273
274     // one more special case: the selected entity is a separated sketch point
275     // or an auxiliary sketch edge; they are not included into the sketch result;
276     // thus, it is necessary to pass through the sketch sub-features and find selected.
277     if (theSelected.empty() && !aResults.empty() &&
278        (theShapeType == GeomAPI_Shape::VERTEX || theShapeType == GeomAPI_Shape::EDGE)) {
279       CompositeFeaturePtr aCF = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
280       std::shared_ptr<GeomAPI_PlanarEdges> aSketchEdges =
281           std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aResults.front()->shape());
282
283       if (aSketchEdges && aCF) {
284         int aNbSubs = aCF->numberOfSubs();
285         for (int aSubInd = 0; aSubInd < aNbSubs; ++aSubInd) {
286           FeaturePtr aSub = aCF->subFeature(aSubInd);
287           const std::list<ResultPtr>& aSubResults = aSub->results();
288           for (std::list<ResultPtr>::const_iterator aSRIt = aSubResults.begin();
289                aSRIt != aSubResults.end(); ++aSRIt) {
290             GeomShapePtr aCurShape = (*aSRIt)->shape();
291             std::list<GeomShapePtr> aSubshapes =
292                 findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE);
293             if (!aSubshapes.empty()) {
294               appendSubshapeOfResult(theSelected, aResults.front(), aSubshapes);
295               break;
296             }
297           }
298         }
299       }
300     }
301
302     return !theSelected.empty();
303   }
304 } // namespace ModelGeomAlgo_Shape