1 // Copyright (C) 2014-2020 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <Selector_Intersect.h>
22 #include <Selector_NameGenerator.h>
23 #include <Selector_NExplode.h>
25 #include <Locale_Convert.h>
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>
35 #include <TopoDS_Builder.hxx>
36 #include <TopoDS_Compound.hxx>
38 Selector_Intersect::Selector_Intersect() : Selector_AlgoWithSubs()
40 myWeakIndex = -1; // no index by default
41 myRecomputeWeakIndex = false;
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)
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());
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()))
60 theResults.Remove(aComIter);
66 bool Selector_Intersect::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
68 if (!useIntersections())
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)
81 aSelectionType = TopAbs_EDGE;
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())))
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());
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
111 if (!anInt.More()) { // all intersectors were correctly named
114 } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) {
115 aLastCommon = aCommon;
116 aLastIntersectors = anIntList;
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()))
127 if (!aCommonIter.More()) { // all geometry is same, result is a compound
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
143 if (!anInt.More()) { // all intersectors were correctly named
148 return false; // solution does not found
151 void Selector_Intersect::store()
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++) {
160 TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
161 if (myWeakIndex != -1) {
162 TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
166 bool Selector_Intersect::restore()
168 Handle(TDataStd_Integer) aShapeTypeAttr;
169 if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
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
179 Handle(TDataStd_Integer) aWeakInt;
180 if (label().FindAttribute(weakID(), aWeakInt)) {
181 myWeakIndex = aWeakInt->Get();
186 TDF_Label Selector_Intersect::restoreByName(std::wstring theName,
187 const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
189 myShapeType = theShapeType;
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()) :
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;
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'[') {
210 case 'e': aSubShapeType = TopAbs_EDGE; break;
211 case 'v': aSubShapeType = TopAbs_VERTEX; break;
216 TDF_Label aSubContext;
217 Selector_Algo* aSubSel =
218 Selector_Algo::restoreByName(newSubLabel(), baseDocument(), aSubStr, aSubShapeType,
219 geometricalNaming(), theNameGenerator, aSubContext);
220 if (!append(aSubSel))
223 if (aSubContext.IsNull()) {
228 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
229 if (!theNameGenerator->isLater(aContext, aSubContext))
230 aContext = aSubContext;
232 aContext = aSubContext;
235 return TDF_Label(); // invalid parentheses
240 bool Selector_Intersect::solve(const TopoDS_Shape& theContext)
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)) {
249 aSubSelectorShapes.Append((*aSubSel)->value());
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()))
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());
279 aResult = aCommon.First();
281 if (!aResult.IsNull()) {
282 Selector_Algo::store(aResult);
288 std::wstring Selector_Intersect::name(Selector_NameGenerator* theNameGenerator)
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++) {
295 aResult += (*aSubSel)->name(theNameGenerator);
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
302 case TopAbs_EDGE: aResult += L"e"; break;
303 case TopAbs_VERTEX: aResult += L"v"; break;
309 if (myWeakIndex != -1) {
310 std::wostringstream aWeakStr;
311 aWeakStr<<"["<<weakNameID()<<myWeakIndex<<"]";
312 aResult += aWeakStr.str();