]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx
Salome HOME
49f458033dbc3ad3b8162b1b49c9a76afd1dbd66
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IBlocksOperations.cxx
1 using namespace std;
2
3 #include "GEOMImpl_IBlocksOperations.hxx"
4
5 #include "GEOMImpl_Types.hxx"
6
7 #include "GEOMImpl_BlockDriver.hxx"
8 #include "GEOMImpl_IBlocks.hxx"
9 #include "GEOMImpl_IBlockTrsf.hxx"
10 #include "GEOMImpl_CopyDriver.hxx"
11 #include "GEOMImpl_Block6Explorer.hxx"
12
13 #include "GEOM_Function.hxx"
14
15 #include "utilities.h"
16 #include "OpUtil.hxx"
17 #include "Utils_ExceptHandlers.hxx"
18
19 #include <TFunction_DriverTable.hxx>
20 #include <TFunction_Driver.hxx>
21 #include <TFunction_Logbook.hxx>
22 #include <TDF_Tool.hxx>
23
24 #include <BRepTools.hxx>
25 #include <BRep_Tool.hxx>
26 #include <BRepClass3d_SolidClassifier.hxx>
27 #include <BRepClass_FaceClassifier.hxx>
28 #include <BRepAdaptor_Surface.hxx>
29 #include <BRepExtrema_DistShapeShape.hxx>
30 #include <BRepGProp.hxx>
31
32 #include <TopoDS.hxx>
33 #include <TopoDS_Edge.hxx>
34 #include <TopoDS_Vertex.hxx>
35 #include <TopExp.hxx>
36 #include <TopExp_Explorer.hxx>
37 #include <TopTools_MapOfShape.hxx>
38 #include <TopTools_Array1OfShape.hxx>
39 #include <TopTools_IndexedMapOfShape.hxx>
40 #include <TopTools_ListIteratorOfListOfShape.hxx>
41 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
42
43 #include <Precision.hxx>
44 #include <GProp_GProps.hxx>
45 #include <TColStd_Array1OfInteger.hxx>
46
47 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
48
49 //=============================================================================
50 /*!
51  *   constructor:
52  */
53 //=============================================================================
54 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
55 : GEOM_IOperations(theEngine, theDocID)
56 {
57   MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
58 }
59
60 //=============================================================================
61 /*!
62  *  destructor
63  */
64 //=============================================================================
65 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
66 {
67   MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
68 }
69
70
71 //=============================================================================
72 /*!
73  *  MakeQuadFaceFourVertices
74  */
75 //=============================================================================
76 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuadFaceFourVertices
77                      (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
78                       Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
79 {
80   SetErrorCode(KO);
81
82   if (thePnt1.IsNull() || thePnt2.IsNull() ||
83       thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
84
85   //Add a new Face object
86   Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
87
88   //Add a new Face function
89   Handle(GEOM_Function) aFunction =
90     aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
91
92   //Check if the function is set correctly
93   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
94
95   GEOMImpl_IBlocks aPI (aFunction);
96
97   Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
98   Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
99   Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
100   Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
101   if (aRef1.IsNull() || aRef2.IsNull() ||
102       aRef3.IsNull() || aRef4.IsNull()) return NULL;
103
104   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
105   aShapesSeq->Append(aRef1);
106   aShapesSeq->Append(aRef2);
107   aShapesSeq->Append(aRef3);
108   aShapesSeq->Append(aRef4);
109
110   aPI.SetShapes(aShapesSeq);
111
112   //Compute the Face value
113   try {
114     if (!GetSolver()->ComputeFunction(aFunction)) {
115       SetErrorCode("Block driver failed to compute a face");
116       return NULL;
117     }
118   }
119   catch (Standard_Failure) {
120     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
121     SetErrorCode(aFail->GetMessageString());
122     return NULL;
123   }
124
125   //Make a Python command
126   TCollection_AsciiString anEntry, aDescr;
127   TDF_Tool::Entry(aFace->GetEntry(), anEntry);
128   aDescr += (anEntry+" = IBlocksOperations.MakeQuadFaceFourVertices(");
129   TDF_Tool::Entry(thePnt1->GetEntry(), anEntry);
130   aDescr += (anEntry+", ");
131   TDF_Tool::Entry(thePnt2->GetEntry(), anEntry);
132   aDescr += (anEntry+", ");
133   TDF_Tool::Entry(thePnt3->GetEntry(), anEntry);
134   aDescr += (anEntry+", ");
135   TDF_Tool::Entry(thePnt4->GetEntry(), anEntry);
136   aDescr += (anEntry+")");
137
138   aFunction->SetDescription(aDescr);
139
140   SetErrorCode(OK);
141   return aFace;
142 }
143
144 //=============================================================================
145 /*!
146  *  MakeQuadFaceFourEdges
147  */
148 //=============================================================================
149 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuadFaceFourEdges
150                      (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
151                       Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
152 {
153   SetErrorCode(KO);
154
155   if (theEdge1.IsNull() || theEdge2.IsNull() ||
156       theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
157
158   //Add a new Face object
159   Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
160
161   //Add a new Face function
162   Handle(GEOM_Function) aFunction =
163     aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
164
165   //Check if the function is set correctly
166   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
167
168   GEOMImpl_IBlocks aPI (aFunction);
169
170   Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
171   Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
172   Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
173   Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
174   if (aRef1.IsNull() || aRef2.IsNull() ||
175       aRef3.IsNull() || aRef4.IsNull()) return NULL;
176
177   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
178   aShapesSeq->Append(aRef1);
179   aShapesSeq->Append(aRef2);
180   aShapesSeq->Append(aRef3);
181   aShapesSeq->Append(aRef4);
182
183   aPI.SetShapes(aShapesSeq);
184
185   //Compute the Face value
186   try {
187     if (!GetSolver()->ComputeFunction(aFunction)) {
188       SetErrorCode("Block driver failed to compute a face");
189       return NULL;
190     }
191   }
192   catch (Standard_Failure) {
193     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
194     SetErrorCode(aFail->GetMessageString());
195     return NULL;
196   }
197
198   //Make a Python command
199   TCollection_AsciiString anEntry, aDescr;
200   TDF_Tool::Entry(aFace->GetEntry(), anEntry);
201   aDescr += (anEntry+" = IBlocksOperations.MakeQuadFaceFourEdges(");
202   TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
203   aDescr += (anEntry+", ");
204   TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
205   aDescr += (anEntry+", ");
206   TDF_Tool::Entry(theEdge3->GetEntry(), anEntry);
207   aDescr += (anEntry+", ");
208   TDF_Tool::Entry(theEdge4->GetEntry(), anEntry);
209   aDescr += (anEntry+")");
210
211   aFunction->SetDescription(aDescr);
212
213   SetErrorCode(OK);
214   return aFace;
215 }
216
217 //=============================================================================
218 /*!
219  *  MakeQuadFaceTwoEdges
220  */
221 //=============================================================================
222 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuadFaceTwoEdges
223                      (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
224 {
225   SetErrorCode(KO);
226
227   if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
228
229   //Add a new Face object
230   Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
231
232   //Add a new Face function
233   Handle(GEOM_Function) aFunction =
234     aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
235
236   //Check if the function is set correctly
237   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
238
239   GEOMImpl_IBlocks aPI (aFunction);
240
241   Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
242   Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
243   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
244
245   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
246   aShapesSeq->Append(aRef1);
247   aShapesSeq->Append(aRef2);
248
249   aPI.SetShapes(aShapesSeq);
250
251   //Compute the Face value
252   try {
253     if (!GetSolver()->ComputeFunction(aFunction)) {
254       SetErrorCode("Block driver failed to compute a face");
255       return NULL;
256     }
257   }
258   catch (Standard_Failure) {
259     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
260     SetErrorCode(aFail->GetMessageString());
261     return NULL;
262   }
263
264   //Make a Python command
265   TCollection_AsciiString anEntry, aDescr;
266   TDF_Tool::Entry(aFace->GetEntry(), anEntry);
267   aDescr += (anEntry+" = IBlocksOperations.MakeQuadFaceTwoEdges(");
268   TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
269   aDescr += (anEntry+", ");
270   TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
271   aDescr += (anEntry+")");
272
273   aFunction->SetDescription(aDescr);
274
275   SetErrorCode(OK);
276   return aFace;
277 }
278
279 //=============================================================================
280 /*!
281  *  MakeHexaSolidSixFaces
282  */
283 //=============================================================================
284 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexaSolidSixFaces
285                      (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
286                       Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
287                       Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
288 {
289   SetErrorCode(KO);
290
291   if (theFace1.IsNull() || theFace2.IsNull() ||
292       theFace3.IsNull() || theFace4.IsNull() ||
293       theFace5.IsNull() || theFace6.IsNull()) return NULL;
294
295   //Add a new Solid object
296   Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
297
298   //Add a new Block function
299   Handle(GEOM_Function) aFunction =
300     aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
301
302   //Check if the function is set correctly
303   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
304
305   GEOMImpl_IBlocks aPI (aFunction);
306
307   Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
308   Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
309   Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
310   Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
311   Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
312   Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
313   if (aRef1.IsNull() || aRef2.IsNull() ||
314       aRef3.IsNull() || aRef4.IsNull() ||
315       aRef5.IsNull() || aRef6.IsNull()) return NULL;
316
317   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
318   aShapesSeq->Append(aRef1);
319   aShapesSeq->Append(aRef2);
320   aShapesSeq->Append(aRef3);
321   aShapesSeq->Append(aRef4);
322   aShapesSeq->Append(aRef5);
323   aShapesSeq->Append(aRef6);
324
325   aPI.SetShapes(aShapesSeq);
326
327   //Compute the Block value
328   try {
329     if (!GetSolver()->ComputeFunction(aFunction)) {
330       SetErrorCode("Block driver failed to compute a block");
331       return NULL;
332     }
333   }
334   catch (Standard_Failure) {
335     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
336     SetErrorCode(aFail->GetMessageString());
337     return NULL;
338   }
339
340   //Make a Python command
341   TCollection_AsciiString anEntry, aDescr;
342   TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
343   aDescr += (anEntry+" = IBlocksOperations.MakeHexaSolidSixFaces(");
344   TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
345   aDescr += (anEntry+", ");
346   TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
347   aDescr += (anEntry+", ");
348   TDF_Tool::Entry(theFace3->GetEntry(), anEntry);
349   aDescr += (anEntry+", ");
350   TDF_Tool::Entry(theFace4->GetEntry(), anEntry);
351   aDescr += (anEntry+", ");
352   TDF_Tool::Entry(theFace5->GetEntry(), anEntry);
353   aDescr += (anEntry+", ");
354   TDF_Tool::Entry(theFace6->GetEntry(), anEntry);
355   aDescr += (anEntry+")");
356
357   aFunction->SetDescription(aDescr);
358
359   SetErrorCode(OK);
360   return aBlock;
361 }
362
363 //=============================================================================
364 /*!
365  *  MakeHexaSolidTwoFaces
366  */
367 //=============================================================================
368 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexaSolidTwoFaces
369                    (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
370 {
371   SetErrorCode(KO);
372
373   if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
374
375   //Add a new Solid object
376   Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
377
378   //Add a new Block function
379   Handle(GEOM_Function) aFunction =
380     aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
381
382   //Check if the function is set correctly
383   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
384
385   GEOMImpl_IBlocks aPI (aFunction);
386
387   Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
388   Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
389   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
390
391   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
392   aShapesSeq->Append(aRef1);
393   aShapesSeq->Append(aRef2);
394
395   aPI.SetShapes(aShapesSeq);
396
397   //Compute the Block value
398   try {
399     if (!GetSolver()->ComputeFunction(aFunction)) {
400       SetErrorCode("Block driver failed to compute a block");
401       return NULL;
402     }
403   }
404   catch (Standard_Failure) {
405     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
406     SetErrorCode(aFail->GetMessageString());
407     return NULL;
408   }
409
410   //Make a Python command
411   TCollection_AsciiString anEntry, aDescr;
412   TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
413   aDescr += (anEntry+" = IBlocksOperations.MakeHexaSolidTwoFaces(");
414   TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
415   aDescr += (anEntry+", ");
416   TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
417   aDescr += (anEntry+")");
418
419   aFunction->SetDescription(aDescr);
420
421   SetErrorCode(OK);
422   return aBlock;
423 }
424
425 //=============================================================================
426 /*!
427  *  GetEdge
428  */
429 //=============================================================================
430 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
431                                                 (Handle(GEOM_Object) theShape,
432                                                  Handle(GEOM_Object) thePoint1,
433                                                  Handle(GEOM_Object) thePoint2)
434 {
435   SetErrorCode(KO);
436
437   //New Edge object
438   Handle(GEOM_Object) aResult;
439
440   // Arguments
441   if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
442
443   TopoDS_Shape aBlockOrComp = theShape->GetValue();
444   if (aBlockOrComp.IsNull()) {
445     SetErrorCode("Block or compound is null");
446     return NULL;
447   }
448   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
449       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
450       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
451     SetErrorCode("Shape is neither a block, nor a compound of blocks");
452     return NULL;
453   }
454
455   TopoDS_Shape anArg1 = thePoint1->GetValue();
456   TopoDS_Shape anArg2 = thePoint2->GetValue();
457   if (anArg1.IsNull() || anArg2.IsNull()) {
458     SetErrorCode("Null shape is given as argument");
459     return NULL;
460   }
461   if (anArg1.ShapeType() != TopAbs_VERTEX ||
462       anArg2.ShapeType() != TopAbs_VERTEX) {
463     SetErrorCode("Element for edge identification is not a vertex");
464     return NULL;
465   }
466
467   //Compute the Edge value
468   try {
469     TopTools_IndexedDataMapOfShapeListOfShape MVE;
470     GEOMImpl_Block6Explorer::MapShapesAndAncestors
471       (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
472
473     TopoDS_Shape V1,V2;
474     Standard_Integer ish, ext = MVE.Extent();
475
476     if (MVE.Contains(anArg1)) {
477       V1 = anArg1;
478     } else {
479       for (ish = 1; ish <= ext; ish++) {
480         TopoDS_Shape aShi = MVE.FindKey(ish);
481         if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
482           V1 = aShi;
483           break;
484         }
485       }
486     }
487
488     if (MVE.Contains(anArg2)) {
489       V2 = anArg2;
490     } else {
491       for (ish = 1; ish <= ext; ish++) {
492         TopoDS_Shape aShi = MVE.FindKey(ish);
493         if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
494           V2 = aShi;
495           break;
496         }
497       }
498     }
499
500     if (V1.IsNull() || V2.IsNull()) {
501       SetErrorCode("The given vertex does not belong to the shape");
502       return NULL;
503     }
504
505     const TopTools_ListOfShape& anEdgesOfV1 = MVE.FindFromKey(V1);
506     const TopTools_ListOfShape& anEdgesOfV2 = MVE.FindFromKey(V2);
507
508     Standard_Integer isFound = 0;
509     TopTools_ListIteratorOfListOfShape anIterE1 (anEdgesOfV1);
510     TopTools_MapOfShape mapShape1;
511     TopoDS_Shape anEdge;
512     for (; anIterE1.More(); anIterE1.Next()) {
513
514       if (mapShape1.Add(anIterE1.Value())) {
515         TopTools_ListIteratorOfListOfShape anIterE2 (anEdgesOfV2);
516         TopTools_MapOfShape mapShape2;
517         for (; anIterE2.More(); anIterE2.Next()) {
518
519           if (mapShape2.Add(anIterE2.Value())) {
520             if (anIterE1.Value().IsSame(anIterE2.Value())) {
521               isFound++;
522
523               // Store the edge, defined by two vertices
524               anEdge = anIterE1.Value();
525             }
526           }
527         }
528       }
529     }
530     if (isFound == 0) {
531       SetErrorCode("The given vertices do not belong to one edge of the given shape");
532       return NULL;
533     } else if (isFound > 1) {
534       SetErrorCode("Multiple edges found by the given vertices of the shape");
535       return NULL;
536     } else {
537       TopTools_IndexedMapOfShape anIndices;
538       TopExp::MapShapes(aBlockOrComp, anIndices);
539       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
540       anArray->SetValue(1, anIndices.FindIndex(anEdge));
541       aResult = GetEngine()->AddSubShape(theShape, anArray);
542     }
543   } catch (Standard_Failure) {
544     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
545     SetErrorCode(aFail->GetMessageString());
546     return NULL;
547   }
548
549   //The GetEdge() doesn't change object so no new function is required.
550   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
551
552   //Make a Python command
553   TCollection_AsciiString anEntry, aDescr;
554   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
555   aDescr += (anEntry+" = IBlocksOperations.GetEdge(");
556   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
557   aDescr += (anEntry+", ");
558   TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
559   aDescr += (anEntry+", ");
560   TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
561   aDescr += (anEntry+")");
562
563   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
564   aNewDescr += aDescr;
565   aFunction->SetDescription(aNewDescr);
566
567   SetErrorCode(OK);
568   return aResult;
569 }
570
571 //=============================================================================
572 /*!
573  *  GetFaceByPoints
574  */
575 //=============================================================================
576 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
577                                                 (Handle(GEOM_Object) theShape,
578                                                  Handle(GEOM_Object) thePoint1,
579                                                  Handle(GEOM_Object) thePoint2,
580                                                  Handle(GEOM_Object) thePoint3,
581                                                  Handle(GEOM_Object) thePoint4)
582 {
583   SetErrorCode(KO);
584
585   //New object
586   Handle(GEOM_Object) aResult;
587
588   // Arguments
589   if (theShape.IsNull() ||
590       thePoint1.IsNull() || thePoint2.IsNull() ||
591       thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
592
593   TopoDS_Shape aBlockOrComp = theShape->GetValue();
594   if (aBlockOrComp.IsNull()) {
595     SetErrorCode("Block or compound is null");
596     return NULL;
597   }
598   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
599       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
600       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
601     SetErrorCode("Shape is neither a block, nor a compound of blocks");
602     return NULL;
603   }
604
605   TopoDS_Shape anArg1 = thePoint1->GetValue();
606   TopoDS_Shape anArg2 = thePoint2->GetValue();
607   TopoDS_Shape anArg3 = thePoint3->GetValue();
608   TopoDS_Shape anArg4 = thePoint4->GetValue();
609   if (anArg1.IsNull() || anArg2.IsNull() ||
610       anArg3.IsNull() || anArg4.IsNull()) {
611     SetErrorCode("Null shape is given as argument");
612     return NULL;
613   }
614   if (anArg1.ShapeType() != TopAbs_VERTEX ||
615       anArg2.ShapeType() != TopAbs_VERTEX ||
616       anArg3.ShapeType() != TopAbs_VERTEX ||
617       anArg4.ShapeType() != TopAbs_VERTEX) {
618     SetErrorCode("Element for face identification is not a vertex");
619     return NULL;
620   }
621
622   //Compute the Face value
623   try {
624     TopoDS_Shape aShape;
625
626     TopTools_IndexedDataMapOfShapeListOfShape MVF;
627     GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
628
629     TopoDS_Shape V1,V2,V3,V4;
630     Standard_Integer ish, ext = MVF.Extent();
631
632     if (MVF.Contains(anArg1)) {
633       V1 = anArg1;
634     } else {
635       for (ish = 1; ish <= ext; ish++) {
636         TopoDS_Shape aShi = MVF.FindKey(ish);
637         if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
638           V1 = aShi;
639           break;
640         }
641       }
642     }
643
644     if (MVF.Contains(anArg2)) {
645       V2 = anArg2;
646     } else {
647       for (ish = 1; ish <= ext; ish++) {
648         TopoDS_Shape aShi = MVF.FindKey(ish);
649         if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
650           V2 = aShi;
651           break;
652         }
653       }
654     }
655
656     if (MVF.Contains(anArg3)) {
657       V3 = anArg3;
658     } else {
659       for (ish = 1; ish <= ext; ish++) {
660         TopoDS_Shape aShi = MVF.FindKey(ish);
661         if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
662           V3 = aShi;
663           break;
664         }
665       }
666     }
667
668     if (MVF.Contains(anArg4)) {
669       V4 = anArg4;
670     } else {
671       for (ish = 1; ish <= ext; ish++) {
672         TopoDS_Shape aShi = MVF.FindKey(ish);
673         if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
674           V4 = aShi;
675           break;
676         }
677       }
678     }
679
680     if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
681       SetErrorCode("The given vertex does not belong to the shape");
682       return NULL;
683     }
684
685     const TopTools_ListOfShape& aFacesOfV1 = MVF.FindFromKey(V1);
686     const TopTools_ListOfShape& aFacesOfV2 = MVF.FindFromKey(V2);
687     const TopTools_ListOfShape& aFacesOfV3 = MVF.FindFromKey(V3);
688     const TopTools_ListOfShape& aFacesOfV4 = MVF.FindFromKey(V4);
689
690     Standard_Integer isFound = 0;
691     TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfV1);
692     for (; anIterF1.More(); anIterF1.Next()) {
693
694       TopoDS_Shape aFace = anIterF1.Value();
695       TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfV2);
696       for (; anIterF2.More(); anIterF2.Next()) {
697
698         if (aFace.IsSame(anIterF2.Value())) {
699           TopTools_ListIteratorOfListOfShape anIterF3 (aFacesOfV3);
700           for (; anIterF3.More(); anIterF3.Next()) {
701
702             if (aFace.IsSame(anIterF3.Value())) {
703               TopTools_ListIteratorOfListOfShape anIterF4 (aFacesOfV4);
704               for (; anIterF4.More(); anIterF4.Next()) {
705
706                 if (aFace.IsSame(anIterF4.Value())) {
707                   isFound++;
708
709                   // Store the face, defined by four vertices
710                   aShape = aFace;
711                 }
712               }
713             }
714           }
715         }
716       }
717     }
718     if (isFound == 0) {
719       SetErrorCode("The given vertices do not belong to one face of the given shape");
720       return NULL;
721     } else if (isFound > 1) {
722       SetErrorCode("The given vertices belong to several faces of the given shape");
723       return NULL;
724     } else {
725       TopTools_IndexedMapOfShape anIndices;
726       TopExp::MapShapes(aBlockOrComp, anIndices);
727       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
728       anArray->SetValue(1, anIndices.FindIndex(aShape));
729       aResult = GetEngine()->AddSubShape(theShape, anArray);
730     }
731   }
732   catch (Standard_Failure) {
733     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
734     SetErrorCode(aFail->GetMessageString());
735     return NULL;
736   }
737
738   //The GetFaceByPoints() doesn't change object so no new function is required.
739   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
740
741   //Make a Python command
742   TCollection_AsciiString anEntry, aDescr;
743   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
744   aDescr += (anEntry+" = IBlocksOperations.GetFaceByPoints(");
745   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
746   aDescr += (anEntry+", ");
747   TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
748   aDescr += (anEntry+", ");
749   TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
750   aDescr += (anEntry+", ");
751   TDF_Tool::Entry(thePoint3->GetEntry(), anEntry);
752   aDescr += (anEntry+", ");
753   TDF_Tool::Entry(thePoint4->GetEntry(), anEntry);
754   aDescr += (anEntry+")");
755
756   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
757   aNewDescr += aDescr;
758   aFunction->SetDescription(aNewDescr);
759
760   SetErrorCode(OK);
761   return aResult;
762 }
763
764 //=============================================================================
765 /*!
766  *  GetFaceByEdges
767  */
768 //=============================================================================
769 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
770                                                 (Handle(GEOM_Object) theShape,
771                                                  Handle(GEOM_Object) theEdge1,
772                                                  Handle(GEOM_Object) theEdge2)
773 {
774   SetErrorCode(KO);
775
776   //New object
777   Handle(GEOM_Object) aResult;
778
779   // Arguments
780   if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
781
782   TopoDS_Shape aBlockOrComp = theShape->GetValue();
783   if (aBlockOrComp.IsNull()) {
784     SetErrorCode("Block or compound is null");
785     return NULL;
786   }
787   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
788       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
789       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
790     SetErrorCode("Shape is neither a block, nor a compound of blocks");
791     return NULL;
792   }
793
794   TopoDS_Shape anArg1 = theEdge1->GetValue();
795   TopoDS_Shape anArg2 = theEdge2->GetValue();
796   if (anArg1.IsNull() || anArg2.IsNull()) {
797     SetErrorCode("Null shape is given as argument");
798     return NULL;
799   }
800   if (anArg1.ShapeType() != TopAbs_EDGE ||
801       anArg2.ShapeType() != TopAbs_EDGE) {
802     SetErrorCode("Element for face identification is not an edge");
803     return NULL;
804   }
805
806   //Compute the Face value
807   try {
808     TopoDS_Shape aShape;
809
810     TopTools_IndexedDataMapOfShapeListOfShape MEF;
811     GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
812
813     TopoDS_Shape E1,E2;
814     Standard_Integer ish, ext = MEF.Extent();
815
816     if (MEF.Contains(anArg1)) {
817       E1 = anArg1;
818     } else {
819       for (ish = 1; ish <= ext; ish++) {
820         TopoDS_Shape aShi = MEF.FindKey(ish);
821         if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
822           E1 = aShi;
823         }
824       }
825     }
826
827     if (MEF.Contains(anArg2)) {
828       E2 = anArg2;
829     } else {
830       for (ish = 1; ish <= ext; ish++) {
831         TopoDS_Shape aShi = MEF.FindKey(ish);
832         if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
833           E2 = aShi;
834         }
835       }
836     }
837
838     if (E1.IsNull() || E2.IsNull()) {
839       SetErrorCode("The given edge does not belong to the shape");
840       return NULL;
841     }
842
843     const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
844     const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
845
846     Standard_Integer isFound = 0;
847     TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
848     for (; anIterF1.More(); anIterF1.Next()) {
849
850       TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
851       for (; anIterF2.More(); anIterF2.Next()) {
852
853         if (anIterF1.Value().IsSame(anIterF2.Value())) {
854           isFound++;
855
856           // Store the face, defined by two edges
857           aShape = anIterF1.Value();
858         }
859       }
860     }
861     if (isFound == 0) {
862       SetErrorCode("The given edges do not belong to one face of the given shape");
863       return NULL;
864     } else if (isFound > 1) {
865       SetErrorCode("The given edges belong to several faces of the given shape");
866       return NULL;
867     } else {
868       TopTools_IndexedMapOfShape anIndices;
869       TopExp::MapShapes(aBlockOrComp, anIndices);
870       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
871       anArray->SetValue(1, anIndices.FindIndex(aShape));
872       aResult = GetEngine()->AddSubShape(theShape, anArray);
873     }
874   }
875   catch (Standard_Failure) {
876     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
877     SetErrorCode(aFail->GetMessageString());
878     return NULL;
879   }
880
881   //The GetFaceByEdges() doesn't change object so no new function is required.
882   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
883
884   //Make a Python command
885   TCollection_AsciiString anEntry, aDescr;
886   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
887   aDescr += (anEntry+" = IBlocksOperations.GetFaceByEdges(");
888   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
889   aDescr += (anEntry+", ");
890   TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
891   aDescr += (anEntry+", ");
892   TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
893   aDescr += (anEntry+")");
894
895   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
896   aNewDescr += aDescr;
897   aFunction->SetDescription(aNewDescr);
898
899   SetErrorCode(OK);
900   return aResult;
901 }
902
903 //=============================================================================
904 /*!
905  *  GetOppositeFace
906  */
907 //=============================================================================
908 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
909                                                 (Handle(GEOM_Object) theShape,
910                                                  Handle(GEOM_Object) theFace)
911 {
912   SetErrorCode(KO);
913
914   //New object
915   Handle(GEOM_Object) aResult;
916
917   // Arguments
918   if (theShape.IsNull() || theFace.IsNull()) return NULL;
919
920   TopoDS_Shape aBlockOrComp = theShape->GetValue();
921   if (aBlockOrComp.IsNull()) {
922     SetErrorCode("Block is null");
923     return NULL;
924   }
925   if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
926     SetErrorCode("Shape is not a block");
927     return NULL;
928   }
929
930   TopoDS_Shape anArg = theFace->GetValue();
931   if (anArg.IsNull()) {
932     SetErrorCode("Null shape is given as argument");
933     return NULL;
934   }
935   if (anArg.ShapeType() != TopAbs_FACE) {
936     SetErrorCode("Element for face identification is not a face");
937     return NULL;
938   }
939
940   //Compute the Face value
941   try {
942     TopoDS_Shape aShape;
943
944     GEOMImpl_Block6Explorer aBlockTool;
945     aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
946     aShape = aBlockTool.GetFace(2);
947
948     TopTools_IndexedMapOfShape anIndices;
949     TopExp::MapShapes(aBlockOrComp, anIndices);
950     Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
951     anArray->SetValue(1, anIndices.FindIndex(aShape));
952     aResult = GetEngine()->AddSubShape(theShape, anArray);
953   }
954   catch (Standard_Failure) {
955     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
956     SetErrorCode(aFail->GetMessageString());
957     return NULL;
958   }
959
960   //The GetOppositeFace() doesn't change object so no new function is required.
961   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
962
963   //Make a Python command
964   TCollection_AsciiString anEntry, aDescr;
965   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
966   aDescr += (anEntry+" = IBlocksOperations.GetOppositeFace(");
967   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
968   aDescr += (anEntry+", ");
969   TDF_Tool::Entry(theFace->GetEntry(), anEntry);
970   aDescr += (anEntry+")");
971
972   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
973   aNewDescr += aDescr;
974   aFunction->SetDescription(aNewDescr);
975
976   SetErrorCode(OK);
977   return aResult;
978 }
979
980 //=============================================================================
981 /*!
982  *  GetFaceNearPoint
983  */
984 //=============================================================================
985 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
986                                                 (Handle(GEOM_Object) theShape,
987                                                  Handle(GEOM_Object) thePoint)
988 {
989   SetErrorCode(KO);
990
991   //New object
992   Handle(GEOM_Object) aResult;
993
994   // Arguments
995   if (theShape.IsNull() || thePoint.IsNull()) return NULL;
996
997   TopoDS_Shape aBlockOrComp = theShape->GetValue();
998   if (aBlockOrComp.IsNull()) {
999     SetErrorCode("Block or compound is null");
1000     return NULL;
1001   }
1002   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
1003       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
1004       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
1005     SetErrorCode("Shape is neither a block, nor a compound of blocks");
1006     return NULL;
1007   }
1008
1009   TopoDS_Shape anArg = thePoint->GetValue();
1010   if (anArg.IsNull()) {
1011     SetErrorCode("Null shape is given as argument");
1012     return NULL;
1013   }
1014   if (anArg.ShapeType() != TopAbs_VERTEX) {
1015     SetErrorCode("Element for face identification is not a vertex");
1016     return NULL;
1017   }
1018
1019   //Compute the Face value
1020   try {
1021     TopoDS_Shape aShape;
1022
1023     TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1024     gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1025
1026     // 1. Explode blocks on faces
1027     TopTools_MapOfShape mapShape;
1028     Standard_Integer nbFaces = 0;
1029     TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1030     for (; exp.More(); exp.Next()) {
1031       if (mapShape.Add(exp.Current())) {
1032         nbFaces++;
1033       }
1034     }
1035
1036     mapShape.Clear();
1037     Standard_Integer ind = 1;
1038     TopTools_Array1OfShape aFaces (1, nbFaces);
1039     TColStd_Array1OfInteger aDistances (1, nbFaces);
1040     for (exp.Init(aBlockOrComp, TopAbs_FACE); exp.More(); exp.Next()) {
1041       if (mapShape.Add(exp.Current())) {
1042         TopoDS_Shape aFace = exp.Current();
1043         aFaces(ind) = aFace;
1044
1045         // 2. Classify the point relatively each face
1046         BRepClass_FaceClassifier FC (TopoDS::Face(aFace), aPnt, Precision::Confusion());
1047         if (FC.State() == TopAbs_IN) {
1048           aDistances(ind) = -1;
1049         } else if (FC.State() == TopAbs_ON) {
1050           aDistances(ind) = 0;
1051         } else { // OUT
1052           aDistances(ind) = 1;
1053         }
1054         ind++;
1055       }
1056     }
1057
1058     // 3. Define face, containing the point or having minimum distance to it
1059     Standard_Integer nearest = 2, nbFound = 0;
1060     for (ind = 1; ind <= nbFaces; ind++) {
1061       if (aDistances(ind) < nearest) {
1062         nearest = aDistances(ind);
1063         aShape = aFaces(ind);
1064         nbFound = 1;
1065       } else if (aDistances(ind) == nearest) {
1066         nbFound++;
1067       } else {
1068       }
1069     }
1070     if (nbFound > 1) {
1071       if (nearest == 0) {
1072         // The point is on boundary of some faces and there are
1073         // no faces, having the point inside
1074         SetErrorCode("Multiple faces near the given point are found");
1075         return NULL;
1076
1077       } else if (nearest == 1) {
1078         // The point is outside some faces and there are
1079         // no faces, having the point inside or on boundary.
1080         // We will get a nearest face
1081         Standard_Real minDist = RealLast();
1082         for (ind = 1; ind <= nbFaces; ind++) {
1083           if (aDistances(ind) == 1) {
1084             BRepExtrema_DistShapeShape aDistTool (aVert, aFaces(ind));
1085             if (!aDistTool.IsDone()) {
1086               SetErrorCode("Can not find a distance from the given point to one of faces");
1087               return NULL;
1088             }
1089             Standard_Real aDist = aDistTool.Value();
1090             if (aDist < minDist) {
1091               minDist = aDist;
1092               aShape = aFaces(ind);
1093             }
1094           }
1095         }
1096       } else { // nearest == -1
1097         // The point is inside some faces.
1098         // We will get a face with nearest center
1099         Standard_Real minDist = RealLast();
1100         for (ind = 1; ind <= nbFaces; ind++) {
1101           if (aDistances(ind) == -1) {
1102             GProp_GProps aSystem;
1103             BRepGProp::SurfaceProperties(aFaces(ind), aSystem);
1104             gp_Pnt aCenterMass = aSystem.CentreOfMass();
1105
1106             Standard_Real aDist = aCenterMass.Distance(aPnt);
1107             if (aDist < minDist) {
1108               minDist = aDist;
1109               aShape = aFaces(ind);
1110             }
1111           }
1112         }
1113       }
1114     }
1115
1116     if (nbFound == 0) {
1117       SetErrorCode("There are no faces near the given point");
1118       return NULL;
1119     } else {
1120       TopTools_IndexedMapOfShape anIndices;
1121       TopExp::MapShapes(aBlockOrComp, anIndices);
1122       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1123       anArray->SetValue(1, anIndices.FindIndex(aShape));
1124       aResult = GetEngine()->AddSubShape(theShape, anArray);
1125     }
1126   }
1127   catch (Standard_Failure) {
1128     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1129     SetErrorCode(aFail->GetMessageString());
1130     return NULL;
1131   }
1132
1133   //The GetFaceNearPoint() doesn't change object so no new function is required.
1134   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1135
1136   //Make a Python command
1137   TCollection_AsciiString anEntry, aDescr;
1138   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1139   aDescr += (anEntry+" = IBlocksOperations.GetFaceNearPoint(");
1140   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
1141   aDescr += (anEntry+", ");
1142   TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
1143   aDescr += (anEntry+")");
1144
1145   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1146   aNewDescr += aDescr;
1147   aFunction->SetDescription(aNewDescr);
1148
1149   SetErrorCode(OK);
1150   return aResult;
1151 }
1152
1153 //=============================================================================
1154 /*!
1155  *  GetFaceByNormale
1156  */
1157 //=============================================================================
1158 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1159                                                 (Handle(GEOM_Object) theShape,
1160                                                  Handle(GEOM_Object) theVector)
1161 {
1162   SetErrorCode(KO);
1163
1164   //New object
1165   Handle(GEOM_Object) aResult;
1166
1167   // Arguments
1168   if (theShape.IsNull() || theVector.IsNull()) return NULL;
1169
1170   TopoDS_Shape aBlockOrComp = theShape->GetValue();
1171   if (aBlockOrComp.IsNull()) {
1172     SetErrorCode("Block or compound is null");
1173     return NULL;
1174   }
1175   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
1176       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
1177       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
1178     SetErrorCode("Shape is neither a block, nor a compound of blocks");
1179     return NULL;
1180   }
1181
1182   TopoDS_Shape anArg = theVector->GetValue();
1183   if (anArg.IsNull()) {
1184     SetErrorCode("Null shape is given as argument");
1185     return NULL;
1186   }
1187   if (anArg.ShapeType() != TopAbs_EDGE) {
1188     SetErrorCode("Element for normale identification is not an edge");
1189     return NULL;
1190   }
1191
1192   //Compute the Face value
1193   try {
1194     TopoDS_Shape aShape;
1195
1196     TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1197     TopoDS_Vertex V1, V2;
1198     TopExp::Vertices(anEdge, V1, V2, Standard_True);
1199     gp_Pnt P1 = BRep_Tool::Pnt(V1);
1200     gp_Pnt P2 = BRep_Tool::Pnt(V2);
1201     gp_Vec aVec (P1, P2);
1202     if (aVec.Magnitude() < Precision::Confusion()) {
1203       SetErrorCode("Vector with null magnitude is given");
1204       return NULL;
1205     }
1206
1207     Standard_Real minAngle = RealLast();
1208     TopTools_MapOfShape mapShape;
1209     Standard_Integer nbFaces = 0;
1210     TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1211     for (; exp.More(); exp.Next()) {
1212       if (mapShape.Add(exp.Current())) {
1213         TopoDS_Face aFace = TopoDS::Face(exp.Current());
1214         BRepAdaptor_Surface SF (aFace);
1215
1216         Standard_Real u, v, x;
1217
1218         // find a point on the surface to get normal direction in
1219         u = SF.FirstUParameter();
1220         x = SF.LastUParameter();
1221         if (Precision::IsInfinite(u)) {
1222           u =  (Precision::IsInfinite(x)) ? 0. : x;
1223         } else if (!Precision::IsInfinite(x)) {
1224           u = (u+x) / 2.;
1225         }
1226
1227         v = SF.FirstVParameter();
1228         x = SF.LastVParameter();
1229         if (Precision::IsInfinite(v)) {
1230           v =  (Precision::IsInfinite(x)) ? 0. : x;
1231         } else if (!Precision::IsInfinite(x)) {
1232           v = (v+x) / 2.;
1233         }
1234
1235         // compute the normal direction
1236         gp_Vec Vec1,Vec2;
1237         SF.D1(u,v,P1,Vec1,Vec2);
1238         gp_Vec V = Vec1.Crossed(Vec2);
1239         x = V.Magnitude();
1240         if (V.Magnitude() < Precision::Confusion()) {
1241           SetErrorCode("Normal vector of a face has null magnitude");
1242           return NULL;
1243         }
1244
1245         // consider the face orientation
1246         if (aFace.Orientation() == TopAbs_REVERSED ||
1247             aFace.Orientation() == TopAbs_INTERNAL) {
1248           V = - V;
1249         }
1250
1251         // compute the angle and compare with the minimal one
1252         Standard_Real anAngle = aVec.Angle(V);
1253         if (anAngle < minAngle) {
1254           minAngle = anAngle;
1255           aShape = aFace;
1256         }
1257       }
1258     }
1259
1260     if (aShape.IsNull()) {
1261       SetErrorCode("Failed to find a face by the given normale");
1262       return NULL;
1263     } else {
1264       TopTools_IndexedMapOfShape anIndices;
1265       TopExp::MapShapes(aBlockOrComp, anIndices);
1266       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1267       anArray->SetValue(1, anIndices.FindIndex(aShape));
1268       aResult = GetEngine()->AddSubShape(theShape, anArray);
1269     }
1270   }
1271   catch (Standard_Failure) {
1272     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1273     SetErrorCode(aFail->GetMessageString());
1274     return NULL;
1275   }
1276
1277   //The GetFaceByNormale() doesn't change object so no new function is required.
1278   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1279
1280   //Make a Python command
1281   TCollection_AsciiString anEntry, aDescr;
1282   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1283   aDescr += (anEntry+" = IBlocksOperations.GetFaceByNormale(");
1284   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
1285   aDescr += (anEntry+", ");
1286   TDF_Tool::Entry(theVector->GetEntry(), anEntry);
1287   aDescr += (anEntry+")");
1288
1289   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1290   aNewDescr += aDescr;
1291   aFunction->SetDescription(aNewDescr);
1292
1293   SetErrorCode(OK);
1294   return aResult;
1295 }
1296
1297 //=============================================================================
1298 /*!
1299  *  IsCompoundOfBlocks
1300  */
1301 //=============================================================================
1302 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1303                                                 (Handle(GEOM_Object)    theCompound,
1304                                                  const Standard_Integer theMinNbFaces,
1305                                                  const Standard_Integer theMaxNbFaces,
1306                                                  Standard_Integer&      theNbBlocks)
1307 {
1308   SetErrorCode(KO);
1309   Standard_Boolean isCompOfBlocks = Standard_False;
1310   theNbBlocks = 0;
1311
1312   if (theCompound.IsNull()) return isCompOfBlocks;
1313   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1314
1315   //Check
1316   isCompOfBlocks = Standard_True;
1317   try {
1318     TopTools_MapOfShape mapShape;
1319     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1320     for (; exp.More(); exp.Next()) {
1321       if (mapShape.Add(exp.Current())) {
1322         TopoDS_Shape aSolid = exp.Current();
1323
1324         TopTools_MapOfShape mapFaces;
1325         TopExp_Explorer expF (aSolid, TopAbs_FACE);
1326         Standard_Integer nbFaces = 0;
1327         for (; expF.More(); expF.Next()) {
1328           if (mapFaces.Add(expF.Current())) {
1329             nbFaces++;
1330             if (nbFaces > theMaxNbFaces) {
1331               isCompOfBlocks = Standard_False;
1332               break;
1333             }
1334           }
1335         }
1336         if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1337           isCompOfBlocks = Standard_False;
1338         } else {
1339           theNbBlocks++;
1340         }
1341       }
1342     }
1343   }
1344   catch (Standard_Failure) {
1345     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1346     SetErrorCode(aFail->GetMessageString());
1347     return isCompOfBlocks;
1348   }
1349
1350   SetErrorCode(OK);
1351   return isCompOfBlocks;
1352 }
1353
1354 //=============================================================================
1355 /*!
1356  *  ExplodeCompoundOfBlocks
1357  */
1358 //=============================================================================
1359 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
1360                                                 (Handle(GEOM_Object)    theCompound,
1361                                                  const Standard_Integer theMinNbFaces,
1362                                                  const Standard_Integer theMaxNbFaces)
1363 {
1364   SetErrorCode(KO);
1365
1366   if (theCompound.IsNull()) return NULL;
1367   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1368   if (aBlockOrComp.IsNull()) return NULL;
1369
1370   Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
1371   Handle(GEOM_Object) anObj;
1372   Handle(GEOM_Function) aFunction;
1373
1374   TopTools_MapOfShape mapShape;
1375   TCollection_AsciiString anAsciiList = "[", anEntry;
1376
1377   // Map shapes
1378   TopTools_IndexedMapOfShape anIndices;
1379   TopExp::MapShapes(aBlockOrComp, anIndices);
1380   Handle(TColStd_HArray1OfInteger) anArray;
1381
1382   // Explode
1383   try {
1384     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1385     for (; exp.More(); exp.Next()) {
1386       if (mapShape.Add(exp.Current())) {
1387         TopoDS_Shape aSolid = exp.Current();
1388
1389         TopTools_MapOfShape mapFaces;
1390         TopExp_Explorer expF (aSolid, TopAbs_FACE);
1391         Standard_Integer nbFaces = 0;
1392         for (; expF.More(); expF.Next()) {
1393           if (mapFaces.Add(expF.Current())) {
1394             nbFaces++;
1395           }
1396         }
1397
1398         if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
1399           anArray = new TColStd_HArray1OfInteger(1,1);
1400           anArray->SetValue(1, anIndices.FindIndex(aSolid));
1401           anObj = GetEngine()->AddSubShape(theCompound, anArray);
1402           aBlocks->Append(anObj);
1403
1404           //Make a Python command
1405           TDF_Tool::Entry(anObj->GetEntry(), anEntry);
1406           anAsciiList += anEntry;
1407           anAsciiList += ",";
1408         }
1409       }
1410     }
1411   }
1412   catch (Standard_Failure) {
1413     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1414     SetErrorCode(aFail->GetMessageString());
1415     return aBlocks;
1416   }
1417
1418   if (aBlocks->IsEmpty()) {
1419     SetErrorCode("There are no specified blocks in the given shape");
1420     return aBlocks;
1421   }
1422
1423   anAsciiList.Trunc(anAsciiList.Length() - 1);
1424   anAsciiList += "]";
1425
1426   //The explode doesn't change object so no new function is required.
1427   aFunction = theCompound->GetLastFunction();
1428
1429   //Make a Python command
1430   TCollection_AsciiString aDescr (anAsciiList);
1431   aDescr += " = IBlocksOperations.ExplodeCompoundOfBlocks(";
1432   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
1433   aDescr += anEntry + ", ";
1434   aDescr += TCollection_AsciiString(theMinNbFaces) + ", ";
1435   aDescr += TCollection_AsciiString(theMaxNbFaces) + ")";
1436
1437   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1438   aNewDescr += aDescr;
1439   aFunction->SetDescription(aNewDescr);
1440
1441   SetErrorCode(OK);
1442   return aBlocks;
1443 }
1444
1445 //=============================================================================
1446 /*!
1447  *  GetBlockNearPoint
1448  */
1449 //=============================================================================
1450 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
1451                                                 (Handle(GEOM_Object) theCompound,
1452                                                  Handle(GEOM_Object) thePoint)
1453 {
1454   SetErrorCode(KO);
1455
1456   //New object
1457   Handle(GEOM_Object) aResult;
1458
1459   // Arguments
1460   if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
1461
1462   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1463   if (aBlockOrComp.IsNull()) {
1464     SetErrorCode("Compound is null");
1465     return NULL;
1466   }
1467   if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
1468       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
1469     SetErrorCode("Shape is neither a block, nor a compound of blocks");
1470     return NULL;
1471   }
1472
1473   TopoDS_Shape anArg = thePoint->GetValue();
1474   if (anArg.IsNull()) {
1475     SetErrorCode("Null shape is given as argument");
1476     return NULL;
1477   }
1478   if (anArg.ShapeType() != TopAbs_VERTEX) {
1479     SetErrorCode("Element for block identification is not a vertex");
1480     return NULL;
1481   }
1482
1483   //Compute the Block value
1484   try {
1485     TopoDS_Shape aShape;
1486     TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1487     gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1488
1489     // 1. Explode compound on blocks
1490     TopTools_MapOfShape mapShape;
1491     Standard_Integer nbSolids = 0;
1492     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1493     for (; exp.More(); exp.Next()) {
1494       if (mapShape.Add(exp.Current())) {
1495         nbSolids++;
1496       }
1497     }
1498
1499     mapShape.Clear();
1500     Standard_Integer ind = 1;
1501     TopTools_Array1OfShape aSolids (1, nbSolids);
1502     TColStd_Array1OfInteger aDistances (1, nbSolids);
1503     for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next()) {
1504       if (mapShape.Add(exp.Current())) {
1505         TopoDS_Shape aSolid = exp.Current();
1506         aSolids(ind) = aSolid;
1507
1508         // 2. Classify the point relatively each block
1509         BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
1510         if (SC.State() == TopAbs_IN) {
1511           aDistances(ind) = -1;
1512         } else if (SC.State() == TopAbs_ON) {
1513           aDistances(ind) = 0;
1514         } else { // OUT
1515           aDistances(ind) = 1;
1516         }
1517         ind++;
1518       }
1519     }
1520
1521     // 3. Define block, containing the point or having minimum distance to it
1522     Standard_Integer nearest = 2, nbFound = 0;
1523     for (ind = 1; ind <= nbSolids; ind++) {
1524       if (aDistances(ind) < nearest) {
1525         nearest = aDistances(ind);
1526         aShape = aSolids(ind);
1527         nbFound = 1;
1528       } else if (aDistances(ind) == nearest) {
1529         nbFound++;
1530       } else {
1531       }
1532     }
1533     if (nbFound > 1) {
1534       if (nearest == 0) {
1535         // The point is on boundary of some blocks and there are
1536         // no blocks, having the point inside their volume
1537         SetErrorCode("Multiple blocks near the given point are found");
1538         return NULL;
1539
1540       } else if (nearest == 1) {
1541         // The point is outside some blocks and there are
1542         // no blocks, having the point inside or on boundary.
1543         // We will get a nearest block
1544         Standard_Real minDist = RealLast();
1545         for (ind = 1; ind <= nbSolids; ind++) {
1546           if (aDistances(ind) == 1) {
1547             BRepExtrema_DistShapeShape aDistTool (aVert, aSolids(ind));
1548             if (!aDistTool.IsDone()) {
1549               SetErrorCode("Can not find a distance from the given point to one of blocks");
1550               return NULL;
1551             }
1552             Standard_Real aDist = aDistTool.Value();
1553             if (aDist < minDist) {
1554               minDist = aDist;
1555               aShape = aSolids(ind);
1556             }
1557           }
1558         }
1559       } else { // nearest == -1
1560         // The point is inside some blocks.
1561         // We will get a block with nearest center
1562         Standard_Real minDist = RealLast();
1563         for (ind = 1; ind <= nbSolids; ind++) {
1564           if (aDistances(ind) == -1) {
1565             GProp_GProps aSystem;
1566             BRepGProp::VolumeProperties(aSolids(ind), aSystem);
1567             gp_Pnt aCenterMass = aSystem.CentreOfMass();
1568
1569             Standard_Real aDist = aCenterMass.Distance(aPnt);
1570             if (aDist < minDist) {
1571               minDist = aDist;
1572               aShape = aSolids(ind);
1573             }
1574           }
1575         }
1576       }
1577     }
1578
1579     if (nbFound == 0) {
1580       SetErrorCode("There are no blocks near the given point");
1581       return NULL;
1582     } else {
1583       TopTools_IndexedMapOfShape anIndices;
1584       TopExp::MapShapes(aBlockOrComp, anIndices);
1585       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1586       anArray->SetValue(1, anIndices.FindIndex(aShape));
1587       aResult = GetEngine()->AddSubShape(theCompound, anArray);
1588     }
1589   }
1590   catch (Standard_Failure) {
1591     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1592     SetErrorCode(aFail->GetMessageString());
1593     return NULL;
1594   }
1595
1596   //The GetBlockNearPoint() doesn't change object so no new function is required.
1597   Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
1598
1599   //Make a Python command
1600   TCollection_AsciiString anEntry, aDescr;
1601   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1602   aDescr += (anEntry+" = IBlocksOperations.GetBlockNearPoint(");
1603   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
1604   aDescr += (anEntry+", ");
1605   TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
1606   aDescr += (anEntry+")");
1607
1608   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1609   aNewDescr += aDescr;
1610   aFunction->SetDescription(aNewDescr);
1611
1612   SetErrorCode(OK);
1613   return aResult;
1614 }
1615
1616 //=============================================================================
1617 /*!
1618  *  GetBlockByParts
1619  */
1620 //=============================================================================
1621 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
1622                       (Handle(GEOM_Object)                         theCompound,
1623                        const Handle(TColStd_HSequenceOfTransient)& theParts)
1624 {
1625   SetErrorCode(KO);
1626
1627   Handle(GEOM_Object) aResult;
1628
1629   if (theCompound.IsNull() || theParts.IsNull()) return NULL;
1630   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1631   if (aBlockOrComp.IsNull()) return NULL;
1632
1633   //Get the parts
1634   Standard_Integer argi, aLen = theParts->Length();
1635   TopTools_Array1OfShape anArgs (1, aLen);
1636   TCollection_AsciiString anEntry, aPartsDescr;
1637   for (argi = 1; argi <= aLen; argi++) {
1638     Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
1639     Handle(GEOM_Function) aRef = anObj->GetLastFunction();
1640     if (aRef.IsNull()) return NULL;
1641
1642     TopoDS_Shape anArg = aRef->GetValue();
1643     if (anArg.IsNull()) {
1644       SetErrorCode("Null shape is given as argument");
1645       return NULL;
1646     }
1647     anArgs(argi) = anArg;
1648
1649     // For Python command
1650     TDF_Tool::Entry(anObj->GetEntry(), anEntry);
1651     if (argi > 1) aPartsDescr += ", ";
1652     aPartsDescr += anEntry;
1653   }
1654
1655   //Compute the Block value
1656   try {
1657     // 1. Explode compound on solids
1658     TopTools_MapOfShape mapShape;
1659     Standard_Integer nbSolids = 0;
1660     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1661     for (; exp.More(); exp.Next()) {
1662       if (mapShape.Add(exp.Current())) {
1663         nbSolids++;
1664       }
1665     }
1666
1667     mapShape.Clear();
1668     Standard_Integer ind = 1;
1669     TopTools_Array1OfShape aSolids (1, nbSolids);
1670     TColStd_Array1OfInteger aNbParts (1, nbSolids);
1671     for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
1672       if (mapShape.Add(exp.Current())) {
1673         TopoDS_Shape aSolid = exp.Current();
1674         aSolids(ind) = aSolid;
1675         aNbParts(ind) = 0;
1676
1677         // 2. Define quantity of parts, contained in each solid
1678         TopTools_IndexedMapOfShape aSubShapes;
1679         TopExp::MapShapes(aSolid, aSubShapes);
1680         for (argi = 1; argi <= aLen; argi++) {
1681           if (aSubShapes.Contains(anArgs(argi))) {
1682             aNbParts(ind)++;
1683           }
1684         }
1685       }
1686     }
1687
1688     // 3. Define solid, containing maximum quantity of parts
1689     Standard_Integer maxNb = 0, nbFound = 0;
1690     TopoDS_Shape aShape;
1691     for (ind = 1; ind <= nbSolids; ind++) {
1692       if (aNbParts(ind) > maxNb) {
1693         maxNb = aNbParts(ind);
1694         aShape = aSolids(ind);
1695         nbFound = 1;
1696       } else if (aNbParts(ind) == maxNb) {
1697         nbFound++;
1698       } else {
1699       }
1700     }
1701     if (nbFound > 1) {
1702       SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
1703       return NULL;
1704     } else if (nbFound == 0) {
1705       SetErrorCode("There are no blocks, containing the given parts");
1706       return NULL;
1707     } else {
1708       TopTools_IndexedMapOfShape anIndices;
1709       TopExp::MapShapes(aBlockOrComp, anIndices);
1710       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1711       anArray->SetValue(1, anIndices.FindIndex(aShape));
1712       aResult = GetEngine()->AddSubShape(theCompound, anArray);
1713     }
1714   } catch (Standard_Failure) {
1715     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1716     SetErrorCode(aFail->GetMessageString());
1717     return NULL;
1718   }
1719
1720   //The GetBlockByParts() doesn't change object so no new function is required.
1721   Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
1722
1723   //Make a Python command
1724   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1725   TCollection_AsciiString aDescr (anEntry);
1726   aDescr += " = IBlocksOperations.GetBlockByParts(";
1727   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
1728   aDescr += anEntry + ", [";
1729   aDescr += aPartsDescr + "])";
1730
1731   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1732   aNewDescr += aDescr;
1733   aFunction->SetDescription(aNewDescr);
1734
1735   SetErrorCode(OK);
1736   return aResult;
1737 }
1738
1739 //=============================================================================
1740 /*!
1741  *  GetBlocksByParts
1742  */
1743 //=============================================================================
1744 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
1745                       (Handle(GEOM_Object)                         theCompound,
1746                        const Handle(TColStd_HSequenceOfTransient)& theParts)
1747 {
1748   SetErrorCode(KO);
1749
1750   if (theCompound.IsNull() || theParts.IsNull()) return NULL;
1751   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1752   if (aBlockOrComp.IsNull()) return NULL;
1753
1754   Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
1755   Handle(GEOM_Object) anObj;
1756   Handle(GEOM_Function) aFunction;
1757
1758   //Get the parts
1759   Standard_Integer argi, aLen = theParts->Length();
1760   TopTools_Array1OfShape anArgs (1, aLen);
1761   TCollection_AsciiString anEntry, aPartsDescr, anAsciiList = "[";
1762   for (argi = 1; argi <= aLen; argi++) {
1763     Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
1764     Handle(GEOM_Function) aRef = anObj->GetLastFunction();
1765     if (aRef.IsNull()) return NULL;
1766
1767     TopoDS_Shape anArg = aRef->GetValue();
1768     if (anArg.IsNull()) {
1769       SetErrorCode("Null shape is given as argument");
1770       return NULL;
1771     }
1772     anArgs(argi) = anArg;
1773
1774     // For Python command
1775     TDF_Tool::Entry(anObj->GetEntry(), anEntry);
1776     if (argi > 1) aPartsDescr += ", ";
1777     aPartsDescr += anEntry;
1778   }
1779
1780   //Get the Blocks
1781   try {
1782     TopTools_MapOfShape mapShape;
1783     Standard_Integer nbSolids = 0;
1784     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1785     for (; exp.More(); exp.Next()) {
1786       if (mapShape.Add(exp.Current())) {
1787         nbSolids++;
1788       }
1789     }
1790
1791     mapShape.Clear();
1792     Standard_Integer ind = 1;
1793     TopTools_Array1OfShape aSolids (1, nbSolids);
1794     TColStd_Array1OfInteger aNbParts (1, nbSolids);
1795     for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
1796       if (mapShape.Add(exp.Current())) {
1797         TopoDS_Shape aSolid = exp.Current();
1798         aSolids(ind) = aSolid;
1799         aNbParts(ind) = 0;
1800
1801         // 2. Define quantity of parts, contained in each solid
1802         TopTools_IndexedMapOfShape aSubShapes;
1803         TopExp::MapShapes(aSolid, aSubShapes);
1804         for (argi = 1; argi <= aLen; argi++) {
1805           if (aSubShapes.Contains(anArgs(argi))) {
1806             aNbParts(ind)++;
1807           }
1808         }
1809       }
1810     }
1811
1812     // 3. Define solid, containing maximum quantity of parts
1813     Standard_Integer maxNb = 0, nbFound = 0;
1814     for (ind = 1; ind <= nbSolids; ind++) {
1815       if (aNbParts(ind) > maxNb) {
1816         maxNb = aNbParts(ind);
1817         nbFound = 1;
1818       } else if (aNbParts(ind) == maxNb) {
1819         nbFound++;
1820       } else {
1821       }
1822     }
1823     if (nbFound == 0) {
1824       SetErrorCode("There are no blocks, containing the given parts");
1825       return NULL;
1826     }
1827
1828     // Map shapes
1829     TopTools_IndexedMapOfShape anIndices;
1830     TopExp::MapShapes(aBlockOrComp, anIndices);
1831     Handle(TColStd_HArray1OfInteger) anArray;
1832
1833     for (ind = 1; ind <= nbSolids; ind++) {
1834       if (aNbParts(ind) == maxNb) {
1835         anArray = new TColStd_HArray1OfInteger(1,1);
1836         anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
1837         anObj = GetEngine()->AddSubShape(theCompound, anArray);
1838         aBlocks->Append(anObj);
1839
1840         //Make a Python command
1841         TDF_Tool::Entry(anObj->GetEntry(), anEntry);
1842         anAsciiList += anEntry;
1843         anAsciiList += ",";
1844       }
1845     }
1846   }
1847   catch (Standard_Failure) {
1848     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1849     SetErrorCode(aFail->GetMessageString());
1850     return NULL;
1851   }
1852
1853   anAsciiList.Trunc(anAsciiList.Length() - 1);
1854   anAsciiList += "]";
1855
1856   //The GetBlocksByParts() doesn't change object so no new function is required.
1857   aFunction = theCompound->GetLastFunction();
1858
1859   //Make a Python command
1860   TCollection_AsciiString aDescr (anAsciiList);
1861   aDescr += " = IBlocksOperations.GetBlocksByParts(";
1862   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
1863   aDescr += anEntry + ", [";
1864   aDescr += aPartsDescr + "])";
1865
1866   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1867   aNewDescr += aDescr;
1868   aFunction->SetDescription(aNewDescr);
1869
1870   SetErrorCode(OK);
1871   return aBlocks;
1872 }
1873
1874 //=============================================================================
1875 /*!
1876  *  MakeMultiTransformation1D
1877  */
1878 //=============================================================================
1879 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
1880                                              (Handle(GEOM_Object)    theObject,
1881                                               const Standard_Integer theDirFace1,
1882                                               const Standard_Integer theDirFace2,
1883                                               const Standard_Integer theNbTimes)
1884 {
1885   SetErrorCode(KO);
1886
1887   if (theObject.IsNull()) return NULL;
1888
1889   Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
1890   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
1891
1892   //Add a new Copy object
1893   Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
1894
1895   //Add a translate function
1896   Handle(GEOM_Function) aFunction =
1897     aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
1898
1899   //Check if the function is set correctly
1900   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
1901
1902   GEOMImpl_IBlockTrsf aTI (aFunction);
1903   aTI.SetOriginal(aLastFunction);
1904   aTI.SetFace1U(theDirFace1);
1905   aTI.SetFace2U(theDirFace2);
1906   aTI.SetNbIterU(theNbTimes);
1907
1908   //Compute the transformation
1909   try {
1910     if (!GetSolver()->ComputeFunction(aFunction)) {
1911       SetErrorCode("Block driver failed to make multi-transformation");
1912       return NULL;
1913     }
1914   }
1915   catch (Standard_Failure) {
1916     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1917     SetErrorCode(aFail->GetMessageString());
1918     return NULL;
1919   }
1920
1921   //Make a Python command
1922   TCollection_AsciiString anEntry, aDescr;
1923   TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
1924   aDescr += (anEntry+" = IBlocksOperations.MakeMultiTransformation1D(");
1925   TDF_Tool::Entry(theObject->GetEntry(), anEntry);
1926   aDescr += (anEntry+", ");
1927   aDescr += (TCollection_AsciiString(theDirFace1)+", ");
1928   aDescr += (TCollection_AsciiString(theDirFace2)+", ");
1929   aDescr += (TCollection_AsciiString(theNbTimes)+") ");
1930
1931   aFunction->SetDescription(aDescr);
1932
1933   SetErrorCode(OK);
1934   return aCopy;
1935 }
1936
1937 //=============================================================================
1938 /*!
1939  *  MakeMultiTransformation2D
1940  */
1941 //=============================================================================
1942 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
1943                                              (Handle(GEOM_Object)    theObject,
1944                                               const Standard_Integer theDirFace1U,
1945                                               const Standard_Integer theDirFace2U,
1946                                               const Standard_Integer theNbTimesU,
1947                                               const Standard_Integer theDirFace1V,
1948                                               const Standard_Integer theDirFace2V,
1949                                               const Standard_Integer theNbTimesV)
1950 {
1951   SetErrorCode(KO);
1952
1953   if (theObject.IsNull()) return NULL;
1954
1955   Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
1956   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
1957
1958   //Add a new Copy object
1959   Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
1960
1961   //Add a translate function
1962   Handle(GEOM_Function) aFunction =
1963     aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
1964
1965   //Check if the function is set correctly
1966   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
1967
1968   GEOMImpl_IBlockTrsf aTI (aFunction);
1969   aTI.SetOriginal(aLastFunction);
1970   aTI.SetFace1U(theDirFace1U);
1971   aTI.SetFace2U(theDirFace2U);
1972   aTI.SetNbIterU(theNbTimesU);
1973   aTI.SetFace1V(theDirFace1V);
1974   aTI.SetFace2V(theDirFace2V);
1975   aTI.SetNbIterV(theNbTimesV);
1976
1977   //Compute the transformation
1978   try {
1979     if (!GetSolver()->ComputeFunction(aFunction)) {
1980       SetErrorCode("Block driver failed to make multi-transformation");
1981       return NULL;
1982     }
1983   }
1984   catch (Standard_Failure) {
1985     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1986     SetErrorCode(aFail->GetMessageString());
1987     return NULL;
1988   }
1989
1990   //Make a Python command
1991   TCollection_AsciiString anEntry, aDescr;
1992   TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
1993   aDescr += (anEntry+" = IBlocksOperations.MakeMultiTransformation2D(");
1994   TDF_Tool::Entry(theObject->GetEntry(), anEntry);
1995   aDescr += (anEntry+", ");
1996   aDescr += (TCollection_AsciiString(theDirFace1U)+", ");
1997   aDescr += (TCollection_AsciiString(theDirFace2U)+", ");
1998   aDescr += (TCollection_AsciiString(theNbTimesU)+", ");
1999   aDescr += (TCollection_AsciiString(theDirFace1V)+", ");
2000   aDescr += (TCollection_AsciiString(theDirFace2V)+", ");
2001   aDescr += (TCollection_AsciiString(theNbTimesV)+") ");
2002
2003   aFunction->SetDescription(aDescr);
2004
2005   SetErrorCode(OK);
2006   return aCopy;
2007 }