Salome HOME
0022471: EDF 2604 GEOM: Suppress the boundary edges of the tools in the fuse operation
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IBooleanOperations.cxx
1 // Copyright (C) 2007-2014  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_IBooleanOperations.hxx>
26
27 #include <GEOM_Function.hxx>
28 #include <GEOM_PythonDump.hxx>
29
30 #include <GEOMImpl_Types.hxx>
31
32 #include <GEOMImpl_BooleanDriver.hxx>
33 #include <GEOMImpl_IBoolean.hxx>
34
35 #include <GEOMImpl_PartitionDriver.hxx>
36 #include <GEOMImpl_IPartition.hxx>
37
38 #include <Basics_OCCTVersion.hxx>
39
40 #include <TDF_Tool.hxx>
41
42 #include "utilities.h"
43
44 #include <Standard_Failure.hxx>
45 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
46
47 //=============================================================================
48 /*!
49  *   constructor:
50  */
51 //=============================================================================
52 GEOMImpl_IBooleanOperations::GEOMImpl_IBooleanOperations (GEOM_Engine* theEngine, int theDocID)
53 : GEOM_IOperations(theEngine, theDocID)
54 {
55   MESSAGE("GEOMImpl_IBooleanOperations::GEOMImpl_IBooleanOperations");
56 }
57
58 //=============================================================================
59 /*!
60  *  destructor
61  */
62 //=============================================================================
63 GEOMImpl_IBooleanOperations::~GEOMImpl_IBooleanOperations()
64 {
65   MESSAGE("GEOMImpl_IBooleanOperations::~GEOMImpl_IBooleanOperations");
66 }
67
68
69 //=============================================================================
70 /*!
71  *  MakeBoolean
72  */
73 //=============================================================================
74 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakeBoolean
75                                   (Handle(GEOM_Object)    theShape1,
76                                    Handle(GEOM_Object)    theShape2,
77                                    const Standard_Integer theOp,
78                                    const Standard_Boolean IsCheckSelfInte)
79 {
80   SetErrorCode(KO);
81
82   if (theShape1.IsNull() || theShape2.IsNull()) return NULL;
83
84   //Add a new Boolean object
85   Handle(GEOM_Object) aBool = GetEngine()->AddObject(GetDocID(), GEOM_BOOLEAN);
86
87   //Add a new Boolean function
88   Handle(GEOM_Function) aFunction;
89   if (theOp == 1) {
90     aFunction = aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_COMMON);
91   } else if (theOp == 2) {
92     aFunction = aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_CUT);
93   } else if (theOp == 3) {
94     aFunction = aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_FUSE);
95   } else if (theOp == 4) {
96     aFunction = aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_SECTION);
97   } else {
98   }
99   if (aFunction.IsNull()) return NULL;
100
101   //Check if the function is set correctly
102   if (aFunction->GetDriverGUID() != GEOMImpl_BooleanDriver::GetID()) return NULL;
103
104   GEOMImpl_IBoolean aCI (aFunction);
105
106   Handle(GEOM_Function) aRef1 = theShape1->GetLastFunction();
107   Handle(GEOM_Function) aRef2 = theShape2->GetLastFunction();
108
109   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
110
111   aCI.SetShape1(aRef1);
112   aCI.SetShape2(aRef2);
113   aCI.SetCheckSelfIntersection(IsCheckSelfInte);
114
115   //Compute the Boolean value
116   try {
117 #if OCC_VERSION_LARGE > 0x06010000
118     OCC_CATCH_SIGNALS;
119 #endif
120     if (!GetSolver()->ComputeFunction(aFunction)) {
121       SetErrorCode("Boolean driver failed");
122       return NULL;
123     }
124   }
125   catch (Standard_Failure) {
126     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
127     SetErrorCode(aFail->GetMessageString());
128     return NULL;
129   }
130
131   //Make a Python command
132   GEOM::TPythonDump pd (aFunction);
133   pd << aBool;
134   if      (theOp == 1) pd << " = geompy.MakeCommon(";
135   else if (theOp == 2) pd << " = geompy.MakeCut(";
136   else if (theOp == 3) pd << " = geompy.MakeFuse(";
137   else if (theOp == 4) pd << " = geompy.MakeSection(";
138   else {}
139   pd << theShape1 << ", " << theShape2;
140
141   if (IsCheckSelfInte) {
142     pd << ", True";
143   }
144
145   pd << ")";
146
147   SetErrorCode(OK);
148   return aBool;
149 }
150
151 //=============================================================================
152 /*!
153  *  MakeFuse
154  */
155 //=============================================================================
156 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakeFuse
157                                   (Handle(GEOM_Object)    theShape1,
158                                    Handle(GEOM_Object)    theShape2,
159                                    const bool             IsCheckSelfInte,
160                                    const bool             IsRmExtraEdges)
161 {
162   SetErrorCode(KO);
163
164   if (theShape1.IsNull() || theShape2.IsNull()) return NULL;
165
166   //Add a new Boolean object
167   Handle(GEOM_Object) aBool = GetEngine()->AddObject(GetDocID(), GEOM_BOOLEAN);
168
169   //Add a new Boolean function
170   Handle(GEOM_Function) aFunction =
171     aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_FUSE);
172
173   if (aFunction.IsNull()) return NULL;
174
175   //Check if the function is set correctly
176   if (aFunction->GetDriverGUID() != GEOMImpl_BooleanDriver::GetID()) return NULL;
177
178   GEOMImpl_IBoolean aCI (aFunction);
179
180   Handle(GEOM_Function) aRef1 = theShape1->GetLastFunction();
181   Handle(GEOM_Function) aRef2 = theShape2->GetLastFunction();
182
183   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
184
185   aCI.SetShape1(aRef1);
186   aCI.SetShape2(aRef2);
187   aCI.SetCheckSelfIntersection(IsCheckSelfInte);
188   aCI.SetRmExtraEdges(IsRmExtraEdges);
189
190   //Compute the Boolean value
191   try {
192 #if OCC_VERSION_LARGE > 0x06010000
193     OCC_CATCH_SIGNALS;
194 #endif
195     if (!GetSolver()->ComputeFunction(aFunction)) {
196       SetErrorCode("Boolean driver failed");
197       return NULL;
198     }
199   }
200   catch (Standard_Failure) {
201     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
202     SetErrorCode(aFail->GetMessageString());
203     return NULL;
204   }
205
206   //Make a Python command
207   GEOM::TPythonDump pd (aFunction);
208
209   pd << aBool << " = geompy.MakeFuse(";
210   pd << theShape1 << ", " << theShape2 << ", "
211      << IsCheckSelfInte << ", " << IsRmExtraEdges << ")";
212
213   SetErrorCode(OK);
214   return aBool;
215 }
216
217 //=============================================================================
218 /*!
219  *  MakeFuseList
220  */
221 //=============================================================================
222 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakeFuseList
223                   (const Handle(TColStd_HSequenceOfTransient)& theShapes,
224                    const bool                                  IsCheckSelfInte,
225                    const bool                                  IsRmExtraEdges)
226 {
227   SetErrorCode(KO);
228
229   if (theShapes.IsNull()) return NULL;
230
231   //Add a new Boolean object
232   Handle(GEOM_Object) aBool = GetEngine()->AddObject(GetDocID(), GEOM_BOOLEAN);
233
234   //Add a new Boolean function
235   Handle(GEOM_Function) aFunction =
236     aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_FUSE_LIST);
237
238   if (aFunction.IsNull()) return NULL;
239
240   //Check if the function is set correctly
241   if (aFunction->GetDriverGUID() != GEOMImpl_BooleanDriver::GetID()) return NULL;
242
243   GEOMImpl_IBoolean aCI (aFunction);
244
245   TCollection_AsciiString aDescription;
246   Handle(TColStd_HSequenceOfTransient) aShapesSeq =
247     getShapeFunctions(theShapes, aDescription);
248
249   if (aShapesSeq.IsNull()) return NULL;
250
251   aCI.SetShapes(aShapesSeq);
252   aCI.SetCheckSelfIntersection(IsCheckSelfInte);
253   aCI.SetRmExtraEdges(IsRmExtraEdges);
254
255   //Compute the Boolean value
256   try {
257 #if OCC_VERSION_LARGE > 0x06010000
258     OCC_CATCH_SIGNALS;
259 #endif
260     if (!GetSolver()->ComputeFunction(aFunction)) {
261       SetErrorCode("Boolean driver failed");
262       return NULL;
263     }
264   }
265   catch (Standard_Failure) {
266     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
267     SetErrorCode(aFail->GetMessageString());
268     return NULL;
269   }
270
271   //Make a Python command
272   GEOM::TPythonDump pd (aFunction);
273
274   pd << aBool << " = geompy.MakeFuseList([" << aDescription.ToCString() << "], "
275      << IsCheckSelfInte << ", " << IsRmExtraEdges << ")";
276
277   SetErrorCode(OK);
278   return aBool;
279 }
280
281 //=============================================================================
282 /*!
283  *  MakeCommonList
284  */
285 //=============================================================================
286 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakeCommonList
287                   (const Handle(TColStd_HSequenceOfTransient)& theShapes,
288                    const Standard_Boolean IsCheckSelfInte)
289 {
290   SetErrorCode(KO);
291
292   if (theShapes.IsNull()) return NULL;
293
294   //Add a new Boolean object
295   Handle(GEOM_Object) aBool = GetEngine()->AddObject(GetDocID(), GEOM_BOOLEAN);
296
297   //Add a new Boolean function
298   Handle(GEOM_Function) aFunction =
299     aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_COMMON_LIST);
300
301   if (aFunction.IsNull()) return NULL;
302
303   //Check if the function is set correctly
304   if (aFunction->GetDriverGUID() != GEOMImpl_BooleanDriver::GetID()) return NULL;
305
306   GEOMImpl_IBoolean aCI (aFunction);
307
308   TCollection_AsciiString aDescription;
309   Handle(TColStd_HSequenceOfTransient) aShapesSeq =
310     getShapeFunctions(theShapes, aDescription);
311
312   if (aShapesSeq.IsNull()) return NULL;
313
314   aCI.SetShapes(aShapesSeq);
315   aCI.SetCheckSelfIntersection(IsCheckSelfInte);
316
317   //Compute the Boolean value
318   try {
319 #if OCC_VERSION_LARGE > 0x06010000
320     OCC_CATCH_SIGNALS;
321 #endif
322     if (!GetSolver()->ComputeFunction(aFunction)) {
323       SetErrorCode("Boolean driver failed");
324       return NULL;
325     }
326   }
327   catch (Standard_Failure) {
328     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
329     SetErrorCode(aFail->GetMessageString());
330     return NULL;
331   }
332
333   //Make a Python command
334   GEOM::TPythonDump pd (aFunction);
335
336   pd << aBool <<
337     " = geompy.MakeCommonList([" << aDescription.ToCString() << "]";
338
339   if (IsCheckSelfInte) {
340     pd << ", True";
341   }
342
343   pd << ")";
344
345   SetErrorCode(OK);
346   return aBool;
347 }
348
349 //=============================================================================
350 /*!
351  *  MakeCutList
352  */
353 //=============================================================================
354 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakeCutList
355                   (Handle(GEOM_Object) theMainShape,
356                    const Handle(TColStd_HSequenceOfTransient)& theShapes,
357                    const Standard_Boolean IsCheckSelfInte)
358 {
359   SetErrorCode(KO);
360
361   if (theShapes.IsNull()) return NULL;
362
363   //Add a new Boolean object
364   Handle(GEOM_Object) aBool = GetEngine()->AddObject(GetDocID(), GEOM_BOOLEAN);
365
366   //Add a new Boolean function
367   Handle(GEOM_Function) aFunction =
368     aBool->AddFunction(GEOMImpl_BooleanDriver::GetID(), BOOLEAN_CUT_LIST);
369
370   if (aFunction.IsNull()) return NULL;
371
372   //Check if the function is set correctly
373   if (aFunction->GetDriverGUID() != GEOMImpl_BooleanDriver::GetID()) return NULL;
374
375   GEOMImpl_IBoolean aCI (aFunction);
376   Handle(GEOM_Function) aMainRef = theMainShape->GetLastFunction();
377
378   if (aMainRef.IsNull()) return NULL;
379
380   TCollection_AsciiString aDescription;
381   Handle(TColStd_HSequenceOfTransient) aShapesSeq =
382     getShapeFunctions(theShapes, aDescription);
383
384   if (aShapesSeq.IsNull()) return NULL;
385
386   aCI.SetShape1(aMainRef);
387   aCI.SetShapes(aShapesSeq);
388   aCI.SetCheckSelfIntersection(IsCheckSelfInte);
389
390   //Compute the Boolean value
391   try {
392 #if OCC_VERSION_LARGE > 0x06010000
393     OCC_CATCH_SIGNALS;
394 #endif
395     if (!GetSolver()->ComputeFunction(aFunction)) {
396       SetErrorCode("Boolean driver failed");
397       return NULL;
398     }
399   }
400   catch (Standard_Failure) {
401     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
402     SetErrorCode(aFail->GetMessageString());
403     return NULL;
404   }
405
406   //Make a Python command
407   GEOM::TPythonDump pd (aFunction);
408
409   pd << aBool << " = geompy.MakeCutList("
410     << theMainShape << ", [" << aDescription.ToCString() << "]";
411
412   if (IsCheckSelfInte) {
413     pd << ", True";
414   }
415
416   pd << ")";
417
418   SetErrorCode(OK);
419   return aBool;
420 }
421
422 //=============================================================================
423 /*!
424  *  MakePartition
425  */
426 //=============================================================================
427 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakePartition
428                              (const Handle(TColStd_HSequenceOfTransient)& theShapes,
429                               const Handle(TColStd_HSequenceOfTransient)& theTools,
430                               const Handle(TColStd_HSequenceOfTransient)& theKeepIns,
431                               const Handle(TColStd_HSequenceOfTransient)& theRemoveIns,
432                               const Standard_Integer                      theLimit,
433                               const Standard_Boolean                      theRemoveWebs,
434                               const Handle(TColStd_HArray1OfInteger)&     theMaterials,
435                               const Standard_Integer theKeepNonlimitShapes,
436                               const Standard_Boolean thePerformSelfIntersections,
437                               const Standard_Boolean IsCheckSelfInte)
438 {
439   SetErrorCode(KO);
440
441   //Add a new Partition object
442   Handle(GEOM_Object) aPartition = GetEngine()->AddObject(GetDocID(), GEOM_PARTITION);
443
444   //Add a new Partition function
445   Handle(GEOM_Function) aFunction;
446   if (thePerformSelfIntersections)
447     aFunction = aPartition->AddFunction(GEOMImpl_PartitionDriver::GetID(), PARTITION_PARTITION);
448   else
449     aFunction = aPartition->AddFunction(GEOMImpl_PartitionDriver::GetID(), PARTITION_NO_SELF_INTERSECTIONS);
450   if (aFunction.IsNull()) return NULL;
451
452   //Check if the function is set correctly
453   if (aFunction->GetDriverGUID() != GEOMImpl_PartitionDriver::GetID()) return NULL;
454
455   GEOMImpl_IPartition aCI (aFunction);
456
457   Handle(TColStd_HSequenceOfTransient) aShapesSeq;
458   Handle(TColStd_HSequenceOfTransient) aToolsSeq;
459   Handle(TColStd_HSequenceOfTransient) aKeepInsSeq;
460   Handle(TColStd_HSequenceOfTransient) aRemInsSeq;
461   TCollection_AsciiString aShapesDescr, aToolsDescr, aKeepInsDescr, aRemoveInsDescr;
462
463   // Shapes
464   aShapesSeq = getShapeFunctions(theShapes, aShapesDescr);
465
466   if (aShapesSeq.IsNull()) {
467     SetErrorCode("NULL shape for Partition");
468     return NULL;
469   }
470
471   // Tools
472   aToolsSeq = getShapeFunctions(theTools, aToolsDescr);
473
474   if (aToolsSeq.IsNull()) {
475     SetErrorCode("NULL tool shape for Partition");
476     return NULL;
477   }
478
479   // Keep Inside
480   aKeepInsSeq = getShapeFunctions(theKeepIns, aKeepInsDescr);
481
482   if (aKeepInsSeq.IsNull()) {
483     SetErrorCode("NULL <keep inside> shape for Partition");
484     return NULL;
485   }
486
487   // Remove Inside
488   aRemInsSeq  = getShapeFunctions(theRemoveIns, aRemoveInsDescr);
489
490   if (aRemInsSeq.IsNull()) {
491     SetErrorCode("NULL <remove inside> shape for Partition");
492     return NULL;
493   }
494
495   aCI.SetShapes(aShapesSeq);
496   aCI.SetTools(aToolsSeq);
497   aCI.SetKeepIns(aKeepInsSeq);
498   aCI.SetRemoveIns(aRemInsSeq);
499
500   // Limit
501   aCI.SetLimit(theLimit);
502   aCI.SetKeepNonlimitShapes(theKeepNonlimitShapes);
503   aCI.SetCheckSelfIntersection(IsCheckSelfInte);
504
505   // Materials
506   if (theRemoveWebs) {
507     if (theMaterials.IsNull()) {
508       Handle(TColStd_HArray1OfInteger) aMaterials =
509         new TColStd_HArray1OfInteger (1, aShapesSeq->Length());
510       aMaterials->Init(0);
511       aCI.SetMaterials(aMaterials);
512     } else {
513       aCI.SetMaterials(theMaterials);
514     }
515   }
516
517   //Compute the Partition
518   try {
519 #if OCC_VERSION_LARGE > 0x06010000
520     OCC_CATCH_SIGNALS;
521 #endif
522     if (!GetSolver()->ComputeFunction(aFunction)) {
523       SetErrorCode("Partition driver failed");
524       return NULL;
525     }
526   }
527   catch (Standard_Failure) {
528     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
529     SetErrorCode(aFail->GetMessageString());
530     return NULL;
531   }
532
533   //Make a Python command
534   GEOM::TPythonDump pd (aFunction);
535   if (thePerformSelfIntersections)
536     pd << aPartition << " = geompy.MakePartition([";
537   else
538     pd << aPartition << " = geompy.MakePartitionNonSelfIntersectedShape([";
539
540   // Shapes, Tools
541   pd << aShapesDescr.ToCString() << "], [" << aToolsDescr.ToCString() << "], [";
542   // Keep Ins, Remove Ins
543   pd << aKeepInsDescr.ToCString() << "], [" << aRemoveInsDescr.ToCString() << "], ";
544   // Limit, Remove Webs
545   pd << TopAbs_ShapeEnum(theLimit) << ", " << (int)theRemoveWebs << ", [";
546   // Materials
547   if (!theMaterials.IsNull() && theMaterials->Length() > 0) {
548     int i = theMaterials->Lower();
549     pd << theMaterials->Value(i);
550     i++;
551     for (; i <= theMaterials->Upper(); i++) {
552       pd << ", " << theMaterials->Value(i);
553     }
554   }
555   pd << "], " << theKeepNonlimitShapes;
556
557   if (IsCheckSelfInte && !thePerformSelfIntersections) {
558     pd << ", True";
559   }
560
561   pd << ")";
562
563   SetErrorCode(OK);
564   return aPartition;
565 }
566
567 //=============================================================================
568 /*!
569  *  MakeHalfPartition
570  */
571 //=============================================================================
572 Handle(GEOM_Object) GEOMImpl_IBooleanOperations::MakeHalfPartition
573        (Handle(GEOM_Object) theShape, Handle(GEOM_Object) thePlane)
574 {
575   SetErrorCode(KO);
576
577   if (theShape.IsNull() || thePlane.IsNull()) return NULL;
578
579   //Add a new Boolean object
580   Handle(GEOM_Object) aPart = GetEngine()->AddObject(GetDocID(), GEOM_PARTITION);
581
582   //Add a new Partition function
583   Handle(GEOM_Function) aFunction =
584     aPart->AddFunction(GEOMImpl_PartitionDriver::GetID(), PARTITION_HALF);
585   if (aFunction.IsNull()) return NULL;
586
587   //Check if the function is set correctly
588   if (aFunction->GetDriverGUID() != GEOMImpl_PartitionDriver::GetID()) return NULL;
589
590   GEOMImpl_IPartition aCI (aFunction);
591
592   Handle(GEOM_Function) aRef1 = theShape->GetLastFunction();
593   Handle(GEOM_Function) aRef2 = thePlane->GetLastFunction();
594
595   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
596
597   aCI.SetShape(aRef1);
598   aCI.SetPlane(aRef2);
599
600   //Compute the Partition value
601   try {
602 #if OCC_VERSION_LARGE > 0x06010000
603     OCC_CATCH_SIGNALS;
604 #endif
605     if (!GetSolver()->ComputeFunction(aFunction)) {
606       SetErrorCode("Partition driver failed");
607       return NULL;
608     }
609   }
610   catch (Standard_Failure) {
611     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
612     SetErrorCode(aFail->GetMessageString());
613     return NULL;
614   }
615
616   //Make a Python command
617   GEOM::TPythonDump pd (aFunction);
618   pd << aPart << " = geompy.MakeHalfPartition("
619      << theShape << ", " << thePlane << ")";
620
621   SetErrorCode(OK);
622   return aPart;
623 }
624
625 //=============================================================================
626 /*!
627  *  getShapeFunctions
628  */
629 //=============================================================================
630 Handle(TColStd_HSequenceOfTransient)
631   GEOMImpl_IBooleanOperations::getShapeFunctions
632                   (const Handle(TColStd_HSequenceOfTransient)& theObjects,
633                          TCollection_AsciiString &theDescription)
634 {
635   Handle(TColStd_HSequenceOfTransient) aResult =
636     new TColStd_HSequenceOfTransient;
637   Standard_Integer aNbObjects = theObjects->Length();
638   Standard_Integer i;
639   TCollection_AsciiString anEntry;
640   Handle(GEOM_Object) anObj;
641   Handle(GEOM_Function) aRefObj;
642
643   // Shapes
644   for (i = 1; i <= aNbObjects; i++) {
645     anObj = Handle(GEOM_Object)::DownCast(theObjects->Value(i));
646     aRefObj = anObj->GetLastFunction();
647
648     if (aRefObj.IsNull()) {
649       aResult.Nullify();
650       break;
651     }
652
653     aResult->Append(aRefObj);
654
655     // For Python command
656     TDF_Tool::Entry(anObj->GetEntry(), anEntry);
657
658     if (i > 1) {
659       theDescription += ", ";
660     }
661
662     theDescription += anEntry;
663   }
664
665   return aResult;
666 }