Salome HOME
using a better solution to do compare doubles for shape physical properties
[modules/shaper.git] / src / Model / Model_FiltersFactory.cpp
1 // Copyright (C) 2014-2024  CEA, EDF
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 "Model_FiltersFactory.h"
21
22 #include "ModelAPI_AttributeBoolean.h"
23 #include "ModelAPI_AttributeSelectionList.h"
24 #include <Events_InfoMessage.h>
25
26 #include "GeomAPI_Edge.h"
27
28 #include <unordered_map>
29 #include <stack>
30
31 typedef std::unordered_map<GeomShapePtr, ResultBodyPtr,
32                           GeomAPI_Shape::Hash, GeomAPI_Shape::Equal> DataMapOfShapesToResults;
33
34 void Model_FiltersFactory::registerFilter(const std::string& theID, ModelAPI_Filter* theFilter)
35 {
36   if (myFilters.find(theID) != myFilters.end()) {
37     Events_InfoMessage("Model_FiltersFactory", "Filter %1 is already registered").arg(theID).send();
38   }
39   else {
40     myFilters[theID] = FilterPtr(theFilter);
41   }
42 }
43
44 struct FilterArgs {
45   FilterPtr myFilter;
46   bool myReverse;
47   std::string myFilterID;
48 };
49
50 /// Returns the filter ID without the filter index
51 static std::string pureFilterID(const std::string& theID)
52 {
53   // remove from aPure "_" + number + "_" starting part
54   if (theID.size() > 3 && theID[0] == '_') {
55     int aNumDigits = 0;
56     while(theID[aNumDigits + 1] < '9' && theID[aNumDigits + 1] > '0')
57       aNumDigits++;
58     if (aNumDigits && theID[aNumDigits + 1] == '_') {
59       return theID.substr(aNumDigits + 2);
60     }
61   }
62   return theID;
63 }
64
65 static void fillMapOfShapesToResults(DataMapOfShapesToResults& theMap,
66                              const ResultBodyPtr& theBodyResult,
67                              const GeomAPI_Shape::ShapeType theShapeType)
68 {
69   std::stack<ResultBodyPtr> stack;
70   stack.push(theBodyResult);
71
72   while(!stack.empty())
73   {
74     ResultBodyPtr aCurrBodyRes = stack.top();
75     stack.pop();
76
77     int nbSubs = aCurrBodyRes->numberOfSubs();
78     if(nbSubs == 0)
79     {
80       GeomShapePtr aShape = aCurrBodyRes->shape();
81       std::list<GeomShapePtr> aSubShapes = aShape->subShapes(theShapeType, true);
82       std::list<GeomShapePtr>::const_iterator aShapesIt;
83       for (aShapesIt = aSubShapes.cbegin(); aShapesIt != aSubShapes.cend(); aShapesIt++)
84       {
85         GeomShapePtr aSubShape = (*aShapesIt);
86
87         // degenerated edge is not valid selection
88         if (theShapeType == GeomAPI_Shape::EDGE)
89           if (aSubShape->edge()->isDegenerated())
90             continue;
91         
92         if (theMap.find(aSubShape) == theMap.end()) 
93         {
94           theMap.emplace(aSubShape, aCurrBodyRes);
95         }
96       }
97     }
98     else
99     {
100         for (int aSubIndex = 0; aSubIndex < nbSubs; aSubIndex++) 
101         {
102           stack.push(aCurrBodyRes->subResult(aSubIndex));
103         }
104     }
105   }
106
107 }
108
109 bool Model_FiltersFactory::isValid(FeaturePtr theFiltersFeature,
110                                    ResultPtr theResult,
111                                    GeomShapePtr theShape)
112 {
113   // check that the shape type corresponds to the attribute list type
114   AttributePtr aBase =
115     std::dynamic_pointer_cast<ModelAPI_FiltersFeature>(theFiltersFeature)->baseAttribute();
116   if (aBase.get()) {
117     std::shared_ptr<ModelAPI_AttributeSelectionList> aList =
118       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aBase);
119     std::string aStrType = aList->selectionType();
120     GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(aStrType);
121     if (theShape->shapeType() != aType)
122       return false;
123   }
124   // prepare all filters args
125   ModelAPI_FiltersArgs anArgs;
126   std::list<FilterArgs> aFilters; /// all filters and the reverse values
127
128   std::list<std::string> aGroups;
129   theFiltersFeature->data()->allGroups(aGroups);
130   for(std::list<std::string>::iterator aGIter = aGroups.begin(); aGIter != aGroups.end(); aGIter++)
131   {
132     std::string aPureID = pureFilterID(*aGIter);
133     if (myFilters.find(aPureID) == myFilters.end())
134       continue;
135     std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
136     theFiltersFeature->data()->attributesOfGroup(*aGIter, anAttrs);
137     std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttrs.begin();
138     for(; anAttrIter != anAttrs.end(); anAttrIter++) {
139       std::string anArgID = (*anAttrIter)->id().substr((*aGIter).length() + 2);
140       if (anArgID.empty()) { // reverse flag
141         std::shared_ptr<ModelAPI_AttributeBoolean> aReverse =
142           std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(*anAttrIter);
143         FilterArgs aFArgs = { myFilters[aPureID] , aReverse->value() , *aGIter };
144         aFilters.push_back(aFArgs);
145
146       } else {
147         anArgs.add(*anAttrIter);
148       }
149     }
150   }
151
152   // iterate filters and check shape for validity for all of them
153   std::list<FilterArgs>::iterator aFilter = aFilters.begin();
154   for(; aFilter != aFilters.end(); aFilter++) {
155     anArgs.setFilter(aFilter->myFilterID);
156     bool aResult = aFilter->myFilter->isOk(theShape, theResult, anArgs);
157
158     if (aFilter->myReverse)
159       aResult = !aResult;
160     if (!aResult) // one filter is failed => exit immediately
161       return false;
162   }
163   // all filters are passed
164   return true;
165 }
166
167 std::list< std::pair<ResultPtr, GeomShapePtr> > Model_FiltersFactory::select
168 (const FiltersFeaturePtr& theFilterFeature,
169  const GeomAPI_Shape::ShapeType theShapeType)
170 {
171   std::list< std::pair<ResultPtr, GeomShapePtr> > aResList;
172
173   DocumentPtr aDoc = theFilterFeature->document();
174   int aNb = aDoc->size(ModelAPI_ResultBody::group());
175   ObjectPtr aObj;
176   ResultBodyPtr aBody;
177   for (int i = 0; i < aNb; i++) 
178   {
179     aObj = aDoc->object(ModelAPI_ResultBody::group(), i);
180     aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aObj);
181     DataMapOfShapesToResults aShapeToResMap;
182     fillMapOfShapesToResults(aShapeToResMap, aBody, theShapeType);
183
184     GeomShapePtr aShape = aBody->shape();
185     std::list<GeomShapePtr> aSubShapes = aShape->subShapes(theShapeType, true);
186     std::list<GeomShapePtr>::const_iterator aShapesIt;
187     for (aShapesIt = aSubShapes.cbegin(); aShapesIt != aSubShapes.cend(); aShapesIt++)
188     {
189       GeomShapePtr aSubShape = (*aShapesIt);
190       // degenerated edge is not valid selection
191       if (theShapeType == GeomAPI_Shape::EDGE)
192         if (aSubShape->edge()->isDegenerated())
193           continue;
194
195
196       if (aShapeToResMap.find(aSubShape) != aShapeToResMap.end()) 
197       {
198         ResultBodyPtr aResBody = aShapeToResMap[aSubShape];
199         if(this->isValid(theFilterFeature, aResBody, aSubShape))
200         {
201            std::pair<ResultPtr, GeomShapePtr> aPair(aResBody, aSubShape);
202           aResList.push_back(aPair);
203         }
204       }
205     }
206   }
207   return aResList;
208 }
209
210 /// Returns list of filters for the given shape type
211 /// \param theType a shape type
212 std::list<FilterPtr> Model_FiltersFactory::filters(GeomAPI_Shape::ShapeType theType)
213 {
214   std::list<FilterPtr> aResult;
215   std::map<std::string, FilterPtr>::const_iterator anIt;
216   std::list<int> aTypes;
217   std::list<int>::const_iterator aTIt;
218   for (anIt = myFilters.cbegin(); anIt != myFilters.cend(); anIt++) {
219     if (anIt->second->isSupported(theType))
220       aResult.push_back(anIt->second);
221   }
222   return aResult;
223 }
224
225 FilterPtr Model_FiltersFactory::filter(std::string theID)
226 {
227   std::string aPureID = pureFilterID(theID);
228   std::map<std::string, FilterPtr>::iterator aFound = myFilters.find(aPureID);
229   return aFound == myFilters.end() ? FilterPtr() : aFound->second;
230 }
231
232 std::string Model_FiltersFactory::id(FilterPtr theFilter)
233 {
234   std::map<std::string, FilterPtr>::iterator anIter = myFilters.begin();
235   for(; anIter != myFilters.end(); anIter++) {
236     if (anIter->second == theFilter)
237       return anIter->first;
238   }
239   return ""; // unknown case
240 }