]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOM_I/GEOM_IHealingOperations_i.cc
Salome HOME
Start potring to the VTK OpenGL2 backend.
[modules/geom.git] / src / GEOM_I / GEOM_IHealingOperations_i.cc
1 // Copyright (C) 2007-2016  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 <list>
26
27 #include "GEOM_IHealingOperations_i.hh"
28 #include "GEOM_Engine.hxx"
29 #include "GEOM_Object.hxx"
30 #include "ShHealOper_ModifStats.hxx"
31
32 #include <utilities.h>
33 #include <OpUtil.hxx>
34 #include <Utils_ExceptHandlers.hxx>
35 #include <Basics_Utils.hxx>
36
37 #include <TColStd_HSequenceOfTransient.hxx>
38
39 //=============================================================================
40 /*!
41  *   constructor:
42  */
43 //=============================================================================
44
45 GEOM_IHealingOperations_i::GEOM_IHealingOperations_i (PortableServer::POA_ptr thePOA,
46                                                       GEOM::GEOM_Gen_ptr theEngine,
47                                                       ::GEOMImpl_IHealingOperations* theImpl)
48 :GEOM_IOperations_i(thePOA, theEngine, theImpl)
49 {
50   MESSAGE("GEOM_IHealingOperations_i::GEOM_IHealingOperations_i");
51 }
52
53 //=============================================================================
54 /*!
55  *  destructor
56  */
57 //=============================================================================
58
59 GEOM_IHealingOperations_i::~GEOM_IHealingOperations_i()
60 {
61   MESSAGE("GEOM_IHealingOperations_i::~GEOM_IHealingOperations_i");
62 }
63
64 //=============================================================================
65 /*!
66  *  Convert
67  */
68 //=============================================================================
69 Handle(TColStd_HArray1OfInteger) GEOM_IHealingOperations_i::Convert
70                                           (const GEOM::short_array& theInArray)
71 {
72   Handle(TColStd_HArray1OfInteger) anOutArray;
73   int n = theInArray.length();
74   if ( n <= 0 )
75     return anOutArray;
76   anOutArray = new TColStd_HArray1OfInteger( 1, n );
77   for (int i = 0; i < n; i++)
78     anOutArray->SetValue( i+1, theInArray[i] );
79   return anOutArray;
80 }
81
82 //=============================================================================
83 /*!
84  *  ProcessShape
85  */
86 //=============================================================================
87 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::ProcessShape (GEOM::GEOM_Object_ptr theObject,
88                                                                const GEOM::string_array& theOperations,
89                                                                const GEOM::string_array& theParams,
90                                                                const GEOM::string_array& theValues)
91 {
92   Kernel_Utils::Localizer loc;
93
94   GEOM::GEOM_Object_var aGEOMObject;
95
96   // Set a not done flag
97   GetOperations()->SetNotDone();
98
99   // Check if theOperations has more than 0 elements and theParams and theValues have the same length
100   //if (theOperations.length() <= 0 || theParams.length() != theValues.length())
101   //  return aGEOMObject._retn();
102
103   // Get the object itself
104   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
105   if (anObject.IsNull())
106     return aGEOMObject._retn();
107
108   // Perform
109   HANDLE_NAMESPACE(GEOM_Object) aNewObject = GetOperations()->ShapeProcess( anObject,
110     ConvertStringArray( theOperations ), ConvertStringArray( theParams ),
111     ConvertStringArray( theValues ) );
112   if ( !GetOperations()->IsDone() || aNewObject.IsNull() )
113     return aGEOMObject._retn();
114
115   return GetObject( aNewObject );
116 }
117
118 //=============================================================================
119 /*!
120  *  GetShapeProcessParameters
121  */
122 //=============================================================================
123 void GEOM_IHealingOperations_i::GetShapeProcessParameters(GEOM::string_array_out theOperations,
124                                                           GEOM::string_array_out theParams,
125                                                           GEOM::string_array_out theValues)
126 {
127   GEOM::string_array_var anOpArray = new GEOM::string_array();
128   GEOM::string_array_var aParArray = new GEOM::string_array();
129   GEOM::string_array_var aValArray = new GEOM::string_array();
130
131   // retrieve the values as stl-lists
132   std::list<std::string> operationsList, paramsList, valuesList;
133   GetOperations()->GetShapeProcessParameters( operationsList, paramsList, valuesList );
134   const int opSize = operationsList.size(),
135   parSize = paramsList.size(),
136   valSize = valuesList.size();
137
138   if ( opSize >= 0 && parSize >= 0 && parSize == valSize ) {
139     // allocate the CORBA arrays, sizes == returned lists' sizes
140     anOpArray->length(opSize);
141     aParArray->length(parSize);
142     aValArray->length(valSize);
143
144     // fill the local CORBA arrays with values from lists
145     std::list<std::string>::iterator opIt, parIt, valIt;
146     int i = 0;
147     for ( opIt = operationsList.begin(); opIt != operationsList.end(); i++,++opIt )
148       anOpArray[i] = CORBA::string_dup( (*opIt).c_str() );
149
150     for ( i = 0, parIt = paramsList.begin(), valIt = valuesList.begin();
151           parIt != paramsList.end(); i++, ++parIt,++valIt ) {
152       aParArray[i] = CORBA::string_dup( (*parIt).c_str() );
153       aValArray[i] = CORBA::string_dup( (*valIt).c_str() );
154     }
155   }
156
157   // initialize out-parameters with local arrays
158   theOperations = anOpArray._retn();
159   theParams = aParArray._retn();
160   theValues = aValArray._retn();
161 }
162
163 //=============================================================================
164 /*!
165  *  GetOperatorParameters
166  */
167 //=============================================================================
168 void GEOM_IHealingOperations_i::GetOperatorParameters (const char* theOperator,
169                                                        GEOM::string_array_out theParams,
170                                                        GEOM::string_array_out theValues)
171 {
172   GEOM::string_array_var aParArray = new GEOM::string_array();
173   GEOM::string_array_var aValArray = new GEOM::string_array();
174
175   // retrieve the values as stl-lists
176   std::list<std::string> paramsList, valuesList;
177   if ( GetOperations()->GetOperatorParameters( theOperator, paramsList, valuesList ) ) {
178     const int parSize = paramsList.size(), valSize = valuesList.size();
179
180     if ( parSize == valSize ) {
181       aParArray->length(parSize);
182       aValArray->length(valSize);
183
184       // fill the local CORBA arrays with values from lists
185       std::list<std::string>::iterator parIt, valIt;
186       int i;
187       for ( i = 0, parIt = paramsList.begin(), valIt = valuesList.begin();
188             parIt != paramsList.end(); i++, ++parIt,++valIt ) {
189         aParArray[i] = CORBA::string_dup( (*parIt).c_str() );
190         aValArray[i] = CORBA::string_dup( (*valIt).c_str() );
191       }
192     }
193   }
194
195   // initialize out-parameters with local arrays
196   theParams = aParArray._retn();
197   theValues = aValArray._retn();
198 }
199
200 //=============================================================================
201 /*!
202  *  SuppressFaces
203  */
204 //=============================================================================
205 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::SuppressFaces (GEOM::GEOM_Object_ptr theObject,
206                                                                 const GEOM::short_array& theFaces)
207 {
208   GEOM::GEOM_Object_var aGEOMObject;
209
210   // Set a not done flag
211   GetOperations()->SetNotDone();
212
213   // Get the object itself
214   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
215   if (anObject.IsNull())
216     return aGEOMObject._retn();
217
218   // if theFaces is empty - it's OK, it means that ALL faces must be removed
219
220   // Perform
221   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
222     GetOperations()->SuppressFaces( anObject, Convert( theFaces ) );
223   if (!GetOperations()->IsDone() || aNewObject.IsNull())
224     return aGEOMObject._retn();
225
226   return  GetObject( aNewObject );
227 }
228
229 //=============================================================================
230 /*!
231  *  CloseContour
232  */
233 //=============================================================================
234 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::CloseContour (GEOM::GEOM_Object_ptr theObject,
235                                                                const GEOM::short_array& theWires,
236                                                                CORBA::Boolean isCommonVertex)
237 {
238   GEOM::GEOM_Object_var aGEOMObject;
239
240   // Set a not done flag
241   GetOperations()->SetNotDone();
242
243   // Get the object itself
244   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
245   if (anObject.IsNull())
246     return aGEOMObject._retn();
247
248   // Perform
249   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
250     GetOperations()->CloseContour( anObject, Convert( theWires ), isCommonVertex );
251   if (!GetOperations()->IsDone() || aNewObject.IsNull())
252     return aGEOMObject._retn();
253
254   return GetObject(aNewObject);
255 }
256
257 //=============================================================================
258 /*!
259  *  RemoveIntWires
260  */
261 //=============================================================================
262 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::RemoveIntWires (GEOM::GEOM_Object_ptr theObject,
263                                                                  const GEOM::short_array& theWires)
264 {
265   GEOM::GEOM_Object_var aGEOMObject;
266
267   // Set a not done flag
268   GetOperations()->SetNotDone();
269
270   // Get the object itself
271   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
272   if (anObject.IsNull())
273     return aGEOMObject._retn();
274
275   // if theWires is empty - it's OK, it means that ALL wires should be removed
276
277   // Perform
278   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
279     GetOperations()->RemoveIntWires( anObject, Convert( theWires ) );
280   if (!GetOperations()->IsDone() || aNewObject.IsNull())
281     return aGEOMObject._retn();
282
283   return GetObject(aNewObject);
284 }
285
286 //=============================================================================
287 /*!
288  *  FillHoles
289  */
290 //=============================================================================
291 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::FillHoles (GEOM::GEOM_Object_ptr theObject,
292                                                             const GEOM::short_array& theWires)
293 {
294   GEOM::GEOM_Object_var aGEOMObject;
295
296   // Set a not done flag
297   GetOperations()->SetNotDone();
298
299   // Get the object itself
300   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
301   if (anObject.IsNull())
302     return aGEOMObject._retn();
303
304   // if theWires is empty - it's OK, it means that ALL wires should be removed
305
306   // Perform
307   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
308     GetOperations()->FillHoles( anObject, Convert( theWires ) );
309   if (!GetOperations()->IsDone() || aNewObject.IsNull())
310     return aGEOMObject._retn();
311
312   return GetObject(aNewObject);
313 }
314
315 //=============================================================================
316 /*!
317  *  Sew
318  */
319 //=============================================================================
320 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::Sew (const GEOM::ListOfGO& theObjects,
321                                                       CORBA::Double         theTolerance)
322 {
323   GEOM::GEOM_Object_var aGEOMObject;
324
325   // Set a not done flag
326   GetOperations()->SetNotDone();
327
328   // Check parameters
329   if (theTolerance < 0)
330     return aGEOMObject._retn();
331
332   //Get the shapes
333   std::list< HANDLE_NAMESPACE(GEOM_Object) > aShapes;
334   if (! GetListOfObjectsImpl( theObjects, aShapes ))
335     return aGEOMObject._retn();
336
337   // Perform
338   HANDLE_NAMESPACE(GEOM_Object) aNewObject = GetOperations()->Sew( aShapes, theTolerance, false );
339   if (!GetOperations()->IsDone() || aNewObject.IsNull())
340     return aGEOMObject._retn();
341
342   return GetObject(aNewObject);
343 }
344
345 //=============================================================================
346 /*!
347  *  SewAllowNonManifold
348  */
349 //=============================================================================
350 GEOM::GEOM_Object_ptr
351 GEOM_IHealingOperations_i::SewAllowNonManifold (const GEOM::ListOfGO& theObjects,
352                                                 CORBA::Double         theTolerance)
353 {
354   GEOM::GEOM_Object_var aGEOMObject;
355
356   // Set a not done flag
357   GetOperations()->SetNotDone();
358
359   // Check parameters
360   if (theTolerance < 0)
361     return aGEOMObject._retn();
362
363   //Get the shapes
364   std::list< HANDLE_NAMESPACE(GEOM_Object) > aShapes;
365   if (! GetListOfObjectsImpl( theObjects, aShapes ))
366     return aGEOMObject._retn();
367
368   // Perform
369   HANDLE_NAMESPACE(GEOM_Object) aNewObject = GetOperations()->Sew( aShapes, theTolerance, true );
370   if (!GetOperations()->IsDone() || aNewObject.IsNull())
371     return aGEOMObject._retn();
372
373   return GetObject(aNewObject);
374 }
375
376 //=============================================================================
377 /*!
378  *  RemoveInternalFaces
379  */
380 //=============================================================================
381 GEOM::GEOM_Object_ptr
382 GEOM_IHealingOperations_i::RemoveInternalFaces (const GEOM::ListOfGO& theSolids)
383 {
384   GEOM::GEOM_Object_var aGEOMObject;
385
386   // Set a not done flag
387   GetOperations()->SetNotDone();
388
389   // Get the objects
390   std::list< HANDLE_NAMESPACE(GEOM_Object) > aShapes;
391   if (! GetListOfObjectsImpl( theSolids, aShapes ))
392     return aGEOMObject._retn();
393
394   // Perform
395   HANDLE_NAMESPACE(GEOM_Object) aNewObject = GetOperations()->RemoveInternalFaces(aShapes);
396   if (!GetOperations()->IsDone() || aNewObject.IsNull())
397     return aGEOMObject._retn();
398
399   return GetObject(aNewObject);
400 }
401
402 //=============================================================================
403 /*!
404  *  DivideEdge
405  */
406 //=============================================================================
407 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::DivideEdge (GEOM::GEOM_Object_ptr theObject,
408                                                              CORBA::Short theIndex,
409                                                              CORBA::Double theValue,
410                                                              CORBA::Boolean isByParameter)
411 {
412   GEOM::GEOM_Object_var aGEOMObject;
413
414   // Set a not done flag
415   GetOperations()->SetNotDone();
416
417   // Check parameters
418   if (theValue < 0 || theValue > 1)
419     return aGEOMObject._retn();
420
421   // Get the object itself
422   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
423   if (anObject.IsNull())
424     return aGEOMObject._retn();
425
426   // Perform
427   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
428     GetOperations()->DivideEdge( anObject, theIndex, theValue, isByParameter );
429   if (!GetOperations()->IsDone() || aNewObject.IsNull())
430     return aGEOMObject._retn();
431
432   return GetObject(aNewObject);
433 }
434
435 //=============================================================================
436 /*!
437  *  DivideEdgeByPoint
438  */
439 //=============================================================================
440 GEOM::GEOM_Object_ptr
441 GEOM_IHealingOperations_i::DivideEdgeByPoint (GEOM::GEOM_Object_ptr theObject,
442                                               CORBA::Short          theIndex,
443                                               const GEOM::ListOfGO& thePoints)
444 {
445   GEOM::GEOM_Object_var aGEOMObject;
446
447   // Set a not done flag
448   GetOperations()->SetNotDone();
449
450   // Get the object itself
451   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
452   if (anObject.IsNull())
453     return aGEOMObject._retn();
454
455   // Get the points
456   std::list< HANDLE_NAMESPACE(GEOM_Object) > aPoints;
457   if (! GetListOfObjectsImpl( thePoints, aPoints ))
458     return aGEOMObject._retn();
459
460   // Perform
461   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
462     GetOperations()->DivideEdgeByPoint( anObject, theIndex, aPoints );
463   if (!GetOperations()->IsDone() || aNewObject.IsNull())
464     return aGEOMObject._retn();
465
466   return GetObject(aNewObject);
467 }
468
469 //=============================================================================
470 /*!
471  *  FuseCollinearEdgesWithinWire
472  */
473 //=============================================================================
474 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::FuseCollinearEdgesWithinWire
475                                           (GEOM::GEOM_Object_ptr theWire,
476                                            const GEOM::ListOfGO& theVertices)
477 {
478   GEOM::GEOM_Object_var aGEOMObject;
479
480   //Set a not done flag
481   GetOperations()->SetNotDone();
482
483   //Get the reference objects
484   HANDLE_NAMESPACE(GEOM_Object) aWire = GetObjectImpl(theWire);
485   if (aWire.IsNull()) return aGEOMObject._retn();
486
487   int ind, aLen;
488   std::list<HANDLE_NAMESPACE(GEOM_Object)> aVerts;
489   //Get the shapes
490   aLen = theVertices.length();
491   for (ind = 0; ind < aLen; ind++) {
492     HANDLE_NAMESPACE(GEOM_Object) aSh = GetObjectImpl(theVertices[ind]);
493     if (aSh.IsNull()) return aGEOMObject._retn();
494     aVerts.push_back(aSh);
495   }
496
497   //Perform operation
498   HANDLE_NAMESPACE(GEOM_Object) anObject =
499     GetOperations()->FuseCollinearEdgesWithinWire(aWire, aVerts);
500   if (!GetOperations()->IsDone() || anObject.IsNull())
501     return aGEOMObject._retn();
502
503   return GetObject(anObject);
504 }
505
506 //=============================================================================
507 /*!
508  *  GetFreeBoundary
509  */
510 //=============================================================================
511 CORBA::Boolean
512 GEOM_IHealingOperations_i::GetFreeBoundary ( const GEOM::ListOfGO & theObjects,
513                                              GEOM::ListOfGO_out     theClosedWires,
514                                              GEOM::ListOfGO_out     theOpenWires )
515 {
516   theClosedWires = new GEOM::ListOfGO;
517   theOpenWires = new GEOM::ListOfGO;
518
519   // Set a not done flag
520   GetOperations()->SetNotDone();
521
522   // Get the objects
523   Handle(TColStd_HSequenceOfTransient) anObjects = new TColStd_HSequenceOfTransient();
524   for ( size_t i = 0; i < theObjects.length(); ++i )
525   {
526     HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObjects[i]);
527     if (anObject.IsNull())
528       return false;
529     anObjects->Append( anObject );
530   }
531
532   Handle(TColStd_HSequenceOfTransient) aClosed = new TColStd_HSequenceOfTransient();
533   Handle(TColStd_HSequenceOfTransient) anOpen  = new TColStd_HSequenceOfTransient();
534   bool res = GetOperations()->GetFreeBoundary( anObjects, aClosed, anOpen );
535
536   if ( !GetOperations()->IsDone() || !res )
537     return false;
538
539   int i, n = aClosed->Length();
540   theClosedWires->length( n );
541   for ( i = 1; i <= n; i++ )
542     (*theClosedWires)[i-1] = GetObject(HANDLE_NAMESPACE(GEOM_Object)::DownCast(aClosed->Value(i)));
543
544   n = anOpen->Length();
545   theOpenWires->length( n );
546   for ( i = 1, n = anOpen->Length(); i <= n; i++ )
547     (*theOpenWires)[i-1] = GetObject(HANDLE_NAMESPACE(GEOM_Object)::DownCast(anOpen->Value(i)));
548
549   return true;
550 }
551
552
553 //=============================================================================
554 /*!
555  *  ChangeOrientation
556  */
557 //=============================================================================
558 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::ChangeOrientation (GEOM::GEOM_Object_ptr theObject)
559 {
560   GEOM::GEOM_Object_var aGEOMObject;
561
562   // Set a not done flag
563   GetOperations()->SetNotDone();
564
565   // Check parameters
566   if ( CORBA::is_nil(theObject) )
567     return aGEOMObject._retn();
568
569   aGEOMObject = GEOM::GEOM_Object::_duplicate(theObject);
570
571   // Get the object itself
572   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
573   if (anObject.IsNull())
574     return aGEOMObject._retn();
575
576   // Perform
577 //  HANDLE_NAMESPACE(GEOM_Object) aNewObject =
578     GetOperations()->ChangeOrientation( anObject );
579 //  if (!GetOperations()->IsDone() || aNewObject.IsNull())
580 //    return aGEOMObject._retn();
581
582   //return GetObject(aNewObject);
583   return aGEOMObject._retn();
584 }
585
586
587 //=============================================================================
588 /*!
589  *  ChangeOrientationCopy
590  */
591 //=============================================================================
592 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::ChangeOrientationCopy (GEOM::GEOM_Object_ptr theObject)
593 {
594   GEOM::GEOM_Object_var aGEOMObject;
595
596   // Set a not done flag
597   GetOperations()->SetNotDone();
598
599   // Get the object itself
600   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
601   if (anObject.IsNull())
602     return aGEOMObject._retn();
603
604   // Perform
605   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
606     GetOperations()->ChangeOrientationCopy( anObject );
607   if (!GetOperations()->IsDone() || aNewObject.IsNull())
608     return aGEOMObject._retn();
609
610   return GetObject(aNewObject);
611 }
612
613 //=============================================================================
614 /*!
615  *  LimitTolerance
616  */
617 //=============================================================================
618 GEOM::GEOM_Object_ptr GEOM_IHealingOperations_i::LimitTolerance (GEOM::GEOM_Object_ptr theObject,
619                                                                  CORBA::Double theTolerance)
620 {
621   GEOM::GEOM_Object_var aGEOMObject;
622
623   // Set a not done flag
624   GetOperations()->SetNotDone();
625
626   // Get the object itself
627   HANDLE_NAMESPACE(GEOM_Object) anObject = GetObjectImpl(theObject);
628   if (anObject.IsNull())
629     return aGEOMObject._retn();
630
631   // Perform
632   HANDLE_NAMESPACE(GEOM_Object) aNewObject =
633     GetOperations()->LimitTolerance(anObject, theTolerance);
634   if (!GetOperations()->IsDone() || aNewObject.IsNull())
635     return aGEOMObject._retn();
636
637   return GetObject(aNewObject);
638 }
639
640 //================================================================================
641 /*!
642  * \brief Return information on what has been done by the last called healing method
643  */
644 //================================================================================
645
646 GEOM::ModifStatistics* GEOM_IHealingOperations_i::GetStatistics()
647 {
648   const ShHealOper_ModifStats& stats = * GetOperations()->GetStatistics();
649   const std::set< ShHealOper_ModifStats::Datum >& modifs = stats.GetData();
650   std::set< ShHealOper_ModifStats::Datum >::const_iterator modif = modifs.begin();
651
652   GEOM::ModifStatistics_var statsVar = new GEOM::ModifStatistics();
653   statsVar->length( modifs.size() );
654   for ( int i = 0; modif != modifs.end(); ++modif, ++i )
655   {
656     statsVar[ i ].name = modif->myModif.c_str();
657     statsVar[ i ].count = modif->myCount;
658
659     // Cut off "Unknown message invoked with the keyword " at the beginning
660     const char* toRm = "Unknown message invoked with the keyword ";
661     const size_t lenToRm = strlen( toRm );
662     if ( modif->myModif.size() > lenToRm &&
663          modif->myModif.compare( 0, lenToRm, toRm ) == 0 )
664       statsVar[ i ].name = modif->myModif.substr( lenToRm ).c_str();
665   }
666
667   return statsVar._retn();
668 }