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