Salome HOME
Fix error with GetExistingSubObjects
[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 #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     TopAbs_ShapeEnum aType_i = aShape_i.ShapeType();
301
302     // 1. If aShape_i is sub-shape of aMainShape - add it
303     if (anObj_i->IsMainShape()) {
304       if (aType_i != aType && aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
305         SetErrorCode("Operation aborted: one of given objects has a wrong type");
306         return;
307       }
308       if (!mapIndices.Contains(aShape_i)) {
309         SetErrorCode("Operation aborted: not a sub-shape given");
310         return;
311       }
312       new_id = mapIndices.FindIndex(aShape_i);
313       if (mapIDs.Add(new_id)) {
314         aNewIDs.Append(new_id);
315       }
316     }
317     // 2. If type of group is not defined - add all sub-shapes of aShape_i
318     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
319       TopTools_IndexedMapOfShape mapIndices_i;
320       TopExp::MapShapes(aShape_i, mapIndices_i);
321       Standard_Integer ii = 1, nbSubSh = mapIndices_i.Extent();
322       Standard_Boolean someGood = Standard_False;
323       for (; ii <= nbSubSh; ii++) {
324         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
325         if (mapIndices.Contains(aSubShape_i)) {
326           someGood = Standard_True;
327           new_id = mapIndices.FindIndex(aSubShape_i);
328           if (mapIDs.Add(new_id)) {
329             aNewIDs.Append(new_id);
330           }
331         }
332       }
333       if (!someGood) {
334         SetErrorCode("Operation aborted: not a sub-shape given");
335         return;
336       }
337     }
338     // 3. If type of group is defined - add all sub-shapes of aShape_i of that type
339     else {
340       TopExp_Explorer aSubShapes_i (aShape_i, aType);
341       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
342         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
343         if (!mapIndices.Contains(aSubShape_i)) {
344           SetErrorCode("Operation aborted: not a sub-shape given");
345           return;
346         }
347         new_id = mapIndices.FindIndex(aSubShape_i);
348         if (mapIDs.Add(new_id)) {
349           aNewIDs.Append(new_id);
350         }
351       }
352     }
353   }
354
355   if (aNewIDs.Extent() > 0) {
356     Standard_Integer k = 1;
357     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
358     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
359     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
360       aNewSeq->SetValue(k, aNewIDsIter.Value());
361     }
362
363     aSSI.SetIndices(aNewSeq);
364
365     // As we do not recompute here our group, lets mark it as Modified
366     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
367     theGroup->SetTic(aTic - 1);
368   }
369
370   //Make a Python command
371   Handle(GEOM_Object) aLatest = GEOM::GetCreatedLast(theSubShapes);
372   aLatest = GEOM::GetCreatedLast(aLatest, theGroup);
373   Handle(GEOM_Function) aLastFunc = aLatest->GetLastFunction();
374
375   GEOM::TPythonDump pd (aLastFunc, /*append=*/true);
376   pd << "geompy.UnionList(" << theGroup << ", [";
377
378   for (i = 1; i <= aLen; i++) {
379     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
380     pd << anObj_i << (( i < aLen ) ? ", " : "])");
381   }
382
383   SetErrorCode(OK);
384 }
385
386 //=============================================================================
387 /*!
388  *  DifferenceList
389  */
390 //=============================================================================
391 void GEOMImpl_IGroupOperations::DifferenceList (Handle(GEOM_Object) theGroup,
392                                                 const Handle(TColStd_HSequenceOfTransient)& theSubShapes)
393 {
394   SetErrorCode(KO);
395   if (theGroup.IsNull()) return;
396
397   Standard_Integer aLen = theSubShapes->Length();
398   if (aLen < 1) {
399     SetErrorCode("The list is empty");
400     return;
401   }
402
403   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
404   if (aFunction.IsNull()) return;
405
406   GEOM_ISubShape aSSI (aFunction);
407
408   // Map of IDs to be removed
409   TColStd_MapOfInteger mapIDsToRemove;
410
411   // Map of current IDs
412   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
413   if (aSeq.IsNull()) return;
414   Standard_Integer aLength = aSeq->Length();
415
416   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
417     return;
418
419   TColStd_MapOfInteger mapIDsCurrent;
420   Standard_Integer j = 1;
421   for (; j <= aLength; j++) {
422     mapIDsCurrent.Add(aSeq->Value(j));
423   }
424
425   // Get Main Shape
426   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
427   if (aMainShapeFunc.IsNull()) return;
428   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
429   if (aLabel.IsRoot()) return;
430   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
431   if (aMainObj.IsNull()) return;
432   TopoDS_Shape aMainShape = aMainObj->GetValue();
433   if (aMainShape.IsNull()) return;
434
435   TopTools_IndexedMapOfShape mapIndices;
436   TopExp::MapShapes(aMainShape, mapIndices);
437
438   // Get group type
439   TopAbs_ShapeEnum aType = GetType(theGroup);
440
441   // Get IDs of sub-shapes to be removed
442   Standard_Integer i, rem_id;
443   for (i = 1; i <= aLen; i++) {
444     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
445
446     TopoDS_Shape aShape_i = anObj_i->GetValue();
447
448     // 1. If aShape_i is sub-shape of aMainShape - remove it
449     if (mapIndices.Contains(aShape_i)) {
450       rem_id = mapIndices.FindIndex(aShape_i);
451       if (mapIDsCurrent.Contains(rem_id)) {
452         mapIDsToRemove.Add(rem_id);
453       }
454     }
455     // 2. If type of group is not defined - remove all sub-shapes of aShape_i
456     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
457       TopTools_IndexedMapOfShape mapIndices_i;
458       TopExp::MapShapes(aShape_i, mapIndices_i);
459       Standard_Integer nbSubSh = mapIndices_i.Extent();
460       Standard_Integer ii = 1;
461       for (; ii <= nbSubSh; ii++) {
462         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
463         if (mapIndices.Contains(aSubShape_i)) {
464           rem_id = mapIndices.FindIndex(aSubShape_i);
465           if (mapIDsCurrent.Contains(rem_id)) {
466             mapIDsToRemove.Add(rem_id);
467           }
468         }
469       }
470     }
471     // 3. If type of group is defined - remove all sub-shapes of aShape_i of that type
472     else {
473       TopExp_Explorer aSubShapes_i (aShape_i, aType);
474       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
475         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
476         if (mapIndices.Contains(aSubShape_i)) {
477           rem_id = mapIndices.FindIndex(aSubShape_i);
478           if (mapIDsCurrent.Contains(rem_id)) {
479             mapIDsToRemove.Add(rem_id);
480           }
481         }
482       }
483     }
484   }
485
486   if (mapIDsToRemove.Extent() > 0) {
487     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
488     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
489
490     for (j = 1; j <= aLength; j++) {
491       if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
492         aNewSeq->SetValue(k, aSeq->Value(j));
493         k++;
494       }
495     }
496
497     aSSI.SetIndices(aNewSeq);
498
499     // As we do not recompute here our group, lets mark it as Modified
500     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
501     theGroup->SetTic(aTic - 1);
502   }
503
504   //Make a Python command
505   Handle(GEOM_Object) aLatest = GEOM::GetCreatedLast(theSubShapes);
506   aLatest = GEOM::GetCreatedLast(aLatest, theGroup);
507   Handle(GEOM_Function) aLastFunc = aLatest->GetLastFunction();
508
509   GEOM::TPythonDump pd (aLastFunc, /*append=*/true);
510   pd << "geompy.DifferenceList(" << theGroup << ", [";
511
512   for (i = 1; i <= aLen; i++) {
513     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
514     pd << anObj_i << (( i < aLen ) ? ", " : "])");
515   }
516
517   SetErrorCode(OK);
518 }
519
520 //=============================================================================
521 /*!
522  *  UnionIDs
523  */
524 //=============================================================================
525 void GEOMImpl_IGroupOperations::UnionIDs (Handle(GEOM_Object) theGroup,
526                                           const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
527 {
528   SetErrorCode(KO);
529   if (theGroup.IsNull()) return;
530
531   Standard_Integer aLen = theSubShapes->Length();
532   if (aLen < 1) {
533     SetErrorCode("The list is empty");
534     return;
535   }
536
537   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
538   if (aFunction.IsNull()) return;
539
540   GEOM_ISubShape aSSI (aFunction);
541
542   // New contents of the group
543   TColStd_ListOfInteger aNewIDs;
544   TColStd_MapOfInteger mapIDs;
545
546   // Add current IDs to the list
547   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
548   if (aSeq.IsNull()) return;
549   Standard_Integer val_j, aLength = aSeq->Length();
550
551   for (Standard_Integer j = 1; j <= aLength; j++) {
552     val_j = aSeq->Value(j);
553     if (val_j > 0 && mapIDs.Add(val_j)) {
554       aNewIDs.Append(val_j);
555     }
556   }
557
558   // Get Main Shape
559   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
560   if (aMainShapeFunc.IsNull()) return;
561   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
562   if (aLabel.IsRoot()) return;
563   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
564   if (aMainObj.IsNull()) return;
565   TopoDS_Shape aMainShape = aMainObj->GetValue();
566   if (aMainShape.IsNull()) return;
567
568   TopTools_IndexedMapOfShape mapIndices;
569   TopExp::MapShapes(aMainShape, mapIndices);
570
571   // Get group type
572   TopAbs_ShapeEnum aType = GetType(theGroup);
573
574   // Get IDs of sub-shapes to add
575   Standard_Integer i, new_id;
576   for (i = 1; i <= aLen; i++) {
577     new_id = theSubShapes->Value(i);
578
579     if (0 < new_id && new_id <= mapIndices.Extent()) {
580       //if (mapIDs.Add(new_id)) { IPAL21297. Why we ignore invalid ids silently?
581       if (mapIDs.Add(new_id) && mapIndices(new_id).ShapeType()==aType ) {
582         aNewIDs.Append(new_id);
583       }
584     }
585   }
586
587   if (aNewIDs.Extent() > 0) {
588     Standard_Integer k = 1;
589     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
590     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
591     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
592       aNewSeq->SetValue(k, aNewIDsIter.Value());
593     }
594
595     aSSI.SetIndices(aNewSeq);
596
597     // As we do not recompute here our group, lets mark it as Modified
598     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
599     theGroup->SetTic(aTic - 1);
600   }
601
602   //Make a Python command
603   GEOM::TPythonDump pd (aFunction, /*append=*/true);
604   pd << "geompy.UnionIDs(" << theGroup << ", [";
605   for (i = 1; i < aLen; i++)
606     pd << theSubShapes->Value(i) << ", ";
607   pd << theSubShapes->Value(aLen) << "])";
608
609   SetErrorCode(OK);
610 }
611
612 //=============================================================================
613 /*!
614  *  DifferenceIDs
615  */
616 //=============================================================================
617 void GEOMImpl_IGroupOperations::DifferenceIDs (Handle(GEOM_Object) theGroup,
618                                                const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
619 {
620   SetErrorCode(KO);
621   if (theGroup.IsNull()) return;
622
623   Standard_Integer aLen = theSubShapes->Length();
624   if (aLen < 1) {
625     SetErrorCode("The list is empty");
626     return;
627   }
628
629   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
630   if (aFunction.IsNull()) return;
631
632   GEOM_ISubShape aSSI (aFunction);
633
634   // Map of IDs to be removed
635   TColStd_MapOfInteger mapIDsToRemove;
636
637   // Map of current IDs
638   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
639   if (aSeq.IsNull()) return;
640   Standard_Integer aLength = aSeq->Length();
641
642   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
643     return;
644
645   TColStd_MapOfInteger mapIDsCurrent;
646   Standard_Integer j = 1;
647   for (; j <= aLength; j++) {
648     mapIDsCurrent.Add(aSeq->Value(j));
649   }
650
651   // Get Main Shape
652   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
653   if (aMainShapeFunc.IsNull()) return;
654   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
655   if (aLabel.IsRoot()) return;
656   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
657   if (aMainObj.IsNull()) return;
658   TopoDS_Shape aMainShape = aMainObj->GetValue();
659   if (aMainShape.IsNull()) return;
660
661   TopTools_IndexedMapOfShape mapIndices;
662   TopExp::MapShapes(aMainShape, mapIndices);
663
664   // Get IDs of sub-shapes to be removed
665   Standard_Integer i, rem_id;
666   for (i = 1; i <= aLen; i++) {
667     rem_id = theSubShapes->Value(i);
668     if (mapIDsCurrent.Contains(rem_id)) {
669       mapIDsToRemove.Add(rem_id);
670     }
671   }
672
673   if (mapIDsToRemove.Extent() > 0) {
674     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
675     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
676
677     for (j = 1; j <= aLength; j++) {
678       if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
679         aNewSeq->SetValue(k, aSeq->Value(j));
680         k++;
681       }
682     }
683
684     aSSI.SetIndices(aNewSeq);
685
686     // As we do not recompute here our group, lets mark it as Modified
687     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
688     theGroup->SetTic(aTic - 1);
689   }
690
691   //Make a Python command
692   GEOM::TPythonDump pd (aFunction, /*append=*/true);
693   pd << "geompy.DifferenceIDs(" << theGroup << ", [";
694   for (i = 1; i < aLen; i++)
695     pd << theSubShapes->Value(i) << ", ";
696   pd << theSubShapes->Value(aLen) << "])";
697
698   SetErrorCode(OK);
699 }
700
701 //=============================================================================
702 /*!
703  *  GetType
704  */
705 //=============================================================================
706 TopAbs_ShapeEnum GEOMImpl_IGroupOperations::GetType(Handle(GEOM_Object) theGroup)
707 {
708   SetErrorCode(KO);
709
710   TDF_Label aFreeLabel = theGroup->GetFreeLabel();
711   Handle(TDataStd_Integer) anAttrib;
712   if(!aFreeLabel.FindAttribute(TDataStd_Integer::GetID(), anAttrib)) return TopAbs_SHAPE;
713
714   SetErrorCode(OK);
715   return (TopAbs_ShapeEnum) anAttrib->Get();
716 }
717
718 //=============================================================================
719 /*!
720  *  GetMainShape
721  */
722 //=============================================================================
723 Handle(GEOM_Object) GEOMImpl_IGroupOperations::GetMainShape (Handle(GEOM_Object) theGroup)
724 {
725   SetErrorCode(KO);
726
727   if(theGroup.IsNull()) return NULL;
728
729   Handle(GEOM_Function) aGroupFunction = theGroup->GetFunction(1);
730   if (aGroupFunction.IsNull()) return NULL;
731
732   GEOM_ISubShape aSSI (aGroupFunction);
733   Handle(GEOM_Function) aMainShapeFunction = aSSI.GetMainShape();
734   if (aMainShapeFunction.IsNull()) return NULL;
735
736   TDF_Label aLabel = aMainShapeFunction->GetOwnerEntry();
737   Handle(GEOM_Object) aMainShape = GEOM_Object::GetObject(aLabel);
738   if (aMainShape.IsNull()) return NULL;
739
740   //Make a Python command
741   //GEOM::TPythonDump(aGroupFunction, /*append=*/true)
742   //  << aMainShape << " = geompy.GetMainShape(" << theGroup << ")";
743
744   SetErrorCode(OK);
745   return aMainShape;
746 }
747
748 //=============================================================================
749 /*!
750  *  GetObjects
751  */
752 //=============================================================================
753 Handle(TColStd_HArray1OfInteger) GEOMImpl_IGroupOperations::GetObjects(Handle(GEOM_Object) theGroup)
754 {
755   SetErrorCode(KO);
756
757   if(theGroup.IsNull()) return NULL;
758
759   Handle(GEOM_Function) aFunction = theGroup->GetFunction(1);
760   if(aFunction.IsNull()) return NULL;
761
762   GEOM_ISubShape aSSI(aFunction);
763   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
764   if(aSeq.IsNull()) return NULL;
765
766   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
767     SetErrorCode(OK);
768     return NULL;
769   }
770
771   SetErrorCode(OK);
772   return aSeq;
773 }