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