Salome HOME
updated copyright message
[modules/shaper.git] / src / Model / Model_FiltersFactory.cpp
1 // Copyright (C) 2014-2023  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 void Model_FiltersFactory::registerFilter(const std::string& theID, ModelAPI_Filter* theFilter)
29 {
30   if (myFilters.find(theID) != myFilters.end()) {
31     Events_InfoMessage("Model_FiltersFactory", "Filter %1 is already registered").arg(theID).send();
32   }
33   else {
34     myFilters[theID] = FilterPtr(theFilter);
35   }
36 }
37
38 struct FilterArgs {
39   FilterPtr myFilter;
40   bool myReverse;
41   std::string myFilterID;
42 };
43
44 /// Returns the filter ID without the filter index
45 static std::string pureFilterID(const std::string& theID)
46 {
47   // remove from aPure "_" + number + "_" starting part
48   if (theID.size() > 3 && theID[0] == '_') {
49     int aNumDigits = 0;
50     while(theID[aNumDigits + 1] < '9' && theID[aNumDigits + 1] > '0')
51       aNumDigits++;
52     if (aNumDigits && theID[aNumDigits + 1] == '_') {
53       return theID.substr(aNumDigits + 2);
54     }
55   }
56   return theID;
57 }
58
59 bool Model_FiltersFactory::isValid(FeaturePtr theFiltersFeature,
60                                    ResultPtr theResult,
61                                    GeomShapePtr theShape)
62 {
63   // check that the shape type corresponds to the attribute list type
64   AttributePtr aBase =
65     std::dynamic_pointer_cast<ModelAPI_FiltersFeature>(theFiltersFeature)->baseAttribute();
66   if (aBase.get()) {
67     std::shared_ptr<ModelAPI_AttributeSelectionList> aList =
68       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aBase);
69     std::string aStrType = aList->selectionType();
70     GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(aStrType);
71     if (theShape->shapeType() != aType)
72       return false;
73   }
74   // prepare all filters args
75   ModelAPI_FiltersArgs anArgs;
76   std::list<FilterArgs> aFilters; /// all filters and the reverse values
77
78   std::list<std::string> aGroups;
79   theFiltersFeature->data()->allGroups(aGroups);
80   for(std::list<std::string>::iterator aGIter = aGroups.begin(); aGIter != aGroups.end(); aGIter++)
81   {
82     std::string aPureID = pureFilterID(*aGIter);
83     if (myFilters.find(aPureID) == myFilters.end())
84       continue;
85     std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
86     theFiltersFeature->data()->attributesOfGroup(*aGIter, anAttrs);
87     std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttrs.begin();
88     for(; anAttrIter != anAttrs.end(); anAttrIter++) {
89       std::string anArgID = (*anAttrIter)->id().substr((*aGIter).length() + 2);
90       if (anArgID.empty()) { // reverse flag
91         std::shared_ptr<ModelAPI_AttributeBoolean> aReverse =
92           std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(*anAttrIter);
93         FilterArgs aFArgs = { myFilters[aPureID] , aReverse->value() , *aGIter };
94         aFilters.push_back(aFArgs);
95
96       } else {
97         anArgs.add(*anAttrIter);
98       }
99     }
100   }
101
102   // iterate filters and check shape for validity for all of them
103   std::list<FilterArgs>::iterator aFilter = aFilters.begin();
104   for(; aFilter != aFilters.end(); aFilter++) {
105     anArgs.setFilter(aFilter->myFilterID);
106     bool aResult = aFilter->myFilter->isOk(theShape, theResult, anArgs);
107     if (aFilter->myReverse)
108       aResult = !aResult;
109     if (!aResult) // one filter is failed => exit immediately
110       return false;
111   }
112   // all filters are passed
113   return true;
114 }
115
116 std::list< std::pair<ResultPtr, GeomShapePtr> > Model_FiltersFactory::select
117 (const FiltersFeaturePtr& theFilterFeature,
118  const GeomAPI_Shape::ShapeType theShapeType)
119 {
120   std::list< std::pair<ResultPtr, GeomShapePtr> > aResList;
121
122   DocumentPtr aDoc = theFilterFeature->document();
123   int aNb = aDoc->size(ModelAPI_ResultBody::group());
124   ObjectPtr aObj;
125   ResultBodyPtr aBody;
126   for (int i = 0; i < aNb; i++) {
127     aObj = aDoc->object(ModelAPI_ResultBody::group(), i);
128     aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aObj);
129     GeomShapePtr aShape = aBody->shape();
130     std::list<GeomShapePtr> aSubShapes = aShape->subShapes(theShapeType, true);
131     std::list<GeomShapePtr>::const_iterator aShapesIt;
132     for (aShapesIt = aSubShapes.cbegin(); aShapesIt != aSubShapes.cend(); aShapesIt++) {
133       GeomShapePtr aSubShape = (*aShapesIt);
134
135       // degenerated edge is not valid selection
136       if (theShapeType == GeomAPI_Shape::EDGE)
137         if (aSubShape->edge()->isDegenerated())
138           continue;
139
140       bool isValid = this->isValid(theFilterFeature, aBody, aSubShape);
141
142       if (isValid) {
143         // bos #24043: Naming on a compsolid works wrong.
144         // Find a simple sub-result for the ViewerPrs context:
145         ResultBodyPtr aContext = aBody;
146         bool isComposite = aContext->numberOfSubs() > 0;
147         while (isComposite) {
148           isComposite = false;
149           int nbSubs = aContext->numberOfSubs();
150           for (int aSubIndex = 0; aSubIndex < nbSubs; aSubIndex++) {
151             ResultBodyPtr aSubResult = aContext->subResult(aSubIndex);
152             GeomShapePtr aSubResultShape = aSubResult->shape();
153             if (aSubResultShape->isSubShape(aSubShape)) {
154               aContext = aSubResult;
155               isComposite = aContext->numberOfSubs() > 0;
156               break;
157             }
158           }
159         }
160         std::pair<ResultPtr, GeomShapePtr> aPair (aContext, aSubShape);
161         aResList.push_back(aPair);
162       }
163     }
164   }
165
166   return aResList;
167 }
168
169 /// Returns list of filters for the given shape type
170 /// \param theType a shape type
171 std::list<FilterPtr> Model_FiltersFactory::filters(GeomAPI_Shape::ShapeType theType)
172 {
173   std::list<FilterPtr> aResult;
174   std::map<std::string, FilterPtr>::const_iterator anIt;
175   std::list<int> aTypes;
176   std::list<int>::const_iterator aTIt;
177   for (anIt = myFilters.cbegin(); anIt != myFilters.cend(); anIt++) {
178     if (anIt->second->isSupported(theType))
179       aResult.push_back(anIt->second);
180   }
181   return aResult;
182 }
183
184 FilterPtr Model_FiltersFactory::filter(std::string theID)
185 {
186   std::string aPureID = pureFilterID(theID);
187   std::map<std::string, FilterPtr>::iterator aFound = myFilters.find(aPureID);
188   return aFound == myFilters.end() ? FilterPtr() : aFound->second;
189 }
190
191 std::string Model_FiltersFactory::id(FilterPtr theFilter)
192 {
193   std::map<std::string, FilterPtr>::iterator anIter = myFilters.begin();
194   for(; anIter != myFilters.end(); anIter++) {
195     if (anIter->second == theFilter)
196       return anIter->first;
197   }
198   return ""; // unknown case
199 }