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