1 // Copyright (C) 2014-2017 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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <Selector_Intersect.h>
23 #include <Selector_NameGenerator.h>
24 #include <Selector_NExplode.h>
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>
34 #include <TopoDS_Builder.hxx>
35 #include <TopoDS_Compound.hxx>
37 Selector_Intersect::Selector_Intersect() : Selector_AlgoWithSubs()
39 myWeakIndex = -1; // no index by default
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)
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());
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()))
58 theResults.Remove(aComIter);
64 bool Selector_Intersect::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
66 if (!useIntersections())
68 myShapeType = theValue.ShapeType();
69 TopAbs_ShapeEnum aSelectionType = myShapeType;
70 // try to find the shape of the higher level type in the context shape
71 bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
72 TopoDS_ListOfShape aLastCommon; // store not good commons, but which may be used for weak naming
73 TopoDS_ListOfShape aLastIntersectors;
74 while(aSelectionType != TopAbs_FACE || !aFacesTried) {
75 if (aSelectionType == TopAbs_FACE) {
76 if (theValue.ShapeType() != TopAbs_VERTEX)
79 aSelectionType = TopAbs_EDGE;
81 aSelectionType = TopAbs_FACE;
82 TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
83 TopoDS_ListOfShape anIntList; // same as anIntersectors
84 for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
85 if (aSelectionType == TopAbs_EDGE &&
86 BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
88 TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
89 for(; aSubExp.More(); aSubExp.Next()) {
90 if (aSubExp.Current().IsSame(theValue)) {
91 if (anIntersectors.Add(aSelExp.Current()))
92 anIntList.Append(aSelExp.Current());
97 // check that solution is only one
98 TopoDS_ListOfShape aCommon;
99 commonShapes(anIntList, theValue.ShapeType(), aCommon);
100 if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
101 // name the intersectors
102 TopoDS_ListOfShape::Iterator anInt(anIntList);
103 for (; anInt.More(); anInt.Next()) {
104 Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(),
105 newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), false);
106 if (!append(aSubAlgo))
107 break; // if some selector is failed, stop and search another solution
109 if (!anInt.More()) { // all intersectors were correctly named
112 } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) {
113 aLastCommon = aCommon;
114 aLastIntersectors = anIntList;
117 if (aLastCommon.Extent() > 1) {
118 if (alwaysGeometricalNaming()) {
119 TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon);
120 TopoDS_Shape aFirst = aCommonIter.Value();
121 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
122 if (!sameGeometry(aFirst, aCommonIter.Value()))
125 if (!aCommonIter.More()) { // all geometry is same, result is a compound
129 // weak naming to distinguish commons coming from intersection
130 Selector_NExplode aNexp(aLastCommon);
131 myWeakIndex = aNexp.index(theValue);
132 if (myWeakIndex != -1) {
133 // name the intersectors
134 TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
135 for (; anInt.More(); anInt.Next()) {
136 Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(),
137 newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), false);
138 if (!append(aSubAlgo))
139 break; // if some selector is failed, stop and search another solution
141 if (!anInt.More()) { // all intersectors were correctly named
146 return false; // solution does not found
149 void Selector_Intersect::store()
151 storeType(Selector_Algo::SELTYPE_INTERSECT);
152 // store all sub-selectors
153 TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
154 std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
155 for(; aSubSel != list().cend(); aSubSel++) {
158 TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
159 if (myWeakIndex != -1) {
160 TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
164 bool Selector_Intersect::restore()
166 Handle(TDataStd_Integer) aShapeTypeAttr;
167 if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
169 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
170 // restore sub-selectors
171 bool aSubResult = true;
172 for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) {
173 Selector_Algo* aSubSel = restoreByLab(aSub.Value(), baseDocument());
174 if (!append(aSubSel, false)) {
175 break; // some empty label left in the end
178 Handle(TDataStd_Integer) aWeakInt;
179 if (label().FindAttribute(weakID(), aWeakInt)) {
180 myWeakIndex = aWeakInt->Get();
185 TDF_Label Selector_Intersect::restoreByName(std::string theName,
186 const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
188 myShapeType = theShapeType;
190 for(size_t aStart = 0; aStart != std::string::npos; aStart = theName.find('[', aStart + 1)) {
191 size_t anEndPos = theName.find(']', aStart + 1);
192 if (anEndPos != std::string::npos) {
193 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
194 if (aSubStr.find(weakNameID()) == 0) { // weak name identifier
195 std::string aWeakIndex = aSubStr.substr(weakNameID().size());
196 myWeakIndex = atoi(aWeakIndex.c_str());
199 TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
200 if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
201 char aShapeChar = theName[anEndPos + 1];
202 if (theName[anEndPos + 1] != '[') {
204 case 'c': aSubShapeType = TopAbs_COMPOUND; break;
205 case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
206 case 's': aSubShapeType = TopAbs_SOLID; break;
207 case 'h': aSubShapeType = TopAbs_SHELL; break;
208 case 'w': aSubShapeType = TopAbs_WIRE; break;
209 case 'e': aSubShapeType = TopAbs_EDGE; break;
210 case 'v': aSubShapeType = TopAbs_VERTEX; break;
215 TDF_Label aSubContext;
216 Selector_Algo* aSubSel =
217 Selector_Algo::restoreByName(
218 newSubLabel(), baseDocument(), aSubStr, aSubShapeType, theNameGenerator, aSubContext);
219 if (!append(aSubSel))
222 if (aSubContext.IsNull()) {
227 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
228 if (!theNameGenerator->isLater(aContext, aSubContext))
229 aContext = aSubContext;
231 aContext = aSubContext;
234 return TDF_Label(); // invalid parentheses
239 bool Selector_Intersect::solve(const TopoDS_Shape& theContext)
241 TopoDS_Shape aResult;
242 TopoDS_ListOfShape aSubSelectorShapes;
243 std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
244 for(; aSubSel != list().cend(); aSubSel++) {
245 if (!(*aSubSel)->solve(theContext)) {
248 aSubSelectorShapes.Append((*aSubSel)->value());
250 TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
251 commonShapes(aSubSelectorShapes, myShapeType, aCommon);
252 if (aCommon.Extent() != 1) {
253 if (myWeakIndex != -1) {
254 Selector_NExplode aNexp(aCommon);
255 aResult = aNexp.shape(myWeakIndex);
256 } else if (geometricalNaming() && aCommon.Extent() > 1) {
257 // check results are on the same geometry, create compound
258 TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
259 TopoDS_Shape aFirst = aCommonIter.Value();
260 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
261 if (!sameGeometry(aFirst, aCommonIter.Value()))
264 if (!aCommonIter.More()) { // all geometry is same, create a result compound
265 TopoDS_Builder aBuilder;
266 TopoDS_Compound aCompound;
267 aBuilder.MakeCompound(aCompound);
268 for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) {
269 aBuilder.Add(aCompound, aCommonIter.Value());
277 aResult = aCommon.First();
279 if (!aResult.IsNull()) {
280 Selector_Algo::store(aResult);
286 std::string Selector_Intersect::name(Selector_NameGenerator* theNameGenerator)
289 // add names of sub-components one by one in "[]" +optionally [weak_name_1]
290 std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
291 for(; aSubSel != list().cend(); aSubSel++) {
293 aResult += (*aSubSel)->name(theNameGenerator);
295 TopoDS_Shape aSubVal = (*aSubSel)->value();
296 if (!aSubVal.IsNull()) {
297 TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
298 if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
300 case TopAbs_COMPOUND: aResult += "c"; break;
301 case TopAbs_COMPSOLID: aResult += "o"; break;
302 case TopAbs_SOLID: aResult += "s"; break;
303 case TopAbs_SHELL: aResult += "h"; break;
304 case TopAbs_WIRE: aResult += "w"; break;
305 case TopAbs_EDGE: aResult += "e"; break;
306 case TopAbs_VERTEX: aResult += "v"; break;
312 if (myWeakIndex != -1) {
313 std::ostringstream aWeakStr;
314 aWeakStr<<"["<<weakNameID()<<myWeakIndex<<"]";
315 aResult += aWeakStr.str();