Salome HOME
Dump with geometrical selection
[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_ResultCompSolid.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   bool findSubshapeByPoint(const std::shared_ptr<ModelAPI_Feature>& theFeature,
152                            const std::shared_ptr<GeomAPI_Pnt>& thePoint,
153                            const GeomAPI_Shape::ShapeType& theShapeType,
154                            std::list<SubshapeOfResult>& theSelected)
155   {
156     static const double TOLERANCE = 1.e-7;
157
158     theSelected.clear();
159
160     const std::list<ResultPtr>& aResults = theFeature->results();
161     for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
162          aResIt != aResults.end(); ++aResIt) {
163       bool isSubshapeFound = false;
164       GeomShapePtr aCurShape = (*aResIt)->shape();
165       // first of all, check the point is within bounding box of the result
166       if (!aCurShape || !isPointWithinBB(thePoint, aCurShape, TOLERANCE))
167         continue;
168       // now, process all sub-shapes of the given type and check their inner points,
169       // but skip the case the selected type is COMPOUND and the shape is a list of sketch edges
170       // (it will be processed later)
171       std::shared_ptr<GeomAPI_PlanarEdges> aSketchEdges =
172           std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aCurShape);
173       if (theShapeType != GeomAPI_Shape::COMPOUND || !aSketchEdges) {
174         ResultCompSolidPtr aCompSolid =
175             std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aResIt);
176         if (aCompSolid) {
177           // process solids
178           int aNbSolids = aCompSolid->numberOfSubs();
179           for (int i = 0; i < aNbSolids; ++i) {
180             ResultPtr aSubResult = aCompSolid->subResult(i);
181             GeomShapePtr aSubSolid = aSubResult->shape();
182             if (aSubSolid && isPointWithinBB(thePoint, aSubSolid, TOLERANCE)) {
183               std::list<GeomShapePtr> aSubshapes =
184                   findSubShape(aSubSolid, theShapeType, thePoint, TOLERANCE);
185               if (!aSubshapes.empty()) {
186                 appendSubshapeOfResult(theSelected, aSubResult, aSubshapes);
187                 isSubshapeFound = true;
188               }
189             }
190           }
191         }
192
193         if (!isSubshapeFound) {
194           std::list<GeomShapePtr> aSubshapes =
195               findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE);
196           if (!aSubshapes.empty()) {
197             appendSubshapeOfResult(theSelected, *aResIt, aSubshapes);
198             isSubshapeFound = true;
199           }
200         }
201       }
202       if (isSubshapeFound)
203         continue;
204
205       // special case for ResultConstruction if the FACE is selected
206       ResultConstructionPtr aResConstr =
207           std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIt);
208       if (aResConstr && theShapeType >= GeomAPI_Shape::FACE) {
209         int aNbFaces = aResConstr->facesNum();
210         for (int aFaceInd = 0; aFaceInd < aNbFaces; ++aFaceInd) {
211           GeomFacePtr aCurFace = aResConstr->face(aFaceInd);
212           // check the point is within bounding box of the face
213           if (!isPointWithinBB(thePoint, aCurFace, TOLERANCE))
214             continue;
215           std::list<GeomShapePtr> aSubshapes =
216               findSubShape(aCurFace, theShapeType, thePoint, TOLERANCE);
217           if (!aSubshapes.empty()) {
218             appendSubshapeOfResult(theSelected, *aResIt, aSubshapes);
219             isSubshapeFound = true;
220           }
221         }
222       }
223       if (isSubshapeFound)
224         continue;
225
226       // next special case: the full sketch is selected
227       // the selection type is a COMPOUND
228       if (aSketchEdges &&
229           aSketchEdges->middlePoint()->distance(thePoint) < TOLERANCE) {
230         // select whole result
231         appendSubshapeOfResult(theSelected, *aResIt, GeomShapePtr());
232         continue;
233       }
234
235       // another special case: the center of circle or the focus of ellipse is selected;
236       // return the corresponding edge and a status of the center
237       if (theShapeType == GeomAPI_Shape::VERTEX) {
238         int aCenterType;
239         GeomShapePtr aSubshape = findEdgeByCenter(aCurShape, thePoint, TOLERANCE, aCenterType);
240         if (aSubshape) {
241           appendSubshapeOfResult(theSelected, *aResIt, aSubshape, aCenterType);
242           continue;
243         }
244       }
245     }
246
247     // one more special case: a vertex selected is a sketch point;
248     // it is not included into sketch result; thus, it is necessary
249     // to pass through the sketch sub-features and verify all points
250     if (theSelected.empty() && theShapeType == GeomAPI_Shape::VERTEX && !aResults.empty()) {
251       CompositeFeaturePtr aCF = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
252       std::shared_ptr<GeomAPI_PlanarEdges> aSketchEdges =
253           std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aResults.front()->shape());
254
255       if (aSketchEdges && aCF) {
256         bool isContinue = true;
257         int aNbSubs = aCF->numberOfSubs();
258         for (int aSubInd = 0; aSubInd < aNbSubs && isContinue; ++aSubInd) {
259           FeaturePtr aSub = aCF->subFeature(aSubInd);
260           const std::list<ResultPtr>& aSubResults = aSub->results();
261           for (std::list<ResultPtr>::const_iterator aSRIt = aSubResults.begin();
262                aSRIt != aSubResults.end(); ++aSRIt) {
263             GeomShapePtr aCurShape = (*aSRIt)->shape();
264             std::list<GeomShapePtr> aSubshapes =
265                 findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE);
266             if (!aSubshapes.empty()) {
267               appendSubshapeOfResult(theSelected, aResults.front(), aSubshapes);
268               isContinue = false;
269               break;
270             }
271           }
272         }
273       }
274     }
275
276     return !theSelected.empty();
277   }
278 } // namespace ModelGeomAlgo_Shape