Salome HOME
Copyright update 2020
[modules/shaper.git] / src / Selector / Selector_Intersect.cpp
1 // Copyright (C) 2014-2020  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 <Selector_Intersect.h>
21
22 #include <Selector_NameGenerator.h>
23 #include <Selector_NExplode.h>
24
25 #include <TNaming_NamedShape.hxx>
26 #include <TDataStd_Name.hxx>
27 #include <TDataStd_Integer.hxx>
28 #include <TDF_ChildIterator.hxx>
29 #include <TopTools_MapOfShape.hxx>
30 #include <TopExp_Explorer.hxx>
31 #include <BRep_Tool.hxx>
32 #include <TopoDS.hxx>
33 #include <TopoDS_Builder.hxx>
34 #include <TopoDS_Compound.hxx>
35
36 Selector_Intersect::Selector_Intersect() : Selector_AlgoWithSubs()
37 {
38   myWeakIndex = -1; // no index by default
39 }
40
41 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
42 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
43   TopoDS_ListOfShape& theResults)
44 {
45   TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
46   for(; aSubSel != theShapes.end(); aSubSel++) {
47     TopTools_MapOfShape aCurrentMap;
48     for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
49       if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
50         theResults.Append(anExp.Current());
51     }
52     if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
53       for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
54         if (aCurrentMap.Contains(aComIter.Value()))
55           aComIter.Next();
56         else
57           theResults.Remove(aComIter);
58       }
59     }
60   }
61 }
62
63 bool Selector_Intersect::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
64 {
65   if (!useIntersections())
66     return false;
67   myShapeType = theValue.ShapeType();
68   TopAbs_ShapeEnum aSelectionType = myShapeType;
69   // try to find the shape of the higher level type in the context shape
70   bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
71   TopoDS_ListOfShape aLastCommon; // store not good commons, but which may be used for weak naming
72   TopoDS_ListOfShape aLastIntersectors;
73   while(aSelectionType != TopAbs_FACE || !aFacesTried) {
74     if (aSelectionType == TopAbs_FACE) {
75       if (theValue.ShapeType() != TopAbs_VERTEX)
76         break;
77       aFacesTried = true;
78       aSelectionType = TopAbs_EDGE;
79     } else
80       aSelectionType = TopAbs_FACE;
81     TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
82     TopoDS_ListOfShape anIntList; // same as anIntersectors
83     for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
84       if (aSelectionType == TopAbs_EDGE &&
85         BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
86         continue;
87       TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
88       for(; aSubExp.More(); aSubExp.Next()) {
89         if (aSubExp.Current().IsSame(theValue)) {
90           if (anIntersectors.Add(aSelExp.Current()))
91             anIntList.Append(aSelExp.Current());
92           break;
93         }
94       }
95     }
96     // check that solution is only one
97     TopoDS_ListOfShape aCommon;
98     commonShapes(anIntList, theValue.ShapeType(), aCommon);
99     if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
100       // name the intersectors
101       TopoDS_ListOfShape::Iterator anInt(anIntList);
102       for (; anInt.More(); anInt.Next()) {
103         Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(),
104           newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), false);
105         if (!append(aSubAlgo))
106           break; // if some selector is failed, stop and search another solution
107       }
108       if (!anInt.More()) { // all intersectors were correctly named
109         return true;
110       }
111     } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty())  {
112       aLastCommon = aCommon;
113       aLastIntersectors = anIntList;
114     }
115   }
116   if (aLastCommon.Extent() > 1) {
117     if (alwaysGeometricalNaming()) {
118       TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon);
119       TopoDS_Shape aFirst = aCommonIter.Value();
120       for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
121         if (!sameGeometry(aFirst, aCommonIter.Value()))
122           break;
123       }
124       if (!aCommonIter.More()) { // all geometry is same, result is a compound
125         return true;
126       }
127     }
128     // weak naming to distinguish commons coming from intersection
129     Selector_NExplode aNexp(aLastCommon);
130     myWeakIndex = aNexp.index(theValue);
131     if (myWeakIndex != -1) {
132       // name the intersectors
133       TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
134       for (; anInt.More(); anInt.Next()) {
135         Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(),
136           newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), false);
137         if (!append(aSubAlgo))
138           break; // if some selector is failed, stop and search another solution
139       }
140       if (!anInt.More()) { // all intersectors were correctly named
141         return true;
142       }
143     }
144   }
145   return false; // solution does not found
146 }
147
148 void Selector_Intersect::store()
149 {
150   storeType(Selector_Algo::SELTYPE_INTERSECT);
151   // store all sub-selectors
152   TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
153   std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
154   for(; aSubSel != list().cend(); aSubSel++) {
155     (*aSubSel)->store();
156   }
157   TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
158   if (myWeakIndex != -1) {
159     TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
160   }
161 }
162
163 bool Selector_Intersect::restore()
164 {
165   Handle(TDataStd_Integer) aShapeTypeAttr;
166   if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
167     return false;
168   myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
169   // restore sub-selectors
170   bool aSubResult = true;
171   for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) {
172     Selector_Algo* aSubSel = restoreByLab(aSub.Value(), baseDocument());
173     if (!append(aSubSel, false)) {
174       break; // some empty label left in the end
175     }
176   }
177   Handle(TDataStd_Integer) aWeakInt;
178   if (label().FindAttribute(weakID(), aWeakInt)) {
179     myWeakIndex = aWeakInt->Get();
180   }
181   return true;
182 }
183
184 TDF_Label Selector_Intersect::restoreByName(std::string theName,
185   const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
186 {
187   myShapeType = theShapeType;
188   TDF_Label aContext;
189   for(size_t aStart = 0; aStart != std::string::npos; aStart = theName.find('[', aStart + 1)) {
190     size_t anEndPos = theName.find(']', aStart + 1);
191     if (anEndPos != std::string::npos) {
192       std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
193       if (aSubStr.find(weakNameID()) == 0) { // weak name identifier
194         std::string aWeakIndex = aSubStr.substr(weakNameID().size());
195         myWeakIndex = atoi(aWeakIndex.c_str());
196         continue;
197       }
198       TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
199       if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
200         char aShapeChar = theName[anEndPos + 1];
201         if (theName[anEndPos + 1] != '[') {
202           switch(aShapeChar) {
203           case 'e': aSubShapeType = TopAbs_EDGE; break;
204           case 'v': aSubShapeType = TopAbs_VERTEX; break;
205           default:;
206           }
207         }
208       }
209       TDF_Label aSubContext;
210       Selector_Algo* aSubSel =
211         Selector_Algo::restoreByName(newSubLabel(), baseDocument(), aSubStr, aSubShapeType,
212           geometricalNaming(), theNameGenerator, aSubContext);
213       if (!append(aSubSel))
214         return TDF_Label();
215
216       if (aSubContext.IsNull()) {
217         delete aSubSel;
218         clearSubAlgos();
219         return TDF_Label();
220       }
221       if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
222         if (!theNameGenerator->isLater(aContext, aSubContext))
223           aContext = aSubContext;
224       } else {
225         aContext = aSubContext;
226       }
227     } else
228       return TDF_Label(); // invalid parentheses
229   }
230   return aContext;
231 }
232
233 bool Selector_Intersect::solve(const TopoDS_Shape& theContext)
234 {
235   TopoDS_Shape aResult;
236   TopoDS_ListOfShape aSubSelectorShapes;
237   std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
238   for(; aSubSel != list().cend(); aSubSel++) {
239     if (!(*aSubSel)->solve(theContext)) {
240       return false;
241     }
242     aSubSelectorShapes.Append((*aSubSel)->value());
243   }
244   TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
245   commonShapes(aSubSelectorShapes, myShapeType, aCommon);
246   if (aCommon.Extent() != 1) {
247     if (myWeakIndex != -1) {
248       Selector_NExplode aNexp(aCommon);
249       aResult = aNexp.shape(myWeakIndex);
250     } else if (geometricalNaming() && aCommon.Extent() > 1) {
251       // check results are on the same geometry, create compound
252       TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
253       TopoDS_Shape aFirst = aCommonIter.Value();
254       for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
255         if (!sameGeometry(aFirst, aCommonIter.Value()))
256           break;
257       }
258       if (!aCommonIter.More()) { // all geometry is same, create a result compound
259         TopoDS_Builder aBuilder;
260         TopoDS_Compound aCompound;
261         aBuilder.MakeCompound(aCompound);
262         for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) {
263           aBuilder.Add(aCompound, aCommonIter.Value());
264         }
265         aResult = aCompound;
266       }
267     } else {
268       return false;
269     }
270   } else {
271     aResult = aCommon.First();
272   }
273   if (!aResult.IsNull()) {
274     Selector_Algo::store(aResult);
275     return true;
276   }
277   return false;
278 }
279
280 std::string Selector_Intersect::name(Selector_NameGenerator* theNameGenerator)
281 {
282   std::string aResult;
283   // add names of sub-components one by one in "[]" +optionally [weak_name_1]
284   std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
285   for(; aSubSel != list().cend(); aSubSel++) {
286     aResult += '[';
287     aResult += (*aSubSel)->name(theNameGenerator);
288     aResult += ']';
289     TopoDS_Shape aSubVal = (*aSubSel)->value();
290     if (!aSubVal.IsNull()) {
291       TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
292       if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
293         switch(aSubType) {
294         case TopAbs_EDGE: aResult += "e"; break;
295         case TopAbs_VERTEX: aResult += "v"; break;
296         default:;
297         }
298       }
299     }
300   }
301   if (myWeakIndex != -1) {
302     std::ostringstream aWeakStr;
303     aWeakStr<<"["<<weakNameID()<<myWeakIndex<<"]";
304     aResult += aWeakStr.str();
305   }
306   return aResult;
307 }