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