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