0026155: TNaming, CurrentShape: order of shapes in Modification compound is unpredictable
[occt.git] / src / TNaming / TNaming_Selector.cxx
1 // Created on: 1999-09-30
2 // Created by: Denis PASCAL
3 // Copyright (c) 1999-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <TNaming_Selector.ixx>
18 #include <TNaming.hxx>
19 #include <TNaming_Naming.hxx>
20 #include <TNaming_Builder.hxx> 
21 #include <TNaming_Identifier.hxx>
22 #include <TNaming_NameType.hxx>
23 #include <TDF_ChildIterator.hxx> 
24 #include <TDF_Tool.hxx>
25 #include <TDF_IDFilter.hxx>
26 #include <TNaming_NamingTool.hxx>
27 #include <TNaming_NewShapeIterator.hxx>
28
29 #include <TopTools_IndexedMapOfShape.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx>
31 #include <TopoDS_Iterator.hxx>
32
33 //#define MDTV_DEB_SEL
34 #ifdef OCCT_DEBUG_SEL
35 //#define MDTV_DEB_BNP
36 #include <TopExp_Explorer.hxx>
37 #include <TCollection_AsciiString.hxx>
38 #include <TNaming_Tool.hxx>
39 #include <BRep_Tool.hxx>
40 #include <TopoDS.hxx>
41 #include <TNaming_UsedShapes.hxx>
42 void PrintEntry(const TDF_Label&       label, const Standard_Boolean allLevels)
43 {
44   TCollection_AsciiString entry;
45   TDF_Tool::Entry(label, entry);
46   cout << "LabelEntry = "<< entry << endl;
47   if(allLevels) {
48     TDF_ChildIterator it (label, allLevels);
49     for (; it.More(); it.Next()) {
50       TDF_Tool::Entry(it.Value(), entry);
51         cout << "ChildLabelEntry = "<< entry << endl;
52       }
53   }
54 }
55 #include <BRepTools.hxx>
56 static void Write(const TopoDS_Shape& shape,
57                       const Standard_CString filename) 
58 {
59   char buf[256];
60   if(strlen(filename) > 255) return;
61 #if defined WNT
62   strcpy_s (buf, filename);
63 #else
64   strcpy (buf, filename);
65 #endif
66   char* p = buf;
67   while (*p) {
68     if(*p == ':')
69       *p = '-';
70     p++;
71   }
72   ofstream save (buf);
73   if(!save) 
74     cout << "File " << buf << " was not created: rdstate = " << save.rdstate() << endl;
75   save << "DBRep_DrawableShape" << endl << endl;
76   if(!shape.IsNull()) BRepTools::Write(shape, save);
77   save.close();
78 }
79 #endif
80
81 #define ORIENTATION_DSOPT
82 #ifdef ORIENTATION_DSOPT
83 #include <TopTools_MapOfOrientedShape.hxx>
84 #include <TopTools_MapIteratorOfMapOfOrientedShape.hxx>
85 #include <TDF_ChildIDIterator.hxx>
86 #include <TNaming_Tool.hxx>
87 #include <TNaming_Iterator.hxx>
88 #include <TNaming_OldShapeIterator.hxx>
89 //==========================================================================================
90 inline static void MapOfOrientedShapes(const TopoDS_Shape& S, TopTools_MapOfOrientedShape& M) 
91 {
92   M.Add(S);
93   TopoDS_Iterator It(S,Standard_True,Standard_True);
94   while (It.More()) {
95     MapOfOrientedShapes(It.Value(),M);
96     It.Next();
97   }
98 }
99 //=======================================================================
100 static void BuildAtomicMap(const TopoDS_Shape& S, TopTools_MapOfOrientedShape& M)
101 {
102   if(S.ShapeType() > TopAbs_COMPSOLID) return;
103   TopoDS_Iterator it(S);
104   for(;it.More();it.Next()) {
105     if(it.Value().ShapeType() > TopAbs_COMPSOLID) 
106       M.Add(it.Value());
107     else 
108       BuildAtomicMap(it.Value(), M);   
109   }
110 }
111
112 //==========================================================================================
113 static const Handle(TNaming_NamedShape) FindPrevNDS(const Handle(TNaming_NamedShape)& CNS)
114 {
115   Handle(TNaming_NamedShape) aNS;
116   TNaming_Iterator it(CNS);
117   if(it.More()) {
118     if(!it.OldShape().IsNull()) {
119       aNS = TNaming_Tool::NamedShape(it.OldShape(), CNS->Label());
120       return aNS;
121     }
122   }
123   return aNS;
124 }
125
126 //==========================================================================================
127 // Purpose: checks correspondens between orientation of sub-shapes of Context and orientation
128 //          of sub-shapes registered in DF and put under result label
129 //==========================================================================================
130 static Standard_Boolean IsSpecificCase(const  TDF_Label& F, const TopoDS_Shape& Context)
131 {
132   Standard_Boolean isFound(Standard_False);
133   TopTools_MapOfOrientedShape shapesOfContext;
134   MapOfOrientedShapes(Context,shapesOfContext);
135   Handle(TNaming_NamedShape) CNS = TNaming_Tool::NamedShape(Context, F);
136 #ifdef OCCT_DEBUG_BNP
137   PrintEntry (CNS->Label(),0);
138 #endif
139   if(!CNS.IsNull()) {
140     TNaming_ListOfNamedShape aLNS;
141     TDF_ChildIDIterator cit(CNS->Label(), TNaming_NamedShape::GetID(), Standard_False);
142     if(!cit.More()) {
143       // Naming data structure is empty - no sub-shapes under resulting shape
144       const Handle(TNaming_NamedShape) aNS = FindPrevNDS(CNS); //look to old shape data structure if exist
145       if(!aNS.IsNull()) {
146 #ifdef OCCT_DEBUG_BNP
147         PrintEntry (aNS->Label(),0);
148 #endif
149         cit.Initialize(aNS->Label(), TNaming_NamedShape::GetID(), Standard_False);
150       } else
151         return Standard_True;
152     }
153
154     for(;cit.More();cit.Next()) {
155       const Handle(TNaming_NamedShape)& NS = Handle(TNaming_NamedShape)::DownCast(cit.Value()); 
156       if(!NS.IsNull()) {  
157         TopoDS_Shape aS = TNaming_Tool::CurrentShape(NS);
158         if(aS.IsNull()) continue;
159 #ifdef OCCT_DEBUG_BNP
160         PrintEntry(NS->Label(), 0);
161         cout <<"ShapeType =" << aS.ShapeType() <<endl;
162         Write (aS, "BNProblem.brep");
163 #endif  
164         if(aS.ShapeType() != TopAbs_COMPOUND) {//single shape at the child label
165           if(!shapesOfContext.Contains(aS)) {
166             isFound = Standard_True;
167             break;
168           }
169         }
170         else {
171           TopTools_MapOfOrientedShape M;
172           BuildAtomicMap(aS, M); 
173           TopTools_MapIteratorOfMapOfOrientedShape it(M);
174           for(;it.More();it.Next()) {         
175             if(!shapesOfContext.Contains(it.Key())) {
176 #ifdef OCCT_DEBUG_BNP
177               cout <<"BNProblem: ShapeType in AtomicMap = " << it.Key().ShapeType() << " TShape = " <<it.Key().TShape() <<" OR = " <<it.Key().Orientation()  <<endl;
178               Write (it.Key(), "BNProblem_AtomicMap_Item.brep");              
179               TopTools_MapIteratorOfMapOfOrientedShape itC(shapesOfContext);
180               for(;itC.More(); itC.Next())
181                 cout <<" ShapeType = " << itC.Key().ShapeType() << " TShape = " << itC.Key().TShape() << " OR = " << itC.Key().Orientation() << endl;
182               
183 #endif  
184               isFound = Standard_True;
185               break;
186             }
187             if(isFound) break;
188           }
189         }
190       }
191     }
192   }
193   return isFound;
194 }
195
196 //==========================================================================================
197 static Standard_Boolean IsSpecificCase2(const  TDF_Label& F, const TopoDS_Shape& Selection)
198 {
199   Standard_Boolean isTheCase(Standard_False);
200   if(Selection.ShapeType() == TopAbs_EDGE) {
201     Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(Selection, F);
202     if(!aNS.IsNull()) { //presented in DF
203 #ifdef OCCT_DEBUG_BNP
204       PrintEntry (aNS->Label(),0);
205 #endif
206       const TopoDS_Shape& aS = TNaming_Tool::CurrentShape(aNS);
207       if(!aS.IsNull() && aS.ShapeType() == Selection.ShapeType()) {
208         if(Selection.Orientation() != aS.Orientation()) {
209           isTheCase = Standard_True;
210         }
211       }
212     }
213   }
214   return isTheCase;
215 }
216 #endif
217 //=======================================================================
218 //function : FindGenerated
219 //purpose  : Finds all generated from the <S>
220 //=======================================================================
221
222 static void FindGenerated(const Handle(TNaming_NamedShape)& NS, const TopoDS_Shape& S, 
223                                 TopTools_ListOfShape& theList)
224
225 {
226   const TDF_Label& LabNS = NS->Label();
227   for (TNaming_NewShapeIterator it (S, LabNS); it.More(); it.Next()) {
228     if (it.Label() == LabNS) {
229       theList.Append(it.Shape());
230     }
231   }
232 }
233 //=======================================================================
234 //function : IsIdentified
235 //purpose  : 
236 //=======================================================================
237 Standard_Boolean TNaming_Selector::IsIdentified (const TDF_Label& L,
238                                                  const TopoDS_Shape& Selection, 
239                                                  Handle(TNaming_NamedShape)& NS,
240                                                  const Standard_Boolean Geometry)
241 {  
242   TopoDS_Shape Context;
243   Standard_Boolean OnlyOne =!Geometry;
244   TNaming_Identifier Ident(L,Selection,Context,OnlyOne);   
245   if (Ident.IsFeature()) {  
246     if   (!OnlyOne)  return Standard_False;
247     else {
248       NS =   Ident.FeatureArg();
249
250       // mpv : external condition
251       TDF_LabelMap Forbiden,Valid;
252       TopTools_IndexedMapOfShape MS;
253       TNaming_NamingTool::CurrentShape(Valid,Forbiden,NS,MS);
254       return (MS.Contains(Selection) && MS.Extent() == 1);
255     }
256   }
257   else if(Ident.Type() == TNaming_GENERATION) {
258     NS = Ident.NamedShapeOfGeneration();
259     if(!NS.IsNull()) {
260       TDF_LabelMap Forbiden,Valid;
261       TopTools_IndexedMapOfShape MS;
262       TNaming_NamingTool::CurrentShape(Valid,Forbiden,NS,MS);
263       if(MS.Contains(Selection) && MS.Extent() == 1) {
264         const TopoDS_Shape& aS = Ident.ShapeArg();
265         TopTools_ListOfShape aList;
266         FindGenerated(NS, aS, aList);
267         Ident.NextArg();
268         while(Ident.MoreArgs()) {
269           const TopoDS_Shape& aS = Ident.ShapeArg();
270           FindGenerated(NS, aS, aList);
271           Ident.NextArg();
272         }
273         const TopoDS_Shape& aC = MS (1);
274         Standard_Boolean isEq(Standard_False);
275         TopTools_ListIteratorOfListOfShape itl(aList);
276         for(;itl.More();itl.Next()) {
277           if(itl.Value() == aC) 
278             isEq = Standard_True;
279           else {
280             isEq = Standard_False;
281             break;
282           }
283         }
284         return isEq;
285       }
286     } else 
287       return Standard_False;
288   }
289   return Standard_False;
290 }
291
292 //=======================================================================
293 //function : TNaming_Selector
294 //purpose  : 
295 //=======================================================================
296
297 TNaming_Selector::TNaming_Selector (const TDF_Label& L) 
298 {
299   myLabel = L;
300 }
301
302 //=======================================================================
303 //function : Select
304 //purpose  : 
305 //=======================================================================
306 Standard_Boolean TNaming_Selector::Select (const TopoDS_Shape& Selection, 
307                                            const TopoDS_Shape& Context,
308                                            const Standard_Boolean Geometry,
309                                            const Standard_Boolean KeepOrientation) const
310 {
311   myLabel.ForgetAllAttributes();  
312   Handle(TNaming_NamedShape)NS;
313   Standard_Boolean aKeepOrientation((Selection.ShapeType() == TopAbs_VERTEX) ? Standard_False : KeepOrientation);
314   if(Selection.ShapeType() == TopAbs_COMPOUND) {
315     Standard_Boolean isVertex(Standard_True);
316     TopoDS_Iterator it(Selection);
317     for(;it.More();it.Next())
318       if(it.Value().ShapeType() != TopAbs_VERTEX) {
319         isVertex = Standard_False;
320         break;
321       }
322     if(isVertex) aKeepOrientation = Standard_False;
323   }
324   /* 
325  // for debug opposite orientation
326  TopoDS_Shape selection;                                                 
327  Standard_Boolean found(Standard_False);
328  TopExp_Explorer exp(Context,TopAbs_EDGE);
329  for(;exp.More();exp.Next()) {
330    TopoDS_Shape E = exp.Current(); 
331    if(E.IsSame(Selection) && E.Orientation() != Selection.Orientation()) {
332      selection = E;
333    found = Standard_True;
334    cout <<" FOUND: Entity orientation = " << selection.Orientation() <<endl;
335    }
336  }
337  if (!found)
338    selection = Selection;
339   */
340
341 #ifdef OCCT_DEBUG_SEL
342   cout << "SELECTION ORIENTATION = " << Selection.Orientation() <<", TShape = " << Selection.TShape() <<endl;
343   //cout << "SELECTION ORIENTATION = " << selection.Orientation() <<", TShape = " << selection.TShape() <<endl;
344   PrintEntry(myLabel, 0);
345   TNaming::Print(myLabel, cout);
346 #endif
347
348   if(aKeepOrientation) {
349 #ifdef ORIENTATION_DSOPT
350     const Standard_Boolean aBNproblem = IsSpecificCase(myLabel, Context) || IsSpecificCase2(myLabel, Selection);
351
352     NS = TNaming_Naming::Name (myLabel,Selection,Context,Geometry,aKeepOrientation,aBNproblem);
353 #else
354       NS = TNaming_Naming::Name (myLabel,Selection,Context,Geometry,aKeepOrientation);
355 #endif    
356   }
357   else
358     if (!IsIdentified (myLabel,Selection,NS,Geometry)) { 
359       NS = TNaming_Naming::Name (myLabel,Selection,Context,Geometry,aKeepOrientation);
360     }
361   if (NS.IsNull()) return Standard_False; 
362   //
363   // namedshape with SELECTED Evolution
364   //
365   TNaming_Builder B (myLabel);
366   // mpv: if oldShape for selection is some shape from used map of shapes,
367   //      then naming structure becomes more complex, can be cycles
368   const TopoDS_Shape& aSelection = TNaming_Tool::CurrentShape(NS); //szy
369 #ifdef OCCT_DEBUG_CHECK_TYPE
370   if(!Selection.IsSame(aSelection) && Selection.ShapeType() != TopAbs_COMPOUND) {
371     TCollection_AsciiString entry;
372     TDF_Tool::Entry(NS->Label(), entry);
373     cout << "Selection is Not Same (NSLabel = " <<entry<<"): " << "TShape1 = " << 
374       Selection.TShape()->This() << " TShape2 = " <<aSelection.TShape()->This() <<endl;
375   }
376 #endif
377   if(aSelection.ShapeType() == TopAbs_COMPOUND && aSelection.ShapeType() != Selection.ShapeType())
378     B.Select(aSelection,aSelection); // type migration
379   else
380     B.Select(Selection,Selection);
381   //
382   // naming with IDENTITY NameType
383   //
384   Handle(TNaming_Naming) N = new TNaming_Naming (); 
385   N->ChangeName().Type(TNaming_IDENTITY);  
386   N->ChangeName().Append(NS);
387   N->ChangeName().Orientation(Selection.Orientation());
388 // inserted by vro 06.09.00:
389   N->ChangeName().ShapeType(Selection.ShapeType());
390
391   myLabel.AddAttribute(N);  
392   return Standard_True; 
393 }
394
395 //=======================================================================
396 //function : Select
397 //purpose  : 
398 //=======================================================================
399 Standard_Boolean TNaming_Selector::Select (const TopoDS_Shape& Selection,
400                                            const Standard_Boolean Geometry,
401                                            const Standard_Boolean KeepOrientation) const
402 {  
403   // we give a Null shape. How to guess what is the good context ?
404   TopoDS_Shape Context;
405 //  return Select (Selection,Context,Geometry);
406 // temporary!!!
407   return Select (Selection,Selection,Geometry, KeepOrientation);
408
409 }
410
411 //=======================================================================
412 //function : Solve
413 //purpose  : 
414 //=======================================================================
415 Standard_Boolean TNaming_Selector::Solve (TDF_LabelMap& Valid) const
416 {
417   Handle(TNaming_Naming) name;
418 #ifdef OCCT_DEBUG_SEL
419         cout <<"TNaming_Selector::Solve==> "; 
420         PrintEntry(myLabel,0);
421 #endif
422   if (myLabel.FindAttribute(TNaming_Naming::GetID(),name)) {
423     return name->Solve(Valid);
424   }
425   return Standard_False;
426 }
427
428 //=======================================================================
429 //function : Arguments
430 //purpose  : 
431 //=======================================================================
432 void TNaming_Selector::Arguments (TDF_AttributeMap& args) const
433 {  
434   TDF_Tool::OutReferences(myLabel,args);
435 }
436
437 //=======================================================================
438 //function : TNaming_Selector
439 //purpose  : 
440 //=======================================================================
441
442 Handle(TNaming_NamedShape) TNaming_Selector::NamedShape() const
443 {
444   Handle(TNaming_NamedShape) NS;
445   myLabel.FindAttribute(TNaming_NamedShape::GetID(),NS);
446   return NS;
447 }