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