Salome HOME
Merge with version on tag OCC-V2_1_0d
[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 <BRep_Tool.hxx>
25 #include <BRepTools.hxx>
26 #include <BRepGProp.hxx>
27 #include <BRepBndLib.hxx>
28 #include <BRepAdaptor_Surface.hxx>
29 #include <BRepClass_FaceClassifier.hxx>
30 #include <BRepClass3d_SolidClassifier.hxx>
31 #include <BRepExtrema_DistShapeShape.hxx>
32
33 #include <TopAbs.hxx>
34 #include <TopoDS.hxx>
35 #include <TopoDS_Edge.hxx>
36 #include <TopoDS_Vertex.hxx>
37 #include <TopoDS_Iterator.hxx>
38 #include <TopExp.hxx>
39 #include <TopExp_Explorer.hxx>
40 #include <TopTools_MapOfShape.hxx>
41 #include <TopTools_Array1OfShape.hxx>
42 #include <TopTools_IndexedMapOfShape.hxx>
43 #include <TopTools_ListIteratorOfListOfShape.hxx>
44 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
45
46 #include <Bnd_Box.hxx>
47 #include <Precision.hxx>
48 #include <GProp_GProps.hxx>
49 #include <TColStd_MapOfInteger.hxx>
50 #include <TColStd_Array1OfReal.hxx>
51 #include <TColStd_Array1OfInteger.hxx>
52 #include <TColStd_Array2OfInteger.hxx>
53
54 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
55
56 //=============================================================================
57 /*!
58  *   constructor:
59  */
60 //=============================================================================
61 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
62 : GEOM_IOperations(theEngine, theDocID)
63 {
64   MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
65 }
66
67 //=============================================================================
68 /*!
69  *  destructor
70  */
71 //=============================================================================
72 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
73 {
74   MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
75 }
76
77
78 //=============================================================================
79 /*!
80  *  MakeQuad
81  */
82 //=============================================================================
83 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
84                      (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
85                       Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
86 {
87   SetErrorCode(KO);
88
89   if (theEdge1.IsNull() || theEdge2.IsNull() ||
90       theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
91
92   //Add a new Face object
93   Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
94
95   //Add a new Face function
96   Handle(GEOM_Function) aFunction =
97     aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
98
99   //Check if the function is set correctly
100   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
101
102   GEOMImpl_IBlocks aPI (aFunction);
103
104   Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
105   Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
106   Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
107   Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
108   if (aRef1.IsNull() || aRef2.IsNull() ||
109       aRef3.IsNull() || aRef4.IsNull()) return NULL;
110
111   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
112   aShapesSeq->Append(aRef1);
113   aShapesSeq->Append(aRef2);
114   aShapesSeq->Append(aRef3);
115   aShapesSeq->Append(aRef4);
116
117   aPI.SetShapes(aShapesSeq);
118
119   //Compute the Face value
120   try {
121     if (!GetSolver()->ComputeFunction(aFunction)) {
122       SetErrorCode("Block driver failed to compute a face");
123       return NULL;
124     }
125   }
126   catch (Standard_Failure) {
127     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
128     SetErrorCode(aFail->GetMessageString());
129     return NULL;
130   }
131
132   //Make a Python command
133   TCollection_AsciiString anEntry, aDescr;
134   TDF_Tool::Entry(aFace->GetEntry(), anEntry);
135   aDescr += anEntry + " = IBlocksOperations.MakeQuad(";
136   TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
137   aDescr += anEntry + ", ";
138   TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
139   aDescr += anEntry + ", ";
140   TDF_Tool::Entry(theEdge3->GetEntry(), anEntry);
141   aDescr += anEntry + ", ";
142   TDF_Tool::Entry(theEdge4->GetEntry(), anEntry);
143   aDescr += anEntry + ")";
144
145   aFunction->SetDescription(aDescr);
146
147   SetErrorCode(OK);
148   return aFace;
149 }
150
151 //=============================================================================
152 /*!
153  *  MakeQuad2Edges
154  */
155 //=============================================================================
156 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
157                      (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
158 {
159   SetErrorCode(KO);
160
161   if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
162
163   //Add a new Face object
164   Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
165
166   //Add a new Face function
167   Handle(GEOM_Function) aFunction =
168     aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
169
170   //Check if the function is set correctly
171   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
172
173   GEOMImpl_IBlocks aPI (aFunction);
174
175   Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
176   Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
177   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
178
179   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
180   aShapesSeq->Append(aRef1);
181   aShapesSeq->Append(aRef2);
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.MakeQuad2Edges(";
202   TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
203   aDescr += anEntry + ", ";
204   TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
205   aDescr += anEntry + ")";
206
207   aFunction->SetDescription(aDescr);
208
209   SetErrorCode(OK);
210   return aFace;
211 }
212
213 //=============================================================================
214 /*!
215  *  MakeQuad4Vertices
216  */
217 //=============================================================================
218 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
219                      (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
220                       Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
221 {
222   SetErrorCode(KO);
223
224   if (thePnt1.IsNull() || thePnt2.IsNull() ||
225       thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
226
227   //Add a new Face object
228   Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
229
230   //Add a new Face function
231   Handle(GEOM_Function) aFunction =
232     aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
233
234   //Check if the function is set correctly
235   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
236
237   GEOMImpl_IBlocks aPI (aFunction);
238
239   Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
240   Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
241   Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
242   Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
243   if (aRef1.IsNull() || aRef2.IsNull() ||
244       aRef3.IsNull() || aRef4.IsNull()) return NULL;
245
246   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
247   aShapesSeq->Append(aRef1);
248   aShapesSeq->Append(aRef2);
249   aShapesSeq->Append(aRef3);
250   aShapesSeq->Append(aRef4);
251
252   aPI.SetShapes(aShapesSeq);
253
254   //Compute the Face value
255   try {
256     if (!GetSolver()->ComputeFunction(aFunction)) {
257       SetErrorCode("Block driver failed to compute a face");
258       return NULL;
259     }
260   }
261   catch (Standard_Failure) {
262     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
263     SetErrorCode(aFail->GetMessageString());
264     return NULL;
265   }
266
267   //Make a Python command
268   TCollection_AsciiString anEntry, aDescr;
269   TDF_Tool::Entry(aFace->GetEntry(), anEntry);
270   aDescr += anEntry + " = IBlocksOperations.MakeQuad4Vertices(";
271   TDF_Tool::Entry(thePnt1->GetEntry(), anEntry);
272   aDescr += anEntry + ", ";
273   TDF_Tool::Entry(thePnt2->GetEntry(), anEntry);
274   aDescr += anEntry + ", ";
275   TDF_Tool::Entry(thePnt3->GetEntry(), anEntry);
276   aDescr += anEntry + ", ";
277   TDF_Tool::Entry(thePnt4->GetEntry(), anEntry);
278   aDescr += anEntry + ")";
279
280   aFunction->SetDescription(aDescr);
281
282   SetErrorCode(OK);
283   return aFace;
284 }
285
286 //=============================================================================
287 /*!
288  *  MakeHexa
289  */
290 //=============================================================================
291 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
292                      (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
293                       Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
294                       Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
295 {
296   SetErrorCode(KO);
297
298   if (theFace1.IsNull() || theFace2.IsNull() ||
299       theFace3.IsNull() || theFace4.IsNull() ||
300       theFace5.IsNull() || theFace6.IsNull()) return NULL;
301
302   //Add a new Solid object
303   Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
304
305   //Add a new Block function
306   Handle(GEOM_Function) aFunction =
307     aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
308
309   //Check if the function is set correctly
310   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
311
312   GEOMImpl_IBlocks aPI (aFunction);
313
314   Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
315   Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
316   Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
317   Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
318   Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
319   Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
320   if (aRef1.IsNull() || aRef2.IsNull() ||
321       aRef3.IsNull() || aRef4.IsNull() ||
322       aRef5.IsNull() || aRef6.IsNull()) return NULL;
323
324   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
325   aShapesSeq->Append(aRef1);
326   aShapesSeq->Append(aRef2);
327   aShapesSeq->Append(aRef3);
328   aShapesSeq->Append(aRef4);
329   aShapesSeq->Append(aRef5);
330   aShapesSeq->Append(aRef6);
331
332   aPI.SetShapes(aShapesSeq);
333
334   //Compute the Block value
335   try {
336     if (!GetSolver()->ComputeFunction(aFunction)) {
337       SetErrorCode("Block driver failed to compute a block");
338       return NULL;
339     }
340   }
341   catch (Standard_Failure) {
342     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
343     SetErrorCode(aFail->GetMessageString());
344     return NULL;
345   }
346
347   //Make a Python command
348   TCollection_AsciiString anEntry, aDescr;
349   TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
350   aDescr += anEntry + " = IBlocksOperations.MakeHexa(";
351   TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
352   aDescr += anEntry + ", ";
353   TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
354   aDescr += anEntry + ", ";
355   TDF_Tool::Entry(theFace3->GetEntry(), anEntry);
356   aDescr += anEntry + ", ";
357   TDF_Tool::Entry(theFace4->GetEntry(), anEntry);
358   aDescr += anEntry + ", ";
359   TDF_Tool::Entry(theFace5->GetEntry(), anEntry);
360   aDescr += anEntry + ", ";
361   TDF_Tool::Entry(theFace6->GetEntry(), anEntry);
362   aDescr += anEntry + ")";
363
364   aFunction->SetDescription(aDescr);
365
366   SetErrorCode(OK);
367   return aBlock;
368 }
369
370 //=============================================================================
371 /*!
372  *  MakeHexa2Faces
373  */
374 //=============================================================================
375 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
376                    (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
377 {
378   SetErrorCode(KO);
379
380   if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
381
382   //Add a new Solid object
383   Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
384
385   //Add a new Block function
386   Handle(GEOM_Function) aFunction =
387     aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
388
389   //Check if the function is set correctly
390   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
391
392   GEOMImpl_IBlocks aPI (aFunction);
393
394   Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
395   Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
396   if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
397
398   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
399   aShapesSeq->Append(aRef1);
400   aShapesSeq->Append(aRef2);
401
402   aPI.SetShapes(aShapesSeq);
403
404   //Compute the Block value
405   try {
406     if (!GetSolver()->ComputeFunction(aFunction)) {
407       SetErrorCode("Block driver failed to compute a block");
408       return NULL;
409     }
410   }
411   catch (Standard_Failure) {
412     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
413     SetErrorCode(aFail->GetMessageString());
414     return NULL;
415   }
416
417   //Make a Python command
418   TCollection_AsciiString anEntry, aDescr;
419   TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
420   aDescr += anEntry + " = IBlocksOperations.MakeHexa2Faces(";
421   TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
422   aDescr += anEntry + ", ";
423   TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
424   aDescr += anEntry + ")";
425
426   aFunction->SetDescription(aDescr);
427
428   SetErrorCode(OK);
429   return aBlock;
430 }
431
432 //=============================================================================
433 /*!
434  *  MakeBlockCompound
435  */
436 //=============================================================================
437 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
438                                               (Handle(GEOM_Object) theCompound)
439 {
440   SetErrorCode(KO);
441
442   if (theCompound.IsNull()) return NULL;
443
444   //Add a new object
445   Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
446
447   //Add a new BlocksComp function
448   Handle(GEOM_Function) aFunction =
449     aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
450
451   //Check if the function is set correctly
452   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
453
454   GEOMImpl_IBlocks aPI (aFunction);
455
456   Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
457   if (aRef1.IsNull()) return NULL;
458
459   Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
460   aShapesSeq->Append(aRef1);
461
462   aPI.SetShapes(aShapesSeq);
463
464   //Compute the Blocks Compound value
465   try {
466     if (!GetSolver()->ComputeFunction(aFunction)) {
467       SetErrorCode("Block driver failed to compute a blocks compound");
468       return NULL;
469     }
470   }
471   catch (Standard_Failure) {
472     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
473     SetErrorCode(aFail->GetMessageString());
474     return NULL;
475   }
476
477   //Make a Python command
478   TCollection_AsciiString anEntry, aDescr;
479   TDF_Tool::Entry(aBlockComp->GetEntry(), anEntry);
480   aDescr += anEntry + " = IBlocksOperations.MakeBlockCompound(";
481   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
482   aDescr += anEntry + ")";
483
484   aFunction->SetDescription(aDescr);
485
486   SetErrorCode(OK);
487   return aBlockComp;
488 }
489
490 //=============================================================================
491 /*!
492  *  GetEdge
493  */
494 //=============================================================================
495 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
496                                                (Handle(GEOM_Object) theShape,
497                                                 const Standard_Real theX,
498                                                 const Standard_Real theY,
499                                                 const Standard_Real theZ,
500                                                 const Standard_Real theEpsilon)
501 {
502   SetErrorCode(KO);
503
504   //New Point object
505   Handle(GEOM_Object) aResult;
506
507   // Arguments
508   if (theShape.IsNull()) return NULL;
509
510   TopoDS_Shape aBlockOrComp = theShape->GetValue();
511   if (aBlockOrComp.IsNull()) {
512     SetErrorCode("Block or compound is null");
513     return NULL;
514   }
515   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
516       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
517       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
518     SetErrorCode("Shape is neither a block, nor a compound of blocks");
519     return NULL;
520   }
521
522   //Compute the Vertex value
523   gp_Pnt P (theX, theY, theZ);
524   Standard_Real eps = Max(theEpsilon, Precision::Confusion());
525
526   TopoDS_Shape V;
527   Standard_Integer isFound = 0;
528   TopTools_MapOfShape mapShape;
529   TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
530
531   for (; exp.More(); exp.Next()) {
532     if (mapShape.Add(exp.Current())) {
533       TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
534       gp_Pnt aPi = BRep_Tool::Pnt(aVi);
535       if (aPi.Distance(P) < eps) {
536         V = aVi;
537         isFound++;
538       }
539     }
540   }
541
542   if (isFound == 0) {
543     SetErrorCode("Vertex has not been found");
544     return NULL;
545   } else if (isFound > 1) {
546     SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
547     return NULL;
548   } else {
549     TopTools_IndexedMapOfShape anIndices;
550     TopExp::MapShapes(aBlockOrComp, anIndices);
551     Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
552     anArray->SetValue(1, anIndices.FindIndex(V));
553     aResult = GetEngine()->AddSubShape(theShape, anArray);
554   }
555
556   //The GetPoint() doesn't change object so no new function is required.
557   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
558
559   //Make a Python command
560   TCollection_AsciiString anEntry, aDescr;
561   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
562   aDescr += anEntry + " = IBlocksOperations.GetPoint(";
563   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
564   aDescr += anEntry + ", ";
565   aDescr += TCollection_AsciiString(theX) + ", ";
566   aDescr += TCollection_AsciiString(theY) + ", ";
567   aDescr += TCollection_AsciiString(theZ) + ", ";
568   aDescr += TCollection_AsciiString(theEpsilon) + ")";
569
570   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
571   aNewDescr += aDescr;
572   aFunction->SetDescription(aNewDescr);
573
574   SetErrorCode(OK);
575   return aResult;
576 }
577
578 //=============================================================================
579 /*!
580  *  GetEdge
581  */
582 //=============================================================================
583 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
584                                                 (Handle(GEOM_Object) theShape,
585                                                  Handle(GEOM_Object) thePoint1,
586                                                  Handle(GEOM_Object) thePoint2)
587 {
588   SetErrorCode(KO);
589
590   //New Edge object
591   Handle(GEOM_Object) aResult;
592
593   // Arguments
594   if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
595
596   TopoDS_Shape aBlockOrComp = theShape->GetValue();
597   if (aBlockOrComp.IsNull()) {
598     SetErrorCode("Block or compound is null");
599     return NULL;
600   }
601   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
602       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
603       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
604     SetErrorCode("Shape is neither a block, nor a compound of blocks");
605     return NULL;
606   }
607
608   TopoDS_Shape anArg1 = thePoint1->GetValue();
609   TopoDS_Shape anArg2 = thePoint2->GetValue();
610   if (anArg1.IsNull() || anArg2.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     SetErrorCode("Element for edge identification is not a vertex");
617     return NULL;
618   }
619
620   //Compute the Edge value
621   try {
622     TopTools_IndexedDataMapOfShapeListOfShape MVE;
623     GEOMImpl_Block6Explorer::MapShapesAndAncestors
624       (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
625
626     TopoDS_Shape V1,V2;
627     Standard_Integer ish, ext = MVE.Extent();
628
629     if (MVE.Contains(anArg1)) {
630       V1 = anArg1;
631     } else {
632       for (ish = 1; ish <= ext; ish++) {
633         TopoDS_Shape aShi = MVE.FindKey(ish);
634         if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
635           V1 = aShi;
636           break;
637         }
638       }
639     }
640
641     if (MVE.Contains(anArg2)) {
642       V2 = anArg2;
643     } else {
644       for (ish = 1; ish <= ext; ish++) {
645         TopoDS_Shape aShi = MVE.FindKey(ish);
646         if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
647           V2 = aShi;
648           break;
649         }
650       }
651     }
652
653     if (V1.IsNull() || V2.IsNull()) {
654       SetErrorCode("The given vertex does not belong to the shape");
655       return NULL;
656     }
657
658     TopoDS_Shape anEdge;
659     Standard_Integer isFound =
660       GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
661     if (isFound == 0) {
662       SetErrorCode("The given vertices do not belong to one edge of the given shape");
663       return NULL;
664     } else if (isFound > 1) {
665       SetErrorCode("Multiple edges found by the given vertices of the shape");
666       return NULL;
667     } else {
668       TopTools_IndexedMapOfShape anIndices;
669       TopExp::MapShapes(aBlockOrComp, anIndices);
670       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
671       anArray->SetValue(1, anIndices.FindIndex(anEdge));
672       aResult = GetEngine()->AddSubShape(theShape, anArray);
673     }
674   } catch (Standard_Failure) {
675     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
676     SetErrorCode(aFail->GetMessageString());
677     return NULL;
678   }
679
680   //The GetEdge() doesn't change object so no new function is required.
681   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
682
683   //Make a Python command
684   TCollection_AsciiString anEntry, aDescr;
685   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
686   aDescr += anEntry + " = IBlocksOperations.GetEdge(";
687   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
688   aDescr += anEntry + ", ";
689   TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
690   aDescr += anEntry + ", ";
691   TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
692   aDescr += anEntry + ")";
693
694   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
695   aNewDescr += aDescr;
696   aFunction->SetDescription(aNewDescr);
697
698   SetErrorCode(OK);
699   return aResult;
700 }
701
702 //=============================================================================
703 /*!
704  *  GetEdgeNearPoint
705  */
706 //=============================================================================
707 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
708                                                 (Handle(GEOM_Object) theShape,
709                                                  Handle(GEOM_Object) thePoint)
710 {
711   SetErrorCode(KO);
712
713   //New object
714   Handle(GEOM_Object) aResult;
715
716   // Arguments
717   if (theShape.IsNull() || thePoint.IsNull()) return NULL;
718
719   TopoDS_Shape aBlockOrComp = theShape->GetValue();
720   if (aBlockOrComp.IsNull()) {
721     SetErrorCode("Block or compound is null");
722     return NULL;
723   }
724   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
725       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
726       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
727     SetErrorCode("Shape is neither a block, nor a compound of blocks");
728     return NULL;
729   }
730
731   TopoDS_Shape anArg = thePoint->GetValue();
732   if (anArg.IsNull()) {
733     SetErrorCode("Null shape is given as argument");
734     return NULL;
735   }
736   if (anArg.ShapeType() != TopAbs_VERTEX) {
737     SetErrorCode("Element for edge identification is not a vertex");
738     return NULL;
739   }
740
741   //Compute the Edge value
742   try {
743     TopoDS_Shape aShape;
744
745     TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
746
747     // 1. Explode blocks on edges
748     TopTools_MapOfShape mapShape;
749     Standard_Integer nbEdges = 0;
750     TopExp_Explorer exp (aBlockOrComp, TopAbs_EDGE);
751     for (; exp.More(); exp.Next()) {
752       if (mapShape.Add(exp.Current())) {
753         nbEdges++;
754       }
755     }
756
757     mapShape.Clear();
758     Standard_Integer ind = 1;
759     TopTools_Array1OfShape anEdges (1, nbEdges);
760     TColStd_Array1OfReal aDistances (1, nbEdges);
761     for (exp.Init(aBlockOrComp, TopAbs_EDGE); exp.More(); exp.Next()) {
762       if (mapShape.Add(exp.Current())) {
763         TopoDS_Shape anEdge = exp.Current();
764         anEdges(ind) = anEdge;
765
766         // 2. Classify the point relatively each edge
767         BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
768         if (!aDistTool.IsDone()) {
769           SetErrorCode("Can not find a distance from the given point to one of edges");
770           return NULL;
771         }
772         aDistances(ind) = aDistTool.Value();
773         ind++;
774       }
775     }
776
777     // 3. Define edge, having minimum distance to the point
778     Standard_Real nearest = RealLast(), nbFound = 0;
779     Standard_Real prec = Precision::Confusion();
780     for (ind = 1; ind <= nbEdges; ind++) {
781       if (Abs(aDistances(ind) - nearest) < prec) {
782         nbFound++;
783       } else if (aDistances(ind) < nearest) {
784         nearest = aDistances(ind);
785         aShape = anEdges(ind);
786         nbFound = 1;
787       } else {
788       }
789     }
790     if (nbFound > 1) {
791       SetErrorCode("Multiple edges near the given point are found");
792       return NULL;
793     } else if (nbFound == 0) {
794       SetErrorCode("There are no edges near the given point");
795       return NULL;
796     } else {
797       TopTools_IndexedMapOfShape anIndices;
798       TopExp::MapShapes(aBlockOrComp, anIndices);
799       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
800       anArray->SetValue(1, anIndices.FindIndex(aShape));
801       aResult = GetEngine()->AddSubShape(theShape, anArray);
802     }
803   }
804   catch (Standard_Failure) {
805     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
806     SetErrorCode(aFail->GetMessageString());
807     return NULL;
808   }
809
810   //The GetEdgeNearPoint() doesn't change object so no new function is required.
811   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
812
813   //Make a Python command
814   TCollection_AsciiString anEntry, aDescr;
815   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
816   aDescr += anEntry + " = IBlocksOperations.GetEdgeNearPoint(";
817   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
818   aDescr += anEntry + ", ";
819   TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
820   aDescr += anEntry + ")";
821
822   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
823   aNewDescr += aDescr;
824   aFunction->SetDescription(aNewDescr);
825
826   SetErrorCode(OK);
827   return aResult;
828 }
829
830 //=============================================================================
831 /*!
832  *  GetFaceByPoints
833  */
834 //=============================================================================
835 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
836                                                 (Handle(GEOM_Object) theShape,
837                                                  Handle(GEOM_Object) thePoint1,
838                                                  Handle(GEOM_Object) thePoint2,
839                                                  Handle(GEOM_Object) thePoint3,
840                                                  Handle(GEOM_Object) thePoint4)
841 {
842   SetErrorCode(KO);
843
844   //New object
845   Handle(GEOM_Object) aResult;
846
847   // Arguments
848   if (theShape.IsNull() ||
849       thePoint1.IsNull() || thePoint2.IsNull() ||
850       thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
851
852   TopoDS_Shape aBlockOrComp = theShape->GetValue();
853   if (aBlockOrComp.IsNull()) {
854     SetErrorCode("Block or compound is null");
855     return NULL;
856   }
857   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
858       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
859       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
860     SetErrorCode("Shape is neither a block, nor a compound of blocks");
861     return NULL;
862   }
863
864   TopoDS_Shape anArg1 = thePoint1->GetValue();
865   TopoDS_Shape anArg2 = thePoint2->GetValue();
866   TopoDS_Shape anArg3 = thePoint3->GetValue();
867   TopoDS_Shape anArg4 = thePoint4->GetValue();
868   if (anArg1.IsNull() || anArg2.IsNull() ||
869       anArg3.IsNull() || anArg4.IsNull()) {
870     SetErrorCode("Null shape is given as argument");
871     return NULL;
872   }
873   if (anArg1.ShapeType() != TopAbs_VERTEX ||
874       anArg2.ShapeType() != TopAbs_VERTEX ||
875       anArg3.ShapeType() != TopAbs_VERTEX ||
876       anArg4.ShapeType() != TopAbs_VERTEX) {
877     SetErrorCode("Element for face identification is not a vertex");
878     return NULL;
879   }
880
881   //Compute the Face value
882   try {
883     TopoDS_Shape aShape;
884
885     TopTools_IndexedDataMapOfShapeListOfShape MVF;
886     GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
887
888     TopoDS_Shape V1,V2,V3,V4;
889     Standard_Integer ish, ext = MVF.Extent();
890
891     if (MVF.Contains(anArg1)) {
892       V1 = anArg1;
893     } else {
894       for (ish = 1; ish <= ext; ish++) {
895         TopoDS_Shape aShi = MVF.FindKey(ish);
896         if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
897           V1 = aShi;
898           break;
899         }
900       }
901     }
902
903     if (MVF.Contains(anArg2)) {
904       V2 = anArg2;
905     } else {
906       for (ish = 1; ish <= ext; ish++) {
907         TopoDS_Shape aShi = MVF.FindKey(ish);
908         if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
909           V2 = aShi;
910           break;
911         }
912       }
913     }
914
915     if (MVF.Contains(anArg3)) {
916       V3 = anArg3;
917     } else {
918       for (ish = 1; ish <= ext; ish++) {
919         TopoDS_Shape aShi = MVF.FindKey(ish);
920         if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
921           V3 = aShi;
922           break;
923         }
924       }
925     }
926
927     if (MVF.Contains(anArg4)) {
928       V4 = anArg4;
929     } else {
930       for (ish = 1; ish <= ext; ish++) {
931         TopoDS_Shape aShi = MVF.FindKey(ish);
932         if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
933           V4 = aShi;
934           break;
935         }
936       }
937     }
938
939     if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
940       SetErrorCode("The given vertex does not belong to the shape");
941       return NULL;
942     }
943
944     Standard_Integer isFound =
945       GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
946     if (isFound == 0) {
947       SetErrorCode("The given vertices do not belong to one face of the given shape");
948       return NULL;
949     } else if (isFound > 1) {
950       SetErrorCode("The given vertices belong to several faces of the given shape");
951       return NULL;
952     } else {
953       TopTools_IndexedMapOfShape anIndices;
954       TopExp::MapShapes(aBlockOrComp, anIndices);
955       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
956       anArray->SetValue(1, anIndices.FindIndex(aShape));
957       aResult = GetEngine()->AddSubShape(theShape, anArray);
958     }
959   }
960   catch (Standard_Failure) {
961     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
962     SetErrorCode(aFail->GetMessageString());
963     return NULL;
964   }
965
966   //The GetFaceByPoints() doesn't change object so no new function is required.
967   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
968
969   //Make a Python command
970   TCollection_AsciiString anEntry, aDescr;
971   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
972   aDescr += anEntry + " = IBlocksOperations.GetFaceByPoints(";
973   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
974   aDescr += anEntry + ", ";
975   TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
976   aDescr += anEntry + ", ";
977   TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
978   aDescr += anEntry + ", ";
979   TDF_Tool::Entry(thePoint3->GetEntry(), anEntry);
980   aDescr += anEntry + ", ";
981   TDF_Tool::Entry(thePoint4->GetEntry(), anEntry);
982   aDescr += anEntry + ")";
983
984   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
985   aNewDescr += aDescr;
986   aFunction->SetDescription(aNewDescr);
987
988   SetErrorCode(OK);
989   return aResult;
990 }
991
992 //=============================================================================
993 /*!
994  *  GetFaceByEdges
995  */
996 //=============================================================================
997 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
998                                                 (Handle(GEOM_Object) theShape,
999                                                  Handle(GEOM_Object) theEdge1,
1000                                                  Handle(GEOM_Object) theEdge2)
1001 {
1002   SetErrorCode(KO);
1003
1004   //New object
1005   Handle(GEOM_Object) aResult;
1006
1007   // Arguments
1008   if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
1009
1010   TopoDS_Shape aBlockOrComp = theShape->GetValue();
1011   if (aBlockOrComp.IsNull()) {
1012     SetErrorCode("Block or compound is null");
1013     return NULL;
1014   }
1015   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
1016       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
1017       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
1018     SetErrorCode("Shape is neither a block, nor a compound of blocks");
1019     return NULL;
1020   }
1021
1022   TopoDS_Shape anArg1 = theEdge1->GetValue();
1023   TopoDS_Shape anArg2 = theEdge2->GetValue();
1024   if (anArg1.IsNull() || anArg2.IsNull()) {
1025     SetErrorCode("Null shape is given as argument");
1026     return NULL;
1027   }
1028   if (anArg1.ShapeType() != TopAbs_EDGE ||
1029       anArg2.ShapeType() != TopAbs_EDGE) {
1030     SetErrorCode("Element for face identification is not an edge");
1031     return NULL;
1032   }
1033
1034   //Compute the Face value
1035   try {
1036     TopoDS_Shape aShape;
1037
1038     TopTools_IndexedDataMapOfShapeListOfShape MEF;
1039     GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
1040
1041     TopoDS_Shape E1,E2;
1042     Standard_Integer ish, ext = MEF.Extent();
1043
1044     if (MEF.Contains(anArg1)) {
1045       E1 = anArg1;
1046     } else {
1047       for (ish = 1; ish <= ext; ish++) {
1048         TopoDS_Shape aShi = MEF.FindKey(ish);
1049         if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
1050           E1 = aShi;
1051         }
1052       }
1053     }
1054
1055     if (MEF.Contains(anArg2)) {
1056       E2 = anArg2;
1057     } else {
1058       for (ish = 1; ish <= ext; ish++) {
1059         TopoDS_Shape aShi = MEF.FindKey(ish);
1060         if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
1061           E2 = aShi;
1062         }
1063       }
1064     }
1065
1066     if (E1.IsNull() || E2.IsNull()) {
1067       SetErrorCode("The given edge does not belong to the shape");
1068       return NULL;
1069     }
1070
1071     const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
1072     const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
1073
1074     Standard_Integer isFound = 0;
1075     TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
1076     for (; anIterF1.More(); anIterF1.Next()) {
1077
1078       TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
1079       for (; anIterF2.More(); anIterF2.Next()) {
1080
1081         if (anIterF1.Value().IsSame(anIterF2.Value())) {
1082           isFound++;
1083
1084           // Store the face, defined by two edges
1085           aShape = anIterF1.Value();
1086         }
1087       }
1088     }
1089     if (isFound == 0) {
1090       SetErrorCode("The given edges do not belong to one face of the given shape");
1091       return NULL;
1092     } else if (isFound > 1) {
1093       SetErrorCode("The given edges belong to several faces of the given shape");
1094       return NULL;
1095     } else {
1096       TopTools_IndexedMapOfShape anIndices;
1097       TopExp::MapShapes(aBlockOrComp, anIndices);
1098       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1099       anArray->SetValue(1, anIndices.FindIndex(aShape));
1100       aResult = GetEngine()->AddSubShape(theShape, anArray);
1101     }
1102   }
1103   catch (Standard_Failure) {
1104     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1105     SetErrorCode(aFail->GetMessageString());
1106     return NULL;
1107   }
1108
1109   //The GetFaceByEdges() doesn't change object so no new function is required.
1110   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1111
1112   //Make a Python command
1113   TCollection_AsciiString anEntry, aDescr;
1114   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1115   aDescr += anEntry + " = IBlocksOperations.GetFaceByEdges(";
1116   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
1117   aDescr += anEntry + ", ";
1118   TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
1119   aDescr += anEntry + ", ";
1120   TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
1121   aDescr += anEntry + ")";
1122
1123   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1124   aNewDescr += aDescr;
1125   aFunction->SetDescription(aNewDescr);
1126
1127   SetErrorCode(OK);
1128   return aResult;
1129 }
1130
1131 //=============================================================================
1132 /*!
1133  *  GetOppositeFace
1134  */
1135 //=============================================================================
1136 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
1137                                                 (Handle(GEOM_Object) theShape,
1138                                                  Handle(GEOM_Object) theFace)
1139 {
1140   SetErrorCode(KO);
1141
1142   //New object
1143   Handle(GEOM_Object) aResult;
1144
1145   // Arguments
1146   if (theShape.IsNull() || theFace.IsNull()) return NULL;
1147
1148   TopoDS_Shape aBlockOrComp = theShape->GetValue();
1149   if (aBlockOrComp.IsNull()) {
1150     SetErrorCode("Block is null");
1151     return NULL;
1152   }
1153   if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
1154     SetErrorCode("Shape is not a block");
1155     return NULL;
1156   }
1157
1158   TopoDS_Shape anArg = theFace->GetValue();
1159   if (anArg.IsNull()) {
1160     SetErrorCode("Null shape is given as argument");
1161     return NULL;
1162   }
1163   if (anArg.ShapeType() != TopAbs_FACE) {
1164     SetErrorCode("Element for face identification is not a face");
1165     return NULL;
1166   }
1167
1168   //Compute the Face value
1169   try {
1170     TopoDS_Shape aShape;
1171
1172     GEOMImpl_Block6Explorer aBlockTool;
1173     aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1174     aShape = aBlockTool.GetFace(2);
1175
1176     TopTools_IndexedMapOfShape anIndices;
1177     TopExp::MapShapes(aBlockOrComp, anIndices);
1178     Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1179     anArray->SetValue(1, anIndices.FindIndex(aShape));
1180     aResult = GetEngine()->AddSubShape(theShape, anArray);
1181   }
1182   catch (Standard_Failure) {
1183     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1184     SetErrorCode(aFail->GetMessageString());
1185     return NULL;
1186   }
1187
1188   //The GetOppositeFace() doesn't change object so no new function is required.
1189   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1190
1191   //Make a Python command
1192   TCollection_AsciiString anEntry, aDescr;
1193   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1194   aDescr += anEntry + " = IBlocksOperations.GetOppositeFace(";
1195   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
1196   aDescr += anEntry + ", ";
1197   TDF_Tool::Entry(theFace->GetEntry(), anEntry);
1198   aDescr += anEntry + ")";
1199
1200   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1201   aNewDescr += aDescr;
1202   aFunction->SetDescription(aNewDescr);
1203
1204   SetErrorCode(OK);
1205   return aResult;
1206 }
1207
1208 //=============================================================================
1209 /*!
1210  *  GetFaceNearPoint
1211  */
1212 //=============================================================================
1213 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1214                                                 (Handle(GEOM_Object) theShape,
1215                                                  Handle(GEOM_Object) thePoint)
1216 {
1217   SetErrorCode(KO);
1218
1219   //New object
1220   Handle(GEOM_Object) aResult;
1221
1222   // Arguments
1223   if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1224
1225   TopoDS_Shape aBlockOrComp = theShape->GetValue();
1226   if (aBlockOrComp.IsNull()) {
1227     SetErrorCode("Block or compound is null");
1228     return NULL;
1229   }
1230   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
1231       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
1232       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
1233     SetErrorCode("Shape is neither a block, nor a compound of blocks");
1234     return NULL;
1235   }
1236
1237   TopoDS_Shape anArg = thePoint->GetValue();
1238   if (anArg.IsNull()) {
1239     SetErrorCode("Null shape is given as argument");
1240     return NULL;
1241   }
1242   if (anArg.ShapeType() != TopAbs_VERTEX) {
1243     SetErrorCode("Element for face identification is not a vertex");
1244     return NULL;
1245   }
1246
1247   //Compute the Face value
1248   try {
1249     TopoDS_Shape aShape;
1250
1251     TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1252     gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1253
1254     // 1. Explode blocks on faces
1255     TopTools_MapOfShape mapShape;
1256     Standard_Integer nbFaces = 0;
1257     TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1258     for (; exp.More(); exp.Next()) {
1259       if (mapShape.Add(exp.Current())) {
1260         nbFaces++;
1261       }
1262     }
1263
1264     mapShape.Clear();
1265     Standard_Integer ind = 1;
1266     TopTools_Array1OfShape aFaces (1, nbFaces);
1267     TColStd_Array1OfInteger aDistances (1, nbFaces);
1268     for (exp.Init(aBlockOrComp, TopAbs_FACE); exp.More(); exp.Next()) {
1269       if (mapShape.Add(exp.Current())) {
1270         TopoDS_Shape aFace = exp.Current();
1271         aFaces(ind) = aFace;
1272
1273         // 2. Classify the point relatively each face
1274         BRepClass_FaceClassifier FC (TopoDS::Face(aFace), aPnt, Precision::Confusion());
1275         if (FC.State() == TopAbs_IN) {
1276           aDistances(ind) = -1;
1277         } else if (FC.State() == TopAbs_ON) {
1278           aDistances(ind) = 0;
1279         } else { // OUT
1280           aDistances(ind) = 1;
1281         }
1282         ind++;
1283       }
1284     }
1285
1286     // 3. Define face, containing the point or having minimum distance to it
1287     Standard_Integer nearest = 2, nbFound = 0;
1288     for (ind = 1; ind <= nbFaces; ind++) {
1289       if (aDistances(ind) < nearest) {
1290         nearest = aDistances(ind);
1291         aShape = aFaces(ind);
1292         nbFound = 1;
1293       } else if (aDistances(ind) == nearest) {
1294         nbFound++;
1295       } else {
1296       }
1297     }
1298     if (nbFound > 1) {
1299       if (nearest == 0) {
1300         // The point is on boundary of some faces and there are
1301         // no faces, having the point inside
1302         SetErrorCode("Multiple faces near the given point are found");
1303         return NULL;
1304
1305       } else if (nearest == 1) {
1306         // The point is outside some faces and there are
1307         // no faces, having the point inside or on boundary.
1308         // We will get a nearest face
1309         Standard_Real minDist = RealLast();
1310         for (ind = 1; ind <= nbFaces; ind++) {
1311           if (aDistances(ind) == 1) {
1312             BRepExtrema_DistShapeShape aDistTool (aVert, aFaces(ind));
1313             if (!aDistTool.IsDone()) {
1314               SetErrorCode("Can not find a distance from the given point to one of faces");
1315               return NULL;
1316             }
1317             Standard_Real aDist = aDistTool.Value();
1318             if (aDist < minDist) {
1319               minDist = aDist;
1320               aShape = aFaces(ind);
1321             }
1322           }
1323         }
1324       } else { // nearest == -1
1325         // The point is inside some faces.
1326         // We will get a face with nearest center
1327         Standard_Real minDist = RealLast();
1328         for (ind = 1; ind <= nbFaces; ind++) {
1329           if (aDistances(ind) == -1) {
1330             GProp_GProps aSystem;
1331             BRepGProp::SurfaceProperties(aFaces(ind), aSystem);
1332             gp_Pnt aCenterMass = aSystem.CentreOfMass();
1333
1334             Standard_Real aDist = aCenterMass.Distance(aPnt);
1335             if (aDist < minDist) {
1336               minDist = aDist;
1337               aShape = aFaces(ind);
1338             }
1339           }
1340         }
1341       }
1342     }
1343
1344     if (nbFound == 0) {
1345       SetErrorCode("There are no faces near the given point");
1346       return NULL;
1347     } else {
1348       TopTools_IndexedMapOfShape anIndices;
1349       TopExp::MapShapes(aBlockOrComp, anIndices);
1350       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1351       anArray->SetValue(1, anIndices.FindIndex(aShape));
1352       aResult = GetEngine()->AddSubShape(theShape, anArray);
1353     }
1354   }
1355   catch (Standard_Failure) {
1356     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1357     SetErrorCode(aFail->GetMessageString());
1358     return NULL;
1359   }
1360
1361   //The GetFaceNearPoint() doesn't change object so no new function is required.
1362   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1363
1364   //Make a Python command
1365   TCollection_AsciiString anEntry, aDescr;
1366   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1367   aDescr += anEntry + " = IBlocksOperations.GetFaceNearPoint(";
1368   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
1369   aDescr += anEntry + ", ";
1370   TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
1371   aDescr += anEntry + ")";
1372
1373   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1374   aNewDescr += aDescr;
1375   aFunction->SetDescription(aNewDescr);
1376
1377   SetErrorCode(OK);
1378   return aResult;
1379 }
1380
1381 //=============================================================================
1382 /*!
1383  *  GetFaceByNormale
1384  */
1385 //=============================================================================
1386 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1387                                                 (Handle(GEOM_Object) theShape,
1388                                                  Handle(GEOM_Object) theVector)
1389 {
1390   SetErrorCode(KO);
1391
1392   //New object
1393   Handle(GEOM_Object) aResult;
1394
1395   // Arguments
1396   if (theShape.IsNull() || theVector.IsNull()) return NULL;
1397
1398   TopoDS_Shape aBlockOrComp = theShape->GetValue();
1399   if (aBlockOrComp.IsNull()) {
1400     SetErrorCode("Block or compound is null");
1401     return NULL;
1402   }
1403   if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
1404       aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
1405       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
1406     SetErrorCode("Shape is neither a block, nor a compound of blocks");
1407     return NULL;
1408   }
1409
1410   TopoDS_Shape anArg = theVector->GetValue();
1411   if (anArg.IsNull()) {
1412     SetErrorCode("Null shape is given as argument");
1413     return NULL;
1414   }
1415   if (anArg.ShapeType() != TopAbs_EDGE) {
1416     SetErrorCode("Element for normale identification is not an edge");
1417     return NULL;
1418   }
1419
1420   //Compute the Face value
1421   try {
1422     TopoDS_Shape aShape;
1423
1424     TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1425     TopoDS_Vertex V1, V2;
1426     TopExp::Vertices(anEdge, V1, V2, Standard_True);
1427     gp_Pnt P1 = BRep_Tool::Pnt(V1);
1428     gp_Pnt P2 = BRep_Tool::Pnt(V2);
1429     gp_Vec aVec (P1, P2);
1430     if (aVec.Magnitude() < Precision::Confusion()) {
1431       SetErrorCode("Vector with null magnitude is given");
1432       return NULL;
1433     }
1434
1435     Standard_Real minAngle = RealLast();
1436     TopTools_MapOfShape mapShape;
1437     TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1438     for (; exp.More(); exp.Next()) {
1439       if (mapShape.Add(exp.Current())) {
1440         TopoDS_Face aFace = TopoDS::Face(exp.Current());
1441         BRepAdaptor_Surface SF (aFace);
1442
1443         Standard_Real u, v, x;
1444
1445         // find a point on the surface to get normal direction in
1446         u = SF.FirstUParameter();
1447         x = SF.LastUParameter();
1448         if (Precision::IsInfinite(u)) {
1449           u =  (Precision::IsInfinite(x)) ? 0. : x;
1450         } else if (!Precision::IsInfinite(x)) {
1451           u = (u+x) / 2.;
1452         }
1453
1454         v = SF.FirstVParameter();
1455         x = SF.LastVParameter();
1456         if (Precision::IsInfinite(v)) {
1457           v =  (Precision::IsInfinite(x)) ? 0. : x;
1458         } else if (!Precision::IsInfinite(x)) {
1459           v = (v+x) / 2.;
1460         }
1461
1462         // compute the normal direction
1463         gp_Vec Vec1,Vec2;
1464         SF.D1(u,v,P1,Vec1,Vec2);
1465         gp_Vec V = Vec1.Crossed(Vec2);
1466         x = V.Magnitude();
1467         if (V.Magnitude() < Precision::Confusion()) {
1468           SetErrorCode("Normal vector of a face has null magnitude");
1469           return NULL;
1470         }
1471
1472         // consider the face orientation
1473         if (aFace.Orientation() == TopAbs_REVERSED ||
1474             aFace.Orientation() == TopAbs_INTERNAL) {
1475           V = - V;
1476         }
1477
1478         // compute the angle and compare with the minimal one
1479         Standard_Real anAngle = aVec.Angle(V);
1480         if (anAngle < minAngle) {
1481           minAngle = anAngle;
1482           aShape = aFace;
1483         }
1484       }
1485     }
1486
1487     if (aShape.IsNull()) {
1488       SetErrorCode("Failed to find a face by the given normale");
1489       return NULL;
1490     } else {
1491       TopTools_IndexedMapOfShape anIndices;
1492       TopExp::MapShapes(aBlockOrComp, anIndices);
1493       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1494       anArray->SetValue(1, anIndices.FindIndex(aShape));
1495       aResult = GetEngine()->AddSubShape(theShape, anArray);
1496     }
1497   }
1498   catch (Standard_Failure) {
1499     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1500     SetErrorCode(aFail->GetMessageString());
1501     return NULL;
1502   }
1503
1504   //The GetFaceByNormale() doesn't change object so no new function is required.
1505   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1506
1507   //Make a Python command
1508   TCollection_AsciiString anEntry, aDescr;
1509   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
1510   aDescr += anEntry + " = IBlocksOperations.GetFaceByNormale(";
1511   TDF_Tool::Entry(theShape->GetEntry(), anEntry);
1512   aDescr += anEntry + ", ";
1513   TDF_Tool::Entry(theVector->GetEntry(), anEntry);
1514   aDescr += anEntry + ")";
1515
1516   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
1517   aNewDescr += aDescr;
1518   aFunction->SetDescription(aNewDescr);
1519
1520   SetErrorCode(OK);
1521   return aResult;
1522 }
1523
1524 //=============================================================================
1525 /*!
1526  *  IsCompoundOfBlocks
1527  */
1528 //=============================================================================
1529 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1530                                                 (Handle(GEOM_Object)    theCompound,
1531                                                  const Standard_Integer theMinNbFaces,
1532                                                  const Standard_Integer theMaxNbFaces,
1533                                                  Standard_Integer&      theNbBlocks)
1534 {
1535   SetErrorCode(KO);
1536   Standard_Boolean isCompOfBlocks = Standard_False;
1537   theNbBlocks = 0;
1538
1539   if (theCompound.IsNull()) return isCompOfBlocks;
1540   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1541
1542   //Check
1543   isCompOfBlocks = Standard_True;
1544   try {
1545     TopTools_MapOfShape mapShape;
1546     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1547     for (; exp.More(); exp.Next()) {
1548       if (mapShape.Add(exp.Current())) {
1549         TopoDS_Shape aSolid = exp.Current();
1550
1551         TopTools_MapOfShape mapFaces;
1552         TopExp_Explorer expF (aSolid, TopAbs_FACE);
1553         Standard_Integer nbFaces = 0;
1554         for (; expF.More(); expF.Next()) {
1555           if (mapFaces.Add(expF.Current())) {
1556             nbFaces++;
1557             if (nbFaces > theMaxNbFaces) {
1558               isCompOfBlocks = Standard_False;
1559               break;
1560             }
1561           }
1562         }
1563         if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1564           isCompOfBlocks = Standard_False;
1565         } else {
1566           theNbBlocks++;
1567         }
1568       }
1569     }
1570   }
1571   catch (Standard_Failure) {
1572     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1573     SetErrorCode(aFail->GetMessageString());
1574     return isCompOfBlocks;
1575   }
1576
1577   SetErrorCode(OK);
1578   return isCompOfBlocks;
1579 }
1580
1581 //=============================================================================
1582 /*!
1583  *  Set of functions, used by CheckCompoundOfBlocks() method
1584  */
1585 //=============================================================================
1586 void AddBlocksFrom (const TopoDS_Shape&  theShape,
1587                     TopTools_ListOfShape& BLO,
1588                     TopTools_ListOfShape& NOT)
1589 {
1590   TopAbs_ShapeEnum aType = theShape.ShapeType();
1591   switch (aType) {
1592   case TopAbs_COMPOUND:
1593   case TopAbs_COMPSOLID:
1594     {
1595       TopoDS_Iterator It (theShape);
1596       for (; It.More(); It.Next()) {
1597         AddBlocksFrom(It.Value(), BLO, NOT);
1598       }
1599     }
1600     break;
1601   case TopAbs_SOLID:
1602     {
1603       TopTools_MapOfShape mapFaces;
1604       TopExp_Explorer expF (theShape, TopAbs_FACE);
1605       Standard_Integer nbFaces = 0;
1606       Standard_Integer nbEdges = 0;
1607       for (; expF.More(); expF.Next()) {
1608         if (mapFaces.Add(expF.Current())) {
1609           nbFaces++;
1610           if (nbFaces > 6) break;
1611
1612           // Check number of edges in the face
1613           TopoDS_Shape aF = expF.Current();
1614           TopExp_Explorer expE (aF, TopAbs_EDGE);
1615           nbEdges = 0;
1616           for (; expE.More(); expE.Next()) {
1617             nbEdges++;
1618             if (nbEdges > 4) break;
1619           }
1620           if (nbEdges != 4) break;
1621         }
1622       }
1623       if (nbFaces == 6 && nbEdges == 4) {
1624         BLO.Append(theShape);
1625       } else {
1626         NOT.Append(theShape);
1627       }
1628     }
1629     break;
1630   default:
1631     NOT.Append(theShape);
1632   }
1633 }
1634
1635 #define REL_NOT_CONNECTED 0
1636 #define REL_OK            1
1637 #define REL_NOT_GLUED     2
1638 #define REL_COLLISION_VV  3
1639 #define REL_COLLISION_FF  4
1640 #define REL_COLLISION_EE  5
1641 #define REL_UNKNOWN       6
1642
1643 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1644                                  const TopoDS_Shape& theBlock2)
1645 {
1646   // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1647   Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1648   Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1649   Bnd_Box B1, B2;
1650   BRepBndLib::Add(theBlock1, B1);
1651   BRepBndLib::Add(theBlock2, B2);
1652 //  BRepBndLib::AddClose(theBlock1, B1);
1653 //  BRepBndLib::AddClose(theBlock2, B2);
1654   B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1655   B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1656   if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1657       Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1658       Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1659 //  Standard_Real prec = Precision::Confusion();
1660 //  if (prec < Xmin1 - Xmax2 || prec < Xmin2 - Xmax1 ||
1661 //      prec < Ymin1 - Ymax2 || prec < Ymin2 - Ymax1 ||
1662 //      prec < Zmin1 - Zmax2 || prec < Zmin2 - Zmax1) {
1663     return REL_NOT_CONNECTED;
1664   }
1665   // to be done
1666
1667   BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1668   if (!dst.IsDone()) {
1669     return REL_UNKNOWN;
1670   }
1671
1672   if (dst.Value() > Precision::Confusion()) {
1673     return REL_NOT_CONNECTED;
1674   }
1675
1676   if (dst.InnerSolution()) {
1677     return REL_COLLISION_VV;
1678   }
1679
1680   Standard_Integer nbSol = dst.NbSolution();
1681   Standard_Integer relation = REL_OK;
1682   Standard_Integer nbVerts = 0;
1683   Standard_Integer nbEdges = 0;
1684   Standard_Integer sol = 1;
1685   for (; sol <= nbSol; sol++) {
1686     BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1687     BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1688     if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1689       nbVerts++;
1690     } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1691       return REL_COLLISION_FF;
1692     } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1693       nbEdges++;
1694     } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1695                (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1696       relation = REL_COLLISION_EE;
1697     } else {
1698     }
1699   }
1700
1701   if (relation != REL_OK) {
1702     return relation;
1703   }
1704
1705   TColStd_Array1OfInteger vertSol (1, nbVerts);
1706   TopTools_Array1OfShape V1 (1, nbVerts);
1707   TopTools_Array1OfShape V2 (1, nbVerts);
1708   Standard_Integer ivs = 0;
1709   for (sol = 1; sol <= nbSol; sol++) {
1710     if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1711         dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1712       TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1713       // Check, that this vertex is far enough from other solution vertices.
1714       Standard_Integer ii = 1;
1715       for (; ii <= ivs; ii++) {
1716         if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1717           continue;
1718         }
1719       }
1720       ivs++;
1721       vertSol(ivs) = sol;
1722       V1(ivs) = Vcur;
1723       V2(ivs) = dst.SupportOnShape2(sol);
1724     }
1725   }
1726
1727   // As we deal only with quadrangles,
1728   // 2, 3 or 4 vertex solutions can be found.
1729   if (ivs <= 1) {
1730     if (nbEdges > 0) {
1731       return REL_COLLISION_FF;
1732     }
1733     return REL_NOT_CONNECTED;
1734   }
1735   if (ivs > 4) {
1736     return REL_UNKNOWN;
1737   }
1738
1739   // Check sharing of coincident entities.
1740   if (ivs == 2 || ivs == 3) {
1741     // Map vertices and edges of the blocks
1742     TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1743     GEOMImpl_Block6Explorer::MapShapesAndAncestors
1744       (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1745     GEOMImpl_Block6Explorer::MapShapesAndAncestors
1746       (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1747
1748     if (ivs == 2) {
1749       // Find common edge
1750       TopoDS_Shape anEdge1, anEdge2;
1751       GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1752       if (anEdge1.IsNull()) return REL_UNKNOWN;
1753
1754       GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1755       if (anEdge2.IsNull()) return REL_UNKNOWN;
1756
1757       if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1758
1759     } else { // ivs == 3
1760       // Find common edges
1761       Standard_Integer e1_v1 = 1;
1762       Standard_Integer e1_v2 = 2;
1763       Standard_Integer e2_v1 = 3;
1764       Standard_Integer e2_v2 = 1;
1765
1766       TopoDS_Shape anEdge11, anEdge12;
1767       GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1768       if (anEdge11.IsNull()) {
1769         e1_v2 = 3;
1770         e2_v1 = 2;
1771         GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1772         if (anEdge11.IsNull()) return REL_UNKNOWN;
1773       }
1774       GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1775       if (anEdge12.IsNull()) {
1776         e2_v2 = 5 - e2_v1;
1777         GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1778         if (anEdge12.IsNull()) return REL_UNKNOWN;
1779       }
1780
1781       TopoDS_Shape anEdge21, anEdge22;
1782       GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
1783       if (anEdge21.IsNull()) return REL_UNKNOWN;
1784       GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
1785       if (anEdge22.IsNull()) return REL_UNKNOWN;
1786
1787       // Check of edges coincidence (with some precision) have to be done here
1788       // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
1789       // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
1790
1791       // Check of edges sharing
1792       if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
1793       if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
1794     }
1795   }
1796
1797   if (ivs == 4) {
1798     // Map vertices and faces of the blocks
1799     TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
1800     GEOMImpl_Block6Explorer::MapShapesAndAncestors
1801       (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
1802     GEOMImpl_Block6Explorer::MapShapesAndAncestors
1803       (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
1804
1805     TopoDS_Shape aFace1, aFace2;
1806     GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
1807     if (aFace1.IsNull()) return REL_UNKNOWN;
1808     GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
1809     if (aFace2.IsNull()) return REL_UNKNOWN;
1810
1811     // Check of faces coincidence (with some precision) have to be done here
1812     // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
1813
1814     // Check of faces sharing
1815     if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
1816   }
1817
1818   return REL_OK;
1819 }
1820
1821 void FindConnected (const Standard_Integer         theBlockIndex,
1822                     const TColStd_Array2OfInteger& theRelations,
1823                     TColStd_MapOfInteger&          theProcessedMap,
1824                     TColStd_MapOfInteger&          theConnectedMap)
1825 {
1826   theConnectedMap.Add(theBlockIndex);
1827   theProcessedMap.Add(theBlockIndex);
1828
1829   Standard_Integer nbBlocks = theRelations.ColLength();
1830   Standard_Integer col = 1;
1831   for (; col <= nbBlocks; col++) {
1832     if (theRelations(theBlockIndex, col) == REL_OK ||
1833         theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
1834       if (!theProcessedMap.Contains(col)) {
1835         FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
1836       }
1837     }
1838   }
1839 }
1840
1841 Standard_Boolean HasAnyConnection (const Standard_Integer         theBlockIndex,
1842                                    const TColStd_MapOfInteger&    theWith,
1843                                    const TColStd_Array2OfInteger& theRelations,
1844                                    TColStd_MapOfInteger&          theProcessedMap)
1845 {
1846   theProcessedMap.Add(theBlockIndex);
1847
1848   Standard_Integer nbBlocks = theRelations.ColLength();
1849   Standard_Integer col = 1;
1850   for (; col <= nbBlocks; col++) {
1851     if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
1852       if (!theProcessedMap.Contains(col)) {
1853         if (theWith.Contains(col))
1854           return Standard_True;
1855         if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
1856           return Standard_True;
1857       }
1858     }
1859   }
1860
1861   return Standard_False;
1862 }
1863
1864 //=============================================================================
1865 /*!
1866  *  CheckCompoundOfBlocks
1867  */
1868 //=============================================================================
1869 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
1870                                                 (Handle(GEOM_Object) theCompound,
1871                                                  list<BCError>&      theErrors)
1872 {
1873   SetErrorCode(KO);
1874
1875   if (theCompound.IsNull()) return Standard_False;
1876   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1877
1878   Standard_Boolean isCompOfBlocks = Standard_True;
1879
1880   // Map sub-shapes and their indices
1881   TopTools_IndexedMapOfShape anIndices;
1882   TopExp::MapShapes(aBlockOrComp, anIndices);
1883
1884   // 1. Report non-blocks
1885   TopTools_ListOfShape NOT; // Not blocks
1886   TopTools_ListOfShape BLO; // All blocks from the given compound
1887   AddBlocksFrom(aBlockOrComp, BLO, NOT);
1888
1889   if (NOT.Extent() > 0) {
1890     isCompOfBlocks = Standard_False;
1891     BCError anErr;
1892     anErr.error = NOT_BLOCK;
1893     TopTools_ListIteratorOfListOfShape NOTit (NOT);
1894     for (; NOTit.More(); NOTit.Next()) {
1895       anErr.incriminated.push_back(anIndices.FindIndex(NOTit.Value()));
1896     }
1897     theErrors.push_back(anErr);
1898   }
1899
1900   Standard_Integer nbBlocks = BLO.Extent();
1901   if (nbBlocks == 0) {
1902     isCompOfBlocks = Standard_False;
1903     SetErrorCode(OK);
1904     return isCompOfBlocks;
1905   }
1906   if (nbBlocks == 1) {
1907     SetErrorCode(OK);
1908     return isCompOfBlocks;
1909   }
1910
1911   // Convert list of blocks into array for easy and fast access
1912   Standard_Integer ibl = 1;
1913   TopTools_Array1OfShape aBlocks (1, nbBlocks);
1914   TopTools_ListIteratorOfListOfShape BLOit (BLO);
1915   for (; BLOit.More(); BLOit.Next(), ibl++) {
1916     aBlocks.SetValue(ibl, BLOit.Value());
1917   }
1918
1919   // 2. Find relations between all blocks,
1920   //    report connection errors (NOT_GLUED and INVALID_CONNECTION)
1921   TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
1922   aRelations.Init(REL_NOT_CONNECTED);
1923
1924   Standard_Integer row = 1;
1925   for (row = 1; row <= nbBlocks; row++) {
1926     TopoDS_Shape aBlock = aBlocks.Value(row);
1927
1928     Standard_Integer col = row + 1;
1929     for (; col <= nbBlocks; col++) {
1930       Standard_Integer aRel = BlocksRelation(aBlock, aBlocks.Value(col));
1931       if (aRel != REL_NOT_CONNECTED) {
1932         aRelations.SetValue(row, col, aRel);
1933         aRelations.SetValue(col, row, aRel);
1934         if (aRel == REL_NOT_GLUED) {
1935           // report connection error
1936           isCompOfBlocks = Standard_False;
1937           BCError anErr;
1938           anErr.error = NOT_GLUED;
1939           anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
1940           anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
1941           theErrors.push_back(anErr);
1942         } else if (aRel == REL_COLLISION_VV ||
1943                    aRel == REL_COLLISION_FF ||
1944                    aRel == REL_COLLISION_EE ||
1945                    aRel == REL_UNKNOWN) {
1946           // report connection error
1947           isCompOfBlocks = Standard_False;
1948           BCError anErr;
1949           anErr.error = INVALID_CONNECTION;
1950           anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
1951           anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
1952           theErrors.push_back(anErr);
1953         } else {
1954         }
1955       }
1956     }
1957   }
1958
1959   // 3. Find largest set of connected (good connection or not glued) blocks
1960   TColStd_MapOfInteger aProcessedMap;
1961   TColStd_MapOfInteger aLargestSet;
1962   TColStd_MapOfInteger aCurrentSet;
1963   for (ibl = 1; ibl <= nbBlocks; ibl++) {
1964     if (!aProcessedMap.Contains(ibl)) {
1965       FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
1966       if (aCurrentSet.Extent() > aLargestSet.Extent()) {
1967         aLargestSet = aCurrentSet;
1968       }
1969     }
1970   }
1971
1972   // 4. Report all blocks, isolated from <aLargestSet>
1973   BCError anErr;
1974   anErr.error = NOT_CONNECTED;
1975   Standard_Boolean hasIsolated = Standard_False;
1976   for (ibl = 1; ibl <= nbBlocks; ibl++) {
1977     if (!aLargestSet.Contains(ibl)) {
1978       aProcessedMap.Clear();
1979       if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
1980         // report connection absence
1981         hasIsolated = Standard_True;
1982         anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl)));
1983       }
1984     }
1985   }
1986   if (hasIsolated) {
1987     isCompOfBlocks = Standard_False;
1988     theErrors.push_back(anErr);
1989   }
1990
1991   SetErrorCode(OK);
1992   return isCompOfBlocks;
1993 }
1994
1995 //=============================================================================
1996 /*!
1997  *  PrintBCErrors
1998  */
1999 //=============================================================================
2000 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2001                                                 (Handle(GEOM_Object)  theCompound,
2002                                                  const list<BCError>& theErrors)
2003 {
2004   TCollection_AsciiString aDescr;
2005
2006   list<BCError>::const_iterator errIt = theErrors.begin();
2007   int i = 0;
2008   for (; errIt != theErrors.end(); i++, errIt++) {
2009     BCError errStruct = *errIt;
2010
2011     switch (errStruct.error) {
2012     case NOT_BLOCK:
2013       aDescr += "\nNot a Blocks: ";
2014       break;
2015     case INVALID_CONNECTION:
2016       aDescr += "\nInvalid connection between two blocks: ";
2017       break;
2018     case NOT_CONNECTED:
2019       aDescr += "\nBlocks, not connected with main body: ";
2020       break;
2021     case NOT_GLUED:
2022       aDescr += "\nNot glued blocks: ";
2023       break;
2024     default:
2025       break;
2026     }
2027
2028     list<int> sshList = errStruct.incriminated;
2029     list<int>::iterator sshIt = sshList.begin();
2030     int jj = 0;
2031     for (; sshIt != sshList.end(); jj++, sshIt++) {
2032       if (jj > 0)
2033         aDescr += ", ";
2034       aDescr += TCollection_AsciiString(*sshIt);
2035     }
2036   }
2037
2038   return aDescr;
2039 }
2040
2041 //=============================================================================
2042 /*!
2043  *  ExplodeCompoundOfBlocks
2044  */
2045 //=============================================================================
2046 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2047                                                 (Handle(GEOM_Object)    theCompound,
2048                                                  const Standard_Integer theMinNbFaces,
2049                                                  const Standard_Integer theMaxNbFaces)
2050 {
2051   SetErrorCode(KO);
2052
2053   if (theCompound.IsNull()) return NULL;
2054   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2055   if (aBlockOrComp.IsNull()) return NULL;
2056
2057   Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2058   Handle(GEOM_Object) anObj;
2059   Handle(GEOM_Function) aFunction;
2060
2061   TopTools_MapOfShape mapShape;
2062   TCollection_AsciiString anAsciiList = "[", anEntry;
2063
2064   // Map shapes
2065   TopTools_IndexedMapOfShape anIndices;
2066   TopExp::MapShapes(aBlockOrComp, anIndices);
2067   Handle(TColStd_HArray1OfInteger) anArray;
2068
2069   // Explode
2070   try {
2071     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2072     for (; exp.More(); exp.Next()) {
2073       if (mapShape.Add(exp.Current())) {
2074         TopoDS_Shape aSolid = exp.Current();
2075
2076         TopTools_MapOfShape mapFaces;
2077         TopExp_Explorer expF (aSolid, TopAbs_FACE);
2078         Standard_Integer nbFaces = 0;
2079         for (; expF.More(); expF.Next()) {
2080           if (mapFaces.Add(expF.Current())) {
2081             nbFaces++;
2082           }
2083         }
2084
2085         if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2086           anArray = new TColStd_HArray1OfInteger(1,1);
2087           anArray->SetValue(1, anIndices.FindIndex(aSolid));
2088           anObj = GetEngine()->AddSubShape(theCompound, anArray);
2089           aBlocks->Append(anObj);
2090
2091           //Make a Python command
2092           TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2093           anAsciiList += anEntry;
2094           anAsciiList += ",";
2095         }
2096       }
2097     }
2098   }
2099   catch (Standard_Failure) {
2100     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2101     SetErrorCode(aFail->GetMessageString());
2102     return aBlocks;
2103   }
2104
2105   if (aBlocks->IsEmpty()) {
2106     SetErrorCode("There are no specified blocks in the given shape");
2107     return aBlocks;
2108   }
2109
2110   anAsciiList.Trunc(anAsciiList.Length() - 1);
2111   anAsciiList += "]";
2112
2113   //The explode doesn't change object so no new function is required.
2114   aFunction = theCompound->GetLastFunction();
2115
2116   //Make a Python command
2117   TCollection_AsciiString aDescr (anAsciiList);
2118   aDescr += " = IBlocksOperations.ExplodeCompoundOfBlocks(";
2119   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
2120   aDescr += anEntry + ", ";
2121   aDescr += TCollection_AsciiString(theMinNbFaces) + ", ";
2122   aDescr += TCollection_AsciiString(theMaxNbFaces) + ")";
2123
2124   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
2125   aNewDescr += aDescr;
2126   aFunction->SetDescription(aNewDescr);
2127
2128   SetErrorCode(OK);
2129   return aBlocks;
2130 }
2131
2132 //=============================================================================
2133 /*!
2134  *  GetBlockNearPoint
2135  */
2136 //=============================================================================
2137 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2138                                                 (Handle(GEOM_Object) theCompound,
2139                                                  Handle(GEOM_Object) thePoint)
2140 {
2141   SetErrorCode(KO);
2142
2143   //New object
2144   Handle(GEOM_Object) aResult;
2145
2146   // Arguments
2147   if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2148
2149   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2150   if (aBlockOrComp.IsNull()) {
2151     SetErrorCode("Compound is null");
2152     return NULL;
2153   }
2154   if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2155       aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2156     SetErrorCode("Shape is neither a block, nor a compound of blocks");
2157     return NULL;
2158   }
2159
2160   TopoDS_Shape anArg = thePoint->GetValue();
2161   if (anArg.IsNull()) {
2162     SetErrorCode("Null shape is given as argument");
2163     return NULL;
2164   }
2165   if (anArg.ShapeType() != TopAbs_VERTEX) {
2166     SetErrorCode("Element for block identification is not a vertex");
2167     return NULL;
2168   }
2169
2170   //Compute the Block value
2171   try {
2172     TopoDS_Shape aShape;
2173     TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2174     gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2175
2176     // 1. Explode compound on blocks
2177     TopTools_MapOfShape mapShape;
2178     Standard_Integer nbSolids = 0;
2179     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2180     for (; exp.More(); exp.Next()) {
2181       if (mapShape.Add(exp.Current())) {
2182         nbSolids++;
2183       }
2184     }
2185
2186     mapShape.Clear();
2187     Standard_Integer ind = 1;
2188     TopTools_Array1OfShape aSolids (1, nbSolids);
2189     TColStd_Array1OfInteger aDistances (1, nbSolids);
2190     for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next()) {
2191       if (mapShape.Add(exp.Current())) {
2192         TopoDS_Shape aSolid = exp.Current();
2193         aSolids(ind) = aSolid;
2194
2195         // 2. Classify the point relatively each block
2196         BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2197         if (SC.State() == TopAbs_IN) {
2198           aDistances(ind) = -1;
2199         } else if (SC.State() == TopAbs_ON) {
2200           aDistances(ind) = 0;
2201         } else { // OUT
2202           aDistances(ind) = 1;
2203         }
2204         ind++;
2205       }
2206     }
2207
2208     // 3. Define block, containing the point or having minimum distance to it
2209     Standard_Integer nearest = 2, nbFound = 0;
2210     for (ind = 1; ind <= nbSolids; ind++) {
2211       if (aDistances(ind) < nearest) {
2212         nearest = aDistances(ind);
2213         aShape = aSolids(ind);
2214         nbFound = 1;
2215       } else if (aDistances(ind) == nearest) {
2216         nbFound++;
2217       } else {
2218       }
2219     }
2220     if (nbFound > 1) {
2221       if (nearest == 0) {
2222         // The point is on boundary of some blocks and there are
2223         // no blocks, having the point inside their volume
2224         SetErrorCode("Multiple blocks near the given point are found");
2225         return NULL;
2226
2227       } else if (nearest == 1) {
2228         // The point is outside some blocks and there are
2229         // no blocks, having the point inside or on boundary.
2230         // We will get a nearest block
2231         Standard_Real minDist = RealLast();
2232         for (ind = 1; ind <= nbSolids; ind++) {
2233           if (aDistances(ind) == 1) {
2234             BRepExtrema_DistShapeShape aDistTool (aVert, aSolids(ind));
2235             if (!aDistTool.IsDone()) {
2236               SetErrorCode("Can not find a distance from the given point to one of blocks");
2237               return NULL;
2238             }
2239             Standard_Real aDist = aDistTool.Value();
2240             if (aDist < minDist) {
2241               minDist = aDist;
2242               aShape = aSolids(ind);
2243             }
2244           }
2245         }
2246       } else { // nearest == -1
2247         // The point is inside some blocks.
2248         // We will get a block with nearest center
2249         Standard_Real minDist = RealLast();
2250         for (ind = 1; ind <= nbSolids; ind++) {
2251           if (aDistances(ind) == -1) {
2252             GProp_GProps aSystem;
2253             BRepGProp::VolumeProperties(aSolids(ind), aSystem);
2254             gp_Pnt aCenterMass = aSystem.CentreOfMass();
2255
2256             Standard_Real aDist = aCenterMass.Distance(aPnt);
2257             if (aDist < minDist) {
2258               minDist = aDist;
2259               aShape = aSolids(ind);
2260             }
2261           }
2262         }
2263       }
2264     }
2265
2266     if (nbFound == 0) {
2267       SetErrorCode("There are no blocks near the given point");
2268       return NULL;
2269     } else {
2270       TopTools_IndexedMapOfShape anIndices;
2271       TopExp::MapShapes(aBlockOrComp, anIndices);
2272       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2273       anArray->SetValue(1, anIndices.FindIndex(aShape));
2274       aResult = GetEngine()->AddSubShape(theCompound, anArray);
2275     }
2276   }
2277   catch (Standard_Failure) {
2278     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2279     SetErrorCode(aFail->GetMessageString());
2280     return NULL;
2281   }
2282
2283   //The GetBlockNearPoint() doesn't change object so no new function is required.
2284   Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
2285
2286   //Make a Python command
2287   TCollection_AsciiString anEntry, aDescr;
2288   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
2289   aDescr += anEntry + " = IBlocksOperations.GetBlockNearPoint(";
2290   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
2291   aDescr += anEntry + ", ";
2292   TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
2293   aDescr += anEntry + ")";
2294
2295   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
2296   aNewDescr += aDescr;
2297   aFunction->SetDescription(aNewDescr);
2298
2299   SetErrorCode(OK);
2300   return aResult;
2301 }
2302
2303 //=============================================================================
2304 /*!
2305  *  GetBlockByParts
2306  */
2307 //=============================================================================
2308 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2309                       (Handle(GEOM_Object)                         theCompound,
2310                        const Handle(TColStd_HSequenceOfTransient)& theParts)
2311 {
2312   SetErrorCode(KO);
2313
2314   Handle(GEOM_Object) aResult;
2315
2316   if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2317   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2318   if (aBlockOrComp.IsNull()) return NULL;
2319
2320   //Get the parts
2321   Standard_Integer argi, aLen = theParts->Length();
2322   TopTools_Array1OfShape anArgs (1, aLen);
2323   TCollection_AsciiString anEntry, aPartsDescr;
2324   for (argi = 1; argi <= aLen; argi++) {
2325     Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2326     Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2327     if (aRef.IsNull()) return NULL;
2328
2329     TopoDS_Shape anArg = aRef->GetValue();
2330     if (anArg.IsNull()) {
2331       SetErrorCode("Null shape is given as argument");
2332       return NULL;
2333     }
2334     anArgs(argi) = anArg;
2335
2336     // For Python command
2337     TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2338     if (argi > 1) aPartsDescr += ", ";
2339     aPartsDescr += anEntry;
2340   }
2341
2342   //Compute the Block value
2343   try {
2344     // 1. Explode compound on solids
2345     TopTools_MapOfShape mapShape;
2346     Standard_Integer nbSolids = 0;
2347     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2348     for (; exp.More(); exp.Next()) {
2349       if (mapShape.Add(exp.Current())) {
2350         nbSolids++;
2351       }
2352     }
2353
2354     mapShape.Clear();
2355     Standard_Integer ind = 1;
2356     TopTools_Array1OfShape aSolids (1, nbSolids);
2357     TColStd_Array1OfInteger aNbParts (1, nbSolids);
2358     for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2359       if (mapShape.Add(exp.Current())) {
2360         TopoDS_Shape aSolid = exp.Current();
2361         aSolids(ind) = aSolid;
2362         aNbParts(ind) = 0;
2363
2364         // 2. Define quantity of parts, contained in each solid
2365         TopTools_IndexedMapOfShape aSubShapes;
2366         TopExp::MapShapes(aSolid, aSubShapes);
2367         for (argi = 1; argi <= aLen; argi++) {
2368           if (aSubShapes.Contains(anArgs(argi))) {
2369             aNbParts(ind)++;
2370           }
2371         }
2372       }
2373     }
2374
2375     // 3. Define solid, containing maximum quantity of parts
2376     Standard_Integer maxNb = 0, nbFound = 0;
2377     TopoDS_Shape aShape;
2378     for (ind = 1; ind <= nbSolids; ind++) {
2379       if (aNbParts(ind) > maxNb) {
2380         maxNb = aNbParts(ind);
2381         aShape = aSolids(ind);
2382         nbFound = 1;
2383       } else if (aNbParts(ind) == maxNb) {
2384         nbFound++;
2385       } else {
2386       }
2387     }
2388     if (nbFound > 1) {
2389       SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
2390       return NULL;
2391     } else if (nbFound == 0) {
2392       SetErrorCode("There are no blocks, containing the given parts");
2393       return NULL;
2394     } else {
2395       TopTools_IndexedMapOfShape anIndices;
2396       TopExp::MapShapes(aBlockOrComp, anIndices);
2397       Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2398       anArray->SetValue(1, anIndices.FindIndex(aShape));
2399       aResult = GetEngine()->AddSubShape(theCompound, anArray);
2400     }
2401   } catch (Standard_Failure) {
2402     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2403     SetErrorCode(aFail->GetMessageString());
2404     return NULL;
2405   }
2406
2407   //The GetBlockByParts() doesn't change object so no new function is required.
2408   Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
2409
2410   //Make a Python command
2411   TDF_Tool::Entry(aResult->GetEntry(), anEntry);
2412   TCollection_AsciiString aDescr (anEntry);
2413   aDescr += " = IBlocksOperations.GetBlockByParts(";
2414   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
2415   aDescr += anEntry + ", [";
2416   aDescr += aPartsDescr + "])";
2417
2418   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
2419   aNewDescr += aDescr;
2420   aFunction->SetDescription(aNewDescr);
2421
2422   SetErrorCode(OK);
2423   return aResult;
2424 }
2425
2426 //=============================================================================
2427 /*!
2428  *  GetBlocksByParts
2429  */
2430 //=============================================================================
2431 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
2432                       (Handle(GEOM_Object)                         theCompound,
2433                        const Handle(TColStd_HSequenceOfTransient)& theParts)
2434 {
2435   SetErrorCode(KO);
2436
2437   if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2438   TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2439   if (aBlockOrComp.IsNull()) return NULL;
2440
2441   Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2442   Handle(GEOM_Object) anObj;
2443   Handle(GEOM_Function) aFunction;
2444
2445   //Get the parts
2446   Standard_Integer argi, aLen = theParts->Length();
2447   TopTools_Array1OfShape anArgs (1, aLen);
2448   TCollection_AsciiString anEntry, aPartsDescr, anAsciiList = "[";
2449   for (argi = 1; argi <= aLen; argi++) {
2450     Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2451     Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2452     if (aRef.IsNull()) return NULL;
2453
2454     TopoDS_Shape anArg = aRef->GetValue();
2455     if (anArg.IsNull()) {
2456       SetErrorCode("Null shape is given as argument");
2457       return NULL;
2458     }
2459     anArgs(argi) = anArg;
2460
2461     // For Python command
2462     TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2463     if (argi > 1) aPartsDescr += ", ";
2464     aPartsDescr += anEntry;
2465   }
2466
2467   //Get the Blocks
2468   try {
2469     TopTools_MapOfShape mapShape;
2470     Standard_Integer nbSolids = 0;
2471     TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2472     for (; exp.More(); exp.Next()) {
2473       if (mapShape.Add(exp.Current())) {
2474         nbSolids++;
2475       }
2476     }
2477
2478     mapShape.Clear();
2479     Standard_Integer ind = 1;
2480     TopTools_Array1OfShape aSolids (1, nbSolids);
2481     TColStd_Array1OfInteger aNbParts (1, nbSolids);
2482     for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2483       if (mapShape.Add(exp.Current())) {
2484         TopoDS_Shape aSolid = exp.Current();
2485         aSolids(ind) = aSolid;
2486         aNbParts(ind) = 0;
2487
2488         // 2. Define quantity of parts, contained in each solid
2489         TopTools_IndexedMapOfShape aSubShapes;
2490         TopExp::MapShapes(aSolid, aSubShapes);
2491         for (argi = 1; argi <= aLen; argi++) {
2492           if (aSubShapes.Contains(anArgs(argi))) {
2493             aNbParts(ind)++;
2494           }
2495         }
2496       }
2497     }
2498
2499     // 3. Define solid, containing maximum quantity of parts
2500     Standard_Integer maxNb = 0, nbFound = 0;
2501     for (ind = 1; ind <= nbSolids; ind++) {
2502       if (aNbParts(ind) > maxNb) {
2503         maxNb = aNbParts(ind);
2504         nbFound = 1;
2505       } else if (aNbParts(ind) == maxNb) {
2506         nbFound++;
2507       } else {
2508       }
2509     }
2510     if (nbFound == 0) {
2511       SetErrorCode("There are no blocks, containing the given parts");
2512       return NULL;
2513     }
2514
2515     // Map shapes
2516     TopTools_IndexedMapOfShape anIndices;
2517     TopExp::MapShapes(aBlockOrComp, anIndices);
2518     Handle(TColStd_HArray1OfInteger) anArray;
2519
2520     for (ind = 1; ind <= nbSolids; ind++) {
2521       if (aNbParts(ind) == maxNb) {
2522         anArray = new TColStd_HArray1OfInteger(1,1);
2523         anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
2524         anObj = GetEngine()->AddSubShape(theCompound, anArray);
2525         aBlocks->Append(anObj);
2526
2527         //Make a Python command
2528         TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2529         anAsciiList += anEntry;
2530         anAsciiList += ",";
2531       }
2532     }
2533   }
2534   catch (Standard_Failure) {
2535     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2536     SetErrorCode(aFail->GetMessageString());
2537     return NULL;
2538   }
2539
2540   anAsciiList.Trunc(anAsciiList.Length() - 1);
2541   anAsciiList += "]";
2542
2543   //The GetBlocksByParts() doesn't change object so no new function is required.
2544   aFunction = theCompound->GetLastFunction();
2545
2546   //Make a Python command
2547   TCollection_AsciiString aDescr (anAsciiList);
2548   aDescr += " = IBlocksOperations.GetBlocksByParts(";
2549   TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
2550   aDescr += anEntry + ", [";
2551   aDescr += aPartsDescr + "])";
2552
2553   TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
2554   aNewDescr += aDescr;
2555   aFunction->SetDescription(aNewDescr);
2556
2557   SetErrorCode(OK);
2558   return aBlocks;
2559 }
2560
2561 //=============================================================================
2562 /*!
2563  *  MakeMultiTransformation1D
2564  */
2565 //=============================================================================
2566 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
2567                                              (Handle(GEOM_Object)    theObject,
2568                                               const Standard_Integer theDirFace1,
2569                                               const Standard_Integer theDirFace2,
2570                                               const Standard_Integer theNbTimes)
2571 {
2572   SetErrorCode(KO);
2573
2574   if (theObject.IsNull()) return NULL;
2575
2576   Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2577   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
2578
2579   //Add a new Copy object
2580   Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2581
2582   //Add a translate function
2583   Handle(GEOM_Function) aFunction =
2584     aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
2585
2586   //Check if the function is set correctly
2587   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2588
2589   GEOMImpl_IBlockTrsf aTI (aFunction);
2590   aTI.SetOriginal(aLastFunction);
2591   aTI.SetFace1U(theDirFace1);
2592   aTI.SetFace2U(theDirFace2);
2593   aTI.SetNbIterU(theNbTimes);
2594
2595   //Compute the transformation
2596   try {
2597     if (!GetSolver()->ComputeFunction(aFunction)) {
2598       SetErrorCode("Block driver failed to make multi-transformation");
2599       return NULL;
2600     }
2601   }
2602   catch (Standard_Failure) {
2603     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2604     SetErrorCode(aFail->GetMessageString());
2605     return NULL;
2606   }
2607
2608   //Make a Python command
2609   TCollection_AsciiString anEntry, aDescr;
2610   TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
2611   aDescr += anEntry + " = IBlocksOperations.MakeMultiTransformation1D(";
2612   TDF_Tool::Entry(theObject->GetEntry(), anEntry);
2613   aDescr += anEntry + ", ";
2614   aDescr += TCollection_AsciiString(theDirFace1) + ", ";
2615   aDescr += TCollection_AsciiString(theDirFace2) + ", ";
2616   aDescr += TCollection_AsciiString(theNbTimes)  + ") ";
2617
2618   aFunction->SetDescription(aDescr);
2619
2620   SetErrorCode(OK);
2621   return aCopy;
2622 }
2623
2624 //=============================================================================
2625 /*!
2626  *  MakeMultiTransformation2D
2627  */
2628 //=============================================================================
2629 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
2630                                              (Handle(GEOM_Object)    theObject,
2631                                               const Standard_Integer theDirFace1U,
2632                                               const Standard_Integer theDirFace2U,
2633                                               const Standard_Integer theNbTimesU,
2634                                               const Standard_Integer theDirFace1V,
2635                                               const Standard_Integer theDirFace2V,
2636                                               const Standard_Integer theNbTimesV)
2637 {
2638   SetErrorCode(KO);
2639
2640   if (theObject.IsNull()) return NULL;
2641
2642   Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2643   if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
2644
2645   //Add a new Copy object
2646   Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2647
2648   //Add a translate function
2649   Handle(GEOM_Function) aFunction =
2650     aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
2651
2652   //Check if the function is set correctly
2653   if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2654
2655   GEOMImpl_IBlockTrsf aTI (aFunction);
2656   aTI.SetOriginal(aLastFunction);
2657   aTI.SetFace1U(theDirFace1U);
2658   aTI.SetFace2U(theDirFace2U);
2659   aTI.SetNbIterU(theNbTimesU);
2660   aTI.SetFace1V(theDirFace1V);
2661   aTI.SetFace2V(theDirFace2V);
2662   aTI.SetNbIterV(theNbTimesV);
2663
2664   //Compute the transformation
2665   try {
2666     if (!GetSolver()->ComputeFunction(aFunction)) {
2667       SetErrorCode("Block driver failed to make multi-transformation");
2668       return NULL;
2669     }
2670   }
2671   catch (Standard_Failure) {
2672     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2673     SetErrorCode(aFail->GetMessageString());
2674     return NULL;
2675   }
2676
2677   //Make a Python command
2678   TCollection_AsciiString anEntry, aDescr;
2679   TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
2680   aDescr += anEntry + " = IBlocksOperations.MakeMultiTransformation2D(";
2681   TDF_Tool::Entry(theObject->GetEntry(), anEntry);
2682   aDescr += anEntry + ", ";
2683   aDescr += TCollection_AsciiString(theDirFace1U) + ", ";
2684   aDescr += TCollection_AsciiString(theDirFace2U) + ", ";
2685   aDescr += TCollection_AsciiString(theNbTimesU)  + ", ";
2686   aDescr += TCollection_AsciiString(theDirFace1V) + ", ";
2687   aDescr += TCollection_AsciiString(theDirFace2V) + ", ";
2688   aDescr += TCollection_AsciiString(theNbTimesV)  + ") ";
2689
2690   aFunction->SetDescription(aDescr);
2691
2692   SetErrorCode(OK);
2693   return aCopy;
2694 }