32ccf23b1076ad4e696aaeec43bf4caf19ca3b09
[occt.git] / src / IGESToBRep / IGESToBRep_Reader.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 //pdn 11.01.99 including <stdio.h> for compilation on NT
15 //#70 rln 03.03.99 syntax correction
16 // sln 11.06.2002 OCC448 : Initialize "read.onlyvisiable" parameter  to control transfering invisiable sub entities which logicaly depend on the grouping entities
17 #include <stdio.h>
18 #include <IGESToBRep_Reader.ixx>
19 #include <Standard_ErrorHandler.hxx>
20 #include <Standard_Failure.hxx>
21 #include <OSD_Timer.hxx>
22
23 #include <gp_Trsf.hxx>
24
25 #include <TopAbs.hxx>
26 #include <TopoDS_Compound.hxx>
27 #include <TopoDS_Shape.hxx>
28 #include <BRep_Builder.hxx>
29 #include <BRepLib.hxx>
30 #include <BRepTools_Modifier.hxx>
31
32 #include <Message_Msg.hxx>
33 #include <Message_Messenger.hxx>
34
35 #include <IGESFile_Read.hxx>
36 #include <IGESData_FileProtocol.hxx>
37 #include <IGESData_GlobalSection.hxx>
38 #include <IGESData_IGESEntity.hxx>
39 #include <IGESSolid.hxx>
40 #include <IGESSolid_Protocol.hxx>
41 #include <IGESAppli.hxx>
42 #include <IGESAppli_Protocol.hxx>
43
44 #include <Interface_Macros.hxx>
45 #include <Interface_CheckTool.hxx>
46 #include <Interface_CheckIterator.hxx>
47 #include <Interface_ShareFlags.hxx>
48 #include <Interface_Static.hxx>
49 #include <Interface_Check.hxx>
50
51 #include <IGESToBRep.hxx>
52 #include <IGESToBRep_Actor.hxx>
53 #include <IGESToBRep_CurveAndSurface.hxx>
54
55 //#include <ShapeCustom.hxx>
56 #include <ShapeExtend_Explorer.hxx>
57 #include <ShapeFix_ShapeTolerance.hxx>
58
59 #include <Transfer_TransferOutput.hxx>
60 #include <Transfer_IteratorOfProcessForTransient.hxx>
61 #include <TransferBRep.hxx>
62 #include <TransferBRep_ShapeBinder.hxx>
63 #include <TransferBRep_ShapeListBinder.hxx>
64 #include <XSAlgo.hxx>
65 #include <XSAlgo_AlgoContainer.hxx>
66
67 #include <ShapeAlgo.hxx>
68 #include <ShapeAlgo_AlgoContainer.hxx>
69 #include <Message_ProgressSentry.hxx>
70
71 #ifdef WNT
72 #include <stdlib.h>
73 #else
74 #include <errno.h>
75 #endif
76 //extern int errno;
77
78 static Handle(IGESData_FileProtocol) protocol;
79
80
81 //=======================================================================
82 //function : IGESToBRep_Reader
83 //purpose  : 
84 //=======================================================================
85     IGESToBRep_Reader::IGESToBRep_Reader ()
86 {
87   theDone = Standard_False;
88   if (protocol.IsNull()) {
89     IGESAppli::Init();  IGESSolid::Init();
90     protocol = new IGESData_FileProtocol;
91     protocol->Add(IGESAppli::Protocol());
92     protocol->Add(IGESSolid::Protocol());
93   }
94   theActor = new IGESToBRep_Actor;
95   theProc = new Transfer_TransientProcess;
96 }
97
98
99 //=======================================================================
100 //function : LoadFile
101 //purpose  : loads a Model from a file
102 //=======================================================================
103
104 Standard_Integer IGESToBRep_Reader::LoadFile (const Standard_CString filename)
105
106   if ( theProc.IsNull() )
107     theProc = new Transfer_TransientProcess;
108   Handle(Message_Messenger) TF = theProc->Messenger();
109   
110   // Message for Diagnostic file.
111   Message_Msg msg2000("IGES_2000");   
112   msg2000.Arg(filename);
113   TF->Send (msg2000, Message_Info);
114   //Message_Msg msg2001("IGES_2001");   // Date
115   Message_Msg msg2005("IGES_2005");
116   msg2005.Arg(theProc->TraceLevel());
117   TF->Send (msg2005, Message_Info);
118   /////////////////////////////////////////////////////////
119   Handle(IGESData_IGESModel) model = new IGESData_IGESModel;
120
121   OSD_Timer c; c.Reset(); c.Start();    
122   char *pfilename=(char *)filename;
123   Standard_Integer StatusFile = IGESFile_Read(pfilename,model,protocol);
124   if (StatusFile != 0) {
125     // Sending of message : IGES file opening error 
126     Message_Msg Msg2("XSTEP_2");
127     TF->Send (Msg2, Message_Info);
128     //Message_Msg Msg3("XSTEP_3");
129     //Message_Msg Msg4("XSTEP_4");
130     //Message_Msg Msg5("XSTEP_5");
131     //Message_Msg Msg6("XSTEP_6");
132     //Message_Msg Msg7("XSTEP_7");
133     // Reasons of the file opening error
134     switch(errno)
135       {
136       case 2  : // Sending of message : No such file or directory
137         {
138           Message_Msg Msg3("XSTEP_3");
139           TF->Send (Msg3, Message_Info);
140         }
141         break;
142       case 12 : // Sending of message : Not enough space
143         {
144           Message_Msg Msg4("XSTEP_4");
145           TF->Send (Msg4, Message_Info);
146         }
147         break;
148       case 13 : // Sending of message : Permission Denied
149         {
150           Message_Msg Msg5("XSTEP_5");
151           TF->Send (Msg5, Message_Info);
152         }
153         break;
154       case 24 : // Sending of message : Too many open files
155         {
156           Message_Msg Msg6("XSTEP_6");
157           TF->Send (Msg6, Message_Info);
158         }
159         break;
160       default : // Sending of message : No determined
161         {
162           Message_Msg Msg7("XSTEP_7");
163           TF->Send (Msg7, Message_Info);
164         }
165         break;
166       }
167   }  
168   
169   Message_Msg Msg8  ("XSTEP_8");
170   Message_Msg Msg25 ("XSTEP_25");
171   Message_Msg Msg26 ("XSTEP_26");
172    // Nb warning in global section.
173
174   Standard_Integer nbWarn = 0,nbFail = 0;
175   // Add the number of warning on enities :
176   Interface_CheckTool cht (model,protocol);
177   Interface_CheckIterator anIter = cht.CompleteCheckList();
178   for(anIter.Start(); anIter.More(); anIter.Next()) {
179     const Handle(Interface_Check) ach = anIter.Value();
180     nbWarn += ach->NbWarnings();
181     nbFail += ach->NbFails();
182   }
183 // Messages nbWarn and nbFail;
184   Msg25.Arg(nbFail);
185   Msg26.Arg(nbWarn);
186   TF->Send (Msg25, Message_Info);
187   TF->Send (Msg26, Message_Info);
188   
189   // Message fin de loading iGES file (elapsed time %s)
190   char t[20];
191   t[0]='\0';
192   Standard_Real second, cpu;
193   Standard_Integer minute, hour;
194   c.Show(second, minute, hour,cpu);
195   if (hour > 0)
196     Sprintf(t,"%dh:%dm:%.2fs",hour,minute,second);
197   else if (minute > 0)
198     Sprintf(t,"%dm:%.2fs",minute,second);
199   else
200     Sprintf(t,"%.2fs",second);
201   // Sending of message : End of Loading
202   Msg8.Arg(t);
203   TF->Send (Msg8, Message_Info);
204   
205   SetModel(model);
206   return StatusFile;
207 }
208
209
210 //=======================================================================
211 //function : SetModel
212 //purpose  : Specifies a Model to work on
213 //=======================================================================
214     void  IGESToBRep_Reader::SetModel (const Handle(IGESData_IGESModel)& model)
215 {
216   theModel = model;
217   theDone  = Standard_False;
218   theShapes.Clear();
219   if ( theProc.IsNull() )
220     theProc = new Transfer_TransientProcess (theModel->NbEntities());
221   else 
222     theProc->Clear();
223 }
224
225
226 //=======================================================================
227 //function : Model
228 //purpose  : returns the Model to be worked on
229 //=======================================================================
230     Handle(IGESData_IGESModel)  IGESToBRep_Reader::Model () const
231       {  return theModel;  }
232
233
234 //=======================================================================
235 //function : SetTransientProcess
236 //purpose  : Specifies a TransferProcess
237 //=======================================================================
238     void  IGESToBRep_Reader::SetTransientProcess
239   (const Handle(Transfer_TransientProcess)& TP)
240      {  theProc = TP;  }
241
242 //=======================================================================
243 //function : TransientProcess
244 //purpose  : Returns the TransferProcess
245 //=======================================================================
246     Handle(Transfer_TransientProcess)  IGESToBRep_Reader::TransientProcess () const
247      {  return theProc;  }
248
249 //=======================================================================
250 //function : Actor
251 //purpose  : returns theActor
252 //=======================================================================
253     Handle(IGESToBRep_Actor)  IGESToBRep_Reader::Actor () const
254       {  return theActor;  }
255
256
257 //=======================================================================
258 //function : Clear
259 //purpose  : Clears the result and Done status
260 //=======================================================================
261     void  IGESToBRep_Reader::Clear ()
262 {
263   theDone  = Standard_False;
264   theShapes.Clear();
265 }
266
267
268 //=======================================================================
269 //function : Check
270 //purpose  : Checks the Model
271 //=======================================================================
272     Standard_Boolean  IGESToBRep_Reader::Check
273   (const Standard_Boolean withprint) const
274 {
275   Interface_CheckTool cht (theModel,protocol);
276   Interface_CheckIterator chl = cht.CompleteCheckList();
277   if (withprint && !theProc.IsNull()) 
278     cht.Print(chl, theProc->Messenger());
279   return chl.IsEmpty(Standard_True);
280 }
281
282
283 //=======================================================================
284 //function : IsDone
285 //purpose  : returns True if the last transfert was a success
286 //=======================================================================
287     Standard_Boolean  IGESToBRep_Reader::IsDone () const
288       {  return theDone;  }
289
290
291 //=======================================================================
292 //function : EncodeRegul
293 //purpose  : INTERNAL to encode regularity on edges
294 //=======================================================================
295
296 static Standard_Boolean  EncodeRegul (const TopoDS_Shape& sh)
297 {
298   Standard_Real tolang = Interface_Static::RVal("read.encoderegularity.angle");
299   if (sh.IsNull()) return Standard_True;
300   if (tolang <= 0) return Standard_True;
301   try {
302     OCC_CATCH_SIGNALS
303     BRepLib::EncodeRegularity (sh,tolang);
304   }
305   catch(Standard_Failure) {
306     return Standard_False;
307   }
308   return Standard_True;
309 }
310
311 //=======================================================================
312 //function : UpdateMap
313 //purpose  : Updates the correspondence map (Transfer_TransientProcess),
314 //           setting as translation results, the shapes received after
315 //           modification by modifier (BRepTools_Modifier)
316 //warning  : BRepTools_Modifier raises exception when it cannot find input
317 //           shape in its internal list
318 //=======================================================================
319
320 // coment as unused PTV 18.09.2000
321 // static void UpdateMap (const Handle(Transfer_TransientProcess)& map,
322 //                     const BRepTools_Modifier& modifier)
323 // {
324 //   Transfer_IteratorOfProcessForTransient iterator = map->CompleteResult(Standard_True);
325 //   for (iterator.Start(); iterator.More(); iterator.Next()) {
326 //     const Handle(Transfer_Binder) binder = iterator.Value();
327 //     try { //to avoid exception in BRepTools_Modifier
328 //       OCC_CATCH_SIGNALS
329 //       if (binder->IsKind (STANDARD_TYPE (TransferBRep_ShapeBinder))) {
330 //      DeclareAndCast(TransferBRep_ShapeBinder, shapebinder, binder);
331 //      if (shapebinder->HasResult()) {
332 //        TopoDS_Shape result = shapebinder->Result();
333 //        TopoDS_Shape modified = modifier.ModifiedShape (result);
334 //        if (shapebinder->Status() != Transfer_StatusUsed) //to avoid exception
335 //          shapebinder->SetResult (modified);
336 //      }
337 //       }
338 //       else if (binder->IsKind (STANDARD_TYPE (TransferBRep_ShapeListBinder))) {
339 //      DeclareAndCast(TransferBRep_ShapeListBinder, shapelistbinder, binder);
340 //      for (Standard_Integer i = 1; i <= shapelistbinder->NbShapes(); i++) {
341 //        TopoDS_Shape result = shapelistbinder->Shape (i);
342 //        TopoDS_Shape modified = modifier.ModifiedShape (result);
343 //        shapelistbinder->SetResult (i, modified);
344 //      }
345 //       }
346 //     }
347 //     catch(Standard_Failure) {
348 //       continue;
349 //     }
350 //   }
351 // }
352
353 //=======================================================================
354 //function : TrimTolerances
355 //purpose  : Trims tolerances of the shape according to static parameters
356 //          
357 //=======================================================================
358
359 static void TrimTolerances (const TopoDS_Shape& shape,
360                             const Standard_Real tol)
361 {
362   if( Interface_Static::IVal("read.maxprecision.mode")==1) {
363     ShapeFix_ShapeTolerance SFST;
364     SFST.LimitTolerance (shape, 0, Max(tol,Interface_Static::RVal ("read.maxprecision.val")));
365   }
366 }
367   
368 //=======================================================================
369 //function : TransferRoots
370 //purpose  : Transfers all Roots Entities
371 //=======================================================================
372 void  IGESToBRep_Reader::TransferRoots (const Standard_Boolean onlyvisible)
373 {
374   if (theModel.IsNull() || theProc.IsNull()) return;
375
376   Handle(Message_Messenger) TF = theProc->Messenger();
377   // Declaration of messages.
378   Message_Msg msg2030("IGES_2030");
379   TF->Send (msg2030, Message_Info);
380   Message_Msg msg2065("IGES_2065");
381   OSD_Timer c; c.Reset(); c.Start();   // Initialisation du CHRONO
382   theDone = Standard_False;
383   theShapes.Clear();
384   
385   Standard_Integer level = theProc->TraceLevel();
386   theProc->SetErrorHandle(Standard_True);
387   theProc->SetRootManagement(Standard_True);
388 //  PrepareTransfer();  -> protocol, actor
389   theActor->SetModel(theModel);
390   Standard_Integer continuity = Interface_Static::IVal("read.iges.bspline.continuity");
391   theActor->SetContinuity (continuity);
392   theProc->SetModel (theModel);
393   theProc->SetActor (theActor);
394   Transfer_TransferOutput TP (theProc,theModel);
395
396   Interface_ShareFlags SH (theModel,protocol);
397   Standard_Integer nb = theModel->NbEntities();
398   ShapeExtend_Explorer SBE;
399
400   
401   Standard_Integer precisionMode = Interface_Static::IVal("read.precision.mode");
402   Message_Msg msg2035("IGES_2035");
403   msg2035.Arg(precisionMode);
404   TF->Send (msg2035, Message_Info);
405   if (precisionMode==1) {
406     Message_Msg msg2040("IGES_2040");
407     msg2040.Arg(Interface_Static::RVal("read.precision.val"));//#70 rln 03.03.99
408     TF->Send (msg2040, Message_Info);
409   }
410   Message_Msg msg2045("IGES_2045");
411   msg2045.Arg(continuity);
412   TF->Send (msg2045, Message_Info);
413   Message_Msg msg2050("IGES_2050");
414   msg2050.Arg(Interface_Static::IVal("read.surfacecurve.mode"));
415   TF->Send (msg2050, Message_Info);
416
417   // sln 11.06.2002 OCC448
418   Interface_Static::SetIVal("read.iges.onlyvisible",onlyvisible);
419   
420   Message_ProgressSentry PS ( theProc->GetProgress(), "Root", 0, nb, 1 );
421   for (Standard_Integer i = 1; i <= nb && PS.More(); i++, PS.Next()) {
422     Handle(IGESData_IGESEntity) ent = theModel->Entity(i);
423     if ( SH.IsShared(ent) || ! theActor->Recognize (ent) ) continue;
424     if (level > 0) {
425       Message_Msg msg2070("IGES_2070");
426       msg2070.Arg(2*i-1);
427       msg2070.Arg(ent->TypeNumber());
428       TF->Send (msg2070, Message_Info);
429     }
430     // on ajoute un traitement pour ne prendre que les entites visibles
431     if ( ! onlyvisible || ent->BlankStatus() == 0 ) {
432       TopoDS_Shape shape;
433       theDone = Standard_True;
434       try {
435         OCC_CATCH_SIGNALS
436         TP.Transfer(ent);
437         shape = TransferBRep::ShapeResult (theProc,ent);
438       } 
439       catch(Standard_Failure) {
440         Message_Msg msg1005("IGES_1005");
441         TF->Send (msg1005, Message_Info);
442         continue;
443       }
444       if (shape.IsNull()) {
445         Message_Msg msg2076("IGES_2076");
446         TF->Send (msg2076, Message_Info);
447       }
448       else {
449         if (SBE.ShapeType(shape,Standard_True) != TopAbs_SHAPE) {
450           if (!shape.IsNull()) {
451             EncodeRegul (shape);
452             //#74 rln 03.03.99 S4135
453             TrimTolerances (shape, theActor->UsedTolerance());
454             theShapes.Append(shape);
455           }
456         }
457       }
458     }
459   }
460   char t [20];
461   t[0]='\0';
462   Standard_Real second, cpu;
463   Standard_Integer minute, hour;
464   c.Show(second, minute, hour,cpu);
465   if (hour > 0)
466     Sprintf(t,"%dh:%dm:%.2fs",hour,minute,second);
467   else if (minute > 0)
468     Sprintf(t,"%dm:%.2fs",minute,second);
469   else
470     Sprintf(t,"%.2fs",second);
471   // Sending of message : End of Loading
472   msg2065.Arg(t);
473   TF->Send (msg2065, Message_Info);
474 }
475
476
477 //=======================================================================
478 //function : Transfer
479 //purpose  : Transfers an Entity given
480 //=======================================================================
481 Standard_Boolean  IGESToBRep_Reader::Transfer(const Standard_Integer num)
482
483   Handle(Message_Messenger) TF = theProc->Messenger();
484   theDone = Standard_False;
485   if (theModel.IsNull()) {
486     Message_Msg msg2031("IGES_2031");
487     TF->Send (msg2031, Message_Info);
488     return Standard_False;
489   }
490   if (num <= 0 || num > theModel->NbEntities()) {
491     Message_Msg msg2032("IGES_2032");
492     msg2032.Arg(num);
493     TF->Send (msg2032, Message_Info);
494     return Standard_False;
495   }
496   // declaration of messages
497   Message_Msg msg2030("IGES_2030");
498   TF->Send (msg2030, Message_Info);
499   Message_Msg msg2065("IGES_2065");
500   OSD_Timer c; c.Reset(); c.Start();   // Initialisation du CHRONO
501   
502   Handle(IGESData_IGESEntity) ent = theModel->Entity(num);
503
504   Message_ProgressSentry PS ( theProc->GetProgress(), "OneEnt", 0, 1, 1 ); //skl
505
506   XSAlgo::AlgoContainer()->PrepareForTransfer();
507   IGESToBRep_CurveAndSurface CAS;
508   CAS.SetModel(theModel);
509   Standard_Real eps;
510   Standard_Integer Ival = Interface_Static::IVal("read.precision.mode");
511   Message_Msg msg2035("IGES_2035");
512   msg2035.Arg(Ival);
513   TF->Send (msg2035, Message_Info);
514   if ( Ival == 0)
515     eps = theModel->GlobalSection().Resolution();
516   else {
517     //mjm : modif du 19/12/97 pour prise en compte effective du parametre
518     eps = Interface_Static::RVal("read.precision.val");
519     Message_Msg msg2040("IGES_2040");
520     msg2040.Arg(eps);//#70 rln 03.03.99
521     TF->Send (msg2040, Message_Info);
522     
523   }
524   Ival = Interface_Static::IVal("read.iges.bspline.approxd1.mode");
525   CAS.SetModeApprox ( (Ival > 0) );
526   Message_Msg msg2045("IGES_2045");
527   Ival = Interface_Static::IVal("read.iges.bspline.continuity");
528   msg2045.Arg(Ival);
529   TF->Send (msg2045, Message_Info);
530   CAS.SetContinuity(Ival);
531   Message_Msg msg2050("IGES_2050");
532   Ival = Interface_Static::IVal("read.surfacecurve.mode");
533   msg2050.Arg(Ival);
534   TF->Send (msg2050, Message_Info);
535   CAS.SetSurfaceCurve (Ival);
536
537   if (eps > 1.E-08) CAS.SetEpsGeom(eps);
538   CAS.SetTransferProcess(theProc);
539
540   Standard_Boolean exceptionRaised = Standard_False;
541   TopoDS_Shape shape;
542   Standard_Integer nbTPitems = theProc->NbMapped();
543   {
544     try {
545       OCC_CATCH_SIGNALS
546       shape = CAS.TransferGeometry (ent);
547     } 
548     catch(Standard_Failure) {
549       Message_Msg msg1015("IGES_1015");
550       TF->Send (msg1015, Message_Info);
551       exceptionRaised = Standard_True;
552     }
553   }
554   if (!exceptionRaised) {
555     // fixing shape
556 //    shape = XSAlgo::AlgoContainer()->PerformFixShape ( shape, theProc, eps*CAS.GetUnitFactor(), CAS.GetMaxTol() );
557
558     Handle(Standard_Transient) info;
559     shape = XSAlgo::AlgoContainer()->ProcessShape( shape, eps*CAS.GetUnitFactor(), CAS.GetMaxTol(),
560                                                    "read.iges.resource.name", 
561                                                    "read.iges.sequence", info,
562                                                    theProc->GetProgress() );
563     XSAlgo::AlgoContainer()->MergeTransferInfo(theProc, info, nbTPitems);
564
565     ShapeExtend_Explorer SBE;
566     if (SBE.ShapeType (shape,Standard_True) != TopAbs_SHAPE) {
567       TransferBRep::SetShapeResult (theProc,ent,shape);
568       theProc->SetRoot (ent);
569       if (!shape.IsNull()) {
570         theDone = Standard_True;
571         EncodeRegul (shape);
572         //#74 rln 03.03.99 S4135
573         TrimTolerances (shape, CAS.GetMaxTol());
574         theShapes.Append(shape);
575       }
576     }
577   }
578
579   PS.Relieve(); //skl
580
581   char t [20];
582   t[0]='\0';
583   Standard_Real second, cpu;
584   Standard_Integer minute, hour;
585   c.Show(second, minute, hour,cpu);
586   if (hour > 0)
587     Sprintf(t,"%dh:%dm:%.2fs",hour,minute,second);
588   else if (minute > 0)
589     Sprintf(t,"%dm:%.2fs",minute,second);
590   else
591     Sprintf(t,"%.2fs",second);
592   // Sending of message : End of Loading
593   msg2065.Arg(t);
594   TF->Send (msg2065, Message_Info);
595   return Standard_True;
596 }
597
598
599 //=======================================================================
600 //function : UsedTolerance
601 //purpose  : Returns the used tolerance (input)
602 //=======================================================================
603     Standard_Real  IGESToBRep_Reader::UsedTolerance () const
604       {  return theActor->UsedTolerance();  }
605
606 //=======================================================================
607 //function : NbShapes
608 //purpose  : Returns the count of produced Shapes
609 //=======================================================================
610     Standard_Integer  IGESToBRep_Reader::NbShapes () const
611       {  return theShapes.Length();  }
612
613
614 //=======================================================================
615 //function : Shape
616 //purpose  : Returns a Shape given its rank
617 //=======================================================================
618     TopoDS_Shape  IGESToBRep_Reader::Shape (const Standard_Integer num) const
619 {
620   TopoDS_Shape res;
621   if (num > 0 && num <= theShapes.Length()) res = theShapes.Value(num);
622   return res;
623 }
624
625
626 //=======================================================================
627 //function : OneShape
628 //purpose  : Returns a unique Shape
629 //=======================================================================
630     TopoDS_Shape  IGESToBRep_Reader::OneShape () const
631 {
632   TopoDS_Shape res;
633   Standard_Integer nb = theShapes.Length();
634   if (nb == 0) return res;
635   else if (nb == 1) return theShapes.Value(1);
636   else {
637     TopoDS_Compound C;
638     BRep_Builder B;
639     B.MakeCompound(C);
640     for (Standard_Integer i = 1; i <= nb; i ++)  B.Add (C,theShapes.Value(i));
641     return C;
642   }
643 }