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