Salome HOME
0021672: [CEA 565] Dump Study from script
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IGroupOperations.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include <Standard_Stream.hxx>
24
25 #include <GEOMImpl_IGroupOperations.hxx>
26
27 #include <GEOMImpl_Types.hxx>
28
29 #include <GEOM_Function.hxx>
30 #include <GEOM_ISubShape.hxx>
31 #include <GEOM_PythonDump.hxx>
32
33 #include "utilities.h"
34 #include <OpUtil.hxx>
35 #include <Utils_ExceptHandlers.hxx>
36
37 #include <TFunction_DriverTable.hxx>
38 #include <TFunction_Driver.hxx>
39 #include <TFunction_Logbook.hxx>
40 #include <TDF_Tool.hxx>
41 #include <TDataStd_Integer.hxx>
42
43 #include <TopExp.hxx>
44 #include <TopExp_Explorer.hxx>
45 #include <TopTools_IndexedMapOfShape.hxx>
46
47 #include <TColStd_HArray1OfInteger.hxx>
48 #include <TColStd_MapOfInteger.hxx>
49 #include <TColStd_ListOfInteger.hxx>
50 #include <TColStd_ListIteratorOfListOfInteger.hxx>
51
52 //=============================================================================
53 /*!
54  *   constructor:
55  */
56 //=============================================================================
57 GEOMImpl_IGroupOperations::GEOMImpl_IGroupOperations (GEOM_Engine* theEngine, int theDocID)
58 : GEOM_IOperations(theEngine, theDocID)
59 {
60   MESSAGE("GEOMImpl_IGroupOperations::GEOMImpl_IGroupOperations");
61 }
62
63 //=============================================================================
64 /*!
65  *  destructor
66  */
67 //=============================================================================
68 GEOMImpl_IGroupOperations::~GEOMImpl_IGroupOperations()
69 {
70   MESSAGE("GEOMImpl_IGroupOperations::~GEOMImpl_IGroupOperations");
71 }
72
73
74 //=============================================================================
75 /*!
76  *  CreateGroup
77  */
78 //=============================================================================
79 Handle(GEOM_Object) GEOMImpl_IGroupOperations::CreateGroup
80        (Handle(GEOM_Object) theMainShape, TopAbs_ShapeEnum theShapeType)
81 {
82   SetErrorCode(KO);
83
84   Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
85   anArray->SetValue(1, -1);
86
87   //Add a new Sub-shape object
88   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(theMainShape, anArray);
89
90   //Set a GROUP type
91   aGroup->SetType(GEOM_GROUP);
92
93   //Set a sub-shape type
94   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
95   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)theShapeType);
96
97   //Make a Python command
98   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
99
100   GEOM::TPythonDump(aFunction) << aGroup
101     << " = geompy.CreateGroup(" << theMainShape << ", " << theShapeType << ")";
102
103   SetErrorCode(OK);
104   return aGroup;
105 }
106
107 //=============================================================================
108 /*!
109  *  AddObject
110  */
111 //=============================================================================
112 void GEOMImpl_IGroupOperations::AddObject(Handle(GEOM_Object) theGroup, int theSubShapeID)
113 {
114   SetErrorCode(KO);
115   if(theGroup.IsNull()) return;
116
117   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
118   if(aFunction.IsNull()) return;
119
120   GEOM_ISubShape aSSI (aFunction);
121
122   // Check sub-shape index validity
123   TDF_Label aLabel = aSSI.GetMainShape()->GetOwnerEntry();
124   if (aLabel.IsRoot()) return;
125   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
126   if (aMainObj.IsNull()) return;
127   TopoDS_Shape aMainShape = aMainObj->GetValue();
128   if (aMainShape.IsNull()) return;
129
130   TopTools_IndexedMapOfShape aMapOfShapes;
131   TopExp::MapShapes(aMainShape, aMapOfShapes);
132
133   if (theSubShapeID < 1 || aMapOfShapes.Extent() < theSubShapeID) {
134     SetErrorCode("Invalid sub-shape index: out of range");
135     return;
136   }
137
138   // Add sub-shape index
139   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
140   if(aSeq.IsNull()) return;
141   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
142     aSeq->SetValue(1, theSubShapeID);
143   }
144   else {
145     Standard_Integer aLength = aSeq->Length();
146     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aLength+1);
147     for(Standard_Integer i = 1; i<=aLength; i++) {
148       aNewSeq->SetValue(i, aSeq->Value(i));
149       if(aSeq->Value(i) == theSubShapeID) {
150         SetErrorCode(ALREADY_PRESENT);
151         return; //
152       }
153     }
154     aNewSeq->SetValue(aLength+1, theSubShapeID);
155     if ( aFunction->IsLastFuntion() ) {
156       aSSI.SetIndices(aNewSeq);
157     }
158     else {
159       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
160       GEOM_ISubShape aSSI2 (aFunction);
161       aSSI2.SetIndices(aNewSeq);
162       aSSI2.SetMainShape( aSSI.GetMainShape() );
163     }
164   }
165
166   // As we do not recompute here our group, lets mark it as Modified
167   Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
168   theGroup->SetTic(aTic - 1);
169
170   //Make a Python command
171   GEOM::TPythonDump(aFunction, /*append=*/true)
172     << "geompy.AddObject(" << theGroup << ", " << theSubShapeID << ")";
173
174   SetErrorCode(OK);
175   return;
176 }
177
178 //=============================================================================
179 /*!
180  *  RemoveObject
181  */
182 //=============================================================================
183 void GEOMImpl_IGroupOperations::RemoveObject (Handle(GEOM_Object) theGroup, int theSubShapeID)
184 {
185   SetErrorCode(KO);
186   if(theGroup.IsNull()) return;
187
188   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
189   if(aFunction.IsNull()) return;
190
191   GEOM_ISubShape aSSI(aFunction);
192   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
193   if(aSeq.IsNull()) return;
194
195   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
196     SetErrorCode(NOT_EXISTS);
197     return;
198   }
199
200   Handle(TColStd_HArray1OfInteger) aNewSeq;
201   Standard_Integer aLength = aSeq->Length();
202   if(aLength == 1) {
203     if(aSeq->Value(1) != theSubShapeID) {
204       SetErrorCode(NOT_EXISTS);
205       return;
206     }
207     aNewSeq = new TColStd_HArray1OfInteger(1,1);
208     aNewSeq->SetValue(1, -1);
209   }
210   else {
211     aNewSeq = new TColStd_HArray1OfInteger(1, aLength-1);
212     Standard_Boolean isFound = Standard_False;
213     for (Standard_Integer i = 1, k = 1; i <= aLength; i++) {
214       if (aSeq->Value(i) == theSubShapeID) {
215         isFound = Standard_True;
216       } else {
217         if (k < aLength) { // this check is to avoid sequence <aNewSeq> overflow
218           aNewSeq->SetValue(k, aSeq->Value(i));
219           k++;
220         }
221       }
222     }
223
224     if (!isFound) {
225       SetErrorCode(NOT_EXISTS);
226       return;
227     }
228   }
229
230   if ( aFunction->IsLastFuntion() ) {
231     aSSI.SetIndices(aNewSeq);
232   }
233   else {
234     aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
235     GEOM_ISubShape aSSI2 (aFunction);
236     aSSI2.SetIndices(aNewSeq);
237     aSSI2.SetMainShape( aSSI.GetMainShape() );
238   }
239
240   // As we do not recompute here our group, lets mark it as Modified
241   TDF_Label aLabel = aSSI.GetMainShape()->GetOwnerEntry();
242   if (aLabel.IsRoot()) return;
243   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
244   if (aMainObj.IsNull()) return;
245   Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
246   theGroup->SetTic(aTic - 1);
247
248   //Make a Python command
249   GEOM::TPythonDump(aFunction, /*append=*/true)
250     << "geompy.RemoveObject(" << theGroup << ", " << theSubShapeID << ")";
251
252   SetErrorCode(OK);
253   return;
254 }
255
256 //=============================================================================
257 /*!
258  *  UnionList
259  */
260 //=============================================================================
261 void GEOMImpl_IGroupOperations::UnionList (Handle(GEOM_Object) theGroup,
262                                            const Handle(TColStd_HSequenceOfTransient)& theSubShapes)
263 {
264   SetErrorCode(KO);
265   if (theGroup.IsNull()) return;
266
267   Standard_Integer aLen = theSubShapes->Length();
268   if (aLen < 1) {
269     //SetErrorCode("The list is empty");
270     SetErrorCode(OK);
271     return;
272   }
273
274   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
275   if (aFunction.IsNull()) return;
276
277   GEOM_ISubShape aSSI (aFunction);
278
279   // New contents of the group
280   TColStd_ListOfInteger aNewIDs;
281   TColStd_MapOfInteger mapIDs;
282
283   // Add current IDs to the list
284   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
285   if (aSeq.IsNull()) return;
286   Standard_Integer val_j, aLength = aSeq->Length();
287
288   for (Standard_Integer j = 1; j <= aLength; j++) {
289     val_j = aSeq->Value(j);
290     if (val_j > 0 && mapIDs.Add(val_j)) {
291       aNewIDs.Append(val_j);
292     }
293   }
294
295   // Get Main Shape
296   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
297   if (aMainShapeFunc.IsNull()) return;
298   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
299   if (aLabel.IsRoot()) return;
300   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
301   if (aMainObj.IsNull()) return;
302   TopoDS_Shape aMainShape = aMainObj->GetValue();
303   if (aMainShape.IsNull()) return;
304
305   TopTools_IndexedMapOfShape mapIndices;
306   TopExp::MapShapes(aMainShape, mapIndices);
307
308   // Get group type
309   TopAbs_ShapeEnum aType = GetType(theGroup);
310
311   // Get IDs of sub-shapes to add
312   Standard_Integer i, new_id;
313   for (i = 1; i <= aLen; i++) {
314     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
315
316     TopoDS_Shape aShape_i = anObj_i->GetValue();
317     if ( aShape_i.IsNull() ) continue;
318     TopAbs_ShapeEnum aType_i = aShape_i.ShapeType();
319
320     // 1. If aShape_i is sub-shape of aMainShape - add it
321     if (anObj_i->IsMainShape()) {
322       if (aType_i != aType && aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
323         SetErrorCode("Operation aborted: one of given objects has a wrong type");
324         return;
325       }
326       if (!mapIndices.Contains(aShape_i)) {
327         SetErrorCode("Operation aborted: not a sub-shape given");
328         return;
329       }
330       new_id = mapIndices.FindIndex(aShape_i);
331       if (mapIDs.Add(new_id)) {
332         aNewIDs.Append(new_id);
333       }
334     }
335     // 2. If type of group is not defined - add all sub-shapes of aShape_i
336     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
337       TopTools_IndexedMapOfShape mapIndices_i;
338       TopExp::MapShapes(aShape_i, mapIndices_i);
339       Standard_Integer ii = 1, nbSubSh = mapIndices_i.Extent();
340       Standard_Boolean someGood = Standard_False;
341       for (; ii <= nbSubSh; ii++) {
342         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
343         if (mapIndices.Contains(aSubShape_i)) {
344           someGood = Standard_True;
345           new_id = mapIndices.FindIndex(aSubShape_i);
346           if (mapIDs.Add(new_id)) {
347             aNewIDs.Append(new_id);
348           }
349         }
350       }
351       if (!someGood) {
352         SetErrorCode("Operation aborted: not a sub-shape given");
353         return;
354       }
355     }
356     // 3. If type of group is defined - add all sub-shapes of aShape_i of that type
357     else {
358       TopExp_Explorer aSubShapes_i (aShape_i, aType);
359       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
360         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
361         if (!mapIndices.Contains(aSubShape_i)) {
362           SetErrorCode("Operation aborted: not a sub-shape given");
363           return;
364         }
365         new_id = mapIndices.FindIndex(aSubShape_i);
366         if (mapIDs.Add(new_id)) {
367           aNewIDs.Append(new_id);
368         }
369       }
370     }
371   }
372
373   if (aNewIDs.Extent() > 0) {
374     Standard_Integer k = 1;
375     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
376     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
377     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
378       aNewSeq->SetValue(k, aNewIDsIter.Value());
379     }
380     if ( aFunction->IsLastFuntion() ) {
381       aSSI.SetIndices(aNewSeq);
382     }
383     else {
384       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
385       GEOM_ISubShape aSSI2 (aFunction);
386       aSSI2.SetIndices(aNewSeq);
387       aSSI2.SetMainShape(aMainShapeFunc);
388     }
389     // As we do not recompute here our group, lets mark it as Modified
390     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
391     theGroup->SetTic(aTic - 1);
392   }
393
394   //Make a Python command
395   GEOM::TPythonDump pd (aFunction, /*append=*/true);
396   pd << "geompy.UnionList(" << theGroup << ", [";
397
398   for (i = 1; i <= aLen; i++) {
399     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
400     pd << anObj_i << (( i < aLen ) ? ", " : "])");
401   }
402
403   SetErrorCode(OK);
404 }
405
406 //=============================================================================
407 /*!
408  *  DifferenceList
409  */
410 //=============================================================================
411 void GEOMImpl_IGroupOperations::DifferenceList (Handle(GEOM_Object) theGroup,
412                                                 const Handle(TColStd_HSequenceOfTransient)& theSubShapes)
413 {
414   SetErrorCode(KO);
415   if (theGroup.IsNull()) return;
416
417   Standard_Integer aLen = theSubShapes->Length();
418   if (aLen < 1) {
419     //SetErrorCode("The list is empty");
420     SetErrorCode(OK);
421     return;
422   }
423
424   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
425   if (aFunction.IsNull()) return;
426
427   GEOM_ISubShape aSSI (aFunction);
428
429   // Map of IDs to be removed
430   TColStd_MapOfInteger mapIDsToRemove;
431
432   // Map of current IDs
433   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
434   if (aSeq.IsNull()) return;
435   Standard_Integer aLength = aSeq->Length();
436
437   // VSR 28/04/2011 commented to allow operation even for empty group
438   //   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
439   //     return;
440
441   TColStd_MapOfInteger mapIDsCurrent;
442   Standard_Integer j = 1;
443   for (; j <= aLength; j++) {
444     mapIDsCurrent.Add(aSeq->Value(j));
445   }
446
447   // Get Main Shape
448   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
449   if (aMainShapeFunc.IsNull()) return;
450   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
451   if (aLabel.IsRoot()) return;
452   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
453   if (aMainObj.IsNull()) return;
454   TopoDS_Shape aMainShape = aMainObj->GetValue();
455   if (aMainShape.IsNull()) return;
456
457   TopTools_IndexedMapOfShape mapIndices;
458   TopExp::MapShapes(aMainShape, mapIndices);
459
460   // Get group type
461   TopAbs_ShapeEnum aType = GetType(theGroup);
462
463   // Get IDs of sub-shapes to be removed
464   Standard_Integer i, rem_id;
465   for (i = 1; i <= aLen; i++) {
466     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
467
468     TopoDS_Shape aShape_i = anObj_i->GetValue();
469
470     // 1. If aShape_i is sub-shape of aMainShape - remove it
471     if (mapIndices.Contains(aShape_i)) {
472       rem_id = mapIndices.FindIndex(aShape_i);
473       if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
474         mapIDsToRemove.Add(rem_id);
475       }
476     }
477     // 2. If type of group is not defined - remove all sub-shapes of aShape_i
478     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
479       TopTools_IndexedMapOfShape mapIndices_i;
480       TopExp::MapShapes(aShape_i, mapIndices_i);
481       Standard_Integer nbSubSh = mapIndices_i.Extent();
482       Standard_Integer ii = 1;
483       for (; ii <= nbSubSh; ii++) {
484         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
485         if (mapIndices.Contains(aSubShape_i)) {
486           rem_id = mapIndices.FindIndex(aSubShape_i);
487           if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
488             mapIDsToRemove.Add(rem_id);
489           }
490         }
491       }
492     }
493     // 3. If type of group is defined - remove all sub-shapes of aShape_i of that type
494     else {
495       TopExp_Explorer aSubShapes_i (aShape_i, aType);
496       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
497         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
498         if (mapIndices.Contains(aSubShape_i)) {
499           rem_id = mapIndices.FindIndex(aSubShape_i);
500           if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
501             mapIDsToRemove.Add(rem_id);
502           }
503         }
504       }
505     }
506   }
507
508   if (mapIDsToRemove.Extent() > 0) {
509     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
510     Handle(TColStd_HArray1OfInteger) aNewSeq;
511     if ( aLength - aRemLength > 0 ) {
512       aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
513       for (j = 1; j <= aLength; j++) {
514         if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
515           aNewSeq->SetValue(k, aSeq->Value(j));
516           k++;
517         }
518       }
519     }
520     else {
521       aNewSeq = new TColStd_HArray1OfInteger(1,1);
522       aNewSeq->SetValue(1, -1);
523     }
524
525     if ( aFunction->IsLastFuntion() ) {
526       aSSI.SetIndices(aNewSeq);
527     }
528     else {
529       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
530       GEOM_ISubShape aSSI2 (aFunction);
531       aSSI2.SetIndices(aNewSeq);
532       aSSI2.SetMainShape(aMainShapeFunc);
533     }
534     // As we do not recompute here our group, lets mark it as Modified
535     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
536     theGroup->SetTic(aTic - 1);
537   }
538
539   //Make a Python command
540   GEOM::TPythonDump pd (aFunction, /*append=*/true);
541   pd << "geompy.DifferenceList(" << theGroup << ", [";
542
543   for (i = 1; i <= aLen; i++) {
544     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
545     pd << anObj_i << (( i < aLen ) ? ", " : "])");
546   }
547
548   SetErrorCode(OK);
549 }
550
551 //=============================================================================
552 /*!
553  *  UnionIDs
554  */
555 //=============================================================================
556 void GEOMImpl_IGroupOperations::UnionIDs (Handle(GEOM_Object) theGroup,
557                                           const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
558 {
559   SetErrorCode(KO);
560   if (theGroup.IsNull()) return;
561
562   Standard_Integer aLen = theSubShapes->Length();
563   if (aLen < 1) {
564     //SetErrorCode("The list is empty");
565     SetErrorCode(OK);
566     return;
567   }
568
569   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
570   if (aFunction.IsNull()) return;
571
572   GEOM_ISubShape aSSI (aFunction);
573
574   // New contents of the group
575   TColStd_ListOfInteger aNewIDs;
576   TColStd_MapOfInteger mapIDs;
577
578   // Add current IDs to the list
579   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
580   if (aSeq.IsNull()) return;
581   Standard_Integer val_j, aLength = aSeq->Length();
582
583   for (Standard_Integer j = 1; j <= aLength; j++) {
584     val_j = aSeq->Value(j);
585     if (val_j > 0 && mapIDs.Add(val_j)) {
586       aNewIDs.Append(val_j);
587     }
588   }
589
590   // Get Main Shape
591   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
592   if (aMainShapeFunc.IsNull()) return;
593   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
594   if (aLabel.IsRoot()) return;
595   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
596   if (aMainObj.IsNull()) return;
597   TopoDS_Shape aMainShape = aMainObj->GetValue();
598   if (aMainShape.IsNull()) return;
599
600   TopTools_IndexedMapOfShape mapIndices;
601   TopExp::MapShapes(aMainShape, mapIndices);
602
603   // Get group type
604   TopAbs_ShapeEnum aType = GetType(theGroup);
605
606   // Get IDs of sub-shapes to add
607   Standard_Integer i, new_id;
608   for (i = 1; i <= aLen; i++) {
609     new_id = theSubShapes->Value(i);
610
611     if (0 < new_id && new_id <= mapIndices.Extent()) {
612       //if (mapIDs.Add(new_id)) { IPAL21297. Why we ignore invalid ids silently?
613       if (mapIDs.Add(new_id) && mapIndices(new_id).ShapeType()==aType ) {
614         aNewIDs.Append(new_id);
615       }
616     }
617   }
618
619   if (aNewIDs.Extent() > 0) {
620     Standard_Integer k = 1;
621     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
622     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
623     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
624       aNewSeq->SetValue(k, aNewIDsIter.Value());
625     }
626     if ( aFunction->IsLastFuntion() ) {
627       aSSI.SetIndices(aNewSeq);
628     }
629     else {
630       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
631       GEOM_ISubShape aSSI2 (aFunction);
632       aSSI2.SetIndices(aNewSeq);
633       aSSI2.SetMainShape(aMainShapeFunc);
634     }
635     // As we do not recompute here our group, lets mark it as Modified
636     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
637     theGroup->SetTic(aTic - 1);
638   }
639
640   //Make a Python command
641   GEOM::TPythonDump pd (aFunction, /*append=*/true);
642   pd << "geompy.UnionIDs(" << theGroup << ", [";
643   for (i = 1; i < aLen; i++)
644     pd << theSubShapes->Value(i) << ", ";
645   pd << theSubShapes->Value(aLen) << "])";
646
647   SetErrorCode(OK);
648 }
649
650 //=============================================================================
651 /*!
652  *  DifferenceIDs
653  */
654 //=============================================================================
655 void GEOMImpl_IGroupOperations::DifferenceIDs (Handle(GEOM_Object) theGroup,
656                                                const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
657 {
658   SetErrorCode(KO);
659   if (theGroup.IsNull()) return;
660
661   Standard_Integer aLen = theSubShapes->Length();
662   if (aLen < 1) {
663     //SetErrorCode("The list is empty");
664     SetErrorCode(OK);
665     return;
666   }
667
668   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
669   if (aFunction.IsNull()) return;
670
671   GEOM_ISubShape aSSI (aFunction);
672
673   // Map of IDs to be removed
674   TColStd_MapOfInteger mapIDsToRemove;
675
676   // Map of current IDs
677   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
678   if (aSeq.IsNull()) return;
679   Standard_Integer aLength = aSeq->Length();
680
681   // VSR 28/04/2011 commented to allow operation even for empty group
682   //   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
683   //     return;
684
685   TColStd_MapOfInteger mapIDsCurrent;
686   Standard_Integer j = 1;
687   for (; j <= aLength; j++) {
688     mapIDsCurrent.Add(aSeq->Value(j));
689   }
690
691   // Get Main Shape
692   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
693   if (aMainShapeFunc.IsNull()) return;
694   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
695   if (aLabel.IsRoot()) return;
696   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
697   if (aMainObj.IsNull()) return;
698   TopoDS_Shape aMainShape = aMainObj->GetValue();
699   if (aMainShape.IsNull()) return;
700
701   TopTools_IndexedMapOfShape mapIndices;
702   TopExp::MapShapes(aMainShape, mapIndices);
703
704   // Get IDs of sub-shapes to be removed
705   Standard_Integer i, rem_id;
706   for (i = 1; i <= aLen; i++) {
707     rem_id = theSubShapes->Value(i);
708     if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
709       mapIDsToRemove.Add(rem_id);
710     }
711   }
712
713   if (mapIDsToRemove.Extent() > 0) {
714     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
715     Handle(TColStd_HArray1OfInteger) aNewSeq;
716     if ( aLength - aRemLength > 0 ) {
717       aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
718       for (j = 1; j <= aLength; j++) {
719         if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
720           aNewSeq->SetValue(k, aSeq->Value(j));
721           k++;
722         }
723       }
724     }
725     else {
726       aNewSeq = new TColStd_HArray1OfInteger(1,1);
727       aNewSeq->SetValue(1, -1);
728     }
729     if ( aFunction->IsLastFuntion() ) {
730       aSSI.SetIndices(aNewSeq);
731     }
732     else {
733       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
734       GEOM_ISubShape aSSI2 (aFunction);
735       aSSI2.SetIndices(aNewSeq);
736       aSSI2.SetMainShape(aMainShapeFunc);
737     }
738     // As we do not recompute here our group, lets mark it as Modified
739     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
740     theGroup->SetTic(aTic - 1);
741   }
742
743   //Make a Python command
744   GEOM::TPythonDump pd (aFunction, /*append=*/true);
745   pd << "geompy.DifferenceIDs(" << theGroup << ", [";
746   for (i = 1; i < aLen; i++)
747     pd << theSubShapes->Value(i) << ", ";
748   pd << theSubShapes->Value(aLen) << "])";
749
750   SetErrorCode(OK);
751 }
752
753 //=============================================================================
754 /*!
755  *  GetType
756  */
757 //=============================================================================
758 TopAbs_ShapeEnum GEOMImpl_IGroupOperations::GetType(Handle(GEOM_Object) theGroup)
759 {
760   SetErrorCode(KO);
761
762   TDF_Label aFreeLabel = theGroup->GetFreeLabel();
763   Handle(TDataStd_Integer) anAttrib;
764   if(!aFreeLabel.FindAttribute(TDataStd_Integer::GetID(), anAttrib)) return TopAbs_SHAPE;
765
766   SetErrorCode(OK);
767   return (TopAbs_ShapeEnum) anAttrib->Get();
768 }
769
770 //=============================================================================
771 /*!
772  *  GetMainShape
773  */
774 //=============================================================================
775 Handle(GEOM_Object) GEOMImpl_IGroupOperations::GetMainShape (Handle(GEOM_Object) theGroup)
776 {
777   SetErrorCode(KO);
778
779   if(theGroup.IsNull()) return NULL;
780
781   Handle(GEOM_Function) aGroupFunction = theGroup->GetFunction(1);
782   if (aGroupFunction.IsNull()) return NULL;
783
784   GEOM_ISubShape aSSI (aGroupFunction);
785   Handle(GEOM_Function) aMainShapeFunction = aSSI.GetMainShape();
786   if (aMainShapeFunction.IsNull()) return NULL;
787
788   TDF_Label aLabel = aMainShapeFunction->GetOwnerEntry();
789   Handle(GEOM_Object) aMainShape = GEOM_Object::GetObject(aLabel);
790   if (aMainShape.IsNull()) return NULL;
791
792   //Make a Python command
793   //GEOM::TPythonDump(aGroupFunction, /*append=*/true)
794   //  << aMainShape << " = geompy.GetMainShape(" << theGroup << ")";
795
796   SetErrorCode(OK);
797   return aMainShape;
798 }
799
800 //=============================================================================
801 /*!
802  *  GetObjects
803  */
804 //=============================================================================
805 Handle(TColStd_HArray1OfInteger) GEOMImpl_IGroupOperations::GetObjects(Handle(GEOM_Object) theGroup)
806 {
807   SetErrorCode(KO);
808
809   if(theGroup.IsNull()) return NULL;
810
811   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
812   if(aFunction.IsNull()) return NULL;
813
814   GEOM_ISubShape aSSI(aFunction);
815   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
816   if(aSeq.IsNull()) return NULL;
817
818   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
819     SetErrorCode(OK);
820     return NULL;
821   }
822
823   SetErrorCode(OK);
824   return aSeq;
825 }