Salome HOME
Issue 0020904: [CEA 411] export VTK in GEOM
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IGroupOperations.cxx
1 //  Copyright (C) 2007-2010  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->GetFunction(1);
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     aSSI.SetIndices(aNewSeq);
156   }
157
158   // As we do not recompute here our group, lets mark it as Modified
159   Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
160   theGroup->SetTic(aTic - 1);
161
162   //Make a Python command
163   GEOM::TPythonDump(aFunction, /*append=*/true)
164     << "geompy.AddObject(" << theGroup << ", " << theSubShapeID << ")";
165
166   SetErrorCode(OK);
167   return;
168 }
169
170 //=============================================================================
171 /*!
172  *  RemoveObject
173  */
174 //=============================================================================
175 void GEOMImpl_IGroupOperations::RemoveObject (Handle(GEOM_Object) theGroup, int theSubShapeID)
176 {
177   SetErrorCode(KO);
178   if(theGroup.IsNull()) return;
179
180   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
181   if(aFunction.IsNull()) return;
182
183   GEOM_ISubShape aSSI(aFunction);
184   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
185   if(aSeq.IsNull()) return;
186
187   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
188     SetErrorCode(NOT_EXISTS);
189     return;
190   }
191
192   Handle(TColStd_HArray1OfInteger) aNewSeq;
193   Standard_Integer aLength = aSeq->Length();
194   if(aLength == 1) {
195     if(aSeq->Value(1) != theSubShapeID) {
196       SetErrorCode(NOT_EXISTS);
197       return;
198     }
199     aNewSeq = new TColStd_HArray1OfInteger(1,1);
200     aNewSeq->SetValue(1, -1);
201   }
202   else {
203     aNewSeq = new TColStd_HArray1OfInteger(1, aLength-1);
204     Standard_Boolean isFound = Standard_False;
205     for (Standard_Integer i = 1, k = 1; i <= aLength; i++) {
206       if (aSeq->Value(i) == theSubShapeID) {
207         isFound = Standard_True;
208       } else {
209         if (k < aLength) { // this check is to avoid sequence <aNewSeq> overflow
210           aNewSeq->SetValue(k, aSeq->Value(i));
211           k++;
212         }
213       }
214     }
215
216     if (!isFound) {
217       SetErrorCode(NOT_EXISTS);
218       return;
219     }
220   }
221
222   aSSI.SetIndices(aNewSeq);
223
224   // As we do not recompute here our group, lets mark it as Modified
225   TDF_Label aLabel = aSSI.GetMainShape()->GetOwnerEntry();
226   if (aLabel.IsRoot()) return;
227   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
228   if (aMainObj.IsNull()) return;
229   Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
230   theGroup->SetTic(aTic - 1);
231
232   //Make a Python command
233   GEOM::TPythonDump(aFunction, /*append=*/true)
234     << "geompy.RemoveObject(" << theGroup << ", " << theSubShapeID << ")";
235
236   SetErrorCode(OK);
237   return;
238 }
239
240 //=============================================================================
241 /*!
242  *  UnionList
243  */
244 //=============================================================================
245 void GEOMImpl_IGroupOperations::UnionList (Handle(GEOM_Object) theGroup,
246                                            const Handle(TColStd_HSequenceOfTransient)& theSubShapes)
247 {
248   SetErrorCode(KO);
249   if (theGroup.IsNull()) return;
250
251   Standard_Integer aLen = theSubShapes->Length();
252   if (aLen < 1) {
253     //SetErrorCode("The list is empty");
254     SetErrorCode(OK);
255     return;
256   }
257
258   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
259   if (aFunction.IsNull()) return;
260
261   GEOM_ISubShape aSSI (aFunction);
262
263   // New contents of the group
264   TColStd_ListOfInteger aNewIDs;
265   TColStd_MapOfInteger mapIDs;
266
267   // Add current IDs to the list
268   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
269   if (aSeq.IsNull()) return;
270   Standard_Integer val_j, aLength = aSeq->Length();
271
272   for (Standard_Integer j = 1; j <= aLength; j++) {
273     val_j = aSeq->Value(j);
274     if (val_j > 0 && mapIDs.Add(val_j)) {
275       aNewIDs.Append(val_j);
276     }
277   }
278
279   // Get Main Shape
280   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
281   if (aMainShapeFunc.IsNull()) return;
282   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
283   if (aLabel.IsRoot()) return;
284   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
285   if (aMainObj.IsNull()) return;
286   TopoDS_Shape aMainShape = aMainObj->GetValue();
287   if (aMainShape.IsNull()) return;
288
289   TopTools_IndexedMapOfShape mapIndices;
290   TopExp::MapShapes(aMainShape, mapIndices);
291
292   // Get group type
293   TopAbs_ShapeEnum aType = GetType(theGroup);
294
295   // Get IDs of sub-shapes to add
296   Standard_Integer i, new_id;
297   for (i = 1; i <= aLen; i++) {
298     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
299
300     TopoDS_Shape aShape_i = anObj_i->GetValue();
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     return;
402   }
403
404   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
405   if (aFunction.IsNull()) return;
406
407   GEOM_ISubShape aSSI (aFunction);
408
409   // Map of IDs to be removed
410   TColStd_MapOfInteger mapIDsToRemove;
411
412   // Map of current IDs
413   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
414   if (aSeq.IsNull()) return;
415   Standard_Integer aLength = aSeq->Length();
416
417   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
418     return;
419
420   TColStd_MapOfInteger mapIDsCurrent;
421   Standard_Integer j = 1;
422   for (; j <= aLength; j++) {
423     mapIDsCurrent.Add(aSeq->Value(j));
424   }
425
426   // Get Main Shape
427   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
428   if (aMainShapeFunc.IsNull()) return;
429   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
430   if (aLabel.IsRoot()) return;
431   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
432   if (aMainObj.IsNull()) return;
433   TopoDS_Shape aMainShape = aMainObj->GetValue();
434   if (aMainShape.IsNull()) return;
435
436   TopTools_IndexedMapOfShape mapIndices;
437   TopExp::MapShapes(aMainShape, mapIndices);
438
439   // Get group type
440   TopAbs_ShapeEnum aType = GetType(theGroup);
441
442   // Get IDs of sub-shapes to be removed
443   Standard_Integer i, rem_id;
444   for (i = 1; i <= aLen; i++) {
445     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
446
447     TopoDS_Shape aShape_i = anObj_i->GetValue();
448
449     // 1. If aShape_i is sub-shape of aMainShape - remove it
450     if (mapIndices.Contains(aShape_i)) {
451       rem_id = mapIndices.FindIndex(aShape_i);
452       if (mapIDsCurrent.Contains(rem_id)) {
453         mapIDsToRemove.Add(rem_id);
454       }
455     }
456     // 2. If type of group is not defined - remove all sub-shapes of aShape_i
457     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
458       TopTools_IndexedMapOfShape mapIndices_i;
459       TopExp::MapShapes(aShape_i, mapIndices_i);
460       Standard_Integer nbSubSh = mapIndices_i.Extent();
461       Standard_Integer ii = 1;
462       for (; ii <= nbSubSh; ii++) {
463         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
464         if (mapIndices.Contains(aSubShape_i)) {
465           rem_id = mapIndices.FindIndex(aSubShape_i);
466           if (mapIDsCurrent.Contains(rem_id)) {
467             mapIDsToRemove.Add(rem_id);
468           }
469         }
470       }
471     }
472     // 3. If type of group is defined - remove all sub-shapes of aShape_i of that type
473     else {
474       TopExp_Explorer aSubShapes_i (aShape_i, aType);
475       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
476         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
477         if (mapIndices.Contains(aSubShape_i)) {
478           rem_id = mapIndices.FindIndex(aSubShape_i);
479           if (mapIDsCurrent.Contains(rem_id)) {
480             mapIDsToRemove.Add(rem_id);
481           }
482         }
483       }
484     }
485   }
486
487   if (mapIDsToRemove.Extent() > 0) {
488     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
489     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
490
491     for (j = 1; j <= aLength; j++) {
492       if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
493         aNewSeq->SetValue(k, aSeq->Value(j));
494         k++;
495       }
496     }
497
498     aSSI.SetIndices(aNewSeq);
499
500     // As we do not recompute here our group, lets mark it as Modified
501     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
502     theGroup->SetTic(aTic - 1);
503   }
504
505   //Make a Python command
506   Handle(GEOM_Object) aLatest = GEOM::GetCreatedLast(theSubShapes);
507   aLatest = GEOM::GetCreatedLast(aLatest, theGroup);
508   Handle(GEOM_Function) aLastFunc = aLatest->GetLastFunction();
509
510   GEOM::TPythonDump pd (aLastFunc, /*append=*/true);
511   pd << "geompy.DifferenceList(" << theGroup << ", [";
512
513   for (i = 1; i <= aLen; i++) {
514     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
515     pd << anObj_i << (( i < aLen ) ? ", " : "])");
516   }
517
518   SetErrorCode(OK);
519 }
520
521 //=============================================================================
522 /*!
523  *  UnionIDs
524  */
525 //=============================================================================
526 void GEOMImpl_IGroupOperations::UnionIDs (Handle(GEOM_Object) theGroup,
527                                           const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
528 {
529   SetErrorCode(KO);
530   if (theGroup.IsNull()) return;
531
532   Standard_Integer aLen = theSubShapes->Length();
533   if (aLen < 1) {
534     SetErrorCode("The list is empty");
535     return;
536   }
537
538   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
539   if (aFunction.IsNull()) return;
540
541   GEOM_ISubShape aSSI (aFunction);
542
543   // New contents of the group
544   TColStd_ListOfInteger aNewIDs;
545   TColStd_MapOfInteger mapIDs;
546
547   // Add current IDs to the list
548   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
549   if (aSeq.IsNull()) return;
550   Standard_Integer val_j, aLength = aSeq->Length();
551
552   for (Standard_Integer j = 1; j <= aLength; j++) {
553     val_j = aSeq->Value(j);
554     if (val_j > 0 && mapIDs.Add(val_j)) {
555       aNewIDs.Append(val_j);
556     }
557   }
558
559   // Get Main Shape
560   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
561   if (aMainShapeFunc.IsNull()) return;
562   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
563   if (aLabel.IsRoot()) return;
564   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
565   if (aMainObj.IsNull()) return;
566   TopoDS_Shape aMainShape = aMainObj->GetValue();
567   if (aMainShape.IsNull()) return;
568
569   TopTools_IndexedMapOfShape mapIndices;
570   TopExp::MapShapes(aMainShape, mapIndices);
571
572   // Get group type
573   TopAbs_ShapeEnum aType = GetType(theGroup);
574
575   // Get IDs of sub-shapes to add
576   Standard_Integer i, new_id;
577   for (i = 1; i <= aLen; i++) {
578     new_id = theSubShapes->Value(i);
579
580     if (0 < new_id && new_id <= mapIndices.Extent()) {
581       //if (mapIDs.Add(new_id)) { IPAL21297. Why we ignore invalid ids silently?
582       if (mapIDs.Add(new_id) && mapIndices(new_id).ShapeType()==aType ) {
583         aNewIDs.Append(new_id);
584       }
585     }
586   }
587
588   if (aNewIDs.Extent() > 0) {
589     Standard_Integer k = 1;
590     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
591     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
592     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
593       aNewSeq->SetValue(k, aNewIDsIter.Value());
594     }
595
596     aSSI.SetIndices(aNewSeq);
597
598     // As we do not recompute here our group, lets mark it as Modified
599     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
600     theGroup->SetTic(aTic - 1);
601   }
602
603   //Make a Python command
604   GEOM::TPythonDump pd (aFunction, /*append=*/true);
605   pd << "geompy.UnionIDs(" << theGroup << ", [";
606   for (i = 1; i < aLen; i++)
607     pd << theSubShapes->Value(i) << ", ";
608   pd << theSubShapes->Value(aLen) << "])";
609
610   SetErrorCode(OK);
611 }
612
613 //=============================================================================
614 /*!
615  *  DifferenceIDs
616  */
617 //=============================================================================
618 void GEOMImpl_IGroupOperations::DifferenceIDs (Handle(GEOM_Object) theGroup,
619                                                const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
620 {
621   SetErrorCode(KO);
622   if (theGroup.IsNull()) return;
623
624   Standard_Integer aLen = theSubShapes->Length();
625   if (aLen < 1) {
626     SetErrorCode("The list is empty");
627     return;
628   }
629
630   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
631   if (aFunction.IsNull()) return;
632
633   GEOM_ISubShape aSSI (aFunction);
634
635   // Map of IDs to be removed
636   TColStd_MapOfInteger mapIDsToRemove;
637
638   // Map of current IDs
639   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
640   if (aSeq.IsNull()) return;
641   Standard_Integer aLength = aSeq->Length();
642
643   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
644     return;
645
646   TColStd_MapOfInteger mapIDsCurrent;
647   Standard_Integer j = 1;
648   for (; j <= aLength; j++) {
649     mapIDsCurrent.Add(aSeq->Value(j));
650   }
651
652   // Get Main Shape
653   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
654   if (aMainShapeFunc.IsNull()) return;
655   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
656   if (aLabel.IsRoot()) return;
657   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
658   if (aMainObj.IsNull()) return;
659   TopoDS_Shape aMainShape = aMainObj->GetValue();
660   if (aMainShape.IsNull()) return;
661
662   TopTools_IndexedMapOfShape mapIndices;
663   TopExp::MapShapes(aMainShape, mapIndices);
664
665   // Get IDs of sub-shapes to be removed
666   Standard_Integer i, rem_id;
667   for (i = 1; i <= aLen; i++) {
668     rem_id = theSubShapes->Value(i);
669     if (mapIDsCurrent.Contains(rem_id)) {
670       mapIDsToRemove.Add(rem_id);
671     }
672   }
673
674   if (mapIDsToRemove.Extent() > 0) {
675     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
676     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
677
678     for (j = 1; j <= aLength; j++) {
679       if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
680         aNewSeq->SetValue(k, aSeq->Value(j));
681         k++;
682       }
683     }
684
685     aSSI.SetIndices(aNewSeq);
686
687     // As we do not recompute here our group, lets mark it as Modified
688     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
689     theGroup->SetTic(aTic - 1);
690   }
691
692   //Make a Python command
693   GEOM::TPythonDump pd (aFunction, /*append=*/true);
694   pd << "geompy.DifferenceIDs(" << theGroup << ", [";
695   for (i = 1; i < aLen; i++)
696     pd << theSubShapes->Value(i) << ", ";
697   pd << theSubShapes->Value(aLen) << "])";
698
699   SetErrorCode(OK);
700 }
701
702 //=============================================================================
703 /*!
704  *  GetType
705  */
706 //=============================================================================
707 TopAbs_ShapeEnum GEOMImpl_IGroupOperations::GetType(Handle(GEOM_Object) theGroup)
708 {
709   SetErrorCode(KO);
710
711   TDF_Label aFreeLabel = theGroup->GetFreeLabel();
712   Handle(TDataStd_Integer) anAttrib;
713   if(!aFreeLabel.FindAttribute(TDataStd_Integer::GetID(), anAttrib)) return TopAbs_SHAPE;
714
715   SetErrorCode(OK);
716   return (TopAbs_ShapeEnum) anAttrib->Get();
717 }
718
719 //=============================================================================
720 /*!
721  *  GetMainShape
722  */
723 //=============================================================================
724 Handle(GEOM_Object) GEOMImpl_IGroupOperations::GetMainShape (Handle(GEOM_Object) theGroup)
725 {
726   SetErrorCode(KO);
727
728   if(theGroup.IsNull()) return NULL;
729
730   Handle(GEOM_Function) aGroupFunction = theGroup->GetFunction(1);
731   if (aGroupFunction.IsNull()) return NULL;
732
733   GEOM_ISubShape aSSI (aGroupFunction);
734   Handle(GEOM_Function) aMainShapeFunction = aSSI.GetMainShape();
735   if (aMainShapeFunction.IsNull()) return NULL;
736
737   TDF_Label aLabel = aMainShapeFunction->GetOwnerEntry();
738   Handle(GEOM_Object) aMainShape = GEOM_Object::GetObject(aLabel);
739   if (aMainShape.IsNull()) return NULL;
740
741   //Make a Python command
742   //GEOM::TPythonDump(aGroupFunction, /*append=*/true)
743   //  << aMainShape << " = geompy.GetMainShape(" << theGroup << ")";
744
745   SetErrorCode(OK);
746   return aMainShape;
747 }
748
749 //=============================================================================
750 /*!
751  *  GetObjects
752  */
753 //=============================================================================
754 Handle(TColStd_HArray1OfInteger) GEOMImpl_IGroupOperations::GetObjects(Handle(GEOM_Object) theGroup)
755 {
756   SetErrorCode(KO);
757
758   if(theGroup.IsNull()) return NULL;
759
760   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
761   if(aFunction.IsNull()) return NULL;
762
763   GEOM_ISubShape aSSI(aFunction);
764   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
765   if(aSeq.IsNull()) return NULL;
766
767   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
768     SetErrorCode(OK);
769     return NULL;
770   }
771
772   SetErrorCode(OK);
773   return aSeq;
774 }