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_Selector.h>
23 #include <TDF_ChildIDIterator.hxx>
24 #include <TopoDS_Iterator.hxx>
25 #include <TopoDS_Builder.hxx>
26 #include <TopExp_Explorer.hxx>
27 #include <TNaming_Tool.hxx>
28 #include <TNaming_NewShapeIterator.hxx>
29 #include <TNaming_OldShapeIterator.hxx>
30 #include <TNaming_SameShapeIterator.hxx>
31 #include <TNaming_Iterator.hxx>
32 #include <TNaming_Builder.hxx>
33 #include <TopTools_MapOfShape.hxx>
35 #include <TDataStd_Integer.hxx>
36 #include <TDataStd_ReferenceArray.hxx>
40 /// type of the selection, integerm keeps the Selector_Type value
41 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
42 /// type of the shape, stored in case it is intersection or container
43 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
44 // reference attribute that contains the reference to labels where the "from" or "base" shapes
45 // of selection are located
46 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
48 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
52 TDF_Label Selector_Selector::label()
57 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
58 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
59 TDF_LabelList& theResult)
61 for(TNaming_Iterator aThisIter(theFinal); aThisIter.More(); aThisIter.Next()) {
62 if (aThisIter.NewShape().IsSame(theValue)) {
63 const TopoDS_Shape& anOldShape = aThisIter.OldShape();
64 // searching for all old shapes in this sequence of modification
65 TNaming_OldShapeIterator anOldIter(anOldShape, theFinal->Label());
66 for(; anOldIter.More(); anOldIter.Next()) {
67 TNaming_Evolution anEvolution = anOldIter.NamedShape()->Evolution();
68 if (anEvolution == TNaming_PRIMITIVE) { // found a good candidate, a base shape
69 // check that this is not in the results already
70 const TDF_Label aResult = anOldIter.NamedShape()->Label();
71 TDF_LabelList::Iterator aResIter(theResult);
72 for(; aResIter.More(); aResIter.Next()) {
73 if (aResIter.Value().IsEqual(aResult))
76 if (!aResIter.More()) // not found, so add this new
77 theResult.Append(aResult);
78 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
79 // continue recursively
80 findBases(anOldIter.NamedShape(), anOldShape, theResult);
87 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
89 if (theValue.IsNull() || theContext.IsNull())
91 // check the value shape can be named as it is, or it is needed to construct it from the
92 // higher level shapes (like a box vertex by faces that form this vertex)
93 if (!TNaming_Tool::HasLabel(myLab, theValue)) {
94 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
95 myShapeType = aSelectionType;
96 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
97 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
98 { // iterate all sub-shapes and select them on sublabels
99 for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
100 if (!selectBySubSelector(theContext, aSubIter.Value())) {
101 return false; // if some selector is failed, everything is failed
104 myType = SELTYPE_CONTAINER;
108 // try to find the shape of the higher level type in the context shape
109 while(aSelectionType != TopAbs_FACE) {
110 if (aSelectionType == TopAbs_VERTEX) aSelectionType = TopAbs_EDGE;
111 else if (aSelectionType == TopAbs_EDGE) aSelectionType = TopAbs_FACE;
112 TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
113 for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
114 TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
115 for(; aSubExp.More(); aSubExp.Next()) {
116 if (aSubExp.Current().IsSame(theValue)) {
117 anIntersectors.Add(aSelExp.Current());
122 //TODO: check if intersectors produce several subs, try to remove one of the intersector
124 //TODO: check that solution is only one
126 // name the intersectors
127 std::list<Selector_Selector> aSubSelList;
128 TopTools_MapOfShape::Iterator anInt(anIntersectors);
129 for (; anInt.More(); anInt.Next()) {
130 if (!selectBySubSelector(theContext, anInt.Value())) {
131 break; // if some selector is failed, stop and search another solution
134 if (!anInt.More()) { // all intersectors were correctly named
135 myType = SELTYPE_INTERSECT;
140 // TODO: searching by neighbours
143 // searching for the base shapes of the value
144 Handle(TNaming_NamedShape) aPrimitiveNS;
145 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
146 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
148 Handle(TNaming_NamedShape) aNS;
149 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
150 TNaming_Evolution anEvolution = aNS->Evolution();
151 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
154 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
155 // check this is a new shape
156 TNaming_Iterator aNSIter(aNS);
157 for(; aNSIter.More(); aNSIter.Next())
158 if (aNSIter.NewShape().IsSame(theValue))
160 if (aNSIter.More()) // new was found
161 aModifList.Append(aNS);
166 if (!aPrimitiveNS.IsNull()) {
167 myType = SELTYPE_PRIMITIVE;
168 myFinal = aPrimitiveNS->Label();
172 if (aModifList.Extent() > 1) { // searching for the best modification result: by context
173 Handle(TNaming_NamedShape) aCandidate;
174 NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
175 for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
176 aCandidate = aModIter.Value();
177 TDF_Label aFatherLab = aCandidate->Label().Father();
178 Handle(TNaming_NamedShape) aFatherNS;
179 if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
180 for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
181 if (theContext.IsSame(anIter.NewShape())) { // found the best modification
188 // take the best candidate, or the last in the iteration
190 aModifList.Append(aCandidate);
193 if (!aModifList.IsEmpty()) {
194 // searching for all the base shapes of this modification
195 findBases(aModifList.First(), theValue, myBases);
196 myFinal = aModifList.First()->Label();
197 myType = SELTYPE_MODIFICATION;
198 return !myBases.IsEmpty();
201 // not found a good result
205 void Selector_Selector::store()
207 myLab.ForgetAllAttributes(true); // remove old naming data
208 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
210 case SELTYPE_CONTAINER:
211 case SELTYPE_INTERSECT: {
212 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
213 // store also all sub-selectors
214 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
215 for(; aSubSel != mySubSelList.end(); aSubSel++) {
220 case SELTYPE_PRIMITIVE: {
221 Handle(TDataStd_ReferenceArray) anArray =
222 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
223 anArray->SetValue(0, myFinal);
226 case SELTYPE_MODIFICATION: {
227 Handle(TDataStd_ReferenceArray) anArray =
228 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
229 TDF_LabelList::Iterator aBIter(myBases);
230 for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
231 anArray->SetValue(anIndex, aBIter.Value());
233 anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
236 default: { // unknown case
242 bool Selector_Selector::restore()
244 Handle(TDataStd_Integer) aTypeAttr;
245 if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
247 myType = Selector_Type(aTypeAttr->Get());
249 case SELTYPE_CONTAINER:
250 case SELTYPE_INTERSECT: {
251 Handle(TDataStd_Integer) aShapeTypeAttr;
252 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
254 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
255 // restore sub-selectors
256 bool aSubResult = true;
257 mySubSelList.clear();
258 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
259 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
260 if (!mySubSelList.back().restore())
265 case SELTYPE_PRIMITIVE: {
266 Handle(TDataStd_ReferenceArray) anArray;
267 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
268 myFinal = anArray->Value(0);
273 case SELTYPE_MODIFICATION: {
274 Handle(TDataStd_ReferenceArray) anArray;
275 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
276 int anUpper = anArray->Upper();
277 for(int anIndex = 0; anIndex < anUpper; anIndex++) {
278 myBases.Append(anArray->Value(anIndex));
280 myFinal = anArray->Value(anUpper);
285 default: { // unknown case
291 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
292 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
293 TopTools_MapOfShape& theResults)
295 for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
296 TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
297 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
298 if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
299 theResults.Add(aBaseIter.Shape());
301 findFinals(aBaseIter.Shape(), theFinal, theResults);
308 bool Selector_Selector::solve()
310 TopoDS_Shape aResult; // null if invalid
312 case SELTYPE_CONTAINER: {
313 TopoDS_Builder aBuilder;
314 switch(myShapeType) {
315 case TopAbs_COMPOUND: {
316 TopoDS_Compound aComp;
317 aBuilder.MakeCompound(aComp);
321 case TopAbs_COMPSOLID: {
322 TopoDS_CompSolid aComp;
323 aBuilder.MakeCompSolid(aComp);
329 aBuilder.MakeShell(aShell);
335 aBuilder.MakeWire(aWire);
340 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
341 for(; aSubSel != mySubSelList.end(); aSubSel++) {
342 if (!aSubSel->solve()) {
345 aBuilder.Add(aResult, aSubSel->value());
349 case SELTYPE_INTERSECT: {
350 TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
351 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
352 for(; aSubSel != mySubSelList.end(); aSubSel++) {
353 if (!aSubSel->solve()) {
356 TopoDS_Shape anArg = aSubSel->value();
357 TopTools_MapOfShape aCurrentMap;
358 for(TopExp_Explorer anExp(anArg, myShapeType); anExp.More(); anExp.Next()) {
359 if (aCurrentMap.Add(anExp.Current()) && aSubSel == mySubSelList.begin())
360 aCommon.Append(anExp.Current());
362 if (aSubSel != mySubSelList.begin()) { // remove from common shapes not in aCurrentMap
363 for(TopoDS_ListOfShape::Iterator aComIter(aCommon); aComIter.More(); ) {
364 if (aCurrentMap.Contains(aComIter.Value()))
367 aCommon.Remove(aComIter);
371 if (aCommon.Extent() != 1)
373 aResult = aCommon.First();
376 case SELTYPE_PRIMITIVE: {
377 Handle(TNaming_NamedShape) aNS;
378 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
379 aResult = aNS->Get();
382 case SELTYPE_MODIFICATION: {
383 TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
384 TDF_LabelList::Iterator aBase(myBases);
385 for(; aBase.More(); aBase.Value()) {
386 TopTools_MapOfShape aFinals;
387 for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
388 findFinals(aBaseShape.NewShape(), myFinal, aFinals);
389 if (!aFinals.IsEmpty()) {
390 if (aFinalsCommon.IsEmpty()) { // just copy all to common
391 for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
392 aFinalsCommon.Append(aFinal.Key());
394 } else { // keep only shapes presented in both lists
395 TopoDS_ListOfShape::Iterator aCommon(aFinalsCommon);
396 for(; aCommon.More(); aCommon.Next()) {
397 if (aFinals.Contains(aCommon.Value())) {
399 } else { // common is not found, remove it
400 aFinalsCommon.Remove(aCommon);
406 if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
407 aResult = aFinalsCommon.First();
409 default: { // unknown case
413 TNaming_Builder aBuilder(myLab);
414 if (!aResult.IsNull()) {
415 aBuilder.Select(aResult, aResult);
418 return false; // builder just erases the named shape in case of error
421 TopoDS_Shape Selector_Selector::value()
423 Handle(TNaming_NamedShape) aNS;
424 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
426 return TopoDS_Shape(); // empty, error shape
429 bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
431 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
432 if (!mySubSelList.back().select(theContext, theValue)) {
433 mySubSelList.clear(); // if one of the selector is failed, all become invalid