1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
24 #pragma warning( disable:4786 )
27 #include <Standard_Stream.hxx>
29 #include <GEOMImpl_IBlocksOperations.hxx>
31 #include <GEOMImpl_Types.hxx>
33 #include <GEOMImpl_BlockDriver.hxx>
34 #include <GEOMImpl_IBlocks.hxx>
35 #include <GEOMImpl_IBlockTrsf.hxx>
36 #include <GEOMImpl_Block6Explorer.hxx>
38 #include <GEOMUtils.hxx>
40 #include <GEOM_Function.hxx>
41 #include <GEOM_PythonDump.hxx>
43 #include <GEOMAlgo_GlueAnalyser.hxx>
44 #include <GEOMAlgo_CoupleOfShapes.hxx>
45 #include <GEOMAlgo_ListOfCoupleOfShapes.hxx>
46 #include <GEOMAlgo_ListIteratorOfListOfCoupleOfShapes.hxx>
47 #include <BlockFix_CheckTool.hxx>
49 #include <Basics_OCCTVersion.hxx>
51 #include "utilities.h"
53 #include <Utils_ExceptHandlers.hxx>
55 #include <TFunction_DriverTable.hxx>
56 #include <TFunction_Driver.hxx>
57 #include <TDataStd_Integer.hxx>
58 #include <TDF_Tool.hxx>
60 #include <BRep_Tool.hxx>
61 #include <BRep_Builder.hxx>
62 #include <BRepTools.hxx>
63 #include <BRepTools_WireExplorer.hxx>
64 #include <BRepGProp.hxx>
65 #include <BRepBndLib.hxx>
66 #include <BRepAdaptor_Surface.hxx>
67 #include <BRepClass_FaceClassifier.hxx>
68 #include <BRepClass3d_SolidClassifier.hxx>
69 #include <BRepExtrema_DistShapeShape.hxx>
73 #include <TopoDS_Edge.hxx>
74 #include <TopoDS_Vertex.hxx>
75 #include <TopoDS_Compound.hxx>
76 #include <TopoDS_Iterator.hxx>
78 #include <TopExp_Explorer.hxx>
79 #include <TopTools_MapOfShape.hxx>
80 #include <TopTools_Array1OfShape.hxx>
81 #include <TopTools_IndexedMapOfShape.hxx>
82 #include <TopTools_DataMapOfShapeInteger.hxx>
83 #include <TopTools_ListIteratorOfListOfShape.hxx>
84 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
85 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
87 #include <Bnd_Box.hxx>
88 #include <GProp_GProps.hxx>
90 #include <Geom_Curve.hxx>
91 #include <Geom_Surface.hxx>
92 #include <ShapeAnalysis_Surface.hxx>
94 #include <TColStd_MapOfInteger.hxx>
95 #include <TColStd_Array1OfReal.hxx>
96 #include <TColStd_Array1OfInteger.hxx>
97 #include <TColStd_Array2OfInteger.hxx>
99 //#include <OSD_Timer.hxx>
101 #include <Precision.hxx>
103 #include <Standard_Failure.hxx>
104 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
108 * This function returns Standard_True if the face is quadrangular. It means
109 * that it has only 1 wire with 4 edges. If there are more then 4 edges in
110 * the wire and theToleranceC1 is not negative the new implementation is used.
111 * According to it the face is quadrangular if it is quadrangular according to
112 * an old implementation or if it has a single wire with more then 4 edges
113 * that form exactly 4 bounds of C1 continuity with the given tolerance.
115 * \param theFace the face to be checked
116 * \param theToleranceC1 if negative, it is not used; otherwise it is used
117 * to check if two neighbor edges of face have C1 continuity.
118 * \return Standard_True if the face is quadrangular; Standard_False otherwise.
120 static Standard_Boolean IsQuadrangle(const TopoDS_Face &theFace,
121 const Standard_Real theToleranceC1)
123 TopExp_Explorer aFExp (theFace, TopAbs_WIRE);
126 // no wire in the face
127 return Standard_False;
130 TopoDS_Shape aWire = aFExp.Current();
135 // multiple wires in the face
136 return Standard_False;
139 // Check number of edges in the face
140 Standard_Integer aNbEdges = 0;
141 TopTools_MapOfShape aMapEdges;
142 TopExp_Explorer aWExp(aWire, TopAbs_EDGE);
144 for (; aWExp.More(); aWExp.Next()) {
145 if (aMapEdges.Add(aWExp.Current())) {
155 return Standard_False;
159 if (theToleranceC1 < 0.) {
160 return Standard_False;
163 // Check if a wire has 4 bounds of C1 continuity.
164 BRepTools_WireExplorer aWireExp(TopoDS::Wire(aWire), theFace);
165 TopTools_ListOfShape anEdges;
167 for (aNbEdges = 0; aWireExp.More(); aWireExp.Next()) {
168 const TopoDS_Edge &anEdge = aWireExp.Current();
170 // Skip degenerated edges.
171 if (!BRep_Tool::Degenerated(anEdge)) {
172 anEdges.Append(anEdge);
178 return Standard_False;
181 // Compute number of sharp corners.
182 anEdges.Append(anEdges.First()); // To make a loop.
184 TopTools_ListIteratorOfListOfShape anIter(anEdges);
185 Standard_Real aPar[2];
186 Standard_Integer aNbCorners = 0;
187 TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.First());
188 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aPar[0], aPar[1]);
189 Handle(Geom_Curve) aCurve2;
191 TopoDS_Vertex aCommonVtx;
195 Standard_Boolean isReversed1 = (anEdge1.Orientation() == TopAbs_REVERSED);
196 Standard_Boolean isReversed2;
198 for (anIter.Next(); anIter.More(); anIter.Next()) {
199 TopoDS_Edge anEdge2 = TopoDS::Edge(anIter.Value());
201 if (!TopExp::CommonVertex(anEdge1, anEdge2, aCommonVtx)) {
203 return Standard_False;
206 // Check the angle between tangent vectors of 2 curves at this point.
207 Standard_Real aParam1 = BRep_Tool::Parameter(aCommonVtx, anEdge1);
208 Standard_Real aParam2 = BRep_Tool::Parameter(aCommonVtx, anEdge2);
210 aCurve2 = BRep_Tool::Curve(anEdge2, aPar[0], aPar[1]);
211 isReversed2 = (anEdge2.Orientation() == TopAbs_REVERSED);
212 aCurve1->D1(aParam1, aPnt, aVec1);
213 aCurve2->D1(aParam2, aPnt, aVec2);
222 const Standard_Real anAngle = aVec1.Angle(aVec2);
224 if (anAngle > theToleranceC1) {
227 if (aNbCorners > 4) {
232 // Go to the next couple of edges.
235 isReversed1 = isReversed2;
238 // Check the total number of corners.
239 if (aNbCorners != 4) {
240 return Standard_False;
244 return Standard_True;
247 //=============================================================================
251 //=============================================================================
252 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
253 : GEOM_IOperations(theEngine, theDocID)
255 MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
258 //=============================================================================
262 //=============================================================================
263 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
265 MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
269 //=============================================================================
273 //=============================================================================
274 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
275 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
276 Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
280 if (theEdge1.IsNull() || theEdge2.IsNull() ||
281 theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
283 //Add a new Face object
284 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
286 //Add a new Face function
287 Handle(GEOM_Function) aFunction =
288 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
290 //Check if the function is set correctly
291 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
293 GEOMImpl_IBlocks aPI (aFunction);
295 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
296 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
297 Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
298 Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
299 if (aRef1.IsNull() || aRef2.IsNull() ||
300 aRef3.IsNull() || aRef4.IsNull()) return NULL;
302 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
303 aShapesSeq->Append(aRef1);
304 aShapesSeq->Append(aRef2);
305 aShapesSeq->Append(aRef3);
306 aShapesSeq->Append(aRef4);
308 aPI.SetShapes(aShapesSeq);
310 //Compute the Face value
313 if (!GetSolver()->ComputeFunction(aFunction)) {
314 SetErrorCode("Block driver failed to compute a face");
318 catch (Standard_Failure) {
319 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
320 SetErrorCode(aFail->GetMessageString());
324 //Make a Python command
325 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
326 << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
332 //=============================================================================
336 //=============================================================================
337 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
338 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
342 if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
344 //Add a new Face object
345 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
347 //Add a new Face function
348 Handle(GEOM_Function) aFunction =
349 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
351 //Check if the function is set correctly
352 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
354 GEOMImpl_IBlocks aPI (aFunction);
356 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
357 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
358 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
360 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
361 aShapesSeq->Append(aRef1);
362 aShapesSeq->Append(aRef2);
364 aPI.SetShapes(aShapesSeq);
366 //Compute the Face value
369 if (!GetSolver()->ComputeFunction(aFunction)) {
370 SetErrorCode("Block driver failed to compute a face");
374 catch (Standard_Failure) {
375 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
376 SetErrorCode(aFail->GetMessageString());
380 //Make a Python command
381 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
382 << theEdge1 << ", " << theEdge2 << ")";
388 //=============================================================================
392 //=============================================================================
393 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
394 (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
395 Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
399 if (thePnt1.IsNull() || thePnt2.IsNull() ||
400 thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
402 //Add a new Face object
403 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
405 //Add a new Face function
406 Handle(GEOM_Function) aFunction =
407 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
409 //Check if the function is set correctly
410 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
412 GEOMImpl_IBlocks aPI (aFunction);
414 Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
415 Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
416 Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
417 Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
418 if (aRef1.IsNull() || aRef2.IsNull() ||
419 aRef3.IsNull() || aRef4.IsNull()) return NULL;
421 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
422 aShapesSeq->Append(aRef1);
423 aShapesSeq->Append(aRef2);
424 aShapesSeq->Append(aRef3);
425 aShapesSeq->Append(aRef4);
427 aPI.SetShapes(aShapesSeq);
429 //Compute the Face value
432 if (!GetSolver()->ComputeFunction(aFunction)) {
433 SetErrorCode("Block driver failed to compute a face");
437 catch (Standard_Failure) {
438 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
439 SetErrorCode(aFail->GetMessageString());
443 //Make a Python command
444 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
445 << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
451 //=============================================================================
455 //=============================================================================
456 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
457 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
458 Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
459 Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
463 if (theFace1.IsNull() || theFace2.IsNull() ||
464 theFace3.IsNull() || theFace4.IsNull() ||
465 theFace5.IsNull() || theFace6.IsNull()) return NULL;
467 //Add a new Solid object
468 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
470 //Add a new Block function
471 Handle(GEOM_Function) aFunction =
472 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
474 //Check if the function is set correctly
475 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
477 GEOMImpl_IBlocks aPI (aFunction);
479 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
480 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
481 Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
482 Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
483 Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
484 Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
485 if (aRef1.IsNull() || aRef2.IsNull() ||
486 aRef3.IsNull() || aRef4.IsNull() ||
487 aRef5.IsNull() || aRef6.IsNull()) return NULL;
489 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
490 aShapesSeq->Append(aRef1);
491 aShapesSeq->Append(aRef2);
492 aShapesSeq->Append(aRef3);
493 aShapesSeq->Append(aRef4);
494 aShapesSeq->Append(aRef5);
495 aShapesSeq->Append(aRef6);
497 aPI.SetShapes(aShapesSeq);
499 //Compute the Block value
502 if (!GetSolver()->ComputeFunction(aFunction)) {
503 SetErrorCode("Block driver failed to compute a block");
507 catch (Standard_Failure) {
508 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
509 SetErrorCode(aFail->GetMessageString());
513 //Make a Python command
514 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
515 << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
516 << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
522 //=============================================================================
526 //=============================================================================
527 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
528 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
532 if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
534 //Add a new Solid object
535 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
537 //Add a new Block function
538 Handle(GEOM_Function) aFunction =
539 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
541 //Check if the function is set correctly
542 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
544 GEOMImpl_IBlocks aPI (aFunction);
546 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
547 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
548 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
550 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
551 aShapesSeq->Append(aRef1);
552 aShapesSeq->Append(aRef2);
554 aPI.SetShapes(aShapesSeq);
556 //Compute the Block value
559 if (!GetSolver()->ComputeFunction(aFunction)) {
560 SetErrorCode("Block driver failed to compute a block");
564 catch (Standard_Failure) {
565 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
566 SetErrorCode(aFail->GetMessageString());
570 //Make a Python command
571 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
572 << theFace1 << ", " << theFace2 << ")";
578 //=============================================================================
582 //=============================================================================
583 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
584 (Handle(GEOM_Object) theCompound)
588 if (theCompound.IsNull()) return NULL;
591 Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
593 //Add a new BlocksComp function
594 Handle(GEOM_Function) aFunction =
595 aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
597 //Check if the function is set correctly
598 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
600 GEOMImpl_IBlocks aPI (aFunction);
602 Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
603 if (aRef1.IsNull()) return NULL;
605 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
606 aShapesSeq->Append(aRef1);
608 aPI.SetShapes(aShapesSeq);
610 //Compute the Blocks Compound value
613 if (!GetSolver()->ComputeFunction(aFunction)) {
614 SetErrorCode("Block driver failed to compute a blocks compound");
618 catch (Standard_Failure) {
619 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
620 SetErrorCode(aFail->GetMessageString());
624 //Make a Python command
625 GEOM::TPythonDump(aFunction) << aBlockComp
626 << " = geompy.MakeBlockCompound(" << theCompound << ")";
632 //=============================================================================
636 //=============================================================================
637 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
638 (Handle(GEOM_Object) theShape,
639 const Standard_Real theX,
640 const Standard_Real theY,
641 const Standard_Real theZ,
642 const Standard_Real theEpsilon)
647 Handle(GEOM_Object) aResult;
650 if (theShape.IsNull()) return NULL;
652 TopoDS_Shape aBlockOrComp = theShape->GetValue();
653 if (aBlockOrComp.IsNull()) {
654 SetErrorCode("Given shape is null");
658 //Compute the Vertex value
659 gp_Pnt P (theX, theY, theZ);
660 Standard_Real eps = Max(theEpsilon, Precision::Confusion());
663 Standard_Integer isFound = 0;
664 TopTools_MapOfShape mapShape;
665 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
667 for (; exp.More(); exp.Next()) {
668 if (mapShape.Add(exp.Current())) {
669 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
670 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
671 if (aPi.Distance(P) < eps) {
679 SetErrorCode("Vertex has not been found");
681 } else if (isFound > 1) {
682 SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
685 TopTools_IndexedMapOfShape anIndices;
686 TopExp::MapShapes(aBlockOrComp, anIndices);
687 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
688 anArray->SetValue(1, anIndices.FindIndex(V));
689 aResult = GetEngine()->AddSubShape(theShape, anArray);
692 //The GetPoint() doesn't change object so no new function is required.
693 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
695 //Make a Python command
696 GEOM::TPythonDump(aFunction, /*append=*/true)
697 << aResult << " = geompy.GetPoint(" << theShape << ", "
698 << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
704 //=============================================================================
708 //=============================================================================
709 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetVertexNearPoint
710 (Handle(GEOM_Object) theShape,
711 Handle(GEOM_Object) thePoint)
716 Handle(GEOM_Object) aResult;
719 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
721 TopoDS_Shape aBlockOrComp = theShape->GetValue();
722 TopoDS_Shape aPoint = thePoint->GetValue();
723 if (aBlockOrComp.IsNull() || aPoint.IsNull()) {
724 SetErrorCode("Given shape is null");
728 if (aPoint.ShapeType() != TopAbs_VERTEX) {
729 SetErrorCode("Element for vertex identification is not a vertex");
733 TopoDS_Vertex aVert = TopoDS::Vertex(aPoint);
734 gp_Pnt aP = BRep_Tool::Pnt(aVert);
736 // Compute the Vertex value
738 bool isFound = false;
739 Standard_Real aDist = RealLast();
740 TopTools_MapOfShape mapShape;
742 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
743 for (; exp.More(); exp.Next()) {
744 if (mapShape.Add(exp.Current())) {
745 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
746 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
747 Standard_Real aDisti = aPi.Distance(aP);
748 if (aDisti < aDist) {
757 SetErrorCode("Vertex has not been found");
761 TopTools_IndexedMapOfShape anIndices;
762 TopExp::MapShapes(aBlockOrComp, anIndices);
763 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
764 anArray->SetValue(1, anIndices.FindIndex(V));
765 aResult = GetEngine()->AddSubShape(theShape, anArray);
767 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
769 // Make a Python command
770 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetVertexNearPoint("
771 << theShape << ", " << thePoint << ")";
777 //=============================================================================
781 //=============================================================================
782 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
783 (Handle(GEOM_Object) theShape,
784 Handle(GEOM_Object) thePoint1,
785 Handle(GEOM_Object) thePoint2)
790 Handle(GEOM_Object) aResult;
793 if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
795 TopoDS_Shape aBlockOrComp = theShape->GetValue();
796 if (aBlockOrComp.IsNull()) {
797 SetErrorCode("Given shape is null");
801 TopoDS_Shape anArg1 = thePoint1->GetValue();
802 TopoDS_Shape anArg2 = thePoint2->GetValue();
803 if (anArg1.IsNull() || anArg2.IsNull()) {
804 SetErrorCode("Null shape is given as argument");
807 if (anArg1.ShapeType() != TopAbs_VERTEX ||
808 anArg2.ShapeType() != TopAbs_VERTEX) {
809 SetErrorCode("Element for edge identification is not a vertex");
813 //Compute the Edge value
816 TopTools_IndexedDataMapOfShapeListOfShape MVE;
817 GEOMImpl_Block6Explorer::MapShapesAndAncestors
818 (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
821 Standard_Integer ish, ext = MVE.Extent();
823 if (MVE.Contains(anArg1)) {
826 for (ish = 1; ish <= ext; ish++) {
827 TopoDS_Shape aShi = MVE.FindKey(ish);
828 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
835 if (MVE.Contains(anArg2)) {
838 for (ish = 1; ish <= ext; ish++) {
839 TopoDS_Shape aShi = MVE.FindKey(ish);
840 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
847 if (V1.IsNull() || V2.IsNull()) {
848 SetErrorCode("The given vertex does not belong to the shape");
853 Standard_Integer isFound =
854 GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
856 SetErrorCode("The given vertices do not belong to one edge of the given shape");
858 } else if (isFound > 1) {
859 SetErrorCode("Multiple edges found by the given vertices of the shape");
862 TopTools_IndexedMapOfShape anIndices;
863 TopExp::MapShapes(aBlockOrComp, anIndices);
864 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
865 anArray->SetValue(1, anIndices.FindIndex(anEdge));
866 aResult = GetEngine()->AddSubShape(theShape, anArray);
868 } catch (Standard_Failure) {
869 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
870 SetErrorCode(aFail->GetMessageString());
874 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
876 //Make a Python command
877 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
878 << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
884 //=============================================================================
888 //=============================================================================
889 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
890 (Handle(GEOM_Object) theShape,
891 Handle(GEOM_Object) thePoint)
896 Handle(GEOM_Object) aResult;
899 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
901 TopoDS_Shape aBlockOrComp = theShape->GetValue();
902 if (aBlockOrComp.IsNull()) {
903 SetErrorCode("Given shape is null");
907 TopoDS_Shape anArg = thePoint->GetValue();
908 if (anArg.IsNull()) {
909 SetErrorCode("Null shape is given as argument");
912 if (anArg.ShapeType() != TopAbs_VERTEX) {
913 SetErrorCode("Element for edge identification is not a vertex");
917 //Compute the Edge value
920 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
921 TopoDS_Shape aShape = GEOMUtils::GetEdgeNearPoint(aBlockOrComp, aVert);
923 TopTools_IndexedMapOfShape anIndices;
924 TopExp::MapShapes(aBlockOrComp, anIndices);
925 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
926 anArray->SetValue(1, anIndices.FindIndex(aShape));
927 aResult = GetEngine()->AddSubShape(theShape, anArray);
929 catch (Standard_Failure) {
930 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
931 SetErrorCode(aFail->GetMessageString());
935 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
937 //Make a Python command
938 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
939 << theShape << ", " << thePoint << ")";
945 //=============================================================================
949 //=============================================================================
950 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
951 (Handle(GEOM_Object) theShape,
952 Handle(GEOM_Object) thePoint1,
953 Handle(GEOM_Object) thePoint2,
954 Handle(GEOM_Object) thePoint3,
955 Handle(GEOM_Object) thePoint4)
960 Handle(GEOM_Object) aResult;
963 if (theShape.IsNull() ||
964 thePoint1.IsNull() || thePoint2.IsNull() ||
965 thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
967 TopoDS_Shape aBlockOrComp = theShape->GetValue();
968 if (aBlockOrComp.IsNull()) {
969 SetErrorCode("Block or compound is null");
973 TopoDS_Shape anArg1 = thePoint1->GetValue();
974 TopoDS_Shape anArg2 = thePoint2->GetValue();
975 TopoDS_Shape anArg3 = thePoint3->GetValue();
976 TopoDS_Shape anArg4 = thePoint4->GetValue();
977 if (anArg1.IsNull() || anArg2.IsNull() ||
978 anArg3.IsNull() || anArg4.IsNull()) {
979 SetErrorCode("Null shape is given as argument");
982 if (anArg1.ShapeType() != TopAbs_VERTEX ||
983 anArg2.ShapeType() != TopAbs_VERTEX ||
984 anArg3.ShapeType() != TopAbs_VERTEX ||
985 anArg4.ShapeType() != TopAbs_VERTEX) {
986 SetErrorCode("Element for face identification is not a vertex");
990 //Compute the Face value
995 TopTools_IndexedDataMapOfShapeListOfShape MVF;
996 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
998 TopoDS_Shape V1,V2,V3,V4;
999 Standard_Integer ish, ext = MVF.Extent();
1001 if (MVF.Contains(anArg1)) {
1004 for (ish = 1; ish <= ext; ish++) {
1005 TopoDS_Shape aShi = MVF.FindKey(ish);
1006 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
1013 if (MVF.Contains(anArg2)) {
1016 for (ish = 1; ish <= ext; ish++) {
1017 TopoDS_Shape aShi = MVF.FindKey(ish);
1018 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
1025 if (MVF.Contains(anArg3)) {
1028 for (ish = 1; ish <= ext; ish++) {
1029 TopoDS_Shape aShi = MVF.FindKey(ish);
1030 if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
1037 if (MVF.Contains(anArg4)) {
1040 for (ish = 1; ish <= ext; ish++) {
1041 TopoDS_Shape aShi = MVF.FindKey(ish);
1042 if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
1049 if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
1050 SetErrorCode("The given vertex does not belong to the shape");
1054 Standard_Integer isFound =
1055 GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
1057 SetErrorCode("The given vertices do not belong to one face of the given shape");
1059 } else if (isFound > 1) {
1060 SetErrorCode("The given vertices belong to several faces of the given shape");
1063 TopTools_IndexedMapOfShape anIndices;
1064 TopExp::MapShapes(aBlockOrComp, anIndices);
1065 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1066 anArray->SetValue(1, anIndices.FindIndex(aShape));
1067 aResult = GetEngine()->AddSubShape(theShape, anArray);
1070 catch (Standard_Failure) {
1071 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1072 SetErrorCode(aFail->GetMessageString());
1076 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1078 //Make a Python command
1079 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
1080 << theShape << ", " << thePoint1 << ", " << thePoint2
1081 << ", " << thePoint3 << ", " << thePoint4 << ")";
1087 //=============================================================================
1091 //=============================================================================
1092 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
1093 (Handle(GEOM_Object) theShape,
1094 Handle(GEOM_Object) theEdge1,
1095 Handle(GEOM_Object) theEdge2)
1100 Handle(GEOM_Object) aResult;
1103 if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
1105 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1106 if (aBlockOrComp.IsNull()) {
1107 SetErrorCode("Block or compound is null");
1111 TopoDS_Shape anArg1 = theEdge1->GetValue();
1112 TopoDS_Shape anArg2 = theEdge2->GetValue();
1113 if (anArg1.IsNull() || anArg2.IsNull()) {
1114 SetErrorCode("Null shape is given as argument");
1117 if (anArg1.ShapeType() != TopAbs_EDGE ||
1118 anArg2.ShapeType() != TopAbs_EDGE) {
1119 SetErrorCode("Element for face identification is not an edge");
1123 //Compute the Face value
1126 TopoDS_Shape aShape;
1128 TopTools_IndexedDataMapOfShapeListOfShape MEF;
1129 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
1132 Standard_Integer ish, ext = MEF.Extent();
1134 if (MEF.Contains(anArg1)) {
1137 for (ish = 1; ish <= ext; ish++) {
1138 TopoDS_Shape aShi = MEF.FindKey(ish);
1139 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
1145 if (MEF.Contains(anArg2)) {
1148 for (ish = 1; ish <= ext; ish++) {
1149 TopoDS_Shape aShi = MEF.FindKey(ish);
1150 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
1156 if (E1.IsNull() || E2.IsNull()) {
1157 SetErrorCode("The given edge does not belong to the shape");
1161 const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
1162 const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
1164 Standard_Integer isFound = 0;
1165 TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
1166 for (; anIterF1.More(); anIterF1.Next()) {
1168 TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
1169 for (; anIterF2.More(); anIterF2.Next()) {
1171 if (anIterF1.Value().IsSame(anIterF2.Value())) {
1174 // Store the face, defined by two edges
1175 aShape = anIterF1.Value();
1180 SetErrorCode("The given edges do not belong to one face of the given shape");
1182 } else if (isFound > 1) {
1183 SetErrorCode("The given edges belong to several faces of the given shape");
1186 TopTools_IndexedMapOfShape anIndices;
1187 TopExp::MapShapes(aBlockOrComp, anIndices);
1188 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1189 anArray->SetValue(1, anIndices.FindIndex(aShape));
1190 aResult = GetEngine()->AddSubShape(theShape, anArray);
1193 catch (Standard_Failure) {
1194 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1195 SetErrorCode(aFail->GetMessageString());
1199 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1201 //Make a Python command
1202 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
1203 << theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
1209 //=============================================================================
1213 //=============================================================================
1214 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
1215 (Handle(GEOM_Object) theShape,
1216 Handle(GEOM_Object) theFace)
1221 Handle(GEOM_Object) aResult;
1224 if (theShape.IsNull() || theFace.IsNull()) return NULL;
1226 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1227 if (aBlockOrComp.IsNull()) {
1228 SetErrorCode("Block is null");
1231 if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
1232 SetErrorCode("Shape is not a block");
1236 TopoDS_Shape anArg = theFace->GetValue();
1237 if (anArg.IsNull()) {
1238 SetErrorCode("Null shape is given as argument");
1241 if (anArg.ShapeType() != TopAbs_FACE) {
1242 SetErrorCode("Element for face identification is not a face");
1246 //Compute the Face value
1249 TopoDS_Shape aShape;
1251 GEOMImpl_Block6Explorer aBlockTool;
1252 aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1253 aShape = aBlockTool.GetFace(2);
1255 TopTools_IndexedMapOfShape anIndices;
1256 TopExp::MapShapes(aBlockOrComp, anIndices);
1257 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1258 anArray->SetValue(1, anIndices.FindIndex(aShape));
1259 aResult = GetEngine()->AddSubShape(theShape, anArray);
1261 catch (Standard_Failure) {
1262 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1263 SetErrorCode(aFail->GetMessageString());
1267 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1269 //Make a Python command
1270 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
1271 << theShape << ", " << theFace << ")";
1277 //=============================================================================
1281 //=============================================================================
1282 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1283 (Handle(GEOM_Object) theShape,
1284 Handle(GEOM_Object) thePoint)
1289 Handle(GEOM_Object) aResult;
1292 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1294 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1295 if (aBlockOrComp.IsNull()) {
1296 SetErrorCode("Block or compound is null");
1300 TopoDS_Shape anArg = thePoint->GetValue();
1301 if (anArg.IsNull()) {
1302 SetErrorCode("Null shape is given as argument");
1305 if (anArg.ShapeType() != TopAbs_VERTEX) {
1306 SetErrorCode("Element for face identification is not a vertex");
1310 //Compute the Face value
1313 TopoDS_Shape aShape;
1315 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1316 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1317 Standard_Real PX, PY, PZ;
1318 aPnt.Coord(PX, PY, PZ);
1320 // 1. Classify the point relatively each face
1321 Standard_Integer nearest = 2, nbFound = 0;
1322 TopTools_DataMapOfShapeInteger mapShapeDist;
1323 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1324 for (; exp.More(); exp.Next()) {
1325 TopoDS_Shape aFace = exp.Current();
1327 if (!mapShapeDist.IsBound(aFace)) {
1328 Standard_Integer aDistance = 2;
1330 // 1.a. Classify relatively Surface
1331 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1332 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1333 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1334 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1335 Standard_Real aDist = p3dOnSurf.Distance(aPnt);
1336 if (aDist > Precision::Confusion()) {
1340 // 1.b. Classify relatively the face itself
1341 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1342 if (FC.State() == TopAbs_IN) {
1344 } else if (FC.State() == TopAbs_ON) {
1351 if (aDistance < nearest) {
1352 nearest = aDistance;
1356 // A first found face, containing the point inside, will be returned.
1357 // It is the solution, if there are no
1358 // coincident or intersecting faces in the compound.
1359 if (nearest == -1) break;
1361 } else if (aDistance == nearest) {
1366 mapShapeDist.Bind(aFace, aDistance);
1367 } // if (!mapShapeDist.IsBound(aFace))
1370 // 2. Define face, containing the point or having minimum distance to it
1373 // The point is on boundary of some faces and there are
1374 // no faces, having the point inside
1375 SetErrorCode("Multiple faces near the given point are found");
1378 } else if (nearest == 1) {
1379 // The point is outside some faces and there are
1380 // no faces, having the point inside or on boundary.
1381 // We will get a nearest face
1382 Standard_Real bigReal = RealLast();
1383 Standard_Real minDist = bigReal;
1384 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1385 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1386 if (mapShapeDistIter.Value() == 1) {
1387 TopoDS_Shape aFace = mapShapeDistIter.Key();
1388 Standard_Real aDist = bigReal;
1390 // 2.a. Fast check of distance - if point projection on surface is on face
1391 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1392 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1393 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1394 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1395 aDist = p3dOnSurf.Distance(aPnt);
1397 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1398 if (FC.State() == TopAbs_OUT) {
1399 if (aDist < minDist) {
1400 // 2.b. Slow check - if point projection on surface is outside of face
1401 BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
1402 if (!aDistTool.IsDone()) {
1403 SetErrorCode("Can not find a distance from the given point to one of faces");
1406 aDist = aDistTool.Value();
1412 if (aDist < minDist) {
1418 } else { // nearest == -1
1419 // // The point is inside some faces.
1420 // // We will get a face with nearest center
1421 // Standard_Real minDist = RealLast();
1422 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1423 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1424 // if (mapShapeDistIter.Value() == -1) {
1425 // TopoDS_Shape aFace = mapShapeDistIter.Key();
1426 // GProp_GProps aSystem;
1427 // BRepGProp::SurfaceProperties(aFace, aSystem);
1428 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
1430 // Standard_Real aDist = aCenterMass.Distance(aPnt);
1431 // if (aDist < minDist) {
1438 } // if (nbFound > 1)
1441 SetErrorCode("There are no faces near the given point");
1444 TopTools_IndexedMapOfShape anIndices;
1445 TopExp::MapShapes(aBlockOrComp, anIndices);
1446 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1447 anArray->SetValue(1, anIndices.FindIndex(aShape));
1448 aResult = GetEngine()->AddSubShape(theShape, anArray);
1451 catch (Standard_Failure) {
1452 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1453 SetErrorCode(aFail->GetMessageString());
1457 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1459 //Make a Python command
1460 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
1461 << theShape << ", " << thePoint << ")";
1467 //=============================================================================
1471 //=============================================================================
1472 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1473 (Handle(GEOM_Object) theShape,
1474 Handle(GEOM_Object) theVector)
1479 Handle(GEOM_Object) aResult;
1482 if (theShape.IsNull() || theVector.IsNull()) return NULL;
1484 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1485 if (aBlockOrComp.IsNull()) {
1486 SetErrorCode("Block or compound is null");
1490 TopoDS_Shape anArg = theVector->GetValue();
1491 if (anArg.IsNull()) {
1492 SetErrorCode("Null shape is given as argument");
1495 if (anArg.ShapeType() != TopAbs_EDGE) {
1496 SetErrorCode("Element for normale identification is not an edge");
1500 //Compute the Face value
1503 TopoDS_Shape aShape;
1505 TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1506 TopoDS_Vertex V1, V2;
1507 TopExp::Vertices(anEdge, V1, V2, Standard_True);
1508 gp_Pnt P1 = BRep_Tool::Pnt(V1);
1509 gp_Pnt P2 = BRep_Tool::Pnt(V2);
1510 gp_Vec aVec (P1, P2);
1511 if (aVec.Magnitude() < Precision::Confusion()) {
1512 SetErrorCode("Vector with null magnitude is given");
1516 Standard_Real minAngle = RealLast();
1517 TopTools_MapOfShape mapShape;
1518 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1519 for (; exp.More(); exp.Next()) {
1520 if (mapShape.Add(exp.Current())) {
1521 TopoDS_Face aFace = TopoDS::Face(exp.Current());
1522 BRepAdaptor_Surface SF (aFace);
1524 Standard_Real u, v, x;
1526 // find a point on the surface to get normal direction in
1527 u = SF.FirstUParameter();
1528 x = SF.LastUParameter();
1529 if (Precision::IsInfinite(u)) {
1530 u = (Precision::IsInfinite(x)) ? 0. : x;
1531 } else if (!Precision::IsInfinite(x)) {
1535 v = SF.FirstVParameter();
1536 x = SF.LastVParameter();
1537 if (Precision::IsInfinite(v)) {
1538 v = (Precision::IsInfinite(x)) ? 0. : x;
1539 } else if (!Precision::IsInfinite(x)) {
1543 // compute the normal direction
1545 SF.D1(u,v,P1,Vec1,Vec2);
1546 gp_Vec V = Vec1.Crossed(Vec2);
1548 if (V.Magnitude() < Precision::Confusion()) {
1549 SetErrorCode("Normal vector of a face has null magnitude");
1553 // consider the face orientation
1554 if (aFace.Orientation() == TopAbs_REVERSED ||
1555 aFace.Orientation() == TopAbs_INTERNAL) {
1559 // compute the angle and compare with the minimal one
1560 Standard_Real anAngle = aVec.Angle(V);
1561 if (anAngle < minAngle) {
1568 if (aShape.IsNull()) {
1569 SetErrorCode("Failed to find a face by the given normale");
1572 TopTools_IndexedMapOfShape anIndices;
1573 TopExp::MapShapes(aBlockOrComp, anIndices);
1574 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1575 anArray->SetValue(1, anIndices.FindIndex(aShape));
1576 aResult = GetEngine()->AddSubShape(theShape, anArray);
1579 catch (Standard_Failure) {
1580 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1581 SetErrorCode(aFail->GetMessageString());
1585 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1587 //Make a Python command
1588 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
1589 << theShape << ", " << theVector << ")";
1595 //=============================================================================
1597 * GetShapesNearPoint
1599 //=============================================================================
1600 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetShapesNearPoint
1601 (Handle(GEOM_Object) theShape,
1602 Handle(GEOM_Object) thePoint,
1603 const Standard_Integer theShapeType,
1604 const Standard_Real theConstTolerance)
1609 Handle(GEOM_Object) aResult;
1612 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1614 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1615 if (aBlockOrComp.IsNull()) {
1616 SetErrorCode("Block or compound is null");
1620 TopoDS_Shape anArg = thePoint->GetValue();
1621 if (anArg.IsNull()) {
1622 SetErrorCode("Null shape is given as argument");
1625 if (anArg.ShapeType() != TopAbs_VERTEX) {
1626 SetErrorCode("Element for face identification is not a vertex");
1630 if (theShapeType < TopAbs_SOLID || TopAbs_VERTEX < theShapeType) {
1631 SetErrorCode("Invalid type of result is requested");
1635 Standard_Real theTolerance = theConstTolerance;
1636 if (theTolerance < Precision::Confusion()) {
1637 theTolerance = Precision::Confusion();
1640 // Compute the result
1643 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1645 TopTools_MapOfShape mapShape;
1646 Standard_Integer nbEdges = 0;
1647 TopExp_Explorer exp (aBlockOrComp, TopAbs_ShapeEnum(theShapeType));
1648 for (; exp.More(); exp.Next()) {
1649 if (mapShape.Add(exp.Current())) {
1655 SetErrorCode("Given shape contains no sub-shapes of requested type");
1659 // Calculate distances and find min
1661 Standard_Integer ind = 1;
1662 Standard_Real aMinDist = RealLast();
1663 TopTools_Array1OfShape anEdges (1, nbEdges);
1664 TColStd_Array1OfReal aDistances (1, nbEdges);
1665 for (exp.Init(aBlockOrComp, TopAbs_ShapeEnum(theShapeType)); exp.More(); exp.Next()) {
1666 if (mapShape.Add(exp.Current())) {
1667 TopoDS_Shape anEdge = exp.Current();
1668 anEdges(ind) = anEdge;
1670 BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
1671 if (!aDistTool.IsDone()) {
1672 SetErrorCode("Can not find a distance from the given point to one of sub-shapes");
1675 aDistances(ind) = aDistTool.Value();
1676 if (aDistances(ind) < aMinDist) {
1677 aMinDist = aDistances(ind);
1683 if (aMinDist < RealLast()) {
1684 // Collect sub-shapes with distance < (aMinDist + theTolerance)
1685 int nbSubShapes = 0;
1686 TopTools_Array1OfShape aNearShapes (1, nbEdges);
1687 for (ind = 1; ind <= nbEdges; ind++) {
1688 if (aDistances(ind) < aMinDist + theTolerance) {
1690 aNearShapes(nbSubShapes) = anEdges(ind);
1695 TopTools_IndexedMapOfShape anIndices;
1696 TopExp::MapShapes(aBlockOrComp, anIndices);
1697 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger (1, nbSubShapes);
1698 for (ind = 1; ind <= nbSubShapes; ind++) {
1699 anArray->SetValue(ind, anIndices.FindIndex(aNearShapes(ind)));
1701 aResult = GetEngine()->AddSubShape(theShape, anArray);
1704 catch (Standard_Failure) {
1705 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1706 SetErrorCode(aFail->GetMessageString());
1710 if (aResult.IsNull())
1713 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1715 //Make a Python command
1716 GEOM::TPythonDump(aFunction)
1717 << aResult << " = geompy.GetShapesNearPoint(" << theShape << ", " << thePoint
1718 << ", " << TopAbs_ShapeEnum(theShapeType) << ", " << theTolerance << ")";
1724 //=============================================================================
1726 * IsCompoundOfBlocks
1728 //=============================================================================
1729 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1730 (Handle(GEOM_Object) theCompound,
1731 const Standard_Integer theMinNbFaces,
1732 const Standard_Integer theMaxNbFaces,
1733 Standard_Integer& theNbBlocks)
1736 Standard_Boolean isCompOfBlocks = Standard_False;
1739 if (theCompound.IsNull()) return isCompOfBlocks;
1740 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1743 isCompOfBlocks = Standard_True;
1746 TopTools_MapOfShape mapShape;
1747 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1748 for (; exp.More(); exp.Next()) {
1749 if (mapShape.Add(exp.Current())) {
1750 TopoDS_Shape aSolid = exp.Current();
1752 TopTools_MapOfShape mapFaces;
1753 TopExp_Explorer expF (aSolid, TopAbs_FACE);
1754 Standard_Integer nbFaces = 0;
1755 for (; expF.More(); expF.Next()) {
1756 if (mapFaces.Add(expF.Current())) {
1758 if (nbFaces > theMaxNbFaces) {
1759 isCompOfBlocks = Standard_False;
1764 if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1765 isCompOfBlocks = Standard_False;
1772 catch (Standard_Failure) {
1773 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1774 SetErrorCode(aFail->GetMessageString());
1775 return isCompOfBlocks;
1779 return isCompOfBlocks;
1782 //=============================================================================
1784 * Set of functions, used by CheckCompoundOfBlocks() method
1786 //=============================================================================
1787 void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
1788 TopTools_ListOfShape& BLO,
1789 TopTools_ListOfShape& NOT,
1790 TopTools_ListOfShape& EXT,
1791 TopTools_ListOfShape& NOQ,
1792 const Standard_Real theToleranceC1)
1794 TopAbs_ShapeEnum aType = theShape.ShapeType();
1796 case TopAbs_COMPOUND:
1797 case TopAbs_COMPSOLID:
1799 TopoDS_Iterator It (theShape);
1800 for (; It.More(); It.Next()) {
1801 AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ, theToleranceC1);
1807 // Check, if there are seam or degenerated edges
1808 BlockFix_CheckTool aTool;
1809 aTool.SetShape(theShape);
1810 aTool.SetAngTolerance(theToleranceC1);
1812 if (aTool.NbPossibleBlocks() > 0) {
1813 EXT.Append(theShape);
1815 // Count faces and edges in each face to recognize blocks
1816 TopTools_MapOfShape mapFaces;
1817 Standard_Integer nbFaces = 0;
1818 Standard_Boolean hasNonQuadr = Standard_False;
1819 TopExp_Explorer expF (theShape, TopAbs_FACE);
1821 for (; expF.More(); expF.Next()) {
1822 TopoDS_Face aF = TopoDS::Face(expF.Current());
1824 if (mapFaces.Add(aF)) {
1827 if (!IsQuadrangle(aF, theToleranceC1)) {
1828 hasNonQuadr = Standard_True;
1829 NOQ.Append(aF);//0021483
1834 if (nbFaces == 6 && !hasNonQuadr) {
1835 BLO.Append(theShape);
1837 NOT.Append(theShape);
1842 case TopAbs_SHELL: //0021483
1843 case TopAbs_FACE: //0021483
1845 // Count edges in each face
1846 TopTools_MapOfShape mapFaces;
1847 TopExp_Explorer expF (theShape, TopAbs_FACE);
1848 for (; expF.More(); expF.Next()) {
1849 TopoDS_Face aF = TopoDS::Face(expF.Current());
1851 if (mapFaces.Add(aF)) {
1852 if (!IsQuadrangle(aF, theToleranceC1)) {
1853 NOQ.Append(aF);//0021483
1860 NOT.Append(theShape);
1864 #define REL_NOT_CONNECTED 0
1866 #define REL_NOT_GLUED 2
1867 #define REL_COLLISION_VV 3
1868 #define REL_COLLISION_FF 4
1869 #define REL_COLLISION_EE 5
1870 #define REL_UNKNOWN 6
1872 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1873 const TopoDS_Shape& theBlock2)
1875 // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1876 Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1877 Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1879 BRepBndLib::Add(theBlock1, B1);
1880 BRepBndLib::Add(theBlock2, B2);
1881 B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1882 B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1883 if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1884 Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1885 Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1886 return REL_NOT_CONNECTED;
1889 BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1890 if (!dst.IsDone()) {
1894 if (dst.Value() > Precision::Confusion()) {
1895 return REL_NOT_CONNECTED;
1898 if (dst.InnerSolution()) {
1899 return REL_COLLISION_VV;
1902 Standard_Integer nbSol = dst.NbSolution();
1903 Standard_Integer relation = REL_OK;
1904 Standard_Integer nbVerts = 0;
1905 Standard_Integer nbEdges = 0;
1906 Standard_Integer sol = 1;
1907 for (; sol <= nbSol; sol++) {
1908 BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1909 BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1910 if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1912 } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1913 return REL_COLLISION_FF;
1914 } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1916 } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1917 (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1918 relation = REL_COLLISION_EE;
1923 if (relation != REL_OK) {
1927 TColStd_Array1OfInteger vertSol (1, nbVerts);
1928 TopTools_Array1OfShape V1 (1, nbVerts);
1929 TopTools_Array1OfShape V2 (1, nbVerts);
1930 Standard_Integer ivs = 0;
1931 for (sol = 1; sol <= nbSol; sol++) {
1932 if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1933 dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1934 TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1935 // Check, that this vertex is far enough from other solution vertices.
1936 Standard_Integer ii = 1;
1937 for (; ii <= ivs; ii++) {
1938 if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1945 V2(ivs) = dst.SupportOnShape2(sol);
1949 // As we deal only with quadrangles,
1950 // 2, 3 or 4 vertex solutions can be found.
1953 return REL_COLLISION_FF;
1955 return REL_NOT_CONNECTED;
1961 // Check sharing of coincident entities.
1962 if (ivs == 2 || ivs == 3) {
1963 // Map vertices and edges of the blocks
1964 TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1965 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1966 (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1967 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1968 (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1972 TopoDS_Shape anEdge1, anEdge2;
1973 GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1974 if (anEdge1.IsNull()) return REL_UNKNOWN;
1976 GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1977 if (anEdge2.IsNull()) return REL_UNKNOWN;
1979 if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1981 } else { // ivs == 3
1982 // Find common edges
1983 Standard_Integer e1_v1 = 1;
1984 Standard_Integer e1_v2 = 2;
1985 Standard_Integer e2_v1 = 3;
1986 Standard_Integer e2_v2 = 1;
1988 TopoDS_Shape anEdge11, anEdge12;
1989 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1990 if (anEdge11.IsNull()) {
1993 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1994 if (anEdge11.IsNull()) return REL_UNKNOWN;
1996 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1997 if (anEdge12.IsNull()) {
1999 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
2000 if (anEdge12.IsNull()) return REL_UNKNOWN;
2003 TopoDS_Shape anEdge21, anEdge22;
2004 GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
2005 if (anEdge21.IsNull()) return REL_UNKNOWN;
2006 GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
2007 if (anEdge22.IsNull()) return REL_UNKNOWN;
2009 // Check of edges coincidence (with some precision) have to be done here
2010 // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
2011 // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
2013 // Check of edges sharing
2014 if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
2015 if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
2020 // Map vertices and faces of the blocks
2021 TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
2022 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2023 (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
2024 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2025 (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
2027 TopoDS_Shape aFace1, aFace2;
2028 GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
2029 if (aFace1.IsNull()) return REL_UNKNOWN;
2030 GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
2031 if (aFace2.IsNull()) return REL_UNKNOWN;
2033 // Check of faces coincidence (with some precision) have to be done here
2034 // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
2036 // Check of faces sharing
2037 if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
2043 void FindConnected (const Standard_Integer theBlockIndex,
2044 const TColStd_Array2OfInteger& theRelations,
2045 TColStd_MapOfInteger& theProcessedMap,
2046 TColStd_MapOfInteger& theConnectedMap)
2048 theConnectedMap.Add(theBlockIndex);
2049 theProcessedMap.Add(theBlockIndex);
2051 Standard_Integer nbBlocks = theRelations.ColLength();
2052 Standard_Integer col = 1;
2053 for (; col <= nbBlocks; col++) {
2054 if (theRelations(theBlockIndex, col) == REL_OK ||
2055 theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
2056 if (!theProcessedMap.Contains(col)) {
2057 FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
2063 Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
2064 const TColStd_MapOfInteger& theWith,
2065 const TColStd_Array2OfInteger& theRelations,
2066 TColStd_MapOfInteger& theProcessedMap)
2068 theProcessedMap.Add(theBlockIndex);
2070 Standard_Integer nbBlocks = theRelations.ColLength();
2071 Standard_Integer col = 1;
2072 for (; col <= nbBlocks; col++) {
2073 if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
2074 if (!theProcessedMap.Contains(col)) {
2075 if (theWith.Contains(col))
2076 return Standard_True;
2077 if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
2078 return Standard_True;
2083 return Standard_False;
2086 //=============================================================================
2090 //=============================================================================
2091 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2092 (Handle(GEOM_Object) theCompound,
2093 const std::list<BCError>& theErrors)
2095 TCollection_AsciiString aDescr;
2097 std::list<BCError>::const_iterator errIt = theErrors.begin();
2099 for (; errIt != theErrors.end(); i++, errIt++) {
2100 BCError errStruct = *errIt;
2102 switch (errStruct.error) {
2104 aDescr += "\n\tNot a Blocks: ";
2107 aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
2109 case INVALID_CONNECTION:
2110 aDescr += "\n\tInvalid connection between two blocks: ";
2113 aDescr += "\n\tBlocks, not connected with main body: ";
2116 aDescr += "\n\tNot glued blocks: ";
2122 std::list<int> sshList = errStruct.incriminated;
2123 std::list<int>::iterator sshIt = sshList.begin();
2125 for (; sshIt != sshList.end(); jj++, sshIt++) {
2128 aDescr += TCollection_AsciiString(*sshIt);
2135 //=============================================================================
2137 * CheckCompoundOfBlocks
2139 //=============================================================================
2140 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
2141 (Handle(GEOM_Object) theCompound,
2142 const Standard_Real theToleranceC1,
2143 std::list<BCError>& theErrors)
2147 if (theCompound.IsNull()) return Standard_False;
2148 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2150 Standard_Boolean isCompOfBlocks = Standard_True;
2152 // Map sub-shapes and their indices
2153 TopTools_IndexedMapOfShape anIndices;
2154 TopExp::MapShapes(aBlockOrComp, anIndices);
2156 // 1. Separate blocks from non-blocks
2157 TopTools_ListOfShape NOT; // Not blocks
2158 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2159 TopTools_ListOfShape BLO; // All blocks from the given compound
2160 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2161 AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ, theToleranceC1);
2163 // Report non-blocks
2164 if (NOT.Extent() > 0) {
2165 isCompOfBlocks = Standard_False;
2167 anErr.error = NOT_BLOCK;
2168 TopTools_ListIteratorOfListOfShape it (NOT);
2169 for (; it.More(); it.Next()) {
2170 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2172 theErrors.push_back(anErr);
2175 // Report solids, having degenerated and/or seam edges
2176 if (EXT.Extent() > 0) {
2177 isCompOfBlocks = Standard_False;
2179 anErr.error = EXTRA_EDGE;
2180 TopTools_ListIteratorOfListOfShape it (EXT);
2181 for (; it.More(); it.Next()) {
2182 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2184 theErrors.push_back(anErr);
2187 Standard_Integer nbBlocks = BLO.Extent();
2188 if (nbBlocks == 0) {
2189 isCompOfBlocks = Standard_False;
2191 return isCompOfBlocks;
2193 if (nbBlocks == 1) {
2195 return isCompOfBlocks;
2198 // Prepare data for 2. and 3.
2199 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2200 aRelations.Init(REL_NOT_CONNECTED);
2202 TopTools_IndexedMapOfShape mapBlocks;
2205 TopoDS_Compound aComp;
2206 BB.MakeCompound(aComp);
2208 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2209 for (; BLOit.More(); BLOit.Next()) {
2210 mapBlocks.Add(BLOit.Value());
2211 BB.Add(aComp, BLOit.Value());
2214 // 2. Find glued blocks (having shared faces)
2215 TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
2216 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2217 (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
2219 Standard_Integer prevInd = 0, curInd = 0;
2220 Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
2221 for (; ind <= nbFaces; ind++) {
2222 const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
2223 if (aGluedBlocks.Extent() > 1) { // Shared face found
2224 TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
2225 TopoDS_Shape prevBlock, curBlock;
2226 for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
2227 curBlock = aGluedBlocksIt.Value();
2228 if (!prevBlock.IsNull()) {
2229 prevInd = mapBlocks.FindIndex(prevBlock);
2230 curInd = mapBlocks.FindIndex(curBlock);
2231 aRelations.SetValue(prevInd, curInd, REL_OK);
2232 aRelations.SetValue(curInd, prevInd, REL_OK);
2234 prevBlock = curBlock;
2239 // 3. Find not glued blocks
2240 GEOMAlgo_GlueAnalyser aGD;
2242 aGD.SetShape(aComp);
2243 aGD.SetTolerance(Precision::Confusion());
2244 aGD.SetCheckGeometry(Standard_True);
2247 Standard_Integer iErr, iWrn;
2248 iErr = aGD.ErrorStatus();
2250 SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
2251 return isCompOfBlocks;
2253 iWrn = aGD.WarningStatus();
2255 MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
2258 // Report not glued blocks
2259 if (aGD.HasSolidsToGlue()) {
2260 isCompOfBlocks = Standard_False;
2261 Standard_Integer aSx1Ind, aSx2Ind;
2263 const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
2264 GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
2265 for (; aItCS.More(); aItCS.Next()) {
2266 const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
2267 const TopoDS_Shape& aSx1 = aCS.Shape1();
2268 const TopoDS_Shape& aSx2 = aCS.Shape2();
2270 aSx1Ind = mapBlocks.FindIndex(aSx1);
2271 aSx2Ind = mapBlocks.FindIndex(aSx2);
2272 aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
2273 aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
2276 anErr.error = NOT_GLUED;
2277 anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
2278 anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
2279 theErrors.push_back(anErr);
2283 // 4. Find largest set of connected (good connection or not glued) blocks
2284 Standard_Integer ibl = 1;
2285 TColStd_MapOfInteger aProcessedMap;
2286 TColStd_MapOfInteger aLargestSet;
2287 TColStd_MapOfInteger aCurrentSet;
2288 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2289 if (!aProcessedMap.Contains(ibl)) {
2290 aCurrentSet.Clear();
2291 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2292 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2293 aLargestSet = aCurrentSet;
2298 // 5. Report all blocks, isolated from <aLargestSet>
2300 anErr.error = NOT_CONNECTED;
2301 Standard_Boolean hasIsolated = Standard_False;
2302 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2303 if (!aLargestSet.Contains(ibl)) {
2304 aProcessedMap.Clear();
2305 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2306 // report connection absence
2307 hasIsolated = Standard_True;
2308 anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
2313 isCompOfBlocks = Standard_False;
2314 theErrors.push_back(anErr);
2318 return isCompOfBlocks;
2321 //=============================================================================
2325 //=============================================================================
2326 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks
2327 (Handle(GEOM_Object) theShape,
2328 const Standard_Real theToleranceC1,
2329 Handle(GEOM_Object)& theNonQuads)
2333 if (theShape.IsNull()) return NULL;
2334 TopoDS_Shape aShape = theShape->GetValue();
2336 // Separate blocks from non-blocks
2337 TopTools_ListOfShape BLO; // All blocks from the given compound
2338 TopTools_ListOfShape NOT; // Not blocks
2339 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2340 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2341 AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ, theToleranceC1);
2343 if (NOT.IsEmpty() && EXT.IsEmpty() && NOQ.IsEmpty()) {
2344 SetErrorCode("NOT_FOUND_ANY");
2348 // Map sub-shapes and their indices
2349 TopTools_IndexedMapOfShape anIndices;
2350 TopExp::MapShapes(aShape, anIndices);
2353 Handle(GEOM_Object) aNonBlocks;
2354 if (NOT.Extent() > 0 || EXT.Extent() > 0) {
2355 Handle(TColStd_HArray1OfInteger) anArray =
2356 new TColStd_HArray1OfInteger (1, NOT.Extent() + EXT.Extent());
2357 Standard_Integer ii = 1;
2358 TopTools_ListIteratorOfListOfShape it1 (NOT);
2359 for (; it1.More(); it1.Next(), ii++) {
2360 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2362 TopTools_ListIteratorOfListOfShape it2 (EXT);
2363 for (; it2.More(); it2.Next(), ii++) {
2364 anArray->SetValue(ii, anIndices.FindIndex(it2.Value()));
2367 aNonBlocks = GetEngine()->AddSubShape(theShape, anArray);
2368 if (aNonBlocks.IsNull()) {
2369 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2372 aNonBlocks->SetType(GEOM_GROUP);
2373 TDF_Label aFreeLabel = aNonBlocks->GetFreeLabel();
2374 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_SOLID);
2378 if (NOQ.Extent() > 0) {
2379 Handle(TColStd_HArray1OfInteger) anArray =
2380 new TColStd_HArray1OfInteger (1, NOQ.Extent());
2381 Standard_Integer ii = 1;
2382 TopTools_ListIteratorOfListOfShape it1 (NOQ);
2383 for (; it1.More(); it1.Next(), ii++) {
2384 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2387 theNonQuads = GetEngine()->AddSubShape(theShape, anArray);
2388 if (theNonQuads.IsNull()) {
2389 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2392 theNonQuads->SetType(GEOM_GROUP);
2393 TDF_Label aFreeLabel = theNonQuads->GetFreeLabel();
2394 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_FACE);
2397 //Make a Python command
2398 Handle(GEOM_Function) aMainShape = theShape->GetLastFunction();
2399 GEOM::TPythonDump pd (aMainShape, /*append=*/true);
2401 if (aNonBlocks.IsNull())
2402 pd << "no_bad_solids";
2406 if (theNonQuads.IsNull())
2407 pd << "no_bad_faces";
2410 pd << ") = geompy.GetNonBlocks(" << theShape << ")";
2416 //=============================================================================
2420 //=============================================================================
2421 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
2422 (Handle(GEOM_Object) theObject,
2423 const Standard_Integer theOptimumNbFaces)
2427 if (theObject.IsNull()) return NULL;
2429 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2430 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2432 //Add a new Copy object
2433 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2436 Handle(GEOM_Function) aFunction =
2437 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
2439 //Check if the function is set correctly
2440 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2442 GEOMImpl_IBlockTrsf aTI (aFunction);
2443 aTI.SetOriginal(aLastFunction);
2444 aTI.SetOptimumNbFaces(theOptimumNbFaces);
2446 //Compute the fixed shape
2449 if (!GetSolver()->ComputeFunction(aFunction)) {
2450 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2454 catch (Standard_Failure) {
2455 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2456 SetErrorCode(aFail->GetMessageString());
2460 //Make a Python command
2461 std::string doUnionFaces = (theOptimumNbFaces < 0) ? "False" : "True";
2462 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.RemoveExtraEdges("
2463 << theObject << ", " << doUnionFaces.data() << ")";
2469 //=============================================================================
2473 //=============================================================================
2474 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::UnionFaces
2475 (Handle(GEOM_Object) theObject)
2479 if (theObject.IsNull()) return NULL;
2481 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2482 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2484 //Add a new Copy object
2485 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2488 Handle(GEOM_Function) aFunction =
2489 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_UNION_FACES);
2491 //Check if the function is set correctly
2492 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2494 GEOMImpl_IBlockTrsf aTI (aFunction);
2495 aTI.SetOriginal(aLastFunction);
2497 //Compute the fixed shape
2500 if (!GetSolver()->ComputeFunction(aFunction)) {
2501 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2505 catch (Standard_Failure) {
2506 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2507 SetErrorCode(aFail->GetMessageString());
2511 //Make a Python command
2512 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.UnionFaces("
2513 << theObject << ")";
2519 //=============================================================================
2523 //=============================================================================
2524 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
2525 (Handle(GEOM_Object) theObject)
2529 if (theObject.IsNull()) return NULL;
2531 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2532 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2534 //Add a new Copy object
2535 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2538 Handle(GEOM_Function) aFunction =
2539 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
2541 //Check if the function is set correctly
2542 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2544 GEOMImpl_IBlockTrsf aTI (aFunction);
2545 aTI.SetOriginal(aLastFunction);
2547 // -1 means do not unite faces on common surface (?except case of seam edge between them?)
2548 //aTI.SetOptimumNbFaces(-1);
2549 aTI.SetOptimumNbFaces(6);
2551 //Compute the fixed shape
2554 if (!GetSolver()->ComputeFunction(aFunction)) {
2555 SetErrorCode("Block driver failed to improve the given blocks compound");
2559 catch (Standard_Failure) {
2560 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2561 SetErrorCode(aFail->GetMessageString());
2565 //Make a Python command
2566 GEOM::TPythonDump(aFunction) << aCopy
2567 << " = geompy.CheckAndImprove(" << theObject << ")";
2573 //=============================================================================
2575 * ExplodeCompoundOfBlocks
2577 //=============================================================================
2578 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2579 (Handle(GEOM_Object) theCompound,
2580 const Standard_Integer theMinNbFaces,
2581 const Standard_Integer theMaxNbFaces)
2585 if (theCompound.IsNull()) return NULL;
2586 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2587 if (aBlockOrComp.IsNull()) return NULL;
2589 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2590 Handle(GEOM_Object) anObj;
2591 Handle(GEOM_Function) aFunction;
2593 TopTools_MapOfShape mapShape;
2594 TCollection_AsciiString anAsciiList, anEntry;
2597 TopTools_IndexedMapOfShape anIndices;
2598 TopExp::MapShapes(aBlockOrComp, anIndices);
2599 Handle(TColStd_HArray1OfInteger) anArray;
2604 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2605 for (; exp.More(); exp.Next()) {
2606 if (mapShape.Add(exp.Current())) {
2607 TopoDS_Shape aSolid = exp.Current();
2609 TopTools_MapOfShape mapFaces;
2610 TopExp_Explorer expF (aSolid, TopAbs_FACE);
2611 Standard_Integer nbFaces = 0;
2612 for (; expF.More(); expF.Next()) {
2613 if (mapFaces.Add(expF.Current())) {
2618 if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2619 anArray = new TColStd_HArray1OfInteger(1,1);
2620 anArray->SetValue(1, anIndices.FindIndex(aSolid));
2621 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2622 aBlocks->Append(anObj);
2624 //Make a Python command
2625 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2626 anAsciiList += anEntry + ", ";
2631 catch (Standard_Failure) {
2632 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2633 SetErrorCode(aFail->GetMessageString());
2637 if (aBlocks->IsEmpty()) {
2638 SetErrorCode("There are no specified blocks in the given shape");
2642 anAsciiList.Trunc(anAsciiList.Length() - 2);
2644 //The explode doesn't change object so no new function is required.
2645 aFunction = theCompound->GetLastFunction();
2647 //Make a Python command
2648 GEOM::TPythonDump(aFunction, /*append=*/true)
2649 << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
2650 << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
2656 //=============================================================================
2660 //=============================================================================
2661 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2662 (Handle(GEOM_Object) theCompound,
2663 Handle(GEOM_Object) thePoint)
2668 Handle(GEOM_Object) aResult;
2671 if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2673 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2674 if (aBlockOrComp.IsNull()) {
2675 SetErrorCode("Compound is null");
2678 if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2679 aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2680 SetErrorCode("Shape to find block in is not a compound");
2684 TopoDS_Shape anArg = thePoint->GetValue();
2685 if (anArg.IsNull()) {
2686 SetErrorCode("Point is null");
2689 if (anArg.ShapeType() != TopAbs_VERTEX) {
2690 SetErrorCode("Shape for block identification is not a vertex");
2694 //Compute the Block value
2697 TopoDS_Shape aShape;
2699 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2700 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2701 Standard_Real PX, PY, PZ;
2702 aPnt.Coord(PX, PY, PZ);
2704 // 1. Classify the point relatively each block
2705 Standard_Integer nearest = 2, nbFound = 0;
2706 TopTools_DataMapOfShapeInteger mapShapeDist;
2707 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2708 for (; exp.More(); exp.Next()) {
2709 TopoDS_Shape aSolid = exp.Current();
2711 if (!mapShapeDist.IsBound(aSolid)) {
2712 Standard_Integer aDistance = 2;
2714 // 1.a. Classify relatively Bounding box
2715 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2717 BRepBndLib::Add(aSolid, BB);
2718 BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2719 if (PX < Xmin || Xmax < PX ||
2720 PY < Ymin || Ymax < PY ||
2721 PZ < Zmin || Zmax < PZ) {
2722 // OUT of bounding box
2725 // 1.b. Classify relatively the solid itself
2726 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2727 if (SC.State() == TopAbs_IN) {
2729 } else if (SC.State() == TopAbs_ON) {
2736 if (aDistance < nearest) {
2737 nearest = aDistance;
2741 // A first found block, containing the point inside, will be returned.
2742 // It is the solution, if there are no intersecting blocks in the compound.
2743 if (nearest == -1) break;
2745 } else if (aDistance == nearest) {
2750 mapShapeDist.Bind(aSolid, aDistance);
2751 } // if (!mapShapeDist.IsBound(aSolid))
2754 // 2. Define block, containing the point or having minimum distance to it
2757 // The point is on boundary of some blocks and there are
2758 // no blocks, having the point inside their volume
2759 SetErrorCode("Multiple blocks near the given point are found");
2762 } else if (nearest == 1) {
2763 // The point is outside some blocks and there are
2764 // no blocks, having the point inside or on boundary.
2765 // We will get a nearest block
2766 Standard_Real minDist = RealLast();
2767 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2768 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2769 if (mapShapeDistIter.Value() == 1) {
2770 TopoDS_Shape aSolid = mapShapeDistIter.Key();
2771 BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
2772 if (!aDistTool.IsDone()) {
2773 SetErrorCode("Can not find a distance from the given point to one of blocks");
2776 Standard_Real aDist = aDistTool.Value();
2777 if (aDist < minDist) {
2783 } else { // nearest == -1
2784 // // The point is inside some blocks.
2785 // // We will get a block with nearest center
2786 // Standard_Real minDist = RealLast();
2787 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2788 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2789 // if (mapShapeDistIter.Value() == -1) {
2790 // TopoDS_Shape aSolid = mapShapeDistIter.Key();
2791 // GProp_GProps aSystem;
2792 // BRepGProp::VolumeProperties(aSolid, aSystem);
2793 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
2795 // Standard_Real aDist = aCenterMass.Distance(aPnt);
2796 // if (aDist < minDist) {
2803 } // if (nbFound > 1)
2806 SetErrorCode("There are no blocks near the given point");
2809 TopTools_IndexedMapOfShape anIndices;
2810 TopExp::MapShapes(aBlockOrComp, anIndices);
2811 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2812 anArray->SetValue(1, anIndices.FindIndex(aShape));
2813 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2816 catch (Standard_Failure) {
2817 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2818 SetErrorCode(aFail->GetMessageString());
2822 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2824 //Make a Python command
2825 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
2826 << theCompound << ", " << thePoint << ")";
2832 //=============================================================================
2836 //=============================================================================
2837 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2838 (Handle(GEOM_Object) theCompound,
2839 const Handle(TColStd_HSequenceOfTransient)& theParts)
2843 Handle(GEOM_Object) aResult;
2845 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2846 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2847 if (aBlockOrComp.IsNull()) return NULL;
2850 Standard_Integer argi, aLen = theParts->Length();
2851 TopTools_Array1OfShape anArgs (1, aLen);
2852 TCollection_AsciiString anEntry, aPartsDescr;
2853 for (argi = 1; argi <= aLen; argi++) {
2854 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2855 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2856 if (aRef.IsNull()) return NULL;
2858 TopoDS_Shape anArg = aRef->GetValue();
2859 if (anArg.IsNull()) {
2860 SetErrorCode("Null shape is given as argument");
2863 anArgs(argi) = anArg;
2865 // For Python command
2866 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2867 if (argi > 1) aPartsDescr += ", ";
2868 aPartsDescr += anEntry;
2871 //Compute the Block value
2874 // 1. Explode compound on solids
2875 TopTools_MapOfShape mapShape;
2876 Standard_Integer nbSolids = 0;
2877 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2878 for (; exp.More(); exp.Next()) {
2879 if (mapShape.Add(exp.Current())) {
2885 Standard_Integer ind = 1;
2886 TopTools_Array1OfShape aSolids (1, nbSolids);
2887 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2888 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2889 if (mapShape.Add(exp.Current())) {
2890 TopoDS_Shape aSolid = exp.Current();
2891 aSolids(ind) = aSolid;
2894 // 2. Define quantity of parts, contained in each solid
2895 TopTools_IndexedMapOfShape aSubShapes;
2896 TopExp::MapShapes(aSolid, aSubShapes);
2897 for (argi = 1; argi <= aLen; argi++) {
2898 if (aSubShapes.Contains(anArgs(argi))) {
2905 // 3. Define solid, containing maximum quantity of parts
2906 Standard_Integer maxNb = 0, nbFound = 0;
2907 TopoDS_Shape aShape;
2908 for (ind = 1; ind <= nbSolids; ind++) {
2909 if (aNbParts(ind) > maxNb) {
2910 maxNb = aNbParts(ind);
2911 aShape = aSolids(ind);
2913 } else if (aNbParts(ind) == maxNb) {
2919 SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
2921 } else if (nbFound == 0) {
2922 SetErrorCode("There are no blocks, containing the given parts");
2925 TopTools_IndexedMapOfShape anIndices;
2926 TopExp::MapShapes(aBlockOrComp, anIndices);
2927 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2928 anArray->SetValue(1, anIndices.FindIndex(aShape));
2929 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2931 } catch (Standard_Failure) {
2932 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2933 SetErrorCode(aFail->GetMessageString());
2937 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2939 //Make a Python command
2940 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
2941 << theCompound << ", [" << aPartsDescr.ToCString() << "])";
2947 //=============================================================================
2951 //=============================================================================
2952 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
2953 (Handle(GEOM_Object) theCompound,
2954 const Handle(TColStd_HSequenceOfTransient)& theParts)
2958 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2959 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2960 if (aBlockOrComp.IsNull()) return NULL;
2962 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2963 Handle(GEOM_Object) anObj;
2964 Handle(GEOM_Function) aFunction;
2967 Standard_Integer argi, aLen = theParts->Length();
2968 TopTools_Array1OfShape anArgs (1, aLen);
2969 TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
2971 for (argi = 1; argi <= aLen; argi++) {
2972 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2973 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2974 if (aRef.IsNull()) return NULL;
2976 TopoDS_Shape anArg = aRef->GetValue();
2977 if (anArg.IsNull()) {
2978 SetErrorCode("Null shape is given as argument");
2981 anArgs(argi) = anArg;
2983 // For Python command
2984 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2985 aPartsDescr += anEntry + ", ";
2991 TopTools_MapOfShape mapShape;
2992 Standard_Integer nbSolids = 0;
2993 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2994 for (; exp.More(); exp.Next()) {
2995 if (mapShape.Add(exp.Current())) {
3001 Standard_Integer ind = 1;
3002 TopTools_Array1OfShape aSolids (1, nbSolids);
3003 TColStd_Array1OfInteger aNbParts (1, nbSolids);
3004 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
3005 if (mapShape.Add(exp.Current())) {
3006 TopoDS_Shape aSolid = exp.Current();
3007 aSolids(ind) = aSolid;
3010 // 2. Define quantity of parts, contained in each solid
3011 TopTools_IndexedMapOfShape aSubShapes;
3012 TopExp::MapShapes(aSolid, aSubShapes);
3013 for (argi = 1; argi <= aLen; argi++) {
3014 if (aSubShapes.Contains(anArgs(argi))) {
3021 // 3. Define solid, containing maximum quantity of parts
3022 Standard_Integer maxNb = 0, nbFound = 0;
3023 for (ind = 1; ind <= nbSolids; ind++) {
3024 if (aNbParts(ind) > maxNb) {
3025 maxNb = aNbParts(ind);
3027 } else if (aNbParts(ind) == maxNb) {
3033 SetErrorCode("There are no blocks, containing the given parts");
3038 TopTools_IndexedMapOfShape anIndices;
3039 TopExp::MapShapes(aBlockOrComp, anIndices);
3040 Handle(TColStd_HArray1OfInteger) anArray;
3042 for (ind = 1; ind <= nbSolids; ind++) {
3043 if (aNbParts(ind) == maxNb) {
3044 anArray = new TColStd_HArray1OfInteger(1,1);
3045 anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
3046 anObj = GetEngine()->AddSubShape(theCompound, anArray);
3047 aBlocks->Append(anObj);
3049 // For Python command
3050 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
3051 anAsciiList += anEntry + ", ";
3052 if (aFunction.IsNull())
3053 aFunction = anObj->GetLastFunction();
3057 catch (Standard_Failure) {
3058 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3059 SetErrorCode(aFail->GetMessageString());
3063 //Make a Python command
3064 aPartsDescr.Trunc(aPartsDescr.Length() - 2);
3065 anAsciiList.Trunc(anAsciiList.Length() - 2);
3067 GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
3068 << "] = geompy.GetBlocksByParts(" << theCompound
3069 << ", [" << aPartsDescr.ToCString() << "])";
3075 //=============================================================================
3077 * MakeMultiTransformation1D
3079 //=============================================================================
3080 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
3081 (Handle(GEOM_Object) theObject,
3082 const Standard_Integer theDirFace1,
3083 const Standard_Integer theDirFace2,
3084 const Standard_Integer theNbTimes)
3088 if (theObject.IsNull()) return NULL;
3090 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3091 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3093 //Add a new Copy object
3094 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3096 //Add a translate function
3097 Handle(GEOM_Function) aFunction =
3098 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
3100 //Check if the function is set correctly
3101 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3103 GEOMImpl_IBlockTrsf aTI (aFunction);
3104 aTI.SetOriginal(aLastFunction);
3105 aTI.SetFace1U(theDirFace1);
3106 aTI.SetFace2U(theDirFace2);
3107 aTI.SetNbIterU(theNbTimes);
3109 //Compute the transformation
3112 if (!GetSolver()->ComputeFunction(aFunction)) {
3113 SetErrorCode("Block driver failed to make multi-transformation");
3117 catch (Standard_Failure) {
3118 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3119 SetErrorCode(aFail->GetMessageString());
3123 //Make a Python command
3124 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
3125 << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
3131 //=============================================================================
3133 * MakeMultiTransformation2D
3135 //=============================================================================
3136 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
3137 (Handle(GEOM_Object) theObject,
3138 const Standard_Integer theDirFace1U,
3139 const Standard_Integer theDirFace2U,
3140 const Standard_Integer theNbTimesU,
3141 const Standard_Integer theDirFace1V,
3142 const Standard_Integer theDirFace2V,
3143 const Standard_Integer theNbTimesV)
3147 if (theObject.IsNull()) return NULL;
3149 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3150 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3152 //Add a new Copy object
3153 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3155 //Add a translate function
3156 Handle(GEOM_Function) aFunction =
3157 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
3159 //Check if the function is set correctly
3160 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3162 GEOMImpl_IBlockTrsf aTI (aFunction);
3163 aTI.SetOriginal(aLastFunction);
3164 aTI.SetFace1U(theDirFace1U);
3165 aTI.SetFace2U(theDirFace2U);
3166 aTI.SetNbIterU(theNbTimesU);
3167 aTI.SetFace1V(theDirFace1V);
3168 aTI.SetFace2V(theDirFace2V);
3169 aTI.SetNbIterV(theNbTimesV);
3171 //Compute the transformation
3174 if (!GetSolver()->ComputeFunction(aFunction)) {
3175 SetErrorCode("Block driver failed to make multi-transformation");
3179 catch (Standard_Failure) {
3180 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3181 SetErrorCode(aFail->GetMessageString());
3185 //Make a Python command
3186 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
3187 << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
3188 << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
3194 //=============================================================================
3198 //=============================================================================
3199 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
3200 (Handle(GEOM_Object) theShape)
3204 if (theShape.IsNull()) return NULL;
3206 TopoDS_Shape aShape = theShape->GetValue();
3207 if (aShape.IsNull()) return NULL;
3209 TopTools_IndexedMapOfShape anIndices;
3210 TopExp::MapShapes(aShape, anIndices);
3212 TopTools_IndexedDataMapOfShapeListOfShape MEW;
3213 GEOMImpl_Block6Explorer::MapShapesAndAncestors
3214 (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
3215 Standard_Integer ie, nbEdges = MEW.Extent();
3218 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3220 TopTools_MapOfShape mapAcceptedEdges;
3221 TCollection_AsciiString aListRes, anEntry;
3223 // Sort shapes in current chain (Mantis issue 21053)
3224 TopTools_DataMapOfShapeListOfShape aMapChains;
3225 TopTools_ListOfShape aFirstInChains;
3227 for (ie = 1; ie <= nbEdges; ie++) {
3228 TopoDS_Shape curE = MEW.FindKey(ie);
3230 if (mapAcceptedEdges.Contains(curE)) continue;
3233 TopTools_ListOfShape currentChain;
3234 TopTools_ListOfShape listPrevEdges;
3236 currentChain.Append(curE);
3237 listPrevEdges.Append(curE);
3238 mapAcceptedEdges.Add(curE);
3240 // Collect all edges pass by pass
3241 while (listPrevEdges.Extent() > 0) {
3242 // List of edges, added to chain on this cycle pass
3243 TopTools_ListOfShape listCurEdges;
3245 // Find the next portion of edges
3246 TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
3247 for (; itE.More(); itE.Next()) {
3248 TopoDS_Shape anE = itE.Value();
3250 // Iterate on faces, having edge <anE>
3251 TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
3252 for (; itW.More(); itW.Next()) {
3253 TopoDS_Shape aW = itW.Value();
3254 TopoDS_Shape anOppE;
3256 BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
3257 Standard_Integer nb = 1, found = 0;
3258 TopTools_Array1OfShape anEdges (1,4);
3259 for (; aWE.More(); aWE.Next(), nb++) {
3264 anEdges(nb) = aWE.Current();
3265 if (anEdges(nb).IsSame(anE)) found = nb;
3268 if (nb == 5 && found > 0) {
3269 // Quadrangle face found, get an opposite edge
3270 Standard_Integer opp = found + 2;
3271 if (opp > 4) opp -= 4;
3272 anOppE = anEdges(opp);
3274 if (!mapAcceptedEdges.Contains(anOppE)) {
3275 // Add found edge to the chain
3276 currentChain.Append(anOppE);
3277 listCurEdges.Append(anOppE);
3278 mapAcceptedEdges.Add(anOppE);
3280 } // if (nb == 5 && found > 0)
3281 } // for (; itF.More(); itF.Next())
3282 } // for (; itE.More(); itE.Next())
3284 listPrevEdges = listCurEdges;
3285 } // while (listPrevEdges.Extent() > 0)
3287 // Sort shapes in current chain (Mantis issue 21053)
3288 GEOMUtils::SortShapes(currentChain, Standard_False);
3289 aFirstInChains.Append(currentChain.First());
3290 aMapChains.Bind(currentChain.First(), currentChain);
3293 // Sort chains (Mantis issue 21053)
3294 GEOMUtils::SortShapes(aFirstInChains, Standard_False);
3296 // Store sorted chains in the document
3297 TopTools_ListIteratorOfListOfShape aChainsIt (aFirstInChains);
3298 for (; aChainsIt.More(); aChainsIt.Next()) {
3299 TopoDS_Shape aFirstInChain = aChainsIt.Value();
3300 const TopTools_ListOfShape& currentChain = aMapChains.Find(aFirstInChain);
3302 // Store the chain in the document
3303 Handle(TColStd_HArray1OfInteger) anArray =
3304 new TColStd_HArray1OfInteger (1, currentChain.Extent());
3306 // Fill array of sub-shape indices
3307 TopTools_ListIteratorOfListOfShape itSub (currentChain);
3308 for (int index = 1; itSub.More(); itSub.Next(), ++index) {
3309 int id = anIndices.FindIndex(itSub.Value());
3310 anArray->SetValue(index, id);
3313 // Add a new group object
3314 Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
3317 aChain->SetType(GEOM_GROUP);
3319 // Set a sub-shape type
3320 TDF_Label aFreeLabel = aChain->GetFreeLabel();
3321 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
3323 // Add the chain to the result
3324 aSeq->Append(aChain);
3326 //Make a Python command
3327 TDF_Tool::Entry(aChain->GetEntry(), anEntry);
3328 aListRes += anEntry + ", ";
3331 if (aSeq->IsEmpty()) {
3332 SetErrorCode("There are no quadrangle faces in the shape");
3336 aListRes.Trunc(aListRes.Length() - 2);
3338 // The Propagation doesn't change object so no new function is required.
3339 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
3341 // Make a Python command
3342 GEOM::TPythonDump(aFunction, /*append=*/true)
3343 << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";