]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOMImpl/GEOMImpl_IGroupOperations.cxx
Salome HOME
Merge from V6_main (04/10/2012)
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IGroupOperations.cxx
1 // Copyright (C) 2007-2012  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->GetLastFunction();
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     if ( aFunction->IsLastFuntion() ) {
155       aSSI.SetIndices(aNewSeq);
156     }
157     else {
158       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
159       GEOM_ISubShape aSSI2 (aFunction);
160       aSSI2.SetIndices(aNewSeq);
161       aSSI2.SetMainShape( aSSI.GetMainShape() );
162     }
163   }
164
165   // As we do not recompute here our group, lets mark it as Modified
166   Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
167   theGroup->SetTic(aTic - 1);
168
169   //Make a Python command
170   GEOM::TPythonDump(aFunction, /*append=*/true)
171     << "geompy.AddObject(" << theGroup << ", " << theSubShapeID << ")";
172
173   SetErrorCode(OK);
174   return;
175 }
176
177 //=============================================================================
178 /*!
179  *  RemoveObject
180  */
181 //=============================================================================
182 void GEOMImpl_IGroupOperations::RemoveObject (Handle(GEOM_Object) theGroup, int theSubShapeID)
183 {
184   SetErrorCode(KO);
185   if(theGroup.IsNull()) return;
186
187   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
188   if(aFunction.IsNull()) return;
189
190   GEOM_ISubShape aSSI(aFunction);
191   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
192   if(aSeq.IsNull()) return;
193
194   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
195     SetErrorCode(NOT_EXISTS);
196     return;
197   }
198
199   Handle(TColStd_HArray1OfInteger) aNewSeq;
200   Standard_Integer aLength = aSeq->Length();
201   if(aLength == 1) {
202     if(aSeq->Value(1) != theSubShapeID) {
203       SetErrorCode(NOT_EXISTS);
204       return;
205     }
206     aNewSeq = new TColStd_HArray1OfInteger(1,1);
207     aNewSeq->SetValue(1, -1);
208   }
209   else {
210     aNewSeq = new TColStd_HArray1OfInteger(1, aLength-1);
211     Standard_Boolean isFound = Standard_False;
212     for (Standard_Integer i = 1, k = 1; i <= aLength; i++) {
213       if (aSeq->Value(i) == theSubShapeID) {
214         isFound = Standard_True;
215       } else {
216         if (k < aLength) { // this check is to avoid sequence <aNewSeq> overflow
217           aNewSeq->SetValue(k, aSeq->Value(i));
218           k++;
219         }
220       }
221     }
222
223     if (!isFound) {
224       SetErrorCode(NOT_EXISTS);
225       return;
226     }
227   }
228
229   if ( aFunction->IsLastFuntion() ) {
230     aSSI.SetIndices(aNewSeq);
231   }
232   else {
233     aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
234     GEOM_ISubShape aSSI2 (aFunction);
235     aSSI2.SetIndices(aNewSeq);
236     aSSI2.SetMainShape( aSSI.GetMainShape() );
237   }
238
239   // As we do not recompute here our group, lets mark it as Modified
240   TDF_Label aLabel = aSSI.GetMainShape()->GetOwnerEntry();
241   if (aLabel.IsRoot()) return;
242   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
243   if (aMainObj.IsNull()) return;
244   Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
245   theGroup->SetTic(aTic - 1);
246
247   //Make a Python command
248   GEOM::TPythonDump(aFunction, /*append=*/true)
249     << "geompy.RemoveObject(" << theGroup << ", " << theSubShapeID << ")";
250
251   SetErrorCode(OK);
252   return;
253 }
254
255 //=============================================================================
256 /*!
257  *  UnionList
258  */
259 //=============================================================================
260 void GEOMImpl_IGroupOperations::UnionList (Handle(GEOM_Object) theGroup,
261                                            const Handle(TColStd_HSequenceOfTransient)& theSubShapes)
262 {
263   SetErrorCode(KO);
264   if (theGroup.IsNull()) return;
265
266   Standard_Integer aLen = theSubShapes->Length();
267   if (aLen < 1) {
268     //SetErrorCode("The list is empty");
269     SetErrorCode(OK);
270     return;
271   }
272
273   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
274   if (aFunction.IsNull()) return;
275
276   GEOM_ISubShape aSSI (aFunction);
277
278   // New contents of the group
279   TColStd_ListOfInteger aNewIDs;
280   TColStd_MapOfInteger mapIDs;
281
282   // Add current IDs to the list
283   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
284   if (aSeq.IsNull()) return;
285   Standard_Integer val_j, aLength = aSeq->Length();
286
287   for (Standard_Integer j = 1; j <= aLength; j++) {
288     val_j = aSeq->Value(j);
289     if (val_j > 0 && mapIDs.Add(val_j)) {
290       aNewIDs.Append(val_j);
291     }
292   }
293
294   // Get Main Shape
295   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
296   if (aMainShapeFunc.IsNull()) return;
297   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
298   if (aLabel.IsRoot()) return;
299   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
300   if (aMainObj.IsNull()) return;
301   TopoDS_Shape aMainShape = aMainObj->GetValue();
302   if (aMainShape.IsNull()) return;
303
304   TopTools_IndexedMapOfShape mapIndices;
305   TopExp::MapShapes(aMainShape, mapIndices);
306
307   // Get group type
308   TopAbs_ShapeEnum aType = GetType(theGroup);
309
310   // Get IDs of sub-shapes to add
311   Standard_Integer i, new_id;
312   for (i = 1; i <= aLen; i++) {
313     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
314
315     TopoDS_Shape aShape_i = anObj_i->GetValue();
316     if ( aShape_i.IsNull() ) continue;
317     TopAbs_ShapeEnum aType_i = aShape_i.ShapeType();
318
319     // 1. If aShape_i is sub-shape of aMainShape - add it
320     if (anObj_i->IsMainShape()) {
321       if (aType_i != aType && aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
322         SetErrorCode("Operation aborted: one of given objects has a wrong type");
323         return;
324       }
325       if (!mapIndices.Contains(aShape_i)) {
326         SetErrorCode("Operation aborted: not a sub-shape given");
327         return;
328       }
329       new_id = mapIndices.FindIndex(aShape_i);
330       if (mapIDs.Add(new_id)) {
331         aNewIDs.Append(new_id);
332       }
333     }
334     // 2. If type of group is not defined - add all sub-shapes of aShape_i
335     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
336       TopTools_IndexedMapOfShape mapIndices_i;
337       TopExp::MapShapes(aShape_i, mapIndices_i);
338       Standard_Integer ii = 1, nbSubSh = mapIndices_i.Extent();
339       Standard_Boolean someGood = Standard_False;
340       for (; ii <= nbSubSh; ii++) {
341         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
342         if (mapIndices.Contains(aSubShape_i)) {
343           someGood = Standard_True;
344           new_id = mapIndices.FindIndex(aSubShape_i);
345           if (mapIDs.Add(new_id)) {
346             aNewIDs.Append(new_id);
347           }
348         }
349       }
350       if (!someGood) {
351         SetErrorCode("Operation aborted: not a sub-shape given");
352         return;
353       }
354     }
355     // 3. If type of group is defined - add all sub-shapes of aShape_i of that type
356     else {
357       TopExp_Explorer aSubShapes_i (aShape_i, aType);
358       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
359         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
360         if (!mapIndices.Contains(aSubShape_i)) {
361           SetErrorCode("Operation aborted: not a sub-shape given");
362           return;
363         }
364         new_id = mapIndices.FindIndex(aSubShape_i);
365         if (mapIDs.Add(new_id)) {
366           aNewIDs.Append(new_id);
367         }
368       }
369     }
370   }
371
372   if (aNewIDs.Extent() > 0) {
373     Standard_Integer k = 1;
374     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
375     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
376     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
377       aNewSeq->SetValue(k, aNewIDsIter.Value());
378     }
379     if ( aFunction->IsLastFuntion() ) {
380       aSSI.SetIndices(aNewSeq);
381     }
382     else {
383       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
384       GEOM_ISubShape aSSI2 (aFunction);
385       aSSI2.SetIndices(aNewSeq);
386       aSSI2.SetMainShape(aMainShapeFunc);
387     }
388     // As we do not recompute here our group, lets mark it as Modified
389     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
390     theGroup->SetTic(aTic - 1);
391   }
392
393   //Make a Python command
394   GEOM::TPythonDump pd (aFunction, /*append=*/true);
395   pd << "geompy.UnionList(" << theGroup << ", [";
396
397   for (i = 1; i <= aLen; i++) {
398     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
399     pd << anObj_i << (( i < aLen ) ? ", " : "])");
400   }
401
402   SetErrorCode(OK);
403 }
404
405 //=============================================================================
406 /*!
407  *  DifferenceList
408  */
409 //=============================================================================
410 void GEOMImpl_IGroupOperations::DifferenceList (Handle(GEOM_Object) theGroup,
411                                                 const Handle(TColStd_HSequenceOfTransient)& theSubShapes)
412 {
413   SetErrorCode(KO);
414   if (theGroup.IsNull()) return;
415
416   Standard_Integer aLen = theSubShapes->Length();
417   if (aLen < 1) {
418     //SetErrorCode("The list is empty");
419     SetErrorCode(OK);
420     return;
421   }
422
423   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
424   if (aFunction.IsNull()) return;
425
426   GEOM_ISubShape aSSI (aFunction);
427
428   // Map of IDs to be removed
429   TColStd_MapOfInteger mapIDsToRemove;
430
431   // Map of current IDs
432   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
433   if (aSeq.IsNull()) return;
434   Standard_Integer aLength = aSeq->Length();
435
436   // VSR 28/04/2011 commented to allow operation even for empty group
437   //   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
438   //     return;
439
440   TColStd_MapOfInteger mapIDsCurrent;
441   Standard_Integer j = 1;
442   for (; j <= aLength; j++) {
443     mapIDsCurrent.Add(aSeq->Value(j));
444   }
445
446   // Get Main Shape
447   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
448   if (aMainShapeFunc.IsNull()) return;
449   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
450   if (aLabel.IsRoot()) return;
451   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
452   if (aMainObj.IsNull()) return;
453   TopoDS_Shape aMainShape = aMainObj->GetValue();
454   if (aMainShape.IsNull()) return;
455
456   TopTools_IndexedMapOfShape mapIndices;
457   TopExp::MapShapes(aMainShape, mapIndices);
458
459   // Get group type
460   TopAbs_ShapeEnum aType = GetType(theGroup);
461
462   // Get IDs of sub-shapes to be removed
463   Standard_Integer i, rem_id;
464   for (i = 1; i <= aLen; i++) {
465     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
466
467     TopoDS_Shape aShape_i = anObj_i->GetValue();
468
469     // 1. If aShape_i is sub-shape of aMainShape - remove it
470     if (mapIndices.Contains(aShape_i)) {
471       rem_id = mapIndices.FindIndex(aShape_i);
472       if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
473         mapIDsToRemove.Add(rem_id);
474       }
475     }
476     // 2. If type of group is not defined - remove all sub-shapes of aShape_i
477     else if (aType == TopAbs_SHAPE || aType == TopAbs_COMPOUND) {
478       TopTools_IndexedMapOfShape mapIndices_i;
479       TopExp::MapShapes(aShape_i, mapIndices_i);
480       Standard_Integer nbSubSh = mapIndices_i.Extent();
481       Standard_Integer ii = 1;
482       for (; ii <= nbSubSh; ii++) {
483         TopoDS_Shape aSubShape_i = mapIndices_i.FindKey(ii);
484         if (mapIndices.Contains(aSubShape_i)) {
485           rem_id = mapIndices.FindIndex(aSubShape_i);
486           if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
487             mapIDsToRemove.Add(rem_id);
488           }
489         }
490       }
491     }
492     // 3. If type of group is defined - remove all sub-shapes of aShape_i of that type
493     else {
494       TopExp_Explorer aSubShapes_i (aShape_i, aType);
495       for (; aSubShapes_i.More(); aSubShapes_i.Next()) {
496         TopoDS_Shape aSubShape_i = aSubShapes_i.Current();
497         if (mapIndices.Contains(aSubShape_i)) {
498           rem_id = mapIndices.FindIndex(aSubShape_i);
499           if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
500             mapIDsToRemove.Add(rem_id);
501           }
502         }
503       }
504     }
505   }
506
507   if (mapIDsToRemove.Extent() > 0) {
508     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
509     Handle(TColStd_HArray1OfInteger) aNewSeq;
510     if ( aLength - aRemLength > 0 ) {
511       aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
512       for (j = 1; j <= aLength; j++) {
513         if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
514           aNewSeq->SetValue(k, aSeq->Value(j));
515           k++;
516         }
517       }
518     }
519     else {
520       aNewSeq = new TColStd_HArray1OfInteger(1,1);
521       aNewSeq->SetValue(1, -1);
522     }
523
524     if ( aFunction->IsLastFuntion() ) {
525       aSSI.SetIndices(aNewSeq);
526     }
527     else {
528       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
529       GEOM_ISubShape aSSI2 (aFunction);
530       aSSI2.SetIndices(aNewSeq);
531       aSSI2.SetMainShape(aMainShapeFunc);
532     }
533     // As we do not recompute here our group, lets mark it as Modified
534     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
535     theGroup->SetTic(aTic - 1);
536   }
537
538   //Make a Python command
539   GEOM::TPythonDump pd (aFunction, /*append=*/true);
540   pd << "geompy.DifferenceList(" << theGroup << ", [";
541
542   for (i = 1; i <= aLen; i++) {
543     Handle(GEOM_Object) anObj_i = Handle(GEOM_Object)::DownCast(theSubShapes->Value(i));
544     pd << anObj_i << (( i < aLen ) ? ", " : "])");
545   }
546
547   SetErrorCode(OK);
548 }
549
550 //=============================================================================
551 /*!
552  *  UnionIDs
553  */
554 //=============================================================================
555 void GEOMImpl_IGroupOperations::UnionIDs (Handle(GEOM_Object) theGroup,
556                                           const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
557 {
558   SetErrorCode(KO);
559   if (theGroup.IsNull()) return;
560
561   Standard_Integer aLen = theSubShapes->Length();
562   if (aLen < 1) {
563     //SetErrorCode("The list is empty");
564     SetErrorCode(OK);
565     return;
566   }
567
568   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
569   if (aFunction.IsNull()) return;
570
571   GEOM_ISubShape aSSI (aFunction);
572
573   // New contents of the group
574   TColStd_ListOfInteger aNewIDs;
575   TColStd_MapOfInteger mapIDs;
576
577   // Add current IDs to the list
578   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
579   if (aSeq.IsNull()) return;
580   Standard_Integer val_j, aLength = aSeq->Length();
581
582   for (Standard_Integer j = 1; j <= aLength; j++) {
583     val_j = aSeq->Value(j);
584     if (val_j > 0 && mapIDs.Add(val_j)) {
585       aNewIDs.Append(val_j);
586     }
587   }
588
589   // Get Main Shape
590   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
591   if (aMainShapeFunc.IsNull()) return;
592   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
593   if (aLabel.IsRoot()) return;
594   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
595   if (aMainObj.IsNull()) return;
596   TopoDS_Shape aMainShape = aMainObj->GetValue();
597   if (aMainShape.IsNull()) return;
598
599   TopTools_IndexedMapOfShape mapIndices;
600   TopExp::MapShapes(aMainShape, mapIndices);
601
602   // Get group type
603   TopAbs_ShapeEnum aType = GetType(theGroup);
604
605   // Get IDs of sub-shapes to add
606   Standard_Integer i, new_id;
607   for (i = 1; i <= aLen; i++) {
608     new_id = theSubShapes->Value(i);
609
610     if (0 < new_id && new_id <= mapIndices.Extent()) {
611       //if (mapIDs.Add(new_id)) { IPAL21297. Why we ignore invalid ids silently?
612       if (mapIDs.Add(new_id) && mapIndices(new_id).ShapeType()==aType ) {
613         aNewIDs.Append(new_id);
614       }
615     }
616   }
617
618   if (aNewIDs.Extent() > 0) {
619     Standard_Integer k = 1;
620     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
621     Handle(TColStd_HArray1OfInteger) aNewSeq = new TColStd_HArray1OfInteger(1, aNewIDs.Extent());
622     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
623       aNewSeq->SetValue(k, aNewIDsIter.Value());
624     }
625     if ( aFunction->IsLastFuntion() ) {
626       aSSI.SetIndices(aNewSeq);
627     }
628     else {
629       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
630       GEOM_ISubShape aSSI2 (aFunction);
631       aSSI2.SetIndices(aNewSeq);
632       aSSI2.SetMainShape(aMainShapeFunc);
633     }
634     // As we do not recompute here our group, lets mark it as Modified
635     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
636     theGroup->SetTic(aTic - 1);
637   }
638
639   //Make a Python command
640   GEOM::TPythonDump pd (aFunction, /*append=*/true);
641   pd << "geompy.UnionIDs(" << theGroup << ", [";
642   for (i = 1; i < aLen; i++)
643     pd << theSubShapes->Value(i) << ", ";
644   pd << theSubShapes->Value(aLen) << "])";
645
646   SetErrorCode(OK);
647 }
648
649 //=============================================================================
650 /*!
651  *  DifferenceIDs
652  */
653 //=============================================================================
654 void GEOMImpl_IGroupOperations::DifferenceIDs (Handle(GEOM_Object) theGroup,
655                                                const Handle(TColStd_HSequenceOfInteger)& theSubShapes)
656 {
657   SetErrorCode(KO);
658   if (theGroup.IsNull()) return;
659
660   Standard_Integer aLen = theSubShapes->Length();
661   if (aLen < 1) {
662     //SetErrorCode("The list is empty");
663     SetErrorCode(OK);
664     return;
665   }
666
667   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
668   if (aFunction.IsNull()) return;
669
670   GEOM_ISubShape aSSI (aFunction);
671
672   // Map of IDs to be removed
673   TColStd_MapOfInteger mapIDsToRemove;
674
675   // Map of current IDs
676   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
677   if (aSeq.IsNull()) return;
678   Standard_Integer aLength = aSeq->Length();
679
680   // VSR 28/04/2011 commented to allow operation even for empty group
681   //   if (aLength == 1 && aSeq->Value(1) == -1) // empty group
682   //     return;
683
684   TColStd_MapOfInteger mapIDsCurrent;
685   Standard_Integer j = 1;
686   for (; j <= aLength; j++) {
687     mapIDsCurrent.Add(aSeq->Value(j));
688   }
689
690   // Get Main Shape
691   Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
692   if (aMainShapeFunc.IsNull()) return;
693   TDF_Label aLabel = aMainShapeFunc->GetOwnerEntry();
694   if (aLabel.IsRoot()) return;
695   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
696   if (aMainObj.IsNull()) return;
697   TopoDS_Shape aMainShape = aMainObj->GetValue();
698   if (aMainShape.IsNull()) return;
699
700   TopTools_IndexedMapOfShape mapIndices;
701   TopExp::MapShapes(aMainShape, mapIndices);
702
703   // Get IDs of sub-shapes to be removed
704   Standard_Integer i, rem_id;
705   for (i = 1; i <= aLen; i++) {
706     rem_id = theSubShapes->Value(i);
707     if (rem_id > 0 && mapIDsCurrent.Contains(rem_id)) {
708       mapIDsToRemove.Add(rem_id);
709     }
710   }
711
712   if (mapIDsToRemove.Extent() > 0) {
713     Standard_Integer k = 1, aRemLength = mapIDsToRemove.Extent();
714     Handle(TColStd_HArray1OfInteger) aNewSeq;
715     if ( aLength - aRemLength > 0 ) {
716       aNewSeq = new TColStd_HArray1OfInteger(1, aLength - aRemLength);
717       for (j = 1; j <= aLength; j++) {
718         if (!mapIDsToRemove.Contains(aSeq->Value(j))) {
719           aNewSeq->SetValue(k, aSeq->Value(j));
720           k++;
721         }
722       }
723     }
724     else {
725       aNewSeq = new TColStd_HArray1OfInteger(1,1);
726       aNewSeq->SetValue(1, -1);
727     }
728     if ( aFunction->IsLastFuntion() ) {
729       aSSI.SetIndices(aNewSeq);
730     }
731     else {
732       aFunction = theGroup->AddFunction( GEOM_Object::GetSubShapeID(), 0, true );
733       GEOM_ISubShape aSSI2 (aFunction);
734       aSSI2.SetIndices(aNewSeq);
735       aSSI2.SetMainShape(aMainShapeFunc);
736     }
737     // As we do not recompute here our group, lets mark it as Modified
738     Standard_Integer aTic = aMainObj->GetTic(); // tic of main shape
739     theGroup->SetTic(aTic - 1);
740   }
741
742   //Make a Python command
743   GEOM::TPythonDump pd (aFunction, /*append=*/true);
744   pd << "geompy.DifferenceIDs(" << theGroup << ", [";
745   for (i = 1; i < aLen; i++)
746     pd << theSubShapes->Value(i) << ", ";
747   pd << theSubShapes->Value(aLen) << "])";
748
749   SetErrorCode(OK);
750 }
751
752 //=============================================================================
753 /*!
754  *  UnionGroups
755  */
756 //=============================================================================
757 Handle(GEOM_Object) GEOMImpl_IGroupOperations::UnionGroups (Handle(GEOM_Object) theGroup1,
758                                                             Handle(GEOM_Object) theGroup2)
759 {
760   SetErrorCode(KO);
761   if (theGroup1.IsNull() || theGroup2.IsNull()) return NULL;
762
763   // Get group type
764   TopAbs_ShapeEnum aType1 = GetType(theGroup1);
765   TopAbs_ShapeEnum aType2 = GetType(theGroup2);
766   TopAbs_ShapeEnum aType = aType1;
767   if (aType1 != aType2) {
768     if (aType1 != TopAbs_SHAPE && aType1 != TopAbs_COMPOUND) {
769       if (aType2 == TopAbs_SHAPE || aType2 == TopAbs_COMPOUND)
770         aType = aType2;
771       else {
772         SetErrorCode("Error: UnionGroups cannot be performed on groups of different type");
773         return NULL;
774       }
775     }
776   }
777
778   // Get Main Shape
779   Handle(GEOM_Function) aFunction1 = theGroup1->GetLastFunction();
780   Handle(GEOM_Function) aFunction2 = theGroup2->GetLastFunction();
781   if (aFunction1.IsNull() || aFunction2.IsNull()) return NULL;
782
783   GEOM_ISubShape aSSI1 (aFunction1);
784   GEOM_ISubShape aSSI2 (aFunction2);
785
786   Handle(GEOM_Function) aMainShapeFunc1 = aSSI1.GetMainShape();
787   Handle(GEOM_Function) aMainShapeFunc2 = aSSI2.GetMainShape();
788   if (aMainShapeFunc1.IsNull() || aMainShapeFunc2.IsNull()) return NULL;
789
790   TDF_Label aLabel1 = aMainShapeFunc1->GetOwnerEntry();
791   TDF_Label aLabel2 = aMainShapeFunc2->GetOwnerEntry();
792   if (aLabel1.IsRoot() || aLabel2.IsRoot()) {
793     SetErrorCode("Error: UnionGroups can be performed only on groups");
794     return NULL;
795   }
796
797   if (aLabel1 != aLabel2) {
798     SetErrorCode("Error: UnionGroups cannot be performed on groups, built on different main shapes");
799     return NULL;
800   }
801
802   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel1);
803   if (aMainObj.IsNull()) return NULL;
804
805   // New contents of the group
806   TColStd_ListOfInteger aNewIDs;
807   TColStd_MapOfInteger mapIDs;
808
809   Handle(TColStd_HArray1OfInteger) aSeq1 = aSSI1.GetIndices();
810   Handle(TColStd_HArray1OfInteger) aSeq2 = aSSI2.GetIndices();
811   if (aSeq1.IsNull() || aSeq2.IsNull()) return NULL;
812
813   Standard_Integer j, val_j;
814   Standard_Integer aLength1 = aSeq1->Length();
815   Standard_Integer aLength2 = aSeq2->Length();
816
817   for (j = 1; j <= aLength1; j++) {
818     val_j = aSeq1->Value(j);
819     if (val_j > 0 && mapIDs.Add(val_j)) {
820       aNewIDs.Append(val_j);
821     }
822   }
823   for (j = 1; j <= aLength2; j++) {
824     val_j = aSeq2->Value(j);
825     if (val_j > 0 && mapIDs.Add(val_j)) {
826       aNewIDs.Append(val_j);
827     }
828   }
829
830   if (aNewIDs.Extent() < 1) {
831     SetErrorCode("Error: UnionGroups cannot be performed on two empty groups");
832     return NULL;
833   }
834
835   // Put new indices from the list into an array
836   Standard_Integer k = 1;
837   TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
838   Handle(TColStd_HArray1OfInteger) aNewArr = new TColStd_HArray1OfInteger (1, aNewIDs.Extent());
839   for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
840     aNewArr->SetValue(k, aNewIDsIter.Value());
841   }
842
843   // Create the Group
844   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(aMainObj, aNewArr);
845   aGroup->SetType(GEOM_GROUP);
846   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
847   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)aType);
848
849   // Make a Python command
850   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
851   GEOM::TPythonDump(aFunction) << aGroup << " = geompy.UnionGroups("
852                                << theGroup1 << ", " << theGroup2 << ")";
853
854   SetErrorCode(OK);
855   return aGroup;
856 }
857
858 //=============================================================================
859 /*!
860  *  IntersectGroups
861  */
862 //=============================================================================
863 Handle(GEOM_Object) GEOMImpl_IGroupOperations::IntersectGroups (Handle(GEOM_Object) theGroup1,
864                                                                 Handle(GEOM_Object) theGroup2)
865 {
866   SetErrorCode(KO);
867   if (theGroup1.IsNull() || theGroup2.IsNull()) return NULL;
868
869   // Get group type
870   TopAbs_ShapeEnum aType1 = GetType(theGroup1);
871   TopAbs_ShapeEnum aType2 = GetType(theGroup2);
872   TopAbs_ShapeEnum aType = aType1;
873   if (aType1 != aType2) {
874     if (aType1 != TopAbs_SHAPE && aType1 != TopAbs_COMPOUND) {
875       if (aType2 == TopAbs_SHAPE || aType2 == TopAbs_COMPOUND)
876         aType = aType2;
877       else {
878         SetErrorCode("Error: IntersectGroups cannot be performed on groups of different type");
879         return NULL;
880       }
881     }
882   }
883
884   // Get Main Shape
885   Handle(GEOM_Function) aFunction1 = theGroup1->GetLastFunction();
886   Handle(GEOM_Function) aFunction2 = theGroup2->GetLastFunction();
887   if (aFunction1.IsNull() || aFunction2.IsNull()) return NULL;
888
889   GEOM_ISubShape aSSI1 (aFunction1);
890   GEOM_ISubShape aSSI2 (aFunction2);
891
892   Handle(GEOM_Function) aMainShapeFunc1 = aSSI1.GetMainShape();
893   Handle(GEOM_Function) aMainShapeFunc2 = aSSI2.GetMainShape();
894   if (aMainShapeFunc1.IsNull() || aMainShapeFunc2.IsNull()) return NULL;
895
896   TDF_Label aLabel1 = aMainShapeFunc1->GetOwnerEntry();
897   TDF_Label aLabel2 = aMainShapeFunc2->GetOwnerEntry();
898   if (aLabel1.IsRoot() || aLabel2.IsRoot()) {
899     SetErrorCode("Error: UnionGroups can be performed only on groups");
900     return NULL;
901   }
902
903   if (aLabel1 != aLabel2) {
904     SetErrorCode("Error: IntersectGroups cannot be performed on groups, built on different main shapes");
905     return NULL;
906   }
907
908   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel1);
909   if (aMainObj.IsNull()) return NULL;
910
911   // New contents of the group
912   TColStd_ListOfInteger aNewIDs;
913   TColStd_MapOfInteger mapIDs;
914
915   Handle(TColStd_HArray1OfInteger) aSeq1 = aSSI1.GetIndices();
916   Handle(TColStd_HArray1OfInteger) aSeq2 = aSSI2.GetIndices();
917   if (aSeq1.IsNull() || aSeq2.IsNull()) return NULL;
918
919   Standard_Integer j, val_j;
920   Standard_Integer aLength1 = aSeq1->Length();
921   Standard_Integer aLength2 = aSeq2->Length();
922
923   for (j = 1; j <= aLength1; j++) {
924     mapIDs.Add(aSeq1->Value(j));
925   }
926   for (j = 1; j <= aLength2; j++) {
927     val_j = aSeq2->Value(j);
928     if (val_j > 0 && !mapIDs.Add(val_j)) {
929       // add index, if it is in mapIDs (filled from Group_1)
930       aNewIDs.Append(val_j);
931     }
932   }
933
934   Handle(TColStd_HArray1OfInteger) aNewArr;
935   if (aNewIDs.Extent() < 1) {
936     aNewArr = new TColStd_HArray1OfInteger (1, 1);
937     aNewArr->SetValue(1, -1);
938   }
939   else {
940     // Put new indices from the list into an array
941     Standard_Integer k = 1;
942     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
943     aNewArr = new TColStd_HArray1OfInteger (1, aNewIDs.Extent());
944     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
945       aNewArr->SetValue(k, aNewIDsIter.Value());
946     }
947   }
948
949   // Create the Group
950   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(aMainObj, aNewArr);
951   aGroup->SetType(GEOM_GROUP);
952   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
953   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)aType);
954
955   // Make a Python command
956   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
957   GEOM::TPythonDump(aFunction) << aGroup << " = geompy.IntersectGroups("
958                                << theGroup1 << ", " << theGroup2 << ")";
959
960   SetErrorCode(OK);
961   return aGroup;
962 }
963
964 //=============================================================================
965 /*!
966  *  CutGroups
967  */
968 //=============================================================================
969 Handle(GEOM_Object) GEOMImpl_IGroupOperations::CutGroups (Handle(GEOM_Object) theGroup1,
970                                                           Handle(GEOM_Object) theGroup2)
971 {
972   SetErrorCode(KO);
973   if (theGroup1.IsNull() || theGroup2.IsNull()) return NULL;
974
975   // Get group type
976   TopAbs_ShapeEnum aType1 = GetType(theGroup1);
977   TopAbs_ShapeEnum aType2 = GetType(theGroup2);
978   TopAbs_ShapeEnum aType = aType1;
979   if (aType1 != aType2) {
980     if (aType1 != TopAbs_SHAPE && aType1 != TopAbs_COMPOUND) {
981       if (aType2 == TopAbs_SHAPE || aType2 == TopAbs_COMPOUND)
982         aType = aType2;
983       else {
984         SetErrorCode("Error: CutGroups cannot be performed on groups of different type");
985         return NULL;
986       }
987     }
988   }
989
990   // Get Main Shape
991   Handle(GEOM_Function) aFunction1 = theGroup1->GetLastFunction();
992   Handle(GEOM_Function) aFunction2 = theGroup2->GetLastFunction();
993   if (aFunction1.IsNull() || aFunction2.IsNull()) return NULL;
994
995   GEOM_ISubShape aSSI1 (aFunction1);
996   GEOM_ISubShape aSSI2 (aFunction2);
997
998   Handle(GEOM_Function) aMainShapeFunc1 = aSSI1.GetMainShape();
999   Handle(GEOM_Function) aMainShapeFunc2 = aSSI2.GetMainShape();
1000   if (aMainShapeFunc1.IsNull() || aMainShapeFunc2.IsNull()) return NULL;
1001
1002   TDF_Label aLabel1 = aMainShapeFunc1->GetOwnerEntry();
1003   TDF_Label aLabel2 = aMainShapeFunc2->GetOwnerEntry();
1004   if (aLabel1.IsRoot() || aLabel2.IsRoot()) {
1005     SetErrorCode("Error: UnionGroups can be performed only on groups");
1006     return NULL;
1007   }
1008
1009   if (aLabel1 != aLabel2) {
1010     SetErrorCode("Error: CutGroups cannot be performed on groups, built on different main shapes");
1011     return NULL;
1012   }
1013
1014   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel1);
1015   if (aMainObj.IsNull()) return NULL;
1016
1017   // New contents of the group
1018   TColStd_ListOfInteger aNewIDs;
1019   TColStd_MapOfInteger mapIDs;
1020
1021   Handle(TColStd_HArray1OfInteger) aSeq1 = aSSI1.GetIndices();
1022   Handle(TColStd_HArray1OfInteger) aSeq2 = aSSI2.GetIndices();
1023   if (aSeq1.IsNull() || aSeq2.IsNull()) return NULL;
1024
1025   Standard_Integer j, val_j;
1026   Standard_Integer aLength1 = aSeq1->Length();
1027   Standard_Integer aLength2 = aSeq2->Length();
1028
1029   for (j = 1; j <= aLength2; j++) {
1030     mapIDs.Add(aSeq2->Value(j));
1031   }
1032   for (j = 1; j <= aLength1; j++) {
1033     val_j = aSeq1->Value(j);
1034     if (val_j > 0 && mapIDs.Add(val_j)) {
1035       // add index, if it is not in mapIDs (filled from Group_2)
1036       aNewIDs.Append(val_j);
1037     }
1038   }
1039
1040   Handle(TColStd_HArray1OfInteger) aNewArr;
1041   if (aNewIDs.Extent() < 1) {
1042     aNewArr = new TColStd_HArray1OfInteger (1, 1);
1043     aNewArr->SetValue(1, -1);
1044   }
1045   else {
1046     // Put new indices from the list into an array
1047     Standard_Integer k = 1;
1048     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
1049     aNewArr = new TColStd_HArray1OfInteger (1, aNewIDs.Extent());
1050     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
1051       aNewArr->SetValue(k, aNewIDsIter.Value());
1052     }
1053   }
1054
1055   // Create the Group
1056   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(aMainObj, aNewArr);
1057   aGroup->SetType(GEOM_GROUP);
1058   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
1059   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)aType);
1060
1061   // Make a Python command
1062   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
1063   GEOM::TPythonDump(aFunction) << aGroup << " = geompy.CutGroups("
1064                                << theGroup1 << ", " << theGroup2 << ")";
1065
1066   SetErrorCode(OK);
1067   return aGroup;
1068 }
1069
1070 //=============================================================================
1071 /*!
1072  *  UnionListOfGroups
1073  */
1074 //=============================================================================
1075 Handle(GEOM_Object) GEOMImpl_IGroupOperations::UnionListOfGroups
1076                          (const Handle(TColStd_HSequenceOfTransient)& theGList)
1077 {
1078   SetErrorCode(KO);
1079   if (theGList.IsNull()) return NULL;
1080
1081   Standard_Integer i, aLen = theGList->Length();
1082   if (aLen < 1) {
1083     SetErrorCode("UnionListOfGroups error: the list of groups is empty");
1084     return NULL;
1085   }
1086
1087   TopAbs_ShapeEnum aType, aType_i;
1088   TDF_Label aLabel, aLabel_i;
1089   TColStd_ListOfInteger aNewIDs;
1090   TColStd_MapOfInteger mapIDs;
1091
1092   // Iterate on the initial groups
1093   for (i = 1; i <= aLen; i++) {
1094     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList->Value(i));
1095
1096     // Get group type
1097     aType_i = GetType(aGr_i);
1098     if (i == 1)
1099       aType = aType_i;
1100     else {
1101       if (aType_i != aType) {
1102         if (aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
1103           if (aType_i == TopAbs_SHAPE || aType_i == TopAbs_COMPOUND)
1104             aType = aType_i;
1105           else {
1106             SetErrorCode("Error: UnionListOfGroups cannot be performed on groups of different type");
1107             return NULL;
1108           }
1109         }
1110       }
1111     }
1112
1113     // Get Main Shape
1114     Handle(GEOM_Function) aFunction_i = aGr_i->GetLastFunction();
1115     if (aFunction_i.IsNull()) return NULL;
1116     GEOM_ISubShape aSSI (aFunction_i);
1117     Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
1118     if (aMainShapeFunc.IsNull()) return NULL;
1119     aLabel_i = aMainShapeFunc->GetOwnerEntry();
1120     if (aLabel_i.IsRoot()) {
1121       SetErrorCode("Error: UnionGroups can be performed only on groups");
1122       return NULL;
1123     }
1124     if (i == 1)
1125       aLabel = aLabel_i;
1126     else {
1127       if (aLabel_i != aLabel) {
1128         SetErrorCode("Error: UnionListOfGroups cannot be performed on groups, built on different main shapes");
1129         return NULL;
1130       }
1131     }
1132
1133     // New contents of the group
1134     Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
1135     if (aSeq.IsNull()) return NULL;
1136
1137     Standard_Integer j, val_j, aLength = aSeq->Length();
1138     for (j = 1; j <= aLength; j++) {
1139       val_j = aSeq->Value(j);
1140       if (val_j > 0 && mapIDs.Add(val_j)) {
1141         aNewIDs.Append(val_j);
1142       }
1143     }
1144   }
1145
1146   // Check the resulting list of indices
1147   if (aNewIDs.Extent() < 1) {
1148     SetErrorCode("Error: UnionListOfGroups cannot be performed on all empty groups");
1149     return NULL;
1150   }
1151
1152   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
1153   if (aMainObj.IsNull()) return NULL;
1154
1155   // Put new indices from the list into an array
1156   Standard_Integer k = 1;
1157   TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
1158   Handle(TColStd_HArray1OfInteger) aNewArr = new TColStd_HArray1OfInteger (1, aNewIDs.Extent());
1159   for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
1160     aNewArr->SetValue(k, aNewIDsIter.Value());
1161   }
1162
1163   // Create the Group
1164   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(aMainObj, aNewArr);
1165   aGroup->SetType(GEOM_GROUP);
1166   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
1167   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)aType);
1168
1169   //Make a Python command
1170   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
1171   GEOM::TPythonDump pd (aFunction);
1172   pd << aGroup << " = geompy.UnionListOfGroups([";
1173   for (i = 1; i <= aLen; i++) {
1174     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList->Value(i));
1175     pd << aGr_i << ((i < aLen) ? ", " : "])");
1176   }
1177
1178   SetErrorCode(OK);
1179   return aGroup;
1180 }
1181
1182 //=============================================================================
1183 /*!
1184  *  IntersectListOfGroups
1185  */
1186 //=============================================================================
1187 Handle(GEOM_Object) GEOMImpl_IGroupOperations::IntersectListOfGroups
1188                          (const Handle(TColStd_HSequenceOfTransient)& theGList)
1189 {
1190   SetErrorCode(KO);
1191   if (theGList.IsNull()) return NULL;
1192
1193   Standard_Integer i, aLen = theGList->Length();
1194   if (aLen < 1) {
1195     SetErrorCode("IntersectListOfGroups error: the list of groups is empty");
1196     return NULL;
1197   }
1198
1199   TopAbs_ShapeEnum aType, aType_i;
1200   TDF_Label aLabel, aLabel_i;
1201   TColStd_ListOfInteger aNewIDs;
1202   TColStd_MapOfInteger mapIDs;
1203
1204   // Iterate on the initial groups
1205   for (i = 1; i <= aLen; i++) {
1206     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList->Value(i));
1207
1208     // Get group type
1209     aType_i = GetType(aGr_i);
1210     if (i == 1)
1211       aType = aType_i;
1212     else {
1213       if (aType_i != aType) {
1214         if (aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
1215           if (aType_i == TopAbs_SHAPE || aType_i == TopAbs_COMPOUND)
1216             aType = aType_i;
1217           else {
1218             SetErrorCode("Error: IntersectListOfGroups cannot be performed on groups of different type");
1219             return NULL;
1220           }
1221         }
1222       }
1223     }
1224
1225     // Get Main Shape
1226     Handle(GEOM_Function) aFunction_i = aGr_i->GetLastFunction();
1227     if (aFunction_i.IsNull()) return NULL;
1228     GEOM_ISubShape aSSI (aFunction_i);
1229     Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
1230     if (aMainShapeFunc.IsNull()) return NULL;
1231     aLabel_i = aMainShapeFunc->GetOwnerEntry();
1232     if (aLabel_i.IsRoot()) {
1233      SetErrorCode("Error: UnionGroups can be performed only on groups");
1234      return NULL;
1235     }
1236     if (i == 1)
1237       aLabel = aLabel_i;
1238     else {
1239       if (aLabel_i != aLabel) {
1240         SetErrorCode("Error: IntersectListOfGroups cannot be performed on groups, built on different main shapes");
1241         return NULL;
1242       }
1243     }
1244
1245     // New contents of the group
1246     Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
1247     if (aSeq.IsNull()) return NULL;
1248
1249     Standard_Integer j, val_j, aLength = aSeq->Length();
1250     for (j = 1; j <= aLength; j++) {
1251       val_j = aSeq->Value(j);
1252       if (val_j > 0) {
1253         if (i == 1) {
1254           // get all elements of the first group
1255           if (mapIDs.Add(val_j))
1256             aNewIDs.Append(val_j);
1257         }
1258         else {
1259           // get only elements, present in all previously processed groups
1260           if (!mapIDs.Add(val_j))
1261             aNewIDs.Append(val_j);
1262         }
1263       }
1264     }
1265
1266     // refill the map with only validated elements
1267     if (i > 1) {
1268       mapIDs.Clear();
1269       TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
1270       for (; aNewIDsIter.More(); aNewIDsIter.Next()) {
1271         mapIDs.Add(aNewIDsIter.Value());
1272       }
1273     }
1274     // clear the resulting list before starting the next sycle
1275     if (i < aLen) {
1276       aNewIDs.Clear();
1277     }
1278   }
1279
1280   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
1281   if (aMainObj.IsNull()) return NULL;
1282
1283   Handle(TColStd_HArray1OfInteger) aNewArr;
1284   if (aNewIDs.Extent() < 1) {
1285     aNewArr = new TColStd_HArray1OfInteger (1, 1);
1286     aNewArr->SetValue(1, -1);
1287   }
1288   else {
1289     // Put new indices from the list into an array
1290     Standard_Integer k = 1;
1291     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
1292     aNewArr = new TColStd_HArray1OfInteger (1, aNewIDs.Extent());
1293     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
1294       aNewArr->SetValue(k, aNewIDsIter.Value());
1295     }
1296   }
1297
1298   // Create the Group
1299   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(aMainObj, aNewArr);
1300   aGroup->SetType(GEOM_GROUP);
1301   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
1302   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)aType);
1303
1304   //Make a Python command
1305   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
1306   GEOM::TPythonDump pd (aFunction);
1307   pd << aGroup << " = geompy.IntersectListOfGroups([";
1308   for (i = 1; i <= aLen; i++) {
1309     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList->Value(i));
1310     pd << aGr_i << ((i < aLen) ? ", " : "])");
1311   }
1312
1313   SetErrorCode(OK);
1314   return aGroup;
1315 }
1316
1317 //=============================================================================
1318 /*!
1319  *  CutListOfGroups
1320  */
1321 //=============================================================================
1322 Handle(GEOM_Object) GEOMImpl_IGroupOperations::CutListOfGroups
1323                         (const Handle(TColStd_HSequenceOfTransient)& theGList1,
1324                          const Handle(TColStd_HSequenceOfTransient)& theGList2)
1325 {
1326   SetErrorCode(KO);
1327   if (theGList1.IsNull() || theGList2.IsNull()) return NULL;
1328
1329   Standard_Integer i;
1330   Standard_Integer aLen1 = theGList1->Length();
1331   Standard_Integer aLen2 = theGList2->Length();
1332   if (aLen1 < 1) {
1333     SetErrorCode("CutListOfGroups error: the first list of groups is empty");
1334     return NULL;
1335   }
1336
1337   TopAbs_ShapeEnum aType, aType_i;
1338   TDF_Label aLabel, aLabel_i;
1339   TColStd_ListOfInteger aNewIDs;
1340   TColStd_MapOfInteger mapIDs;
1341
1342   // 1. Collect indices to be excluded (from theGList2) into the mapIDs
1343   for (i = 1; i <= aLen2; i++) {
1344     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList2->Value(i));
1345
1346     // Get group type
1347     aType_i = GetType(aGr_i);
1348     if (i == 1)
1349       aType = aType_i;
1350     else {
1351       if (aType_i != aType) {
1352         if (aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
1353           if (aType_i == TopAbs_SHAPE || aType_i == TopAbs_COMPOUND)
1354             aType = aType_i;
1355           else {
1356             SetErrorCode("Error: CutListOfGroups cannot be performed on groups of different type");
1357             return NULL;
1358           }
1359         }
1360       }
1361     }
1362
1363     // Get Main Shape
1364     Handle(GEOM_Function) aFunction_i = aGr_i->GetLastFunction();
1365     if (aFunction_i.IsNull()) return NULL;
1366     GEOM_ISubShape aSSI (aFunction_i);
1367     Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
1368     if (aMainShapeFunc.IsNull()) return NULL;
1369     aLabel_i = aMainShapeFunc->GetOwnerEntry();
1370     if (aLabel_i.IsRoot()) {
1371       SetErrorCode("Error: UnionGroups can be performed only on groups");
1372       return NULL;
1373     }
1374     if (i == 1)
1375       aLabel = aLabel_i;
1376     else {
1377       if (aLabel_i != aLabel) {
1378         SetErrorCode("Error: CutListOfGroups cannot be performed on groups, built on different main shapes");
1379         return NULL;
1380       }
1381     }
1382
1383     // Indiced to exclude
1384     Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
1385     if (aSeq.IsNull()) return NULL;
1386
1387     Standard_Integer j, aLength = aSeq->Length();
1388     for (j = 1; j <= aLength; j++) {
1389       mapIDs.Add(aSeq->Value(j));
1390     }
1391   }
1392
1393   // 2. Collect indices from theGList1, avoiding indices from theGList2 (mapIDs)
1394   for (i = 1; i <= aLen1; i++) {
1395     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList1->Value(i));
1396
1397     // Get group type
1398     aType_i = GetType(aGr_i);
1399     if (i == 1 && aLen2 < 1)
1400       aType = aType_i;
1401     else {
1402       if (aType_i != aType) {
1403         if (aType != TopAbs_SHAPE && aType != TopAbs_COMPOUND) {
1404           if (aType_i == TopAbs_SHAPE || aType_i == TopAbs_COMPOUND)
1405             aType = aType_i;
1406           else {
1407             SetErrorCode("Error: CutListOfGroups cannot be performed on groups of different type");
1408             return NULL;
1409           }
1410         }
1411       }
1412     }
1413
1414     // Get Main Shape
1415     Handle(GEOM_Function) aFunction_i = aGr_i->GetLastFunction();
1416     if (aFunction_i.IsNull()) return NULL;
1417     GEOM_ISubShape aSSI (aFunction_i);
1418     Handle(GEOM_Function) aMainShapeFunc = aSSI.GetMainShape();
1419     if (aMainShapeFunc.IsNull()) return NULL;
1420     aLabel_i = aMainShapeFunc->GetOwnerEntry();
1421     if (aLabel_i.IsRoot()) {
1422       SetErrorCode("Error: UnionGroups can be performed only on groups");
1423       return NULL;
1424     }
1425     if (i == 1 && aLen2 < 1)
1426       aLabel = aLabel_i;
1427     else {
1428       if (aLabel_i != aLabel) {
1429         SetErrorCode("Error: CutListOfGroups cannot be performed on groups, built on different main shapes");
1430         return NULL;
1431       }
1432     }
1433
1434     // New contents of the group
1435     Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
1436     if (aSeq.IsNull()) return NULL;
1437
1438     Standard_Integer j, val_j, aLength = aSeq->Length();
1439     for (j = 1; j <= aLength; j++) {
1440       val_j = aSeq->Value(j);
1441       if (val_j > 0 && mapIDs.Add(val_j)) {
1442         // get only elements, not present in mapIDs (theGList2)
1443         aNewIDs.Append(val_j);
1444       }
1445     }
1446   }
1447
1448   Handle(GEOM_Object) aMainObj = GEOM_Object::GetObject(aLabel);
1449   if (aMainObj.IsNull()) return NULL;
1450
1451   Handle(TColStd_HArray1OfInteger) aNewArr;
1452   if (aNewIDs.Extent() < 1) {
1453     aNewArr = new TColStd_HArray1OfInteger (1, 1);
1454     aNewArr->SetValue(1, -1);
1455   }
1456   else {
1457     // Put new indices from the list into an array
1458     Standard_Integer k = 1;
1459     TColStd_ListIteratorOfListOfInteger aNewIDsIter (aNewIDs);
1460     aNewArr = new TColStd_HArray1OfInteger (1, aNewIDs.Extent());
1461     for (; aNewIDsIter.More(); aNewIDsIter.Next(), k++) {
1462       aNewArr->SetValue(k, aNewIDsIter.Value());
1463     }
1464   }
1465
1466   // Create the Group
1467   Handle(GEOM_Object) aGroup = GetEngine()->AddSubShape(aMainObj, aNewArr);
1468   aGroup->SetType(GEOM_GROUP);
1469   TDF_Label aFreeLabel = aGroup->GetFreeLabel();
1470   TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)aType);
1471
1472   //Make a Python command
1473   Handle(GEOM_Function) aFunction = aGroup->GetFunction(1);
1474   GEOM::TPythonDump pd (aFunction);
1475   pd << aGroup << " = geompy.CutListOfGroups([";
1476   for (i = 1; i <= aLen1; i++) {
1477     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList1->Value(i));
1478     pd << aGr_i << ((i < aLen1) ? ", " : "], [");
1479   }
1480   for (i = 1; i <= aLen2; i++) {
1481     Handle(GEOM_Object) aGr_i = Handle(GEOM_Object)::DownCast(theGList2->Value(i));
1482     pd << aGr_i << ((i < aLen2) ? ", " : "])");
1483   }
1484
1485   SetErrorCode(OK);
1486   return aGroup;
1487 }
1488
1489 //=============================================================================
1490 /*!
1491  *  GetType
1492  */
1493 //=============================================================================
1494 TopAbs_ShapeEnum GEOMImpl_IGroupOperations::GetType(Handle(GEOM_Object) theGroup)
1495 {
1496   SetErrorCode(KO);
1497
1498   TDF_Label aFreeLabel = theGroup->GetFreeLabel();
1499   Handle(TDataStd_Integer) anAttrib;
1500   if(!aFreeLabel.FindAttribute(TDataStd_Integer::GetID(), anAttrib)) return TopAbs_SHAPE;
1501
1502   SetErrorCode(OK);
1503   return (TopAbs_ShapeEnum) anAttrib->Get();
1504 }
1505
1506 //=============================================================================
1507 /*!
1508  *  GetMainShape
1509  */
1510 //=============================================================================
1511 Handle(GEOM_Object) GEOMImpl_IGroupOperations::GetMainShape (Handle(GEOM_Object) theGroup)
1512 {
1513   SetErrorCode(KO);
1514
1515   if(theGroup.IsNull()) return NULL;
1516
1517   Handle(GEOM_Function) aGroupFunction = theGroup->GetFunction(1);
1518   if (aGroupFunction.IsNull()) return NULL;
1519
1520   GEOM_ISubShape aSSI (aGroupFunction);
1521   Handle(GEOM_Function) aMainShapeFunction = aSSI.GetMainShape();
1522   if (aMainShapeFunction.IsNull()) return NULL;
1523
1524   TDF_Label aLabel = aMainShapeFunction->GetOwnerEntry();
1525   Handle(GEOM_Object) aMainShape = GEOM_Object::GetObject(aLabel);
1526   if (aMainShape.IsNull()) return NULL;
1527
1528   //Make a Python command
1529   //GEOM::TPythonDump(aGroupFunction, /*append=*/true)
1530   //  << aMainShape << " = geompy.GetMainShape(" << theGroup << ")";
1531
1532   SetErrorCode(OK);
1533   return aMainShape;
1534 }
1535
1536 //=============================================================================
1537 /*!
1538  *  GetObjects
1539  */
1540 //=============================================================================
1541 Handle(TColStd_HArray1OfInteger) GEOMImpl_IGroupOperations::GetObjects(Handle(GEOM_Object) theGroup)
1542 {
1543   SetErrorCode(KO);
1544
1545   if(theGroup.IsNull()) return NULL;
1546
1547   Handle(GEOM_Function) aFunction = theGroup->GetLastFunction();
1548   if(aFunction.IsNull()) return NULL;
1549
1550   GEOM_ISubShape aSSI(aFunction);
1551   Handle(TColStd_HArray1OfInteger) aSeq = aSSI.GetIndices();
1552   if(aSeq.IsNull()) return NULL;
1553
1554   if(aSeq->Length() == 1 && aSeq->Value(1) == -1) {
1555     SetErrorCode(OK);
1556     return NULL;
1557   }
1558
1559   SetErrorCode(OK);
1560   return aSeq;
1561 }